So I finally sat down and spent a Saturday morning extending IPBoard chat client. It works by rerouting IPBoard.prototype.chat to a custom function, which then transforms the message text through a series of WTF-regexes. This script should be installed as a Greasemonkey script, but it could also be copy-pasta'd into a developer tool's javascript window.
Features
Extra commands:
/users
/kick regex
/ban regex
/confirm
/quit
/mute
Text emotes:
:lenny: ( ?? ?? ??)
:wat: ?__?
Backslash escaping:
\n Newline
\e Zero width space (for escaping)
\t Em-width space
\xYYYY Equivalent to &#YYYY;
Support for custom BBCode tags.
Here is the script:// ==UserScript==// @name IPBoard Chat Extensions// @namespace fastcall22.com// @description For GAMSDEV// @include http://www.gamedev.net/chat/// @version 1// @grant none// ==/UserScript==(function ipb_ext(){ var Chat = IPBoard.prototype.chat; // util Chat.ext_post_message = function(textContent) { var post = document.createElement('li'); post.setAttribute('class','post chat-myown'); post.textContent = textContent; document.getElementById('storage_chatroom') .appendChild(post); post.scrollIntoView(false); }; Chat.ext_search_users = function(query) { var result = {}; var q_reg = new RegExp(query||'.'); for ( var id in Chat.forumIdMap._object ) { var name = Chat.nameFormatting._object[id][2]; if ( q_reg.test(name) ) result[name] = id; } return result; }; Chat.ext_user_action = function(action,target_id){ ipb.chat.sendMessageToChild( "server="+serverHost + "&path="+serverPath + "&room="+roomId + "&user="+userId + "&access_key=" + accessKey + "&action="+action + "&against="+target_id ); ipb.chat.lastAction = parseInt(new Date().getTime().toString().substring(0, 10)); }; // config var null_f = function(){}; Chat.ext_empty_event = { stopPropagation: null_f, preventDefault: null_f }; Chat.ext_confirm_action = null; var make_action = function(action){ return function(query) { if ( !query.trim() ) return; var users = Chat.ext_search_users(query); Chat.ext_confirm_action = function() { for ( var k in users ) Chat.ext_user_action(action,users[k]); }; var str = ''; for ( var k in users ) { if ( str ) str += ', '; str += k; } Chat.ext_post_message("Send /confirm to "+action+": "+str+". Send /cancel to ignore"); }; }; Chat.ext_commands = { kick: make_action('kick'), ban: make_action('ban'), test: function() {Chat.test = !(Chat.test || false)}, debug: function() {Chat.debug = !(Chat.debug || false)}, users: function(query) { var list = Chat.ext_search_users(query); var str = ''; for ( var k in list ) { if ( str ) str += ', '; str += k; } Chat.ext_post_message(str); }, confirm: function() { if ( !Chat.ext_confirm_action ) return; Chat.ext_confirm_action(); Chat.ext_confirm_action = null; }, cancel: function() { Chat.ext_confirm_action = null; }, mute: function() { document.getElementById('sound_toggle').click(); }, quit: function(){ document.getElementById('leave_room').click(); }, }; Chat.ext_escape = { 'n': '\n', 't': '?', 'e': '?', }; Chat.ext_emotes = { fear: ':f34r:', lenny: '( ?? ?? ??)', wat: '?__?', }; Chat.ext_bbc = { rick: function(param,content) { // never gonna give you up // never gonna let you down // never gonna run around // and desert you } }; // helpers Chat.bbc_filter = function ext_bbc_filter(_,tag,param,content) { var f = Chat.ext_bbc[tag]; if ( !f ) return _; return f(param,content); }; Chat.ext_filters = [ /* commands */ [ /^\/(\w+)\s*(.*)$/, function ext_command_filter(_,cmd,argstr) { var args = argstr.split(' '); var f = Chat.ext_commands[cmd]; if ( !f ) return _; f.apply(null,args); return ''; } ], /* emotes */ [ /:(\w+):/g, function ext_emote_filter(_,tag) { return Chat.ext_emotes[tag] || _; } ], /* backslash */ [ /\\(?:(x[0-9a-fA-f]{4})|([a-z]))/g, function ext_backslash_filter(_,hex,code) { if ( hex ) return '&#'+hex+';'; return Chat.ext_escape
|| _; } ], /* BBC w/ content */ [ /\[(\w+)(?:=(.+))?\](.*?)\[\/\1\]/g, Chat.bbc_filter ], /* self-closing BBC tags */ [ /\[(\w+)(?:=(.+))?\s*()\/\]/g, Chat.bbc_filter ], /* general */ [ /\t/g, '?' ] ]; Chat.ext_filter_message = function(str) { Chat.ext_filters.forEach(function(f){ if ( !str.length ) return; if ( Chat.debug ) console.log(f,str); str = String.prototype.replace.apply(str,f); }); return str; }; Chat.ext_send = function ext_send(e) { if ( e.preventDefault ) e.preventDefault(); if ( e.stopPropagation ) e.stopPropagation(); var message = (document.getElementById('message_textarea').value || '').trim(); if ( Chat.debug ) console.log('send',message); if ( !message ) return; var filtered = Chat.ext_filter_message(message) || null; document.getElementById('message_textarea').value = filtered; if ( filtered ) return Chat.ipb_sendChat.call(this,Chat.ext_empty_event); }; Chat.ipb_sendChat = Chat.sendChat; Chat.sendChat = Chat.ext_send;})();
Notable points of interest:
Chat.ext_send
Chat.ext_filter_message
Chat.ext_filters
The extension is pretty dumb, but it works. So, have fun!
how do I use this is with IE11?