18

Shows a select-button on mouse over on code-blocks to select the whole block for easier copying.

Sorry to not provide a file for download but i am sure you will manage somehow, adjust includes as needed:

// ==UserScript==
// @name           Select Code Block Buttons
// @namespace      stackoverflow
// @include        *stackoverflow.com*
// @version        2.0.0
// ==/UserScript==

// @ts-check

(function ()
{
    const style = `
        div > .gm_select_button {
            position: absolute !important;
            border: none !important;
            outline: none !important;
            cursor: pointer !important;
            background-color: black !important;
            color: white !important;
            font-size: 12px !important;
            padding: 3px !important;
            top: 0 !important;
            right: 0 !important;
            transition: opacity linear 0.3s !important;
            will-change: opacity !important;

            opacity: 0;
        }
        div:hover > .gm_select_button {
            opacity: 0.5 !important;
        }
    `;
    const styleNode = document.createElement("style");
    styleNode.type = "text/css";
    styleNode.innerHTML = style;
    document.head.appendChild(styleNode);

    [...document.querySelectorAll("pre")].forEach((codeBlock, i) =>
    {
        const container = document.createElement("div");
        container.style.position = "relative";
        codeBlock.parentElement.replaceChild(container, codeBlock);
        container.appendChild(codeBlock);

        const button = document.createElement("button");
        button.classList.add("gm_select_button");
        button.textContent = "Select";
        container.appendChild(button);

        button.addEventListener("click", () => selectText(codeBlock));
    });

    function selectText(element)
    {
        if (document.body.createTextRange)
        {
            var range = document.body.createTextRange();
            range.moveToElementText(element);
            range.select();
        } else if (window.getSelection)
        {
            var selection = window.getSelection();
            var range = document.createRange();
            range.selectNodeContents(element);
            selection.removeAllRanges();
            selection.addRange(range);
        }
    }
})();

Edits:

  • Added the jQuery frame from the SE keyboard shortcuts script.
  • Changed text selection code to be a bit more browser-independent.
  • Buttons are now created on mouse-over, making sure that the placement is correct as the layout may change (e.g. by expanding a comment thread).
  • Removed cancer.
  • Mark the button style properties as !important because they get overridden otherwise.

(Requires a fairly current browser.)

6
  • Has anyone successfully used this in Google-Chrome on MacOSX or Linux?
    – halirutan
    Nov 12, 2012 at 16:09
  • @halirutan: Text selection unfortunately is a bit browser dependent, i changed the code to alleviate that but i did not expect chrome to behave differently in the first place so i do not know if this will change anything for you...
    – brunnerh
    Nov 12, 2012 at 19:35
  • Unfortunately it does not help. When I have time I may try to read JavaScript ;-)
    – halirutan
    Nov 12, 2012 at 20:13
  • It seems like this script removes the ability to comment on posts when used in Tampermonkey under Google Chrome.
    – Werner
    Aug 31, 2015 at 22:09
  • I'd really like to have a button to copy that userscript to my clipboard...
    – Aran-Fey
    May 27, 2018 at 9:30
  • I've been using this with Chrome in Windows 10 for about a year and haven't noticed any issues with interference of commenting on posts. I'm interested if someone has a way to make this also work within apps.Slack.com
    – Ben
    Mar 16, 2020 at 20:32

2 Answers 2

7

Foreword: I have absolutely no idea what I did.

The above script did not work in Chrome. Therefore, I read through some documentation about user-scripts and found that Chrome does not support unsafeWindow. Digging further, I found this answer where @tghw describes how to mimic the behavior. Combining your selector with the approach in the answer gives a script which seems to work in Chrome.

It would be very nice, if you could look over the code and bring it in a clean form.

// ==UserScript==
// @name         Select Code Block Buttons
// @namespace    stack
// @match        https://stackoverflow.com/*
// @match        http://mathematica.stackexchange.com/*
// ==/UserScript==

function addJQuery(callback) {
    var script = document.createElement("script");
    script.setAttribute("src", "//ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js");
    script.addEventListener('load', function() {
        var script = document.createElement("script");
        script.textContent = "(" + callback.toString() + ")();";
        document.body.appendChild(script);
    }, false);
    document.body.appendChild(script);
}

