// 0.3.3 // - Options accordion. Can be used to turn a feature on and off. // - -dt-'s script compatibility mode // (can be [en/dis]able via the options accordion) // - Forced to be iso-8859-1. // 0.3.2 // - More timeouts for user to go away. // - Better handling of commands.. For example: // /test => "I am testing" // is defined, if you type // /test the shoutbox // it will become I am testing the shoutbox. // - Will no more allow /help to be sent via shoutbox. // - Quick text box is moved to lower-left // - Quick texts sliding... // 0.3.2pre // - Hidden feature requested by MeEtc. // 0.3.1 // - Some commands will not be executed using XMLHttpRequest. // - Hide the menu when the user clicks other places. // 0.3.0 // - When you click on a user's name, you can choose to quote them, view their profile, or send them a PM. // - Quick texts. // - An error message (toast) will be displayed when the post was not sucessful. // 0.2.1 // - Message sending bux fix. // 0.2.0 // - Message sending using XMLHttpRequest. // - Alert when a user comes in or go out. // - Some code rewrited. // - Fixed users online bug. // 0.1.2 // - Some fixes, thanks to WDZ. // - Comments added, so it would be easier to edit. // ==UserScript== // @name Messenger Plus! Live Shoutbox Improvements // @namespace http://www.msghelp.net/ // @description ..... // @include http://msghelp.net/shoutbox.php* // @include *.msghelp.net/shoutbox.php* // @exclude *action=stats* // @exclude *action=edit* // ==/UserScript== (function(window){ // // We prefer to use unsafeWindow's document because it has control over // everything. // var document = window.document; // // WDZ's way to detect the page. If we are not on page 1, bye bye. // var links = document.getElementsByTagName('link')[0]; var i; for (i = 0; i < links.length; i ++) { if (links[i].rel == 'prev') return; } // // No message form? Ahhhh. Bye. // if (typeof document.msgform.message == 'undefined') return; // // Toasters // var alerts = document.createElement('div'); alerts.appendChild (document.createElement('div')); alerts.style.position = 'fixed'; alerts.style.bottom = '0'; alerts.style.right = '0'; document.body.appendChild (alerts); // // This makes the animations smoother // function _smooth(x) { if (x == 1) { return 1; } else if (x == 0) { return 0; } else if (x < 0.5) { x *= 2; x *= x; x /= 2; } else { x *= 2; x -= 1; x = 1 - x; x *= x; x = 1 - x; x += 1; x /= 2; } return x; } // // Creates a toast. // function _alert(x) { // // Create 2 elements and set their style. // var ca = [document.createElement('div'), document.createElement('div')]; ca[0].appendChild(ca[1]); ca[0].style.width = '24em'; ca[0].style.overflow = 'hidden'; ca[1].style.textAlign = 'center'; ca[1].style.border = '1px solid #7493B8'; ca[1].style.borderWidth = '1px 0 0 1px'; ca[1].style.padding = '1em'; ca[1].style.background = '#E5EFFA'; ca[1].style.color = '#1C2530'; ca[1].style.font = '8pt Tahoma'; ca[1].innerHTML = x; // // Animation: Slide out // var o2 = 1; var o2f = 0; function f2() { o2 -= 0.08; if (o2 < 0) o2 = 0; ca[0].style.height = Math.round(_smooth(o2) * o2f) + 'px'; if (o2 > 0) setTimeout (f2, 30); else ca[0].parentNode.removeChild (ca[0]); } // // Animation: Fade in // var o1 = 0; function f1() { o1 += 4; if (o1 > 100) o1 = 100; ca[0].style.MozOpacity = o1 / 100; ca[0].style.opacity = o1 / 100; if (o1 < 100) setTimeout (f1, 20); else setTimeout (function() { o2f = ca[0].offsetHeight; f2 (); }, 6000); } // // Add to the toast list. // setTimeout (function() { f1 (); ca[0].style.display = 'block'; }, (alerts.childNodes.length - 1) * 1234); ca[0].style.display = 'none'; alerts.insertBefore (ca[0], alerts.firstChild); } // // Welcome toast was here. // // // Get the default value // var dfv = document.msgform.message.defaultValue; // // Used with range // var ranger = document.createElement('div'); document.body.appendChild(ranger); // // XMLHttpRequest // function _xh() { return new XMLHttpRequest(); } var timrr = 0; // // Parses the HTML into objects. // function _parse(x, y) { var r = document.createRange(); r.selectNode (ranger); var d = r.createContextualFragment(x); //window.console.dirxml (d); var i; var e = {}; for (i = 0; i < d.childNodes.length; i ++) { if (typeof e[d.childNodes[i].nodeName] == 'undefined') e[d.childNodes[i].nodeName] = []; e[d.childNodes[i].nodeName][e[d.childNodes[i].nodeName].length] = d.childNodes[i]; } return e; } // // Parse #2 - parse the data recieved from _parse. // var oldctl = {}; var firsttime = 1; function _parse2(e) { var oldimsrc = document.images["rfswitch"].src; document.getElementsByTagName('table')[0].innerHTML = e['TABLE'][0].innerHTML; document.getElementsByTagName('table')[5].innerHTML = e['TABLE'][1].innerHTML; document.msgform.validshout.value = e['FORM'][0].getElementsByTagName('input')[2].value; document.images["rfswitch"].src = oldimsrc; var newctl = {}; var i; var nl = e['TABLE'][1].getElementsByTagName('a'); var par = nl[0].parentNode.parentNode; for (i = 1; i < nl.length; i ++) { newctl[nl[i].innerHTML] = 1; nl[i].style.textDecoration = 'none'; } if (!firsttime) { for (i in oldctl) { if (typeof newctl[i] == 'undefined') { if (oldctl[i] == 1) { newctl[i] = 2; } else if (oldctl[i][1] == 2) { _alert (i + ' left the shoutbox.'); } } } for (i in newctl) { if (typeof oldctl[i] == 'undefined') { _alert (i + ' entered the shoutbox.'); } } } oldctl = newctl; firsttime = 0; } // // This function re-refreshes. // function _refresh() { var x = _xh(); // // Status handling. // x.onreadystatechange = function() { if (x.readyState == 4 && x.status == 200) { try { _parse2 (_parse(x.responseText)); } catch (er) { _alert ('Could not parse the response text.'); } } }; // // Open a request. // x.open ('get', location.href.indexOf('?') == -1 ? location.href + '?dtuniqid=' + Math.random() : location.href + '&dtuniqid=' + Math.random(), true); x.overrideMimeType ('text/html; charset=iso-8859-1'); x.send (''); // // Queue a timer. // timrr = setTimeout (_refresh, 11111); } // // Focus the message entry // setTimeout (function() { document.msgform.message.focus (); }, 100); // // Edit the message box. // document.msgform.message.style.width = '20%'; document.msgform.message.style.fontSize = '13px'; // // Quick Texts! // var qm = document.createElement('div'); qm.style.position = 'fixed'; qm.style.bottom = '6em'; qm.style.width = '24em'; qm.style.left = '2em'; document.body.style.paddingBottom = '0em'; qm.style.padding = '1px'; qm.className = 'tborder'; document.body.appendChild (qm); var qmph = document.createElement('div'); qm.appendChild (qmph); var qmt = document.createElement('div'); qmt.style.marginBottom = '1px'; qmt.style.padding = '5px'; qmt.style.fontWeight = 'bold'; qmt.appendChild (document.createTextNode('Quick Texts (hover me)')); qmt.className = 'trow1'; qmph.appendChild (qmt); var qmbc = document.createElement('div'); qmbc.style.height = '0'; qmbc.style.overflow = 'hidden'; var qmb = document.createElement('div'); qmb.style.padding = '4px'; qmb.className = 'trow2'; qmph.appendChild (qmbc); qmbc.appendChild (qmb); var qmd = {}; // // Show the quick messages list on mouse over. // var qmdat = 0; var qmto = 0; var qmtim = 0; function qmfollow() { if (qmdat < qmto) { qmdat += 0.07; if (qmdat >= qmto) { qmdat = qmto; qmbc.style.height = ''; } else { qmbc.style.height = Math.round(_smooth(qmdat) * qmb.offsetHeight) + 'px'; qmtim = setTimeout(qmfollow, 24); } } else if (qmdat > qmto) { qmdat -= 0.07; if (qmdat < qmto) qmdat = qmto; qmbc.style.height = Math.round(_smooth(qmdat) * qmb.offsetHeight) + 'px'; qmtim = setTimeout(qmfollow, 24); } } qmph.onmouseover = function() { qmto = 1; clearTimeout (qmtim); qmtim = setTimeout(qmfollow, 16); } qmph.onmouseout = function() { qmto = 0; clearTimeout (qmtim); qmtim = setTimeout(qmfollow, 16); } // // Saves the quick message list. // function qmSave() { function qmEscape(z) { return z.replace(/(\\|')/g, '\\$1'); } var o = ''; for (i in qmd) { if (o != '') o += ','; o += '[\'' + (qmEscape(i)) + '\',\'' + (qmEscape(qmd[i])) + '\']'; } GM_setValue('quicks', escape('[' + o + ']')); qmUpdate (); } // // Options! // var opph = document.createElement('div'); qm.appendChild (opph); var opt = document.createElement('div'); opt.style.marginBottom = '1px'; opt.style.padding = '5px'; opt.style.fontWeight = 'bold'; opt.appendChild (document.createTextNode('Options (hover me)')); opt.className = 'trow1'; opph.appendChild (opt); var opbc = document.createElement('div'); opbc.style.height = '0'; opbc.style.overflow = 'hidden'; var opb = document.createElement('div'); opb.style.padding = '4px'; opb.className = 'trow2'; opph.appendChild (opbc); opbc.appendChild (opb); var opdat = 0; var opto = 0; var optim = 0; function opfollow() { if (opdat < opto) { opdat += 0.07; if (opdat >= opto) { opdat = opto; opbc.style.height = ''; } else { opbc.style.height = Math.round(_smooth(opdat) * opb.offsetHeight) + 'px'; optim = setTimeout(opfollow, 24); } } else if (opdat > opto) { opdat -= 0.07; if (opdat < opto) opdat = opto; opbc.style.height = Math.round(_smooth(opdat) * opb.offsetHeight) + 'px'; optim = setTimeout(opfollow, 24); } } opph.onmouseover = function() { opto = 1; clearTimeout (optim); optim = setTimeout(opfollow, 16); } opph.onmouseout = function() { opto = 0; clearTimeout (optim); optim = setTimeout(opfollow, 16); } var opts = {}; function optAddVal(vald, labl, df) { var dc = document.createElement('div'); dc.appendChild (document.createTextNode(labl)); dc.style.padding = '0.4em 0'; var ah = document.createElement('a'); function updLook() { ah.innerHTML = opts[vald] ? '[ON]' : '[off]'; } ah.href = '#'; ah.onclick = function() { var nv = GM_getValue(vald, df) ^ 1; opts[vald] = nv; GM_setValue(vald, nv); updLook (); return false; }; dc.appendChild (ah); opts[vald] = GM_getValue(vald, df); updLook (); opb.appendChild (dc); } optAddVal ('dtcompat', '* Enable text sending using XMLHttpRequest (-dt-\'s shoutbox cc script will fail if this is set to on) ', 1); optAddVal ('toasts', '* Enable toasts (disable this to get rid of stupid, annoying toasts) ', 1); optAddVal ('quicktexts', '* Parse quick texts (you still can edit the list of quick texts when this is not turned on) ', 1); var old_alert = _alert; _alert = function(x) { if (opts.toasts) { old_alert (x); } } // // Saves the quick message list. // function qmSave() { function qmEscape(z) { return z.replace(/(\\|')/g, '\\$1'); } var o = ''; for (i in qmd) { if (o != '') o += ','; o += '[\'' + (qmEscape(i)) + '\',\'' + (qmEscape(qmd[i])) + '\']'; } GM_setValue('quicks', escape('[' + o + ']')); qmUpdate (); } // // Update the quick message list. // function qmUpdate() { // // Reset the body and the data. // qmb.innerHTML = ''; qmd = {}; // // Add one to list. // function a2l(x) { qmd[x[0]] = x[1]; var cm = document.createElement('div'); var cl = [document.createElement('a'), document.createElement('a'), document.createElement('a')]; cl[0].href = '#'; cl[1].href = '#'; cl[2].href = '#'; cl[0].appendChild (document.createTextNode('/' + x[0])); cl[1].appendChild (document.createTextNode('Edit')); cl[2].appendChild (document.createTextNode('Delete')); cl[0].onclick = function() { document.msgform.message.value = '/' + x[0]; document.msgform.message.focus (); return false; }; cl[1].onclick = function() { var yzz = prompt('Please enter the text to bind with this command.', qmd[x[0]]); if (!yzz || yzz == '') { alert ('Error: No text specified.'); return false; } qmd[x[0]] = yzz; qmSave (); return false; }; cl[2].onclick = function() { delete qmd[x[0]]; qmSave (); return false; }; cm.appendChild (cl[0]); cm.appendChild (document.createTextNode(' (')); cm.appendChild (cl[1]); cm.appendChild (document.createTextNode(' / ')); cm.appendChild (cl[2]); cm.appendChild (document.createTextNode(')')); qmb.appendChild (cm); } // // Get the data. // var gmd = eval(unescape(GM_getValue('quicks', escape('[]')))); // // Make the list. // if (gmd.length == 0) { var nm = document.createElement('div'); nm.style.textAlign = 'center'; nm.appendChild (document.createTextNode('No quick messages.')); qmb.appendChild (nm); } else { var i; for (i = 0; i < gmd.length; i ++) { a2l (gmd[i]); } } // // Add new one // var am = document.createElement('div'); am.style.textAlign = 'center'; am.style.paddingTop = '1em'; var al = document.createElement('a'); al.href = '#'; al.appendChild (document.createTextNode('(Create one!)')); al.onclick = function() { var xzz = prompt('Please enter the command.\r\n\r\nFor example, if you input "ttyl", you can access it by typing "/ttyl" in the message entry.', ''); if (!xzz || xzz == '') { alert ('Error: No commands specified.'); return false; } var yzz = prompt('Please enter the text to bind with this command.', ''); if (!yzz || yzz == '') { alert ('Error: No text specified.'); return false; } qmd[xzz] = yzz; qmSave (); return false; }; am.appendChild (al); qmb.appendChild (am); } qmUpdate (); // // Show the error // function showError() { var $z = GM_getValue ('error', 0); $z ++; GM_setValue ('error', $z); _alert ('Error: An error has occured while sending the message.
You may talk too fast, you may quoted a non-existant shout or a server error has occured. Please try again.

