C&C: Tiberium Alliances Chat Helper Enhanced Yiannis Mod

Automates the use of chat and message BB-Codes: [coords][url][player][alliance][b][i][s][u] - Contact list for whispering - Type /chelp <enter> in chat for help.

// ==UserScript==
// @name        C&C: Tiberium Alliances Chat Helper Enhanced Yiannis Mod
// @namespace   https://prodgame*.alliances.commandandconquer.com/*/index.aspx*
// @description Automates the use of chat and message BB-Codes: [coords][url][player][alliance][b][i][s][u] - Contact list for whispering - Type /chelp <enter> in chat for help.
// @include     https://prodgame*.alliances.commandandconquer.com/*/index.aspx*
// @version     3.2.1
// @icon        https://sites.google.com/site/titlemod/home/favicon.png
// @grant       none
// ==/UserScript==
 
// type: /chelp in any text box and hit <enter> for a list of commands
 
// Please report urls that are not tagged properly
 
// window.chatHelper_suppressBrowserAltKeys suppresses normal browser menu keys [Alt+(a,p,b,i,u,s)] when you are in a textarea so that the menus don't open.
 
(function () {
    var chatHelper_main = function () {
        window.chatHelper_debug = 0; //initial debug level, top level for easy console access
        var chlog = function chlog(str,lvl){
            if (lvl > 0) { //lvl 1+
                if (window.chatHelper_debug == 1) { // lvl 1
                    console.log("ChatHelper_debug: "+str+"\n");
                }
                if (window.chatHelper_debug == 2) { // lvl 2
                    console.log("ChatHelper_debug: "+str+"\n");
                }
 
            } else { //lvl 0 or no arg passed to lvl
                console.log("ChatHelper_log: "+str+"\n");
            }
        };
        try {
            function createchatHelper() {
                var onkeyupDelay = 50; //ms to wait after a keyupevent before searching contacts list. Lower for faster searching. Higher for better performance.
                window.chatHelper_suppressBrowserAltKeys = true;
                window.chatHelper_version = "3.2.0";
                window.chatHelper_name = "C&C: Tiberium Alliances Chat Helper Enhanced";
                chlog(window.chatHelper_name + ' v' + window.chatHelper_version + ': loading.',0);
                var saveObj = {
                    saveObjVer : "3.2.0",
                    contacts : []
                };
 
                var validCharPatt = /[-\w\.]/;
                var isWhisp = false;
                var contacts = [];
                var timer;
                var _sub;
 
 
                function getCaretPos(obj) {
                    // getCaretPos from: http://userscripts.org/scripts/show/151099
                    obj.focus();
 
                    if (obj.selectionStart) {
                        return obj.selectionStart; //Gecko
                    } else if (document.selection) //IE
                    {
                        var sel = document.selection.createRange();
                        var clone = sel.duplicate();
                        sel.collapse(true);
                        clone.moveToElementText(obj);
                        clone.setEndPoint('EndToEnd', sel);
                        return clone.text.length;
                    }
 
                    return 0;
                }
 
                function moveCaret(inputObject, pos) {
                    // moveCaretPos from: http://userscripts.org/scripts/show/151099
                    if (inputObject.selectionStart) {
                        inputObject.setSelectionRange(pos, pos);
                        inputObject.focus();
                    }
                }
 
                function getCursorWordPos(inputField) {
                    var pos = getCaretPos(inputField);
                    var inText = inputField.value;
                    var lc = inText.charAt(pos - 1);
                    if (lc.match(validCharPatt) !== null) {
                        var sPos = pos;
                        var ePos = pos;
                        var t = inputField.value;
                        while (sPos >= 0 && t.charAt(sPos - 1).match(validCharPatt) !== null) {
                            sPos--;
                        }
                        while (ePos <= t.length && t.charAt(ePos).match(validCharPatt) !== null) {
                            ePos++;
                        }
                        //inputField.setSelectionRange(sPos,ePos);
                        return [sPos, ePos];
                    }
                }
 
                function tagWith(tag, inputField) {
                    var eTag = tag.replace('[', '[/'); //closing tag
                    var tagLen = tag.length;
                    var eTagLen = eTag.length;
                    if (inputField !== null) {
                        var pos = getCaretPos(inputField);
                        var inText = inputField.value;
                        //save scroll position
                        if (inputField.type === 'textarea')
                            var st = inputField.scrollTop;
                        //if there is selected text
                        if (inputField.selectionStart !== inputField.selectionEnd) {
                            var a = inText.slice(0, inputField.selectionStart);
                            var b = inText.slice(inputField.selectionStart, inputField.selectionEnd);
                            var c = inText.slice(inputField.selectionEnd, inText.length);
                            inputField.value = a + tag + b + eTag + c;
                            moveCaret(inputField, pos + tagLen + eTagLen + b.length);
                            //if ((input IS empty) OR (the last char was a space)) AND next char ISNOT a left sqbracket
                        } else if ((inText === "" || inText.charAt(pos - 1) === " ") && (inText.charAt(pos) !== '[')) {
                            inputField.value = inText.substr(0, pos) + tag + eTag + inText.substr(pos, inText.length);
                            moveCaret(inputField, pos + tagLen);
                            //if last character is a valid playername character
                        } else if (inText.charAt(pos - 1).match(validCharPatt) !== null) {
                            var arr = getCursorWordPos(inputField); //
                            var s = arr[0];
                            var e = arr[1];
                            inputField.value = inText.slice(0, s) + tag + inText.slice(s, e) + eTag + inText.slice(e, inText.length);
                            moveCaret(inputField, e + tagLen + eTagLen);
                        }
                        //restore scroll position
                        if (inputField.type === 'textarea')
                            inputField.scrollTop = st;
                    }
                }
 
                function showHelp() {
                    alert("Type /chelp in any text box to show this message.\n\nEnter key in chat:\tsearches your chat string for Urls and Coords and wraps them before submission.\n\nAlt + 1\t:\tsearches for Urls and Coords in a message or forum post and tags accordingly. Cursor is moved to the beginning.\nAlt + 2\t:\tManual URL insertion popup window\nAlt + 0\t:\tclears all tags\n\nWord wraps: tags a selected word -or- tags the word where the cursor is (if chat is empty or you hit <space> empty tags are inserted).\nAttempts to preserve cursor and scroll position.\n|\tAlt + p or Alt + 3\t:\tplayer tags\n|\tAlt + a or Alt + 4\t:\talliance tags\n|\tAlt + b\t\t\t:\tbold tags\n|\tAlt + i\t\t\t:\titalic tags\n|\tAlt + u\t\t\t:\tunderline tags\n|__\tAlt + s\t\t\t:\tstrikethrough tags\n\nContact list commands:\n/list -or- /contacts\n/add\n/del\n/del all - wipes your whole contact list");
                }
 
                function saveData() {
                    saveObj.contacts = contacts;
                    var jString = JSON.stringify(saveObj);
                    chlog("saveJSON: "+jString, 1);
                    localStorage.setItem('chatHelper', jString);
                }
 
                function loadData() {
                    try{
                        if (localStorage.getItem('myContacts')) { //should be removed eventually
                            var dat = localStorage.getItem('myContacts');
                            dat = dat.split(',');
                            saveObj.contacts = dat;
 
                            //unset old storage 
                            localStorage.removeItem('myContacts');
                        } else if (localStorage.getItem('chatHelper')) {
                            var saveObjTmp = JSON.parse(localStorage.getItem('chatHelper'));
                            if (saveObjTmp.saveObjVer != window.chatHelper_version){
                                //version changed
                                var va = saveObjTmp.saveObjVer.split('.');
                                var vb = window.chatHelper_version.split('.');
 
                                if (va[0] != vb[0]){ //major version change
                                    chlog("ChatHelper: Major version change from v"+va[0]+"."+va[1]+"."+va[2]+" to v"+vb[0]+"."+vb[1]+"."+vb[2]);
                                } else {
                                    if (va[1] != vb[1]){ //minor version change
                                        chlog("ChatHelper: Minor version change from v"+va[0]+"."+va[1]+"."+va[2]+" to v"+vb[0]+"."+vb[1]+"."+vb[2]);
                                    } else {
                                        if (va[2] != vb[2]){ //patch release
                                            chlog("ChatHelper: Version Patched from v"+va[0]+"."+va[1]+"."+va[2]+" to v"+vb[0]+"."+vb[1]+"."+vb[2]);
                                        }
                                    }
                                }
                            } else {
                                //no version change
                                localStorage.getItem('chatHelper');
                            }
                            saveObj = saveObjTmp;
                        }
                        contacts = saveObj.contacts;
                        saveData();
                    }catch(err){
                        chlog(err);
                    }
                }
 
                if (!localStorage.myContacts) {
                    chlog("Deprecated contacts variable does not exist.",1);
                    loadData();
                } else {
                    //contacts = loadData();
                    loadData();
                    chlog("Contacts: " + contacts, 1);
                }
 
                function saveContact(fr) {
                    chlog("Number of contacts == "+contacts.length,1);
                    contacts.push(fr);
                    chlog(fr + " added to contacts list.",1);
                    saveData();
                }
 
                function caseInsensitiveSort(a, b) {
                    a = a.toLowerCase();
                    b = b.toLowerCase();
                    if (a > b)
                        return 1;
                    if (a < b)
                        return -1;
                    return 0;
                }
 
                function listContacts() {
                    var len = contacts.length;
                    var a = contacts.sort(caseInsensitiveSort);
                    if (len == 1) {
                        alert(len + " Contact:\n\n" + a.join("\n") + "\n");
                    } else if (len > 1) {
                        alert(len + " Contacts:\n\n" + a.join("\n") + "\n");
                    } else {
                        var p = prompt("Your contacts list is empty.\n\nType a name here to add a contact:\n", "");
                        if (p) {
                            saveContact(p);
                        }
                    }
                }
 
                function deleteContact(fr) {
                    if (fr === "all") {
                        contacts = [];
                        chlog("All contacts deleted",1);
                        saveData();
                    } else {
                        var ind = contacts.indexOf(fr);
                        if (ind > -1) {
                            saveObj.contacts = contacts.splice(ind, 1);
                            saveData();
                            chlog(contacts,1);
                            chlog(fr + " deleted from contacts list.");
                        }
                    }
                }
                function keyUpTimer(kEv) {
                    kEv = kEv || window.event;
                    if (kEv.target.type === "text" && kEv.target.value !== '') {
                        var inputField = kEv.target;
                        var inText = inputField.value;
                        var len = inText.length;
                        var sub;
                        var kc = kEv.keyCode;
                        if (len >= 10 && inText.match(/^(\/whisper)/) !== null) {
                            isWhisp = true;
                        }
                        if (isWhisp && len >= 10 && !kEv.altGraphKey && !kEv.ctrlKey && !kEv.altKey && kc > 47 && kc < 91) {
                            chlog("keyUpTimer keyCode =="+kEv.keyCode,1);
                            sub = inText.substr(9);
                            if (!sub.match(/\s/)) {
                                for (var i = 0; i < contacts.length; i++) {
                                    var slen = sub.length;
                                    if (contacts[i][slen - 1] === sub[slen - 1] && contacts[i].substr(0, slen) == sub) {
                                        inputField.value = "/whisper " + contacts[i] + " ";
                                        inputField.setSelectionRange(10 + slen - 1, 10 + contacts[i].length, "forward");
                                    }
                                }
                            } else {
                                isWhisp = false;
                            }
                        } else {
                            isWhisp = false;
                        }
                    }
                }
 
                document.onkeyup = function (kEv) {
                    clearTimeout(timer);
                    timer = setTimeout(function () {
                        keyUpTimer(kEv);
                    }, onkeyupDelay);
                };
 
                function delayedConfirm() {
                    if (confirm("Add " + _sub + " to your contacts list?\n\nYou can see a list of your contacts by typing /list")) {
                        saveContact(_sub);
                    }
                }
 
                function autoTag(inputField, inText) {
//                    var isUrl = false;
//                    var lookBack;
                    ////auto coords
                    inText = inText.replace(/(\[coords\])*([0-9]{3,4})[:|.]([0-9]{3,4})([:|.]\w+)?(\[\/coords\])*/gi, function(){
                        var result = new Array();
                        result.push('[coords]');
                        result.push(arguments[2]);
                        result.push(':');
                        result.push(arguments[3]);
                        if(arguments[4] !== undefined) {
                            result.push(arguments[4].replace('.',':'));
                        }
                        result.push('[/coords]');
                        return result.join('');
                    });                    // shorthand for player
                    ////auto url
                    inText = inText.replace(/(\[url\])*(https?:\/\/)?([\da-z\.-]+)(\.[a-z]{2,6})([\/\w\.\-\=\?\&#]*)*\/?(\[\/url\])*/gi, function(){
                        var result = new Array();
                        result.push('[url]');
                        result.push(arguments[2]); // http[s]://
                        result.push(arguments[3]); // domain
                        result.push(arguments[4]); // ext
                        result.push(arguments[5]); // query string
                        result.push('[/url]');
                        return result.join('');
                    });
                    inText = inText.replace(/\[p\]([a-z0-9_\-\s]+)\[\/p\]/gi, '[player]$1[/player]');
                    // shorthand for alliance
                    inText = inText.replace(/\[a\]([a-z0-9_\-\s]+)\[\/a\]/gi, '[alliance]$1[/alliance]');
 
                    return inText;
                }
 
                document.onkeydown = function (kEv) {
                    kEv = kEv || window.event;
 
                    /* Tab key
                    if (kEv.keyCode == 9){
                        chlog("Tab key pressed",1)
                        var input = qx.core.Init.getApplication().getChat().getChatWidget().getEditable(); // Input
                        kEv.preventDefault();
                        kEv.stopPropagation();
                    }
                     */
                    if (kEv.keyCode === 13) {
                        var inputField = document.querySelector('input:focus, textarea:focus');
                        var inText = inputField.value;
                        var add = inText.match(/^(\/add)/);
                        var del = inText.match(/^(\/del)/);
                        var showContacts = inText.match(/^((\/contacts)|(\/list))/);
                        var sub;
                        var cf;
                        if (inText.match(/^(\/whisper)/) !== null || add !== null) {
                            if (add !== null) {
                                sub = inText.substr(5);
                            } else {
                                sub = inText.substr(9);
                            }
                            if (sub.match(/^(\w*)\s/)) {
                                //if space after player name (is a whisper or a typo)
                                var arr = sub.match(/^(\w*)/);
                                sub = arr[0].replace(/\s$/, "");
                                if (contacts.indexOf(sub) == -1) {
                                    //not in contacts list
                                    _sub = sub;
                                    setTimeout(delayedConfirm, 500);
                                }
                            } else if (contacts.indexOf(sub) == -1) {
                                //no message to send, not in contacts, promt to add, clear input
                                chlog("clearing input field",1);
                                inputField.focus(); //?necessary?
                                inputField.value = "";
                                var cf = confirm("Add " + sub + " to your contacts list?\n\nYou can see a list of your contacts by typing /list");
                                if (cf) {
                                    saveContact(sub);
                                    return false;
                                } else {
                                    return false;
                                }
                            } else if (sub && contacts.indexOf(sub) > -1) {
                                //not a whisper, reject duplicate contact
                                alert(sub + " is already in your contacts list.");
                            }
                        }
                        //remove contact(s)
                        if (del) {
                            sub = inText.substr(5);
                            chlog("clearing input field",1);
                            inputField.value = "";
                            if ((contacts.indexOf(sub) > -1 || sub == "all") && confirm("Really delete " + sub + " from your contacts?")) {
                                deleteContact(sub);
                            } else {
                                alert(sub + " is not in your contacts list.");
                            }
                            return false;
                        }
                        // show contacts list
                        if (showContacts) {
                            chlog("clearing input field",1);
                            inputField.value = "";
                            listContacts();
                            return false;
 
                        }
                        // /chelp dialog
                        if (inText.length === 6 && inText.match(/^(\/chelp)/) !== null) {
                            chlog("clearing input field",1);
                            inputField.value = "";
                            showHelp();
                            return false;
                        }
 
                        if (inputField !== null) {
                            chlog("onEnter auto-tagging",1);
 
                            inText = autoTag(inputField, inText); //auto-tag
 
                            if (inText !== inputField.value) {
                                inputField.value = inText;
                            }
                        }
                    }
 
                    if (kEv.altKey && !kEv.shiftKey && !kEv.altGraphKey && !kEv.ctrlKey && kEv.target !== null && (kEv.target.type === "textarea" || kEv.target.type === "text")) {
                        var inputField = kEv.target;
                        var inText = inputField.value;
                        // Alt key, not Ctrl or AltGr
                        if (kEv.altKey && !kEv.altGraphKey && !kEv.ctrlKey) {
                            var cc = kEv.charCode;
                            var kc = kEv.keyCode;
                            chlog("charCode == "+cc,1);
                            chlog("keyCode == "+kc,1);
 
                            /* Alt+1 for auto Coordinates/Urls in message body */
                            if (inputField.type === "textarea" && (cc === 49 || kc === 49)) {
                                var pos = getCaretPos(inputField);
                                chlog("attempting Alt+1 message auto-tag",1);
                                if (inputField !== null) {
                                    var st = inputField.scrollTop;
 
                                    inText = autoTag(inputField, inText); //auto-tag
 
                                    if (inText !== "" || inText !== inputField.value) {
                                        inputField.value = inText;
                                        inputField.scrollTop = st;
                                        moveCaret(inputField, 0);
                                    }
                                }
                            }
                            /* Alt+2 for URLs fallback */
                            if (cc === 50 || kc === 50) {
                                if (inputField !== null) {
                                    var url = prompt("Website (Syntax: google.com or www.google.com)", "");
                                    if (url !== null) {
                                        inputField.value += '[url]' + url + '[/url]';
                                    }
                                }
                            }
                            /* Alt+3 or Alt+p for players */
                            if ((cc === 112 || kc === 80) || (cc === 51 || kc === 51)) {
                                tagWith('[player]', inputField);
                                if (window.chatHelper_suppressBrowserAltKeys)
                                    return false;
                            }
                            /* Alt+4 or Alt+a for alliances */
                            if ((cc === 97 || kc === 65) || (cc === 52 || kc === 52)) {
                                tagWith('[alliance]', inputField);
                                if (window.chatHelper_suppressBrowserAltKeys)
                                    return false;
                            }
                            /* Alt+0 to clear tags */
                            if (cc === 48 || kc === 48) {
                                if (inputField.type === 'textarea')
                                    var st = inputField.scrollTop;
                                if (inputField !== null) {
                                    inText = inText.replace(/\[\/?coords\]/gi, '');
                                    inText = inText.replace(/\[\/?url\]/gi, '');
                                    inText = inText.replace(/\[\/?player\]/gi, '');
                                    inText = inText.replace(/\[\/?alliance\]/gi, '');
                                    inText = inText.replace(/\[\/?b\]/gi, '');
                                    inText = inText.replace(/\[\/?i\]/gi, '');
                                    inText = inText.replace(/\[\/?u\]/gi, '');
                                    inText = inText.replace(/\[\/?s\]/gi, '');
                                    inputField.value = inText;
                                }
                                if (inputField.type === 'textarea')
                                    inputField.scrollTop = st;
                            }
                            /* Alt+b for bold */
                            if (cc === 98 || kc === 66) {
                                tagWith('[b]', inputField);
                                if (window.chatHelper_suppressBrowserAltKeys)
                                    return false;
                            }
                            /* Alt+i for italics */
                            if (cc === 105 || kc === 73) {
                                tagWith('[i]', inputField);
                                if (window.chatHelper_suppressBrowserAltKeys)
                                    return false;
                            }
                            /* Alt+u for underline */
                            if (cc === 117 || kc === 85) {
                                tagWith('[u]', inputField);
                                if (window.chatHelper_suppressBrowserAltKeys)
                                    return false;
                            }
                            /* Alt+s for strikethrough */
                            if (cc === 115 || kc === 83) {
                                tagWith('[s]', inputField);
                                if (window.chatHelper_suppressBrowserAltKeys)
                                    return false;
                            }
                        }
                    }
                };
           }
    }catch (err) {
        chlog("createchatHelper: "+ err,1);
        console.error(err);
        }
 
    function chatHelper_checkIfLoaded() {
        try {
            if (typeof qx !== 'undefined') {
                createchatHelper();
            } else {
                window.setTimeout(chatHelper_checkIfLoaded, 1333);
            }
        } catch (err) {
            console.log("chatHelper_checkIfLoaded: ", err);
        }
    }
    window.setTimeout(chatHelper_checkIfLoaded, 1333);
};
 try {
 var chatHelper = document.createElement("script");
chatHelper.innerHTML = "(" + chatHelper_main.toString() + ")();";
chatHelper.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(chatHelper);
} catch (err) {
    console.log("chatHelper: init error: ", err);
}
})();