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 */
4 // Holds anything kiwi client specific (ie. front, gateway, kiwi.plugs..)
13 * Suppresses console.log
14 * @param {Boolean} debug Whether to re-enable console.log or not
16 function manageDebug(debug
) {
18 var log
, consoleBackUp
;
20 consoleBackUp
= window
.console
.log
;
21 window
.console
.log = function () {
23 consoleBackUp
.apply(console
, arguments
);
27 log
= window
.opera
? window
.opera
.postError
: alert
;
29 window
.console
.log = function (str
) {
38 * Generate a random string of given length
39 * @param {Number} string_length The length of the random string
40 * @returns {String} The random string
42 function randomString(string_length
) {
43 var chars
= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz",
47 for (i
= 0; i
< string_length
; i
++) {
48 rnum
= Math
.floor(Math
.random() * chars
.length
);
49 randomstring
+= chars
.substring(rnum
, rnum
+ 1);
57 if (typeof String
.prototype.trim
=== 'undefined') {
58 String
.prototype.trim = function () {
59 return this.replace(/^\s+|\s+$/g, "");
65 * @param {Number} length The length of padding
66 * @param {String} characher The character to pad with
67 * @returns {String} The padded string
69 if (typeof String
.prototype.lpad
=== 'undefined') {
70 String
.prototype.lpad = function (length
, character
) {
73 for (i
= 0; i
< length
; i
++) {
76 return (padding
+ this).slice(-length
);
82 * Convert seconds into hours:minutes:seconds
83 * @param {Number} secs The number of seconds to converts
84 * @returns {Object} An object representing the hours/minutes/second conversion of secs
86 function secondsToTime(secs
) {
87 var hours
, minutes
, seconds
, divisor_for_minutes
, divisor_for_seconds
, obj
;
88 hours
= Math
.floor(secs
/ (60 * 60));
90 divisor_for_minutes
= secs
% (60 * 60);
91 minutes
= Math
.floor(divisor_for_minutes
/ 60);
93 divisor_for_seconds
= divisor_for_minutes
% 60;
94 seconds
= Math
.ceil(divisor_for_seconds
);
110 * Formats a message. Adds bold, underline and colouring
111 * @param {String} msg The message to format
112 * @returns {String} The HTML formatted message
114 function formatIRCMsg (msg
) {
117 if ((!msg
) || (typeof msg
!== 'string')) {
122 if (msg
.indexOf(String
.fromCharCode(2)) !== -1) {
124 while (msg
.indexOf(String
.fromCharCode(2)) !== -1) {
125 msg
= msg
.replace(String
.fromCharCode(2), next
);
126 next
= (next
=== '<b>') ? '</b>' : '<b>';
128 if (next
=== '</b>') {
134 if (msg
.indexOf(String
.fromCharCode(31)) !== -1) {
136 while (msg
.indexOf(String
.fromCharCode(31)) !== -1) {
137 msg
= msg
.replace(String
.fromCharCode(31), next
);
138 next
= (next
=== '<u>') ? '</u>' : '<u>';
140 if (next
=== '</u>') {
149 msg
= (function (msg
) {
150 var replace
, colourMatch
, col
, i
, match
, to
, endCol
, fg
, bg
, str
;
155 colourMatch = function (str
) {
156 var re
= /^\x03([0-9][0-5]?)(,([0-9][0-5]?))?/;
162 col = function (num
) {
163 switch (parseInt(num
, 10)) {
200 if (msg
.indexOf('\x03') !== -1) {
201 i
= msg
.indexOf('\x03');
202 replace
= msg
.substr(0, i
);
203 while (i
< msg
.length
) {
207 match
= colourMatch(msg
.substr(i
, 6));
209 //console.log(match);
211 to
= msg
.indexOf('\x03', i
+ 1);
212 endCol
= msg
.indexOf(String
.fromCharCode(15), i
+ 1);
217 to
= ((to
< endCol
) ? to
: endCol
);
223 //console.log(i, to);
226 str
= msg
.substring(i
+ 1 + match
[1].length
+ ((bg
!== null) ? match
[2].length
+ 1 : 0), to
);
228 replace
+= '<span style="' + ((fg
!== null) ? 'color: ' + fg
+ '; ' : '') + ((bg
!== null) ? 'background-color: ' + bg
+ ';' : '') + '">' + str
+ '</span>';
231 if ((msg
[i
] !== '\x03') && (msg
[i
] !== String
.fromCharCode(15))) {
254 Each function in each object is looped through and ran. The resulting text
255 is expected to be returned.
260 onaddmsg: function (event
, opts
) {
265 event
.msg
= event
.msg
.replace(/^((https?\:\/\/|ftp\:\/\/)|(www\.))(\S+)(\w{2,4})(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?(\.jpg|\.jpeg|\.gif|\.bmp|\.png)$/gi, function (url
) {
266 // Don't let any future plugins change it (ie. html_safe plugins)
267 event
.event_bubbles
= false;
269 var img
= '<img class="link_img_a" src="' + url
+ '" height="100%" width="100%" />';
270 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>';
279 onaddmsg: function (event
, opts
) {
280 event
.msg
= $('<div/>').text(event
.msg
).html();
281 event
.nick
= $('<div/>').text(event
.nick
).html();
289 onaddmsg: function (event
, opts
) {
290 //if (kiwi.front.cur_channel.name.toLowerCase() !== kiwi.front.tabviews[event.tabview.toLowerCase()].name) {
291 // kiwi.front.tabviews[event.tabview].activity();
300 onaddmsg: function (event
, opts
) {
301 //var tab = Tabviews.getTab(event.tabview.toLowerCase());
303 // If we have a highlight...
304 //if (event.msg.toLowerCase().indexOf(kiwi.gateway.nick.toLowerCase()) > -1) {
305 // if (Tabview.getCurrentTab() !== tab) {
308 // if (kiwi.front.isChannel(tab.name)) {
309 // event.msg = '<span style="color:red;">' + event.msg + '</span>';
313 // If it's a PM, highlight
314 //if (!kiwi.front.isChannel(tab.name) && tab.name !== "server"
315 // && Tabview.getCurrentTab().name.toLowerCase() !== tab.name
327 //Following method taken from: http://snipplr.com/view/13533/convert-text-urls-into-links/
328 name
: "linkify_plain",
329 onaddmsg: function (event
, opts
) {
334 event
.msg
= event
.msg
.replace(/((https?\:\/\/|ftp\:\/\/)|(www\.))(\S+)(\w{2,4})(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/gi, function (url
) {
336 // If it's any of the supported images in the images plugin, skip it
337 if (url
.match(/(\.jpg|\.jpeg|\.gif|\.bmp|\.png)$/)) {
342 if (url
.match('^https?:\/\/')) {
343 //nice = nice.replace(/^https?:\/\//i,'')
344 nice
= url
; // Shutting up JSLint...
346 url
= 'http://' + url
;
349 //return '<a class="link_ext" target="_blank" rel="nofollow" href="' + url + '">' + nice + '<div class="tt box"></div></a>';
350 return '<a class="link_ext" target="_blank" rel="nofollow" href="' + url
+ '">' + nice
+ '</a>';
359 onaddmsg: function (event
, opts
) {
364 event
.msg
= event
.msg
.replace(/\n/gi, function (txt
) {
374 * Disabled due to many websites closing kiwi with iframe busting
377 oninit: function (event, opts) {
378 $('#windows a.link_ext').live('mouseover', this.mouseover);
379 $('#windows a.link_ext').live('mouseout', this.mouseout);
380 $('#windows a.link_ext').live('click', this.mouseclick);
383 onunload: function (event, opts) {
384 // TODO: make this work (remove all .link_ext_browser as created in mouseover())
385 $('#windows a.link_ext').die('mouseover', this.mouseover);
386 $('#windows a.link_ext').die('mouseout', this.mouseout);
387 $('#windows a.link_ext').die('click', this.mouseclick);
392 mouseover: function (e) {
397 if (tt.text() === '') {
398 tooltip = $('<a class="link_ext_browser">Open in Kiwi..</a>');
402 tt.css('top', -tt.outerHeight() + 'px');
403 tt.css('left', (a.outerWidth() / 2) - (tt.outerWidth() / 2));
406 mouseout: function (e) {
411 mouseclick: function (e) {
415 switch (e.target.className) {
420 case 'link_ext_browser':
421 t = new Utilityview('Browser');
422 t.topic = a.attr('href');
424 t.iframe = $('<iframe border="0" class="utility_view" src="" style="width:100%;height:100%;border:none;"></iframe>');
425 t.iframe.attr('src', a.attr('href'));
426 t.div.append(t.iframe);
438 onaddmsg: function (event
, opts
) {
443 //if (typeof kiwi.front.tabviews[event.tabview].nick_colours === 'undefined') {
444 // kiwi.front.tabviews[event.tabview].nick_colours = {};
447 //if (typeof kiwi.front.tabviews[event.tabview].nick_colours[event.nick] === 'undefined') {
448 // kiwi.front.tabviews[event.tabview].nick_colours[event.nick] = this.randColour();
451 //var c = kiwi.front.tabviews[event.tabview].nick_colours[event.nick];
452 var c
= this.randColour();
453 event
.nick
= '<span style="color:' + c
+ ';">' + event
.nick
+ '</span>';
460 randColour: function () {
461 var h
= this.rand(-250, 0),
462 s
= this.rand(30, 100),
463 l
= this.rand(20, 70);
464 return 'hsl(' + h
+ ',' + s
+ '%,' + l
+ '%)';
468 rand: function (min
, max
) {
469 return parseInt(Math
.random() * (max
- min
+ 1), 10) + min
;
475 oninit: function (event
, opts
) {
476 console
.log('registering namespace');
477 $(gateway
).bind("kiwi.lol.browser", function (e
, data
) {
478 console
.log('YAY kiwitest');
498 kiwi
.plugs
.loaded
= {};
501 * @param {Object} plugin The plugin to be loaded
502 * @returns {Boolean} True on success, false on failure
504 kiwi
.plugs
.loadPlugin = function (plugin
) {
506 if (typeof plugin
.name
!== 'string') {
510 plugin_ret
= kiwi
.plugs
.run('plugin_load', {plugin
: plugin
});
511 if (typeof plugin_ret
=== 'object') {
512 kiwi
.plugs
.loaded
[plugin_ret
.plugin
.name
] = plugin_ret
.plugin
;
513 kiwi
.plugs
.loaded
[plugin_ret
.plugin
.name
].local_data
= new kiwi
.dataStore('kiwi_plugin_' + plugin_ret
.plugin
.name
);
515 kiwi
.plugs
.run('init', {}, {run_only
: plugin_ret
.plugin
.name
});
522 * @param {String} plugin_name The name of the plugin to unload
524 kiwi
.plugs
.unloadPlugin = function (plugin_name
) {
525 if (typeof kiwi
.plugs
.loaded
[plugin_name
] !== 'object') {
529 kiwi
.plugs
.run('unload', {}, {run_only
: plugin_name
});
530 delete kiwi
.plugs
.loaded
[plugin_name
];
536 * Run an event against all loaded plugins
537 * @param {String} event_name The name of the event
538 * @param {Object} event_data The data to pass to the plugin
539 * @param {Object} opts Options
540 * @returns {Object} Event data, possibly modified by the plugins
542 kiwi
.plugs
.run = function (event_name
, event_data
, opts
) {
543 var ret
= event_data
,
547 // Set some defaults if not provided
548 event_data
= (typeof event_data
=== 'undefined') ? {} : event_data
;
549 opts
= (typeof opts
=== 'undefined') ? {} : opts
;
551 for (plugin_name
in kiwi
.plugs
.loaded
) {
552 // If we're only calling 1 plugin, make sure it's that one
553 if (typeof opts
.run_only
=== 'string' && opts
.run_only
!== plugin_name
) {
557 if (typeof kiwi
.plugs
.loaded
[plugin_name
]['on' + event_name
] === 'function') {
559 ret_tmp
= kiwi
.plugs
.loaded
[plugin_name
]['on' + event_name
](ret
, opts
);
560 if (ret_tmp
=== null) {
565 if (typeof ret
.event_bubbles
=== 'boolean' && ret
.event_bubbles
=== false) {
566 delete ret
.event_bubbles
;
581 * @param {String} data_namespace The namespace for the data store
583 kiwi
.dataStore = function (data_namespace
) {
584 var namespace = data_namespace
;
586 this.get = function (key
) {
587 return $.jStorage
.get(data_namespace
+ '_' + key
);
590 this.set = function (key
, value
) {
591 return $.jStorage
.set(data_namespace
+ '_' + key
, value
);
595 kiwi
.data
= new kiwi
.dataStore('kiwi');
601 * jQuery jStorage plugin
602 * https://github.com/andris9/jStorage/
604 (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
.$);