You made ' + $z + ' error' + ($z == 1 ? '' : 's') + ' to date.'); return $z; } // // Edit the sending behavior. // document.msgform.onsubmit = function() { // // Check message and create XMLHttpRequest. // if (document.msgform.message.value == dfv || document.msgform.message.value.match(/^\s*$/)) return false; // // Command key? // if (opts.quicktexts) { if (document.msgform.message.value.charAt(0) == '/') { var crp = document.msgform.message.value.substr(1); var crp2 = (crp.indexOf(' ') == -1 ? crp : crp.substr(0, crp.indexOf(' '))); var crp3 = (crp.indexOf(' ') == -1 ? '' : crp.substr(crp.indexOf(' ') + 1)); // // Is that quick text exists? // if (typeof qmd[crp] != 'undefined') { document.msgform.message.value = qmd[crp]; // // Command with arguments? // } else if (typeof qmd[crp2] != 'undefined') { document.msgform.message.value = qmd[crp2] + ' ' + crp3; // // Simulate an error? // } else if (document.msgform.message.value == '/errstats') { document.msgform.message.value = 'My error-penis is ' + GM_getValue('error', 0) + ' cm long!! :pound:'; // MeEtc // // Normal commands? // } else if (document.msgform.message.value.match(/\/(ls\d*|shout|theme|help)/)) { // // Prevent AJAX submit by using some system commands. // return true; } } } else { if (document.msgform.message.value.match(/\/(ls\d*|shout|theme|help)/)) { // // Prevent AJAX submit by using some system commands. // return true; } } // // -dt-'s compatibility hack. // if (!opts['dtcompat']) return unsafeWindow.checkName (); var x = _xh(); // // Status handling. // x.onreadystatechange = function() { if (x.readyState == 4 && x.status == 200) { try { _parse2 (_parse(x.responseText)); document.msgform.message.value = ''; } catch (er) { showError(); } document.msgform.message.disabled = false; setTimeout (function() { document.msgform.message.focus (); }, 100); } }; // // Open a request. // x.open ('post', 'shoutbox.php?dtuniqid=' + Math.random(), true); x.setRequestHeader ('Content-Type', 'application/x-www-form-urlencoded; charset=iso-8859-1'); x.overrideMimeType ('text/html; charset=iso-8859-1'); x.send ('rf=' + encodeURIComponent(document.msgform.rf.value) + '&action=send&validshout=' + encodeURIComponent(document.msgform.validshout.value) + '&message=' + escape(document.msgform.message.value).replace(/%u([a-f0-9]+)/gi, function (x, y) { return '&#' + parseInt(y, 16) + ';'; })); document.msgform.blur (); document.msgform.message.disabled = true; // // Just return false // return false; }; // // Refreshing hack. // if (document.images) { var loadon = new Image(15, 16); var loadoff = new Image(15, 16); loadon.src = "images/refreshon.gif"; loadoff.src = "images/refreshoff.gif"; } // // Don't do the old refresh. // window.sbRefresh = function() {}; // This function should do NOTHING! // // Use the new one! // //window.rfSwitch = function() { // // New switching method. // if (document.images["rfswitch"].src == loadon.src) { // document.images["rfswitch"].src = loadoff.src; // document.msgform.rf.value = '0'; // _alert ('Auto-reload turned off.'); // clearTimeout (timrr); // } else { // document.images["rfswitch"].src = loadon.src; // document.msgform.rf.value = '1'; // clearTimeout (timrr); // _alert ('Auto-reload turned on.'); // setTimeout (_refresh, 6000); // } //}; // // These functions get the top and left position of an element. // Modified from DtJS. http://dttvb.yi.org/dtjs/ // function gp(el) { var tmp = [el.offsetLeft, el.offsetTop]; el = el.offsetParent; while (el) { tmp[0] += el.offsetLeft; tmp[1] += el.offsetTop; el = el.offsetParent; } return tmp; } // // User Menu Construction // var lmdat = [0, 0]; var lm = document.createElement('div'); lm.style.position = 'absolute'; lm.style.padding = '1px'; lm.style.width = '15em'; lm.style.paddingTop = '0'; lm.className = 'tborder'; lm.style.display = 'none'; document.body.appendChild (lm); var lmid = 0; var lmtid = 0; // // This function hides the menu and returns true. // function lmh() { clearTimeout (lmtid); setTimeout (function() { lm.style.display = 'none'; }, 100); return true; } // // This function makes it easy to add more menu. // function lmc(tx, fu) { var ce = document.createElement('div'); ce.style.padding = '3px'; ce.style.marginTop = '1px'; ce.style.cursor = 'pointer'; ce.appendChild (document.createTextNode(tx)); ce.onclick = fu; ce.onmouseover = function() { ce.style.fontWeight = 'bold'; }; ce.onmouseout = function() { ce.style.fontWeight = ''; }; ce.className = 'trow' + ((lmid++ % 2) + 1); lm.appendChild (ce); return ce; } // // Now add some menus using that function. // lmc ('Quote this shout', function() { var hd = '/quote ' + lmdat[0] + ' '; document.msgform.message.value = document.msgform.message.value.replace (new RegExp('^\\s*/quote\\s+\\d+\\s*', 'i'), ''); if (document.msgform.message.value == dfv || document.msgform.message.value.match(/^\s*$/)) document.msgform.message.value = ''; document.msgform.message.value = hd + document.msgform.message.value; document.msgform.message.focus (); setTimeout (function() { document.msgform.message.selectionStart = hd.length; document.msgform.message.selectionEnd = document.msgform.message.value.length; }, 100); }); lmc ('View profile', function() { window.open ('member.php?uid=' + lmdat[1], '_blank'); }); lmc ('Send private message', function() { window.open ('private.php?action=send&uid=' + lmdat[1], '_blank'); }); // // Mouseclicking on a user // (function() { // // This function occurs on mouse down. // function oc(e) { // // Cancel the default behavior? // var ex = 0; var idm; var idu; // // Get the target. // var ce = e.target; // // Look for the link. // while (ce.nodeName != 'BODY' && ce.nodeName != 'HTML') { if (ce.nodeName == 'A') break; ce = ce.parentNode; } // // Cancel if link not found. // if (ce.nodeName != 'A') return lmh(); // // Cancel if not a member link. // if (ce.title != 'View profile') return lmh(); // // Cancel if the ID not specified. // if (!(idu = ce.href.match(/uid=(\d+)/))) return lmh(); // // Cancel if no shout ID is specified. // if (!(idm = ce.parentNode.parentNode.title.match(/ID (\d+)/))) if (!(idm = ce.parentNode.parentNode.parentNode.title.match(/ID (\d+)/))) return lmh(); // // OK, now prevent standard things to happen. // ex = 1; // // Set the values for the menu.. // lmdat = [idm[1], idu[1]]; // // Get the position of the link. // var geo = gp(ce); // // And place the popup menu.. // lm.style.left = geo[0] + 'px'; lm.style.top = (geo[1] + ce.offsetHeight) + 'px'; // // Display the menu! // lm.style.display = 'block'; // // This do the trick! ;) // if (ex) { e.stopPropagation (); e.preventDefault (); } } document.addEventListener ('click', oc, false); })(); // // Queue for update if previously. // if (document.images["rfswitch"].src == loadon.src) { timrr = setTimeout (_refresh, 8000); } else { _alert ('Note: Auto-reload feature is not turned on. Click the auto-reload button at the bottom-left corner of this page to turn it on.'); } })(typeof unsafeWindow == 'undefined' ? window : unsafeWindow);