// kotolingr
// version 0.212
// 2007-02-09 (last updated 2007-02-13)
// by ento (http://kotonoha.cc/user/ento)
//
// This script resides at http://userscripts.org/scripts/source/7439
//
// --------------------------------------------------------------------
//
// This is a Greasemonkey user script.
//
// To install, you need Greasemonkey: http://greasemonkey.mozdev.org/
// Then restart Firefox and revisit this script.
// Under Tools, there will be a new menu item to "Install User Script".
//
// To uninstall, go to Tools/Manage User Scripts,
// select "kotolingr", and click Uninstall.
//
// --------------------------------------------------------------------
//
// What I can do:
// * insert a o/x button to the kotonoha x lingr room chat interface
// * keep track of the koto posted by the kotonoha bot
//
// -----------------------------------------------------------------
// changelog
//
// 2007-02-13 script cleanup. no longer gpl, no functional changes
// 2007-02-12 added koto tracking
// 2007-02-09 first release
// -----------------------------------------------------------------
//
// ==UserScript==
// @name kotolingr
// @namespace http://kotonoha.cc/user/ento
// @description kotonoha x lingr o/x button
// @include http://www.lingr.com/room/kotonoha
// ==/UserScript==
/*
kotolingr
*/
//GM_log('globals');
// globals
var maru_string = "%E2%97%8B"; // encodeURI('○');
var batsu_string = "%C3%97"; // encodeURI('×');
//GM_log('controllers');
/*
controller functions
*/
function kl_button_action(answer){
// when answer == true
// case old_value action
// 1 'o' send 'o'
// 2 'ocomment' send 'ocomment'
// 3 '' set value 'o'
// 4 'comment' send 'ocomment'
// 5 'x' set value 'o'
// 6 'xcomment' send 'ocomment'
var field = document.getElementById('speakField');
var new_mode = answer ? maru_string : batsu_string;
var old_value = field.value;
if(kl_is_kotomode(field)){
// remove the old mode string
var old_mode = kl_pop_character(field);
}
// this is for case 4, 6
// we must evaluate with the mode string removed
var immediate = '' != field.value;
// set to new mode
kl_push_character(field, new_mode);
// check for case 1, 2, 4, 6 and send
if(old_value == field.value || immediate){
document.getElementById('speakForm').wrappedJSObject.onsubmit();
}
// move focus
field.focus();
}
// looks whether the given element's inner html begins with maru/batsu
function kl_is_kotomode(element){
var mode_string = kl_mode_string(element);
if (maru_string == mode_string || batsu_string == mode_string){
return true;
}
return false;
}
// simply encode and return the first character of the element value
function kl_mode_string(element){
return encodeURI(element.value.substr(0,1));
}
// push aChar
function kl_push_character(element, aChar){
element.value = decodeURI(aChar) + element.value;
}
// pop a character
function kl_pop_character(element){
var first = element.value.substr(0, 1);
element.value = element.value.slice(1);
return first;
}
//GM_log('event handlers');
/*
event handlers
*/
// function names below should be descriptive enough
function kl_batsu_onclick(event){
kl_button_action(false);
return false;
}
function kl_batsu_onkeypress(event){
if(kl_should_handle_keypress(event)){
return kl_batsu_onclick(event);
}
return true;
}
function kl_maru_onclick(event){
kl_button_action(true);
return false;
}
function kl_maru_onkeypress(event){
if(kl_should_handle_keypress(event)){
return kl_maru_onclick(event);
}
return true;
}
function kl_should_handle_keypress(event){
var key = event.keyCode || event.charCode;
return 13 == key; // return
}
//GM_log('message handlers');
/*
message handlers: extracting koto
*/
// replacement for the normal notifyMessage function
function kl_notify_message(msg, render, realtime){
// get the chatroom
var chatroom = unsafeWindow.chatroom;
// let it do the normal operation
chatroom.notifyMessage(msg, render, realtime);
// if it's from the bot
if(kl_is_koto(msg)){
// extract the koto from the txt (automatons seem to pass it along in h)
var match = msg.h.match(/[\n.]*<li[^>]*class="[^"]*messageText[^"]*"[^>]*>([\n.]*.*[\n.]*)<\/li>/m);
if(!match){ return; }
kl_update_koto(match[1]);
}
}
// is the message a koto posted by the bot?
function kl_is_koto(msg){
return 'user' == msg.type && 'kotonoha bot' == msg.hdl && /automaton/.test(msg.h) && /kotonoha\.cc\/no\//.test(msg.h);
}
// update the kotp placeholder with the argument string
function kl_update_koto(txt){
// get the place holder
var koto = document.getElementById('kl_koto');
if(!koto){ return; }
// dump the txt into the koto element
koto.innerHTML = txt;
}
// replace the handler with our own
function kl_update_chatroom_chatsystem(property, oldvalue, newvalue){
if(newvalue.options){
newvalue.options.notifyMessage = kl_notify_message;
}
}
// initialization
function kl_setup_koto_handling(){
// make a placeholder for the koto
var koto = document.createElement('span');
koto.setAttribute('id', 'kl_koto');
var header = document.getElementById('pageHeader');
var h1s = header.getElementsByTagName('h1');
if(h1s){
h1s[0].appendChild(koto);
}
// style it
addGlobalStyle("#kl_koto { color: #777777; font-size: 0.55em; } #kl_koto a { color: #0F5887; } #kl_koto a:hover, #kl_koto a:focus { color: #DE8000} #kl_koto, #kl_koto a { font-family: 'Gill Sans','Verdana','Helvetica',sans-serif; }");
// hook to the chatsystem
var room = unsafeWindow.chatroom;
if(room && room.chatSystem){
kl_update_chatroom_chatsystem('chatSystem', null, room.chatSystem);
}
// watch for future changes (fixme: not sure if this is needed)
unsafeWindow.watch('chatroom',
function(property, oldvalue, newvalue){
if(newvalue){
if(newvalue.chatSystem){
kl_update_chatroom_chatsystem('chatSystem', null, newvalue.chatSytem)
}
newvalue.watch('chatSystem', kl_update_chatroom_chatsystem);
}
},
true);
}
/*
making buttons
*/
// generic image button maker with click and keypress callback
function kl_make_image_button(img_src, onclick, onkeypress, before){
// an image
var img_node = document.createElement('img');
img_node.src = img_src;
img_node.className = 'kl_button_image';
// make it look buttonnish
img_node.style.border = '1px outset #f0f0f0';
img_node.addEventListener('mousedown', kl_button_inset, false);
img_node.addEventListener('mouseup', kl_button_outset, false);
img_node.addEventListener('mouseout', kl_button_outset, false);
// in an a
var a_node = document.createElement('a');
a_node.appendChild(img_node);
a_node.addEventListener('click', onclick, false);
// in a div
var div_node = document.createElement('div');
div_node.appendChild(a_node);
div_node.addEventListener('keypress', onkeypress, false);
// styling and positioning
div_node.className = 'kl_button';
div_node.style.left = '70%';
div_node.style.marginLeft = '42px';
div_node.style.position = 'absolute';
div_node.style.top = '0pt';
before.parentNode.insertBefore(div_node, before);
return div_node;
}
// glue code for maru button
function kl_make_maru_button(before){
var img_src = kl_image_source_maru();
return kl_make_image_button(img_src,
kl_maru_onclick, kl_maru_onkeypress,
before);
}
// glue code for batsu button
function kl_make_batsu_button(before){
var img_src = kl_image_source_batsu();
return kl_make_image_button(img_src,
kl_batsu_onclick, kl_batsu_onkeypress,
before);
}
// base64 encoded maru image (c) purprin
function kl_image_source_maru(){
return 'data:image/png;base64,' +
'iVBORw0KGgoAAAANSUhEUgAAABIAAAASEAIAAACJPMVDAAAACXBIWXMAAABI' +
'AAAASABGyWs+AAAACXZwQWcAAAASAAAAEgAjOG5KAAAD4UlEQVQ4y62Ve0zV' +
'ZRjHP78fh7uHNwIquZgFBAwZclUuZlwaRnHzgouwZLGK0twoqc2WYDVXKSVU' +
'y1QYhVZI4SwIhFJhExAqU0AhIjMQAoTzOxw6IodDfxBNxDUcfv97t++ez/s8' +
'z97vK2k0Go1GwyyJhWKNEOcvXBqC+lUtNdD+dvdjMLxwJAmMjcZUsFsk1oDn' +
'apcnIfxxn6Xg7uPcAcozSoKizK4pzYYZC2WVEIWHKu3hzFednwL+pIPNmNUW' +
'sPnQun/aqQ34uxS0paNJIC2QGiH4iOe98FRGzBaYiL0WNBOpuv6gyxpPFiK3' +
'vuQN6K/SdMOS2Ps2QNyR0Ghwq3UqBn386M/TJazes84S4vc9vVr4JqReA42X' +
'ztdBj8tgK2z1Xd8nhPyLMW7a/29nEqY7hNgRV+QO/eOaPFhbv/J5iCsJSQdt' +
'jHbsZmOZMfatYr8QVZFN43AwtsYPHO3tamBbYmoCGPeN+yiKPGX94uMfzsFf' +
'm4cfgITIsAiIrwgNnBtmSsq7SrqixNwfFA/JSQ+1QM/gYA4Ue1YHT3tk/dGJ' +
'JiEa3mw7CYsP31MBCSVhvaCEKV5zw8xAeihOivJI1jIDuG10eg0aMy54gbZq' +
'TBZC/jG8YwjGEw3b4eGQwOMw2qwrvHXMjN0vH3lOUWL8g1bARNbE09C0r30J' +
'yJ1ePe+DiZe8Abx1i/3mA5kpzxOL6sB0QHUYfq3tVoM8XDByACyrzT8AqxPm' +
'T9w+mFWcRTVYO1kkwnDVyFlQSRVSHtCHATBjXuO7QRpGgEE0IB2UskFl66ru' +
'hK4Xe9WgO6MPAjOk28IazdVvAt2remdwXuZwN8iuGY6bwJhvDITW7Rczb19j' +
'bUv/KAND20QXuO903ghyUJlnDpiaqmqhKqTpLrA0t35LiPlgFnirXYQ4JjUV' +
'gMk7Jgcg2NJzLcjmKdJxRQlf4aOHbp+BACjLqQNEkai5daRoFz1ClOc3REPX' +
'7t5JCHb1qAT1Z2av/5cg6+sjbMHxJfsaKN/fsBe+vlaXB+ohm8y5IW1OCwch' +
'KrNPfwulUSefBYeP7kiBlJpoedozI/XH9kw6CLGr4EsJenOvVINHrcsExAWG' +
'HgP3U875ML7zas/0kzcbtPQToovL26Dcvz4SWkYuuoH9cmELmVnrSkAdYRZw' +
'QxBff0cpSnVViKLLVT9B88sdr4AxzPg5WB+y0IH6nFU+UEw26I7qm0G3Th8L' +
'cqpkBr6KmwOkJa/qAznNaPifL2ZKk98bLBRl8yerB4TolHp2wym71u+gw/bP' +
'B+GK0LrD5G8EwJ1n1b4QvNJrL4S+4P0oeKS5RIGSphhuFnj/AHN0lmOdi73X' +
'AAAAAElFTkSuQmCC';
}
// base64 encoded batsu image (c) purprin
function kl_image_source_batsu(){
return 'data:image/png;base64,' +
'iVBORw0KGgoAAAANSUhEUgAAABIAAAASEAIAAACJPMVDAAAACXBIWXMAAABI' +
'AAAASABGyWs+AAAACXZwQWcAAAASAAAAEgAjOG5KAAADb0lEQVQ4y72Uf0zU' +
'ZRzHX9877hAin4LNEowfRUBwuDYhofhDa23qqK1Wa1Zom226Az2YHGHLWa4N' +
'uB+CeCo0xWrRopuXGs2S1lx/lI6x3aKDuKA8sxOna/csPLn74l1/3M5BIR6r' +
'9fnn2Z4f79ee5/N+P0ogEAgEAvwvpYkNQizx6FOEODn53noh1KngxL8RFSK4' +
'O5AlRP9MT6YQd1WkqHNg0P/U+3oYeLcvDNbjO6qEiGwN/bF4TGj5n6+BxbY9' +
'Cl86e80wcMS59W+wdS2vfAUPZ63cA/7BX4uhLVArhIj2q+2JYcId18ug9S2j' +
'Ea5t8T8Chk0V+2Dtque6YnuU2T0TIqlYKQeb2WSE8aHhj+CB7/OXQpPmwDEp' +
'lUH9PfNinpg6D2131+bBlfxLG6HE8ZgD6l22z6UMPa82zQOLH9aWRTVgTd9x' +
'HH4pGHFATn6hFsyHOn+SEm/SxfhO9cVgCVgK6t6GyzrfKSjdW6mH7Rdai6QM' +
'Z8+YZysrt3OjENplUTe07218Eryj7nLIXVpUBE2pjj5QN4bXQNtm4zrwr75w' +
'Alb6KrvBpFoHpbzhClX/U1NZ2PpC6Aa0mWC/VK8B75C7EHL2FbZCuGs6Ape9' +
'vjeh9IPK9WDyWZ1STqeHzt9OTUkkZ0JoBRqwbTLlwET0xwfjK8Wbyw3Q0G0f' +
'lzJ0RP1iYR0NCdXMiDoO6kBo29z5cN60HWac6ulEVO74jMrpSAFYkutqwOca' +
'OzvfMxasenQMdq7oiEipPn3Tv+ibCaHZErkJloy6ujgm994iA7xhP/gMND97' +
'uB0yh3NrwOt2l4A9o75KCP1a7beLgMWtb/vNdAp8H46djFu/sW//Z1JGdimT' +
'Umpzkz8B87IDVlielvM6eHvdQWhfvfOKEPqLSdY7wOKhttc2HI0nLBbqxt6O' +
'T2cnLFZS6pypHjCf7cyG+zwremB0aqgL9mebq4VIduks8/RMiKRjyjmwT9aH' +
'4efff3gHsq7mnYHmmsOdUirVuoaFmx//rlp02w7B1VH/LjB0V3jBpLFMSBkK' +
'qfpbsK/v/1jAiReOlkFmed4INH930COlpjs5PRGnxZGxj7glYDwD13r8Zni5' +
'tGFYyscN1T23YEs8+hToy3CsgQ1przqk1KWlPpQ4Zi4yuDuQBd/scUXhpapa' +
'n5TXz93QJRTq/6r+AtOKlAVIIHkkAAAAAElFTkSuQmCC';
}
/*
niceties
*/
function kl_button_outset(event){
var target = event.target.wrappedJSObject;
if('kl_button_image' == target.className){
target.style.borderStyle = 'outset';
event.preventDefault();
}
}
function kl_button_inset(event){
var target = event.target.wrappedJSObject;
if('kl_button_image' == target.className){
target.style.borderStyle = 'inset';
event.preventDefault();
}
}
// taken from http://diveintogreasemonkey.org/patterns/add-css.html
function addGlobalStyle(css) {
var head, style;
head = document.getElementsByTagName('head')[0];
if (!head) { return; }
style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = css;
head.appendChild(style);
}
/*
debugging
*/
function GM_inspect(object){
var s = '';
for(p in object){
s += p + ":" + object[p] + "\n";
}
GM_log(s);
return true;
}
/*
main
*/
//GM_log('field');
// get the speak field
var field = document.getElementById('speakField');
//GM_log('sayit');
// adjust the say it button
var sayit = document.getElementById('speakFormSubmit');
sayit.style.marginLeft = '63px'; // 42(original) + 18(button width) + 3
sayit.style.marginTop = '5px';
//GM_log('maru');
// make the maru button
var maru = kl_make_maru_button(sayit);
maru.setAttribute('id', 'kl_maru');
maru.style.marginTop = '-5px';
//GM_log('batsu');
// make the batsu button
var batsu = kl_make_batsu_button(sayit);
batsu.setAttribute('id', 'kl_batsu');
batsu.style.marginTop = '16px';
//GM_log('navigation');
// navigation
field.setAttribute('tabIndex', '1');
maru.setAttribute('tabIndex', '2');
batsu.setAttribute('tabIndex', '3');
sayit.setAttribute('tabIndex', '4'); // fixme: doesn't seem to work
//GM_log('message handler');
// message handler
kl_setup_koto_handling();
kl_update_koto('with kotolingr');
// fin.