Guide Lines Mod for Vivaldi



  • Preview
    0_1513441083719_GIF.gif

    Motivation
    I was recently reading some papers in a pdf and, the print being quite small and compact, I found myself having trouble following the line wraps. Were the pdf printed, I could just place another piece of paper on top and use that as a guide, but I wanted something in-browser. I am aware of certain extensions that can add rulers to the screen, but...

    A) I have no idea what is in, nor any inclination to dive into some else's extension code
    B) These solutions are a bit overkill for what I wanted*
    C) I wanted to build a solution myself

    Installation
    This is installed as a custom.js mod:

    /*
    * GUIDES for Vivaldi (a mod for Vivaldi)
    * Written by LonM
    * No Copyright Reserved
    */
    "use strict";
    
    // New buttons will be added as children of these elements
    const BUTTON_QUERY = "#footer > div.status-toolbar > span.captureactions";
    
    const GUIDELINES_CSS = `
    .browser-guide {
        display: block;
        background: var(--colorAccentBg);
        position: fixed;
    }
    .browser-guide-vertical {
        height: 100vh;
        width: 3px;
        cursor: ew-resize;
        top: 0px !important;
    }
    
    .browser-guide-horizontal {
        width: 100vw;
        height: 3px;
        cursor: ns-resize;
        left: 0px !important;
    }
    `;
    
    let GUIDE_COUNT = 0;
    // Dragging - a guide will move with the cursor until the mouse button is let go
    let CURRENTLY_DRAGGING = [];
    // Following - a guide will move with the cursor until the mouse is clicked
    let CURRENTLY_FOLLOWING = [];
    
    // Initialiser on browser load
    setTimeout(function waitForBrowser(){
        const button_loc = document.querySelector(BUTTON_QUERY);
        if (button_loc) {
            create_buttons();
            inject_css();
            document.addEventListener("mousemove", browser_cursor_move);
        } else {
            setTimeout(waitForBrowser, 500);
        }
    }, 500)
    
    // Add the "create guide" buttons to browser
    function create_buttons(){
        const new_button_h = document.createElement("button");
        new_button_h.innerHTML = "—";
        new_button_h.className = "button-toolbar-small";
        new_button_h.addEventListener("click", function(e){
            new_guide_clicked(e, "browser-guide-horizontal");
        });
        
        const new_button_v = document.createElement("button");
        new_button_v.innerHTML = "|";
        new_button_v.className = "button-toolbar-small";
        new_button_v.addEventListener("click", function(e){
            new_guide_clicked(e, "browser-guide-vertical");
        });
    
        document.querySelector(BUTTON_QUERY).appendChild(new_button_h);
        document.querySelector(BUTTON_QUERY).appendChild(new_button_v);
    }
    
    // Inject css so a separate modfile is not required
    function inject_css(){
        const style = document.createElement('style');
        style.innerHTML = GUIDELINES_CSS;
        document.body.appendChild(style);
    }
    
    // Create a new guide and make it follow the cursor
    function new_guide_clicked(e, classname){
        const new_guide = document.createElement("div");
        new_guide.className = "browser-guide "+classname;
        new_guide.addEventListener("mousedown", guide_drag_start);
        new_guide.addEventListener("mouseup", guide_drop);
        new_guide.style.top = e.clientY + "px";
        new_guide.style.left = e.clientX + "px";
        new_guide.id = "guide-" + GUIDE_COUNT;
        GUIDE_COUNT++;
        document.body.appendChild(new_guide);
        CURRENTLY_FOLLOWING.push(new_guide.id);
    }
    
    // Clicked a guide
    function guide_drag_start(e){
        const cf_index = CURRENTLY_FOLLOWING.indexOf(e.target.id);
        const cm_index = CURRENTLY_DRAGGING.indexOf(e.target.id);
        // If currently following, stop following
        if(cf_index >= 0){
            delete CURRENTLY_FOLLOWING[cf_index];
        }
        // ALT key pressed - delete this guide
        if(e.altKey){
            const selected_guide = document.querySelector("#"+e.target.id);
            selected_guide.parentElement.removeChild(selected_guide);
            // Clean up any drag references to the guide
            if(cm_index >= 0){
                delete CURRENTLY_DRAGGING[index];
            }
            return;
        }
        if(e.shiftKey){
            // SHIFT key pressed - start following
            if(cf_index === -1){
                CURRENTLY_FOLLOWING.push(e.target.id);
            }
        } else {
            // Guide starts dragging
            if(cm_index === -1){
                CURRENTLY_DRAGGING.push(e.target.id);
            }
        }
    }
    
    // Moved the mouse - move any guides currently being dragged or any that are following the cursor
    function browser_cursor_move(e){
        [CURRENTLY_DRAGGING,CURRENTLY_FOLLOWING].forEach(guide_list => {
            guide_list.forEach(guide => {
                const selected_guide = document.querySelector("#"+guide);
                if(!selected_guide){return;}
                selected_guide.style.left = e.clientX + "px";
                selected_guide.style.top = e.clientY + "px";
            });
        });
    }
    
    // Mouse let go - Any currently dragged guides should be dropped
    function guide_drop(e){
        CURRENTLY_DRAGGING = [];
    }
    

    Usage

    • Once installed you will need to restart the browser.
    • The guide buttons are added to the status bar.
    • Click the | button in the status bar to add a vertical guide.
    • Click the button to add a horizontal guide.
    • After creating a new guide it follows the mouse. Click to place it down.
    • Click and drag any guide to move it, letting go to place it down.
    • Press and hold "Shift" and click any guide to have it follow your cursor until you next click.

    Note: You can let go of shift once the guide is following your cursor

    • You can shift+click multiple guides.

    Note: The guides are stacked on top of each other in the browser DOM when created. If you want to select multiple, shift-click the first created guide (the one underneath), and then the second created (the one on top).

    • Press and hold "Alt" and click a guide to delete it
    • The guides appear on the browser itself, so are visible regardless of which tab you use. They are restricted to the current window and don't remember their existence when you close the window.

    Configuration

    • You can change the colour and size of the guides by editing the CSS within the script. By default it uses the browser accent colour.
    • You can change the "hotkeys" used (Shift and Alt) by editing the e.altKey and e.shiftKey references to one of the command keys defined here (e.g. Shift, Alt, Meta and Ctrl).

    The keys might be called something else on a mac, I'm not sure.

    • You can change the location the buttons are added to by editing the BUTTON_QUERY variable. Note you may also need to change the button class in the new_guide_clicked function if you're putting it somewhere other than the status bar.

    Remarks
    This is an experimental mod, so feel free to test it and let me know of any problems it has.
    When a guide is deleted, an error is logged to the browser console Cannot read property 'draggable' of null, this seems to be something within the vivaldi code that handles the events on browser dom elements - I have no idea how to fix this.

    *I am aware that it is also overkill to make a browser mod. I also have no idea how to properly format B ) so that it doesn't turn into an emoji in this forum.



  • Hi LonM,
    really nice mod you wrote. First time I saw it, I had no use case for this. But now I had a climate-graph with a rough graduation and for that the guide lines were really useful. Thanks.
    The only thing that didn't work was to delete a guide. The AltKey-Event doesn't seems to reach the script. So I changed it to a CtrlKey-Event and now it's fine.
    I also made a little change to the function guide_drag_start(e), using an if-else if -else-Block.

    // Clicked a guide
    function guide_drag_start(e){
        const cf_index = CURRENTLY_FOLLOWING.indexOf(e.target.id);
        const cm_index = CURRENTLY_DRAGGING.indexOf(e.target.id);
        // If currently following, stop following
        if(cf_index >= 0){
            delete CURRENTLY_FOLLOWING[cf_index];
        }
        // CTRL key pressed - delete this guide
        else if(e.ctrlKey){
            const selected_guide = document.querySelector("#"+e.target.id);
            selected_guide.parentElement.removeChild(selected_guide);
            // Clean up any drag references to the guide
            if(cm_index >= 0){
                delete CURRENTLY_DRAGGING[index];
            }
            return;
        }
        else if(e.shiftKey){
            // SHIFT key pressed - start following
            if(cf_index === -1){
                CURRENTLY_FOLLOWING.push(e.target.id);
            }
        } else {
            // Guide starts dragging
            if(cm_index === -1){
                CURRENTLY_DRAGGING.push(e.target.id);
            }
        }
    }
    

    Don't know if it has to do with that, but I've no error logged to the browser console when deleting a guide.



  • @lonm You and your mods are awesome <3


Log in to reply
 

Looks like your connection to Vivaldi Forum was lost, please wait while we try to reconnect.