Greasy Fork is available in English.

irccloud formatting helper

Intercept ctrl+i and ctrl+b on irccloud and add the relevant

// ==UserScript==
// @name         irccloud formatting helper
// @namespace    http://example.com/
// @version      0.1
// @description  Intercept ctrl+i and ctrl+b on irccloud and add the relevant
//               control characters.
// @author       Steve Howard
// @match        https://www.irccloud.com/*
// @grant        none
// ==/UserScript==
/* jshint -W097 */
'use strict';

/**
 * formatHelper: String -> String
 * Converts IRC control characters to HTML tags to preview formatting
 */
function formatForBrowser (str) {
    var controlCharRegex = /(\x1d|\x02)/g;
    var pieces = str.split(controlCharRegex);
    var output = [];

    var bold = false, italic = false;

    for (var i = 0, end = pieces.length; i < end; ++i) {
        var piece = pieces[i];

        if (piece.match(/\x1d/)) {
            italic = !italic;
            output.push(italic ? '<i>' : '</i>');
        }
        else if (piece.match(/\x02/)) {
            bold = !bold;
            output.push(bold ? '<b>' : '</b>');
        }
        else {
            output.push(piece);
        }
    }

    return output.join('');
}

/**
 * createOverlay: Node -> Node
 * Creates a div that copies the same 
 */
function createOverlay (msg) {
    var o = document.createElement('div');
    o.style.width = msg.style.width;
    o.style.height = msg.style.height;
    o.style.whiteSpace = 'pre';

    o.addEventListener('click', function () { 
        msg.focus();
    });
    
    msg.addEventListener('keyup', function () {
        // Can't just make this a global variable because RegExps store state
        var controlCharRegex = /(\x1d|\x02)/g;
        if (controlCharRegex.test(msg.value)) {
            // If there were control characters, use the overlay/side by side view to preview message
            // Easier to check the contents than inspect the state from the above; clears itself when necessary
            o.innerHTML = formatForBrowser(msg.value);
            o.style.display = 'block';
        }
        else {
            // otherwise the text box by itself is much faster
            o.style.display = 'none';
        }
    });

    return o;
}


function main (msg) {
    var overlay = createOverlay(msg);
    msg.parentNode.appendChild(overlay);

    function keyHandler (e) {
        function emitControlCharacter (c) {
            var st = msg.selectionStart, en = msg.selectionEnd;

            // check for text selection. If so, insert control character twice
            if (st < en) {
                var val = msg.value;
                msg.value = val.substring(0, st) + c + val.substring(st, en) + c + val.substring(en);
            }
            else {
                msg.value += c;
            }
        }

        if (e.ctrlKey) {
            switch (e.keyCode) {
                case 73: // 'i'
                    emitControlCharacter('\x1d');
                    break;

                case 66: // 'b'
                    emitControlCharacter('\x02');
                    break;
            }
        }
    }

    msg.addEventListener('keyup', keyHandler);
}

(function () {
    var initialized = {};
    
    var observer = new MutationObserver(function (mutations) {
        mutations.forEach(function (mutation) {
            Array.from(mutation.addedNodes).forEach(function (node) {
                var msg = node.querySelector && node.querySelector('[name=msg]');
                if (msg && !initialized[msg.id]) {
                    main(msg);
                    initialized[msg.id] = true;
                }
            });
        });
    });

    observer.observe(document.body, { childList: true, subtree: true });
})();