// ==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);
}
})();