Merge branch 'development'
[KiwiIRC.git] / client / assets / dev / utils.js
CommitLineData
2dd6a025
D
1/*jslint devel: true, browser: true, continue: true, sloppy: true, forin: true, plusplus: true, maxerr: 50, indent: 4, nomen: true, regexp: true*/
2/*globals $, front, gateway, Utilityview */
3
2dd6a025
D
4
5
6/**
7* Suppresses console.log
8* @param {Boolean} debug Whether to re-enable console.log or not
9*/
10function manageDebug(debug) {
2dd6a025
D
11 var log, consoleBackUp;
12 if (window.console) {
13 consoleBackUp = window.console.log;
14 window.console.log = function () {
15 if (debug) {
16 consoleBackUp.apply(console, arguments);
17 }
18 };
19 } else {
20 log = window.opera ? window.opera.postError : alert;
21 window.console = {};
22 window.console.log = function (str) {
23 if (debug) {
24 log(str);
25 }
26 };
27 }
28}
29
30/**
31* Generate a random string of given length
32* @param {Number} string_length The length of the random string
33* @returns {String} The random string
34*/
35function randomString(string_length) {
36 var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz",
37 randomstring = '',
38 i,
39 rnum;
40 for (i = 0; i < string_length; i++) {
41 rnum = Math.floor(Math.random() * chars.length);
42 randomstring += chars.substring(rnum, rnum + 1);
43 }
44 return randomstring;
45}
46
47/**
48* String.trim shim
49*/
50if (typeof String.prototype.trim === 'undefined') {
51 String.prototype.trim = function () {
52 return this.replace(/^\s+|\s+$/g, "");
53 };
54}
55
56/**
57* String.lpad shim
58* @param {Number} length The length of padding
59* @param {String} characher The character to pad with
60* @returns {String} The padded string
61*/
62if (typeof String.prototype.lpad === 'undefined') {
63 String.prototype.lpad = function (length, character) {
64 var padding = "",
65 i;
66 for (i = 0; i < length; i++) {
67 padding += character;
68 }
69 return (padding + this).slice(-length);
70 };
71}
72
73
74/**
75* Convert seconds into hours:minutes:seconds
76* @param {Number} secs The number of seconds to converts
77* @returns {Object} An object representing the hours/minutes/second conversion of secs
78*/
79function secondsToTime(secs) {
80 var hours, minutes, seconds, divisor_for_minutes, divisor_for_seconds, obj;
81 hours = Math.floor(secs / (60 * 60));
82
83 divisor_for_minutes = secs % (60 * 60);
84 minutes = Math.floor(divisor_for_minutes / 60);
85
86 divisor_for_seconds = divisor_for_minutes % 60;
87 seconds = Math.ceil(divisor_for_seconds);
88
89 obj = {
90 "h": hours,
91 "m": minutes,
92 "s": seconds
93 };
94 return obj;
95}
96
97
98
99
64c6bcb4
D
100
101
102/* Command input Alias + re-writing */
103function InputPreProcessor () {
104 this.recursive_depth = 3;
105
106 this.aliases = {};
107 this.vars = {version: 1};
108
109 // Current recursive depth
110 var depth = 0;
111
112
113 // Takes an array of words to process!
114 this.processInput = function (input) {
115 var words = input || [],
116 alias = this.aliases[words[0]],
117 alias_len,
118 current_alias_word = '',
119 compiled = [];
120
121 // If an alias wasn't found, return the original input
122 if (!alias) return input;
123
124 // Split the alias up into useable words
125 alias = alias.split(' ');
126 alias_len = alias.length;
127
128 // Iterate over each word and pop them into the final compiled array.
129 // Any $ words are processed with the result ending into the compiled array.
130 for (var i=0; i<alias_len; i++) {
131 current_alias_word = alias[i];
132
133 // Non $ word
134 if (current_alias_word[0] !== '$') {
135 compiled.push(current_alias_word);
136 continue;
137 }
138
139 // Refering to an input word ($N)
140 if (!isNaN(current_alias_word[1])) {
141 var num = current_alias_word.match(/\$(\d+)(\+)?(\d+)?/);
142
143 // Did we find anything or does the word it refers to non-existant?
144 if (!num || !words[num[1]]) continue;
145
146 if (num[2] === '+' && num[3]) {
147 // Add X number of words
148 compiled = compiled.concat(words.slice(parseInt(num[1], 10), parseInt(num[1], 10) + parseInt(num[3], 10)));
149 } else if (num[2] === '+') {
150 // Add the remaining of the words
151 compiled = compiled.concat(words.slice(parseInt(num[1], 10)));
152 } else {
153 // Add a single word
154 compiled.push(words[parseInt(num[1], 10)]);
155 }
156
157 continue;
158 }
159
160
161 // Refering to a variable
162 if (typeof this.vars[current_alias_word.substr(1)] !== 'undefined') {
163
164 // Get the variable
165 compiled.push(this.vars[current_alias_word.substr(1)]);
166
167 continue;
168 }
169
170 }
171
172 return compiled;
173 };
174
175
176 this.process = function (input) {
177 input = input || '';
178
179 var words = input.split(' ');
180
181 depth++;
182 if (depth >= this.recursive_depth) {
183 depth--;
184 return input;
185 }
186
187 if (this.aliases[words[0]]) {
188 words = this.processInput(words);
189
190 if (this.aliases[words[0]]) {
191 words = this.process(words.join(' ')).split(' ');
192 }
193
194 }
195
196 depth--;
197 return words.join(' ');
198 };
199}
200
201
202
203
204
205
206
21536e7b
D
207
208
209
210
1167a85d
D
211/**
212 * Convert HSL to RGB formatted colour
213 */
214function hsl2rgb(h, s, l) {
215 var m1, m2, hue;
216 var r, g, b
217 s /=100;
218 l /= 100;
219 if (s == 0)
220 r = g = b = (l * 255);
221 else {
222 function HueToRgb(m1, m2, hue) {
223 var v;
224 if (hue < 0)
225 hue += 1;
226 else if (hue > 1)
227 hue -= 1;
228
229 if (6 * hue < 1)
230 v = m1 + (m2 - m1) * hue * 6;
231 else if (2 * hue < 1)
232 v = m2;
233 else if (3 * hue < 2)
234 v = m1 + (m2 - m1) * (2/3 - hue) * 6;
235 else
236 v = m1;
237
238 return 255 * v;
239 }
240 if (l <= 0.5)
241 m2 = l * (s + 1);
242 else
243 m2 = l + s - l * s;
244 m1 = l * 2 - m2;
245 hue = h / 360;
246 r = HueToRgb(m1, m2, hue + 1/3);
247 g = HueToRgb(m1, m2, hue);
248 b = HueToRgb(m1, m2, hue - 1/3);
249 }
250 return [r,g,b];
251}
252
253
254
255
2dd6a025 256
2dd6a025
D
257/**
258* Formats a message. Adds bold, underline and colouring
259* @param {String} msg The message to format
260* @returns {String} The HTML formatted message
261*/
262function formatIRCMsg (msg) {
263 var re, next;
264
265 if ((!msg) || (typeof msg !== 'string')) {
266 return '';
267 }
268
269 // bold
270 if (msg.indexOf(String.fromCharCode(2)) !== -1) {
271 next = '<b>';
272 while (msg.indexOf(String.fromCharCode(2)) !== -1) {
273 msg = msg.replace(String.fromCharCode(2), next);
274 next = (next === '<b>') ? '</b>' : '<b>';
275 }
276 if (next === '</b>') {
277 msg = msg + '</b>';
278 }
279 }
280
281 // underline
282 if (msg.indexOf(String.fromCharCode(31)) !== -1) {
283 next = '<u>';
284 while (msg.indexOf(String.fromCharCode(31)) !== -1) {
285 msg = msg.replace(String.fromCharCode(31), next);
286 next = (next === '<u>') ? '</u>' : '<u>';
287 }
288 if (next === '</u>') {
289 msg = msg + '</u>';
290 }
291 }
292
293 // colour
294 /**
295 * @inner
296 */
297 msg = (function (msg) {
298 var replace, colourMatch, col, i, match, to, endCol, fg, bg, str;
299 replace = '';
300 /**
301 * @inner
302 */
303 colourMatch = function (str) {
304 var re = /^\x03([0-9][0-5]?)(,([0-9][0-5]?))?/;
305 return re.exec(str);
306 };
307 /**
308 * @inner
309 */
310 col = function (num) {
311 switch (parseInt(num, 10)) {
312 case 0:
313 return '#FFFFFF';
314 case 1:
315 return '#000000';
316 case 2:
317 return '#000080';
318 case 3:
319 return '#008000';
320 case 4:
321 return '#FF0000';
322 case 5:
323 return '#800040';
324 case 6:
325 return '#800080';
326 case 7:
327 return '#FF8040';
328 case 8:
329 return '#FFFF00';
330 case 9:
331 return '#80FF00';
332 case 10:
333 return '#008080';
334 case 11:
335 return '#00FFFF';
336 case 12:
337 return '#0000FF';
338 case 13:
339 return '#FF55FF';
340 case 14:
341 return '#808080';
342 case 15:
343 return '#C0C0C0';
344 default:
345 return null;
346 }
347 };
348 if (msg.indexOf('\x03') !== -1) {
349 i = msg.indexOf('\x03');
350 replace = msg.substr(0, i);
351 while (i < msg.length) {
352 /**
353 * @inner
354 */
355 match = colourMatch(msg.substr(i, 6));
356 if (match) {
357 //console.log(match);
358 // Next colour code
359 to = msg.indexOf('\x03', i + 1);
360 endCol = msg.indexOf(String.fromCharCode(15), i + 1);
361 if (endCol !== -1) {
362 if (to === -1) {
363 to = endCol;
364 } else {
365 to = ((to < endCol) ? to : endCol);
366 }
367 }
368 if (to === -1) {
369 to = msg.length;
370 }
371 //console.log(i, to);
372 fg = col(match[1]);
373 bg = col(match[3]);
9e8814a3 374 str = msg.substring(i + 1 + match[1].length + ((bg !== null) ? match[2].length : 0), to);
2dd6a025
D
375 //console.log(str);
376 replace += '<span style="' + ((fg !== null) ? 'color: ' + fg + '; ' : '') + ((bg !== null) ? 'background-color: ' + bg + ';' : '') + '">' + str + '</span>';
377 i = to;
378 } else {
379 if ((msg[i] !== '\x03') && (msg[i] !== String.fromCharCode(15))) {
380 replace += msg[i];
381 }
382 i++;
383 }
384 }
385 return replace;
386 }
387 return msg;
388 }(msg));
389
390 return msg;
391}
392
393
394
395
51a4c383
D
396function formatDate (d) {
397 d = d || new Date();
398 return d.toLocaleDateString() + ', ' + d.getHours().toString() + ':' + d.getMinutes().toString() + ':' + d.getSeconds().toString();
399}
400
401
402
403
2dd6a025
D
404
405
406
407
408/*
409 PLUGINS
410 Each function in each object is looped through and ran. The resulting text
411 is expected to be returned.
412*/
413var plugins = [
414 {
415 name: "images",
416 onaddmsg: function (event, opts) {
417 if (!event.msg) {
418 return event;
419 }
420
421 event.msg = event.msg.replace(/^((https?\:\/\/|ftp\:\/\/)|(www\.))(\S+)(\w{2,4})(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?(\.jpg|\.jpeg|\.gif|\.bmp|\.png)$/gi, function (url) {
422 // Don't let any future plugins change it (ie. html_safe plugins)
423 event.event_bubbles = false;
424
425 var img = '<img class="link_img_a" src="' + url + '" height="100%" width="100%" />';
426 return '<a class="link_ext link_img" target="_blank" rel="nofollow" href="' + url + '" style="height:50px;width:50px;display:block">' + img + '<div class="tt box"></div></a>';
427 });
428
429 return event;
430 }
431 },
432
433 {
434 name: "html_safe",
435 onaddmsg: function (event, opts) {
436 event.msg = $('<div/>').text(event.msg).html();
437 event.nick = $('<div/>').text(event.nick).html();
438
439 return event;
440 }
441 },
442
443 {
444 name: "activity",
445 onaddmsg: function (event, opts) {
eaaf73b0
D
446 //if (_kiwi.front.cur_channel.name.toLowerCase() !== _kiwi.front.tabviews[event.tabview.toLowerCase()].name) {
447 // _kiwi.front.tabviews[event.tabview].activity();
2dd6a025
D
448 //}
449
450 return event;
451 }
452 },
453
454 {
455 name: "highlight",
456 onaddmsg: function (event, opts) {
457 //var tab = Tabviews.getTab(event.tabview.toLowerCase());
458
459 // If we have a highlight...
eaaf73b0 460 //if (event.msg.toLowerCase().indexOf(_kiwi.gateway.nick.toLowerCase()) > -1) {
2dd6a025
D
461 // if (Tabview.getCurrentTab() !== tab) {
462 // tab.highlight();
463 // }
eaaf73b0 464 // if (_kiwi.front.isChannel(tab.name)) {
2dd6a025
D
465 // event.msg = '<span style="color:red;">' + event.msg + '</span>';
466 // }
467 //}
468
469 // If it's a PM, highlight
eaaf73b0 470 //if (!_kiwi.front.isChannel(tab.name) && tab.name !== "server"
2dd6a025
D
471 // && Tabview.getCurrentTab().name.toLowerCase() !== tab.name
472 //) {
473 // tab.highlight();
474 //}
475
476 return event;
477 }
478 },
479
480
481
482 {
483 //Following method taken from: http://snipplr.com/view/13533/convert-text-urls-into-links/
484 name: "linkify_plain",
485 onaddmsg: function (event, opts) {
486 if (!event.msg) {
487 return event;
488 }
489
490 event.msg = event.msg.replace(/((https?\:\/\/|ftp\:\/\/)|(www\.))(\S+)(\w{2,4})(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/gi, function (url) {
491 var nice;
492 // If it's any of the supported images in the images plugin, skip it
493 if (url.match(/(\.jpg|\.jpeg|\.gif|\.bmp|\.png)$/)) {
494 return url;
495 }
496
497 nice = url;
498 if (url.match('^https?:\/\/')) {
499 //nice = nice.replace(/^https?:\/\//i,'')
500 nice = url; // Shutting up JSLint...
501 } else {
502 url = 'http://' + url;
503 }
504
505 //return '<a class="link_ext" target="_blank" rel="nofollow" href="' + url + '">' + nice + '<div class="tt box"></div></a>';
506 return '<a class="link_ext" target="_blank" rel="nofollow" href="' + url + '">' + nice + '</a>';
507 });
508
509 return event;
510 }
511 },
512
513 {
514 name: "lftobr",
515 onaddmsg: function (event, opts) {
516 if (!event.msg) {
517 return event;
518 }
519
520 event.msg = event.msg.replace(/\n/gi, function (txt) {
521 return '<br/>';
522 });
523
524 return event;
525 }
526 },
527
528
529 /*
530 * Disabled due to many websites closing kiwi with iframe busting
531 {
532 name: "inBrowser",
533 oninit: function (event, opts) {
534 $('#windows a.link_ext').live('mouseover', this.mouseover);
535 $('#windows a.link_ext').live('mouseout', this.mouseout);
536 $('#windows a.link_ext').live('click', this.mouseclick);
537 },
538
539 onunload: function (event, opts) {
540 // TODO: make this work (remove all .link_ext_browser as created in mouseover())
541 $('#windows a.link_ext').die('mouseover', this.mouseover);
542 $('#windows a.link_ext').die('mouseout', this.mouseout);
543 $('#windows a.link_ext').die('click', this.mouseclick);
544 },
545
546
547
548 mouseover: function (e) {
549 var a = $(this),
550 tt = $('.tt', a),
551 tooltip;
552
553 if (tt.text() === '') {
eaaf73b0 554 tooltip = $('<a class="link_ext_browser">Open in _kiwi..</a>');
2dd6a025
D
555 tt.append(tooltip);
556 }
557
558 tt.css('top', -tt.outerHeight() + 'px');
559 tt.css('left', (a.outerWidth() / 2) - (tt.outerWidth() / 2));
560 },
561
562 mouseout: function (e) {
563 var a = $(this),
564 tt = $('.tt', a);
565 },
566
567 mouseclick: function (e) {
568 var a = $(this),
569 t;
570
571 switch (e.target.className) {
572 case 'link_ext':
573 case 'link_img_a':
574 return true;
575 //break;
576 case 'link_ext_browser':
577 t = new Utilityview('Browser');
578 t.topic = a.attr('href');
579
580 t.iframe = $('<iframe border="0" class="utility_view" src="" style="width:100%;height:100%;border:none;"></iframe>');
581 t.iframe.attr('src', a.attr('href'));
582 t.div.append(t.iframe);
583 t.show();
584 break;
585 }
586 return false;
587
588 }
589 },
590 */
591
592 {
593 name: "nick_colour",
594 onaddmsg: function (event, opts) {
595 if (!event.msg) {
596 return event;
597 }
598
eaaf73b0
D
599 //if (typeof _kiwi.front.tabviews[event.tabview].nick_colours === 'undefined') {
600 // _kiwi.front.tabviews[event.tabview].nick_colours = {};
2dd6a025
D
601 //}
602
eaaf73b0
D
603 //if (typeof _kiwi.front.tabviews[event.tabview].nick_colours[event.nick] === 'undefined') {
604 // _kiwi.front.tabviews[event.tabview].nick_colours[event.nick] = this.randColour();
2dd6a025
D
605 //}
606
eaaf73b0 607 //var c = _kiwi.front.tabviews[event.tabview].nick_colours[event.nick];
2dd6a025
D
608 var c = this.randColour();
609 event.nick = '<span style="color:' + c + ';">' + event.nick + '</span>';
610
611 return event;
612 },
613
614
615
616 randColour: function () {
617 var h = this.rand(-250, 0),
618 s = this.rand(30, 100),
619 l = this.rand(20, 70);
620 return 'hsl(' + h + ',' + s + '%,' + l + '%)';
621 },
622
623
624 rand: function (min, max) {
625 return parseInt(Math.random() * (max - min + 1), 10) + min;
626 }
627 },
628
629 {
630 name: "kiwitest",
631 oninit: function (event, opts) {
632 console.log('registering namespace');
eaaf73b0 633 $(gateway).bind("_kiwi.lol.browser", function (e, data) {
2dd6a025
D
634 console.log('YAY kiwitest');
635 console.log(data);
636 });
637 }
638 }
639];
640
641
642
643
644
645
646
2dd6a025
D
647
648/**
649* @constructor
650* @param {String} data_namespace The namespace for the data store
651*/
eaaf73b0 652_kiwi.dataStore = function (data_namespace) {
2dd6a025
D
653 var namespace = data_namespace;
654
655 this.get = function (key) {
656 return $.jStorage.get(data_namespace + '_' + key);
657 };
658
659 this.set = function (key, value) {
660 return $.jStorage.set(data_namespace + '_' + key, value);
661 };
662};
663
eaaf73b0 664_kiwi.data = new _kiwi.dataStore('kiwi');
2dd6a025
D
665
666
667
668
669/*
670 * jQuery jStorage plugin
671 * https://github.com/andris9/jStorage/
672 */
673(function(f){if(!f||!(f.toJSON||Object.toJSON||window.JSON)){throw new Error("jQuery, MooTools or Prototype needs to be loaded before jStorage!")}var g={},d={jStorage:"{}"},h=null,j=0,l=f.toJSON||Object.toJSON||(window.JSON&&(JSON.encode||JSON.stringify)),e=f.evalJSON||(window.JSON&&(JSON.decode||JSON.parse))||function(m){return String(m).evalJSON()},i=false;_XMLService={isXML:function(n){var m=(n?n.ownerDocument||n:0).documentElement;return m?m.nodeName!=="HTML":false},encode:function(n){if(!this.isXML(n)){return false}try{return new XMLSerializer().serializeToString(n)}catch(m){try{return n.xml}catch(o){}}return false},decode:function(n){var m=("DOMParser" in window&&(new DOMParser()).parseFromString)||(window.ActiveXObject&&function(p){var q=new ActiveXObject("Microsoft.XMLDOM");q.async="false";q.loadXML(p);return q}),o;if(!m){return false}o=m.call("DOMParser" in window&&(new DOMParser())||window,n,"text/xml");return this.isXML(o)?o:false}};function k(){if("localStorage" in window){try{if(window.localStorage){d=window.localStorage;i="localStorage"}}catch(p){}}else{if("globalStorage" in window){try{if(window.globalStorage){d=window.globalStorage[window.location.hostname];i="globalStorage"}}catch(o){}}else{h=document.createElement("link");if(h.addBehavior){h.style.behavior="url(#default#userData)";document.getElementsByTagName("head")[0].appendChild(h);h.load("jStorage");var n="{}";try{n=h.getAttribute("jStorage")}catch(m){}d.jStorage=n;i="userDataBehavior"}else{h=null;return}}}b()}function b(){if(d.jStorage){try{g=e(String(d.jStorage))}catch(m){d.jStorage="{}"}}else{d.jStorage="{}"}j=d.jStorage?String(d.jStorage).length:0}function c(){try{d.jStorage=l(g);if(h){h.setAttribute("jStorage",d.jStorage);h.save("jStorage")}j=d.jStorage?String(d.jStorage).length:0}catch(m){}}function a(m){if(!m||(typeof m!="string"&&typeof m!="number")){throw new TypeError("Key name must be string or numeric")}return true}f.jStorage={version:"0.1.5.1",set:function(m,n){a(m);if(_XMLService.isXML(n)){n={_is_xml:true,xml:_XMLService.encode(n)}}g[m]=n;c();return n},get:function(m,n){a(m);if(m in g){if(g[m]&&typeof g[m]=="object"&&g[m]._is_xml&&g[m]._is_xml){return _XMLService.decode(g[m].xml)}else{return g[m]}}return typeof(n)=="undefined"?null:n},deleteKey:function(m){a(m);if(m in g){delete g[m];c();return true}return false},flush:function(){g={};c();return true},storageObj:function(){function m(){}m.prototype=g;return new m()},index:function(){var m=[],n;for(n in g){if(g.hasOwnProperty(n)){m.push(n)}}return m},storageSize:function(){return j},currentBackend:function(){return i},storageAvailable:function(){return !!i},reInit:function(){var m,o;if(h&&h.addBehavior){m=document.createElement("link");h.parentNode.replaceChild(m,h);h=m;h.style.behavior="url(#default#userData)";document.getElementsByTagName("head")[0].appendChild(h);h.load("jStorage");o="{}";try{o=h.getAttribute("jStorage")}catch(n){}d.jStorage=o;i="userDataBehavior"}b()}};k()})(window.jQuery||window.$);