function main()
{

    $(document).ready(addButtons);

    function selectText(element)
    {
        var doc = document;
        if (doc.body.createTextRange)
        {
            var range = doc.body.createTextRange();
            range.moveToElementText(element);
            range.select();
        } else if (window.getSelection)
        {
            var selection = window.getSelection();
            var range = doc.createRange();
            range.selectNodeContents(element);
            selection.removeAllRanges();
            selection.addRange(range);
        }
    }

    function addButtons()
    {
        $("pre").each(function (i, codeBlock)
        {
            var qContainer = $("<div></div>");
            var id = "select-button-" + i;
            $(codeBlock).replaceWith(qContainer);
            qContainer.append(codeBlock);

            qContainer.mouseenter(function ()
            {
                var qButton = $('<div style="position: absolute; opacity: 0; display: inline; cursor: pointer;' +
                                 'background-color: #000; color: #fff; font-size: 12pt; padding: 3px;">' +
                                 'Select</div>');
                qButton.attr("id", id);
                qContainer.append(qButton);
                var left = $(codeBlock).offset().left + $(codeBlock).width() - qButton.width();
                var top = $(codeBlock).offset().top;
                qButton.css("left", left);
                qButton.css("top", top);
                qButton.click(function ()
                {
                    selectText(codeBlock);
                });
                qButton.stop(true, true).animate({ opacity: '+=0.6' });
            });
            qContainer.mouseleave(function ()
            {
                $("#" + id).stop(true, true).animate({ opacity: '-=0.6' }, function () { $("#" + id).remove(); });
            });
        });
    }
}

// load jQuery and execute the main function
addJQuery(main);

Update

As I see now, the Official Keyboard Shortcut Script uses a similar technique. This is maybe a better template how to make it work in both, Chrome and Firefox.

1
  • Thanks for debugging this. I now added the code from the SE keyboard shortcuts. If you want you can test it to see if that also works for you...
    – brunnerh
    Nov 13, 2012 at 18:11
2

Or how about a simple script to select all on double-click? This is my preferred method, since I have terrible aim with my couch keyboard and my large font size often means I've scrolled part of the code block out of view -- namely the part with the "click me" button.

I tried halirutan's script but it seemed to interfere with "add comment" links. So I decided to write my own. Seems to work just fine in Firefox with Greasemonkey and Chrome with Tampermonkey.

// ==UserScript==
// @name        Dbl-Click Select All in Stack Exchange code blocks
// @namespace   http://stackapps.com/
// @description Double-click a code block to select all
// @include     /^https?:\/\/stackoverflow\.com\/.+/
// @include     /^https?:\/\/.*\.stackexchange\.com\/.+/
// @include     /^https?:\/\/stackapps\.com\/.+/
// @version     1
// @grant       none
// ==/UserScript==

function selectAll() {
    var range = document.createRange();
    range.selectNodeContents(this.childNodes[0]);
    var selection = window.getSelection();
    selection.removeAllRanges();
    selection.addRange(range);
}

var pre = document.getElementsByTagName('pre');
for (var i=0; i<pre.length; i++) {
    pre[i].addEventListener('dblclick', selectAll, true);
    pre[i].title = 'double-click to select all';
}

And what's with all the jQuery stuff? These other scripts on this page are much more complicated than they need to be. Not everything has to be done with jQuery, you know. My stars and garters!

3
  • I am not a fan of jQuery, in fact i really dislike it, but if you get into the messy business of modifying pages in hindsight it helps. Ideally you just never do that of course.
    – brunnerh
    Dec 7, 2014 at 19:30
  • As far as I've seen, most of the benefits of jQuery come from allowing modern features to degrade gracefully in older web browsers, and for the various plugins people have written. Otherwise, IMHO, requiring an 85k library to call a function with one line of code that might've taken 5 or 6 lines to write without the library is just lazy and wasteful. The minimal benefit does not justify the cost. I guess I'm too much a crotchety old luddite to understand why jQuery is so popular. My prejudice against jQuery may not be fair, but I just want jQuery to get off my lawn. :)
    – rojo
    Dec 7, 2014 at 19:51
  • Laziness is a virtue for a programmer, to me writing 5 lines of code when it could be replaced by one is just wasteful. I don't really care much about library size, JavaScript files can be cached by the browser like anything else; people worry about things like that too much in my opinion. My biggest issue with jQuery is that it is usually the wrong tool for the tasks it is used and designed for. It is the best hammer for "cutting" planks there is, of course the results will be mediocre at best for obvious reasons. jQuery should die and things like KnockOut and Angular are to take its place.
    – brunnerh
    Dec 8, 2014 at 2:50

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .