8 function selectedText () {
9 var sel = window.getSelection();
10 if (!sel || sel.rangeCount < 1) return "";
11 var s = sel.toString();
13 for (var f = 0; f < s.length; f++) {
15 if (ch < ' ') api.print("{"+ch.charCodeAt(0)+"}");
16 else if (ch == ' ') api.print("{ }");
27 function unselectText () {
28 var sel = window.getSelection();
29 if (!sel || sel.rangeCount < 1) return "";
30 sel.removeAllRanges();
37 function setMyUNI (uni) {
45 function chatStarted (uni) {
46 //api.printLn(">>>"+uni);
50 function optionChanged (optname) {
54 function optionRemoved (optname) {
58 function date2Str (dt) {
59 function n2s (n, len) {
62 while (res.length < len) res = "0"+res;
65 var res = dt.getFullYear()+"/"+n2s(dt.getMonth()+1)+"/"+n2s(dt.getDate())+" "+
66 n2s(dt.getHours())+":"+n2s(dt.getMinutes())+":"+n2s(dt.getSeconds());
71 function delChatMessage (id) {
72 var div = document.getElementById("msg_"+id);
74 div.parentNode.removeChild(div);
84 var div = document.createElement("hr");
85 document.body.appendChild(div);
89 function chatAtBottom () {
90 var curY = window.pageYOffset;
91 var de = document.documentElement.offsetHeight;
92 var vh = window.innerHeight;
93 return (curY+vh >= de);
97 function isChatAtBottom () {
98 api.setWasBottom(chatAtBottom());
105 function addSysMsg (msg) {
106 //msg = msg.replace(/\n/g, "<br />\n");
109 api.printLn("addSysMsg: before: h="+document.body.offsetHeight+"; ofs="+window.pageYOffset+"; ch="+document.body.clientHeight+"; ih="+window.innerHeight);
110 api.printLn(" "+document.documentElement.scrollHeight);
111 api.printLn(" "+document.documentElement.offsetHeight);
113 var wasAtBottom = chatAtBottom();
115 if (!lastMsgDiv || lastUNI != "system console") {
116 var div = document.createElement("div");
117 div.setAttribute("class", "message");
119 var hdrdiv = document.createElement("div");
120 hdrdiv.setAttribute("class", "sysmsghead");
121 hdrdiv.innerText = "system console";
122 div.appendChild(hdrdiv);
124 var txtdiv = document.createElement("div");
125 txtdiv.setAttribute("class", "sysmsgtext");
126 txtdiv.innerHTML = msg;
127 div.appendChild(txtdiv);
130 lastUNI = "system console";
132 document.body.appendChild(div);
134 var divdiv = document.createElement("div");
135 divdiv.setAttribute("class", "msgdelimiter");
136 lastMsgDiv.appendChild(divdiv);
138 var txtdiv = document.createElement("div");
139 txtdiv.setAttribute("class", "sysmsgtext");
140 txtdiv.innerHTML = msg;
141 lastMsgDiv.appendChild(txtdiv);
144 api.printLn("addSysMsg: after: h="+document.body.offsetHeight+"; ofs="+window.pageYOffset+"; ch="+document.body.clientHeight+"; ih="+window.innerHeight);
145 api.printLn(" "+document.documentElement.scrollHeight);
146 api.printLn(" "+document.documentElement.offsetHeight);
149 api.printLn("addSysMsg: refreshed: h="+document.body.offsetHeight+"; ofs="+window.pageYOffset+"; ch="+document.body.clientHeight+"; ih="+window.innerHeight);
150 api.printLn(" "+document.documentElement.scrollHeight);
151 api.printLn(" "+document.documentElement.offsetHeight);
153 api.scrollToBottom();
154 api.printLn("addSysMsg: scrolled: h="+document.body.offsetHeight+"; ofs="+window.pageYOffset+"; ch="+document.body.clientHeight+"; ih="+window.innerHeight);
155 api.printLn(" "+document.documentElement.scrollHeight);
156 api.printLn(" "+document.documentElement.offsetHeight);
158 var fs = api.getOption("/chat/forcescroll");
159 //api.printLn("fs="+fs+"; wasBt="+wasAtBottom);
160 if (fs > 1 || ((fs === null || fs == 1) && wasAtBottom)) {
161 api.scrollToBottom();
168 function shrinkList () {
169 var maxMsg = api.getOption("/chat/maxmessages");
170 if (typeof(maxMsg) == "number") {
171 if (maxMsg > 0 && msgCount > maxMsg) {
172 var toLeft = api.getOption("/chat/maxmessagesleft");
173 if (typeof(toLeft) != "number") toLeft = maxMsg;
174 while (msgCount > toLeft) {
175 delChatMessage(msgFirst);
184 function fixLongWords (s) {
185 for (var f = 0; f < s.length; ) {
186 while (f < s.length && s.charAt(f) <= ' ') f++;
187 if (f >= s.length) break;
189 while (f < s.length && s.charAt(f) > ' ') {
191 if (s.charAt(f-1) == "&") {
192 while (f < s.length && s.charAt(f) != ';') f++;
196 if (s.charAt(f-1) == "<") {
197 while (f < s.length && s.charAt(f) != '>') f++;
201 if (st >= 32 && f < s.length) {
202 s = s.substr(0, f)+"­"+s.substr(f, s.length);
213 function colorizeQuotes (s) {
216 for (var f = 0; f < t.length; f++) {
217 //if (t[f] == '>') t[f] = '!';
218 t[f] = t[f]+"("+(t[f].charCodeAt(0))+")";
222 var lines = s.split("\n");
224 var trim = function (st) {
225 return st.replace(/^\s+|\s+$/g, "");
227 var trimR = function (st) {
228 return st.replace(/\s+$/g, "");
230 var jj = function (st, end, addnl) {
232 if (end >= lines.length) end = lines.length-1;
233 for (var f = st; f <= end; f++) {
234 if (res) res += "\n";
237 if (addnl) res += "\n";
240 var qlevel = function (s) {
242 if (s.length < 1) return lvl;
243 var mir = (s.charAt(0) == '\u00bb');
244 for (var f = 0; f < s.length; f++) {
245 var ch = s.charAt(f);
251 if (ch == '\u00bb') lvl++; else break;
253 if (ch == '>') lvl++;
254 else if (ch == '&' && s.substr(f, 4) == ">") { lvl++; f += 3; }
261 // search for "big" quotes
262 for (var f = 0; f < lines.length; f++) {
263 var s = trimR(lines[f]);
266 s = '<span class="msgquotebig">'+jj(0, f)+"</span>\n"+jj(f+1, lines.length-1);
270 // mark "small" quotes
271 for (var f = 0; f < lines.length; f++) {
272 var s = trimR(lines[f]);
276 s = '<span class="msgquote'+lvl+'">'+s+"</span>";
280 //return "cnt: "+(lines.length)+ "\n"+jj(0, lines.length-1);
281 return jj(0, lines.length-1);
290 * string .action (or null/false/empty string)
292 function addChatMessage (msg) {
293 var wasAtBottom = chatAtBottom();
295 var user = api.contactInfo(msg.uni);
296 var nick = user ? user.verbatim : msg.uni;
298 var isMine = msg.ismine, unixDate = msg.unixdate, text = msg.text;
300 //api.printLn("t=["+text+"]");
301 text = text.replace(/\r\n/g, "\n");
302 text = text.replace(/<br\s*>/g, "\n");
303 text = text.replace(/<br\s*\/>/g, "\n");
305 text = fixLongWords(text);
306 text = colorizeQuotes(text);
307 text = text.replace(/\n/g, "<br />\n");
309 msgCur++; msgCount++;
311 var div = document.createElement("div");
312 div.setAttribute("id", "msg_"+msgCur);
313 div.setAttribute("class", "message");
315 var timespan = document.createElement("span");
316 timespan.setAttribute("class", "time");
319 dt.setTime(unixDate*1000);
320 timespan.innerHTML = date2Str(dt);
321 div.appendChild(timespan);
324 var markspan = document.createElement("span");
325 markspan.setAttribute("style", "float:right;padding:2px;color:#"+(id%2?"999":"0c0"));
326 markspan.setAttribute("id", "mark_msg_"+id);
327 markspan.innerHTML = "*";
328 div.appendChild(markspan);
331 var hdrdiv = document.createElement("div");
332 hdrdiv.setAttribute("class", "msghead "+(isMine?"msgmine":"msgalien"));
333 hdrdiv.innerText = nick;
334 if (!isMine) hdrdiv.innerHTML = "<b>"+hdrdiv.innerHTML+"</b>";
335 //hdrdiv.style.color = isMine?"#f70":"#aaa";
336 div.appendChild(hdrdiv);
340 var adiv = document.createElement("div");
341 adiv.setAttribute("class", "actiontext");
342 adiv.innerHTML = "*<b>"+nick+"</b> "+msg.action;
343 adiv.style.color = isMine?"#f70":"#aaa";
344 div.appendChild(adiv);
347 var txtdiv = document.createElement("div");
348 txtdiv.setAttribute("class", "msgtext");
349 txtdiv.innerHTML = text;
350 txtdiv.style.color = isMine?"#f70":"#aaa";
351 div.appendChild(txtdiv);
353 document.body.appendChild(div);
355 var fs = api.getOption("/chat/forcescroll");
356 //api.printLn("fs="+fs+"; wasBt="+wasAtBottom);
357 if (fs > 1 || ((fs === null || fs == 1) && wasAtBottom)) {
359 api.scrollToBottom();
368 api.printLn("type: "+typeof(v)+"; value: "+v);
371 function parr (arr) {
373 if (typeof(k) != "string") continue;
375 api.printLn("["+k+"]: ("+typeof(v)+") ["+v+"]");
380 var info = api.contactInfo("psyc://ketmar.no-ip.org/@dyskgit");
381 api.printLn(">>"+info);
390 pval(api.test("str"));
392 pval(api.test([1,2]));
393 pval(api.test({a:4, b:5}));
398 var ok = api.addMessage(
399 "psyc://127.0.0.1/@Testbed", // place
400 "psyc://127.0.0.1/~rtorrent_bot", // user
401 0, // current time (or any other unixtime)
402 "test of the <b>rTorrent</b>-<i>bot</i>\nsecond line",
403 " DONTTOUCH|" // no action, "\x20DONTTOUCH|" means 'don't de-htmlize message' mode; action text can be added after '|'
406 api.addMessageEx() has one more arg:
407 `popupMsg` -- message for popup window; prepend it with '\x01' to
408 disable de-htmlization
412 function testAddMessage () {
413 var ok = api.addMessage(
414 "psyc://ketmar.no-ip.org/@Testbed",
415 "psyc://ketmar.no-ip.org/~rtorrent_bot",
417 "test of the <b>rTorrent</b>-<i>bot</i>\nsecond line",
418 " DONTTOUCH|" // no action, 'don't de-htmlize message' mode
420 api.printLn("addMessage: "+(ok?"ok":"FAILED"));
424 window.onload = function () {
425 //api.printLn("!!!");
426 document.body.innerHTML = '<div style="position:fixed;right:4px;top:4px;background-color:#fff;border:1px solid #666;padding:5px;"><img alt="" width="130" height="26" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIIAAAAaCAAAAABeXdsPAAAAAnRSTlMA/1uRIrUAAAKmSURBVBgZxcFfaJV1HMfx93NOj5ud0kq7KLUJyUyPwSKjeRiRRTwIEhrK9MKLLsbsosgdDBklXUyk6I9mEWgXgpyr2M3AEPQmMEFEhIEP2J+xqRcqZtnSraPbp+f5PWuec57nG7s7rxdqOqTqvlefaZItg1MSuvkCTdQ7JdTD1kq2vQv4T+HdSqav34KPKrFd7dR7oxIbeBZY1FfJ1N8Bh8TIPI7JMLqCxLJTMozCqJzPqfPI73LehrXnZRiANvEd9MlyeT6xwo+y7IUjcsZaqeH1KdHB4jFZeuHhKwTw1J+yHG8h8olMqyBQ4vKlGj8rcbXgDcky+TQQEgDfy7QOaL8jy3Ae8mdke4dtMh0lEhIAW6uynAAOy3K3l8jGaVlGWvxhWf7ZSCQkILKylPKVnImlUJUzVEp5EueADBNraFOiv5SynFhIQLZFVTmdvKLEi1gKJ5Vp8k3olnN3MYaQAMMxxa6v5jU5FQ9T4VtlmNwEdMs5iCUkwOD5sTx4vuPxPzw/w0NEcr7jYQkJiHl+JMfc5f1YjkZ+jBo53/GwhARElpxW5LdtzNWyUcV+op5/cFqR3a3M+kzO+1hCAiLDcv5ewhx9IOcG9T5VYjuzDssJsYQEQFtViSIZFpbSxuQMUe+qEmVmdcu5/16p0SqckADo0owiGY7L9Dr1xpUoM+vR6zLcu72CSEgAdGlGkbTnJmS5Mp9640qUeWCPTHuIhARAl2YUSftYlqkNNBhXoswDj12U5RyRkNNA6x0liqQNy7KbRmeVKFOj85YM0y/DE7e4sRD4Us6vBVJW35Ohv4VGO+VUX6LW2j9kGID1QoeA/OYdscdJ67x2M9OFLaTleiqRb4rUe/5IJdMXHfih0NR+n6ZZ+oOEpF8Gd/Y0xYeDf0lCTfcvvNUp6vFYBGgAAAAASUVORK5CYII=" /></div>';
428 //setTimeout(testAddMessage, 5000);
431 function htmlEscape (s) {
432 s = s.replace(/[\x01-\x1f]/g, "_").
433 replace(/[&]/g, "&").
434 replace(/[<]/g, "<").
435 replace(/[>]/g, ">").
436 replace(/[\x22]/g, """);
441 function doPktRTorrent (pkt) {
442 var s = "torrent: <b>"+htmlEscape(pkt.vars["_torrent_name"])+"</b> <i>("+pkt.vars["_torrent_hash"]+")</i>\n";
443 s += "action: <b>"+pkt.vars["_torrent_action"]+"</b>\n";
444 var udt = new Date();
445 udt = Math.floor(udt.getTime()/1000);
449 uni:"psyc://ketmar.no-ip.org/~rtorrent",
457 function onPSYCPacket () {
458 //dumpPacket(psycpkt);
461 if (pkt.method && pkt.method == "_notice_rtorrent") doPktRTorrent(pkt);