merging extensive changes from prawnsalad/KiwiIRC
[KiwiIRC.git] / client / js / util.js
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
4 // Holds anything kiwi client specific (ie. front, gateway, kiwi.plugs..)
5 /**
6 * @namespace
7 */
8 var kiwi = {};
9
10
11
12 /**
13 * Suppresses console.log
14 * @param {Boolean} debug Whether to re-enable console.log or not
15 */
16 function manageDebug(debug) {
17 /* var log, consoleBackUp;
18 if (window.console) {
19 consoleBackUp = window.console.log;
20 window.console.log = function () {
21 if (debug) {
22 consoleBackUp.apply(console, arguments);
23 }
24 };
25 } else {
26 log = window.opera ? window.opera.postError : alert;
27 window.console = {};
28 window.console.log = function (str) {
29 if (debug) {
30 log(str);
31 }
32 };
33 }*/
34 }
35
36 /**
37 * Generate a random string of given length
38 * @param {Number} string_length The length of the random string
39 * @returns {String} The random string
40 */
41 function randomString(string_length) {
42 var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz",
43 randomstring = '',
44 i,
45 rnum;
46 for (i = 0; i < string_length; i++) {
47 rnum = Math.floor(Math.random() * chars.length);
48 randomstring += chars.substring(rnum, rnum + 1);
49 }
50 return randomstring;
51 }
52
53 /**
54 * String.trim shim
55 */
56 if (typeof String.prototype.trim === 'undefined') {
57 String.prototype.trim = function () {
58 return this.replace(/^\s+|\s+$/g, "");
59 };
60 }
61
62 /**
63 * String.lpad shim
64 * @param {Number} length The length of padding
65 * @param {String} characher The character to pad with
66 * @returns {String} The padded string
67 */
68 if (typeof String.prototype.lpad === 'undefined') {
69 String.prototype.lpad = function (length, character) {
70 var padding = "",
71 i;
72 for (i = 0; i < length; i++) {
73 padding += character;
74 }
75 return (padding + this).slice(-length);
76 };
77 }
78
79
80 /**
81 * Convert seconds into hours:minutes:seconds
82 * @param {Number} secs The number of seconds to converts
83 * @returns {Object} An object representing the hours/minutes/second conversion of secs
84 */
85 function secondsToTime(secs) {
86 var hours, minutes, seconds, divisor_for_minutes, divisor_for_seconds, obj;
87 hours = Math.floor(secs / (60 * 60));
88
89 divisor_for_minutes = secs % (60 * 60);
90 minutes = Math.floor(divisor_for_minutes / 60);
91
92 divisor_for_seconds = divisor_for_minutes % 60;
93 seconds = Math.ceil(divisor_for_seconds);
94
95 obj = {
96 "h": hours,
97 "m": minutes,
98 "s": seconds
99 };
100 return obj;
101 }
102
103
104 /*
105 PLUGINS
106 Each function in each object is looped through and ran. The resulting text
107 is expected to be returned.
108 */
109 var plugins = [
110 {
111 name: "images",
112 onaddmsg: function (event, opts) {
113 if (!event.msg) {
114 return event;
115 }
116
117 event.msg = event.msg.replace(/^((https?\:\/\/|ftp\:\/\/)|(www\.))(\S+)(\w{2,4})(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?(\.jpg|\.jpeg|\.gif|\.bmp|\.png)$/gi, function (url) {
118 // Don't let any future plugins change it (ie. html_safe plugins)
119 event.event_bubbles = false;
120
121 var img = '<img class="link_img_a" src="' + url + '" height="100%" width="100%" />';
122 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>';
123 });
124
125 return event;
126 }
127 },
128
129 {
130 name: "html_safe",
131 onaddmsg: function (event, opts) {
132 event.msg = $('<div/>').text(event.msg).html();
133 event.nick = $('<div/>').text(event.nick).html();
134
135 return event;
136 }
137 },
138
139 {
140 name: "activity",
141 onaddmsg: function (event, opts) {
142 //if (kiwi.front.cur_channel.name.toLowerCase() !== kiwi.front.tabviews[event.tabview.toLowerCase()].name) {
143 // kiwi.front.tabviews[event.tabview].activity();
144 //}
145
146 return event;
147 }
148 },
149
150 {
151 name: "highlight",
152 onaddmsg: function (event, opts) {
153 //var tab = Tabviews.getTab(event.tabview.toLowerCase());
154
155 // If we have a highlight...
156 //if (event.msg.toLowerCase().indexOf(kiwi.gateway.nick.toLowerCase()) > -1) {
157 // if (Tabview.getCurrentTab() !== tab) {
158 // tab.highlight();
159 // }
160 // if (kiwi.front.isChannel(tab.name)) {
161 // event.msg = '<span style="color:red;">' + event.msg + '</span>';
162 // }
163 //}
164
165 // If it's a PM, highlight
166 //if (!kiwi.front.isChannel(tab.name) && tab.name !== "server"
167 // && Tabview.getCurrentTab().name.toLowerCase() !== tab.name
168 //) {
169 // tab.highlight();
170 //}
171
172 return event;
173 }
174 },
175
176
177
178 {
179 //Following method taken from: http://snipplr.com/view/13533/convert-text-urls-into-links/
180 name: "linkify_plain",
181 onaddmsg: function (event, opts) {
182 if (!event.msg) {
183 return event;
184 }
185
186 event.msg = event.msg.replace(/((https?\:\/\/|ftp\:\/\/)|(www\.))(\S+)(\w{2,4})(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/gi, function (url) {
187 var nice;
188 // If it's any of the supported images in the images plugin, skip it
189 if (url.match(/(\.jpg|\.jpeg|\.gif|\.bmp|\.png)$/)) {
190 return url;
191 }
192
193 nice = url;
194 if (url.match('^https?:\/\/')) {
195 //nice = nice.replace(/^https?:\/\//i,'')
196 nice = url; // Shutting up JSLint...
197 } else {
198 url = 'http://' + url;
199 }
200
201 //return '<a class="link_ext" target="_blank" rel="nofollow" href="' + url + '">' + nice + '<div class="tt box"></div></a>';
202 return '<a class="link_ext" target="_blank" rel="nofollow" href="' + url + '">' + nice + '</a>';
203 });
204
205 return event;
206 }
207 },
208
209 {
210 name: "lftobr",
211 onaddmsg: function (event, opts) {
212 if (!event.msg) {
213 return event;
214 }
215
216 event.msg = event.msg.replace(/\n/gi, function (txt) {
217 return '<br/>';
218 });
219
220 return event;
221 }
222 },
223
224
225 /*
226 * Disabled due to many websites closing kiwi with iframe busting
227 {
228 name: "inBrowser",
229 oninit: function (event, opts) {
230 $('#windows a.link_ext').live('mouseover', this.mouseover);
231 $('#windows a.link_ext').live('mouseout', this.mouseout);
232 $('#windows a.link_ext').live('click', this.mouseclick);
233 },
234
235 onunload: function (event, opts) {
236 // TODO: make this work (remove all .link_ext_browser as created in mouseover())
237 $('#windows a.link_ext').die('mouseover', this.mouseover);
238 $('#windows a.link_ext').die('mouseout', this.mouseout);
239 $('#windows a.link_ext').die('click', this.mouseclick);
240 },
241
242
243
244 mouseover: function (e) {
245 var a = $(this),
246 tt = $('.tt', a),
247 tooltip;
248
249 if (tt.text() === '') {
250 tooltip = $('<a class="link_ext_browser">Open in Kiwi..</a>');
251 tt.append(tooltip);
252 }
253
254 tt.css('top', -tt.outerHeight() + 'px');
255 tt.css('left', (a.outerWidth() / 2) - (tt.outerWidth() / 2));
256 },
257
258 mouseout: function (e) {
259 var a = $(this),
260 tt = $('.tt', a);
261 },
262
263 mouseclick: function (e) {
264 var a = $(this),
265 t;
266
267 switch (e.target.className) {
268 case 'link_ext':
269 case 'link_img_a':
270 return true;
271 //break;
272 case 'link_ext_browser':
273 t = new Utilityview('Browser');
274 t.topic = a.attr('href');
275
276 t.iframe = $('<iframe border="0" class="utility_view" src="" style="width:100%;height:100%;border:none;"></iframe>');
277 t.iframe.attr('src', a.attr('href'));
278 t.div.append(t.iframe);
279 t.show();
280 break;
281 }
282 return false;
283
284 }
285 },
286 */
287
288 {
289 name: "nick_colour",
290 onaddmsg: function (event, opts) {
291 if (!event.msg) {
292 return event;
293 }
294
295 //if (typeof kiwi.front.tabviews[event.tabview].nick_colours === 'undefined') {
296 // kiwi.front.tabviews[event.tabview].nick_colours = {};
297 //}
298
299 //if (typeof kiwi.front.tabviews[event.tabview].nick_colours[event.nick] === 'undefined') {
300 // kiwi.front.tabviews[event.tabview].nick_colours[event.nick] = this.randColour();
301 //}
302
303 //var c = kiwi.front.tabviews[event.tabview].nick_colours[event.nick];
304 var c = this.randColour();
305 event.nick = '<span style="color:' + c + ';">' + event.nick + '</span>';
306
307 return event;
308 },
309
310
311
312 randColour: function () {
313 var h = this.rand(-250, 0),
314 s = this.rand(30, 100),
315 l = this.rand(20, 70);
316 return 'hsl(' + h + ',' + s + '%,' + l + '%)';
317 },
318
319
320 rand: function (min, max) {
321 return parseInt(Math.random() * (max - min + 1), 10) + min;
322 }
323 },
324
325 {
326 name: "kiwitest",
327 oninit: function (event, opts) {
328 console.log('registering namespace');
329 $(gateway).bind("kiwi.lol.browser", function (e, data) {
330 console.log('YAY kiwitest');
331 console.log(data);
332 });
333 }
334 }
335 ];
336
337
338
339
340
341
342
343 /**
344 * @namespace
345 */
346 kiwi.plugs = {};
347 /**
348 * Loaded plugins
349 */
350 kiwi.plugs.loaded = {};
351 /**
352 * Load a plugin
353 * @param {Object} plugin The plugin to be loaded
354 * @returns {Boolean} True on success, false on failure
355 */
356 kiwi.plugs.loadPlugin = function (plugin) {
357 var plugin_ret;
358 if (typeof plugin.name !== 'string') {
359 return false;
360 }
361
362 plugin_ret = kiwi.plugs.run('plugin_load', {plugin: plugin});
363 if (typeof plugin_ret === 'object') {
364 kiwi.plugs.loaded[plugin_ret.plugin.name] = plugin_ret.plugin;
365 kiwi.plugs.loaded[plugin_ret.plugin.name].local_data = new kiwi.dataStore('kiwi_plugin_' + plugin_ret.plugin.name);
366 }
367 kiwi.plugs.run('init', {}, {run_only: plugin_ret.plugin.name});
368
369 return true;
370 };
371
372 /**
373 * Unload a plugin
374 * @param {String} plugin_name The name of the plugin to unload
375 */
376 kiwi.plugs.unloadPlugin = function (plugin_name) {
377 if (typeof kiwi.plugs.loaded[plugin_name] !== 'object') {
378 return;
379 }
380
381 kiwi.plugs.run('unload', {}, {run_only: plugin_name});
382 delete kiwi.plugs.loaded[plugin_name];
383 };
384
385
386
387 /**
388 * Run an event against all loaded plugins
389 * @param {String} event_name The name of the event
390 * @param {Object} event_data The data to pass to the plugin
391 * @param {Object} opts Options
392 * @returns {Object} Event data, possibly modified by the plugins
393 */
394 kiwi.plugs.run = function (event_name, event_data, opts) {
395 var ret = event_data,
396 ret_tmp,
397 plugin_name;
398
399 // Set some defaults if not provided
400 event_data = (typeof event_data === 'undefined') ? {} : event_data;
401 opts = (typeof opts === 'undefined') ? {} : opts;
402
403 for (plugin_name in kiwi.plugs.loaded) {
404 // If we're only calling 1 plugin, make sure it's that one
405 if (typeof opts.run_only === 'string' && opts.run_only !== plugin_name) {
406 continue;
407 }
408
409 if (typeof kiwi.plugs.loaded[plugin_name]['on' + event_name] === 'function') {
410 try {
411 ret_tmp = kiwi.plugs.loaded[plugin_name]['on' + event_name](ret, opts);
412 if (ret_tmp === null) {
413 return null;
414 }
415 ret = ret_tmp;
416
417 if (typeof ret.event_bubbles === 'boolean' && ret.event_bubbles === false) {
418 delete ret.event_bubbles;
419 return ret;
420 }
421 } catch (e) {
422 }
423 }
424 }
425
426 return ret;
427 };
428
429
430
431 /**
432 * @constructor
433 * @param {String} data_namespace The namespace for the data store
434 */
435 kiwi.dataStore = function (data_namespace) {
436 var namespace = data_namespace;
437
438 this.get = function (key) {
439 return $.jStorage.get(data_namespace + '_' + key);
440 };
441
442 this.set = function (key, value) {
443 return $.jStorage.set(data_namespace + '_' + key, value);
444 };
445 };
446
447 kiwi.data = new kiwi.dataStore('kiwi');
448
449
450
451
452 /*
453 * jQuery Templates Plugin 1.0.0pre
454 * http://github.com/jquery/jquery-tmpl
455 * Requires jQuery 1.4.2
456 *
457 * Copyright Software Freedom Conservancy, Inc.
458 * Dual licensed under the MIT or GPL Version 2 licenses.
459 * http://jquery.org/license
460 */
461 (function(a){var r=a.fn.domManip,d="_tmplitem",q=/^[^<]*(<[\w\W]+>)[^>]*$|\{\{\! /,b={},f={},e,p={key:0,data:{}},i=0,c=0,l=[];function g(g,d,h,e){var c={data:e||(e===0||e===false)?e:d?d.data:{},_wrap:d?d._wrap:null,tmpl:null,parent:d||null,nodes:[],calls:u,nest:w,wrap:x,html:v,update:t};g&&a.extend(c,g,{nodes:[],parent:d});if(h){c.tmpl=h;c._ctnt=c._ctnt||c.tmpl(a,c);c.key=++i;(l.length?f:b)[i]=c}return c}a.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(f,d){a.fn[f]=function(n){var g=[],i=a(n),k,h,m,l,j=this.length===1&&this[0].parentNode;e=b||{};if(j&&j.nodeType===11&&j.childNodes.length===1&&i.length===1){i[d](this[0]);g=this}else{for(h=0,m=i.length;h<m;h++){c=h;k=(h>0?this.clone(true):this).get();a(i[h])[d](k);g=g.concat(k)}c=0;g=this.pushStack(g,f,i.selector)}l=e;e=null;a.tmpl.complete(l);return g}});a.fn.extend({tmpl:function(d,c,b){return a.tmpl(this[0],d,c,b)},tmplItem:function(){return a.tmplItem(this[0])},template:function(b){return a.template(b,this[0])},domManip:function(d,m,k){if(d[0]&&a.isArray(d[0])){var g=a.makeArray(arguments),h=d[0],j=h.length,i=0,f;while(i<j&&!(f=a.data(h[i++],"tmplItem")));if(f&&c)g[2]=function(b){a.tmpl.afterManip(this,b,k)};r.apply(this,g)}else r.apply(this,arguments);c=0;!e&&a.tmpl.complete(b);return this}});a.extend({tmpl:function(d,h,e,c){var i,k=!c;if(k){c=p;d=a.template[d]||a.template(null,d);f={}}else if(!d){d=c.tmpl;b[c.key]=c;c.nodes=[];c.wrapped&&n(c,c.wrapped);return a(j(c,null,c.tmpl(a,c)))}if(!d)return[];if(typeof h==="function")h=h.call(c||{});e&&e.wrapped&&n(e,e.wrapped);i=a.isArray(h)?a.map(h,function(a){return a?g(e,c,d,a):null}):[g(e,c,d,h)];return k?a(j(c,null,i)):i},tmplItem:function(b){var c;if(b instanceof a)b=b[0];while(b&&b.nodeType===1&&!(c=a.data(b,"tmplItem"))&&(b=b.parentNode));return c||p},template:function(c,b){if(b){if(typeof b==="string")b=o(b);else if(b instanceof a)b=b[0]||{};if(b.nodeType)b=a.data(b,"tmpl")||a.data(b,"tmpl",o(b.innerHTML));return typeof c==="string"?(a.template[c]=b):b}return c?typeof c!=="string"?a.template(null,c):a.template[c]||a.template(null,q.test(c)?c:a(c)):null},encode:function(a){return(""+a).split("<").join("&lt;").split(">").join("&gt;").split('"').join("&#34;").split("'").join("&#39;")}});a.extend(a.tmpl,{tag:{tmpl:{_default:{$2:"null"},open:"if($notnull_1){__=__.concat($item.nest($1,$2));}"},wrap:{_default:{$2:"null"},open:"$item.calls(__,$1,$2);__=[];",close:"call=$item.calls();__=call._.concat($item.wrap(call,__));"},each:{_default:{$2:"$index, $value"},open:"if($notnull_1){$.each($1a,function($2){with(this){",close:"}});}"},"if":{open:"if(($notnull_1) && $1a){",close:"}"},"else":{_default:{$1:"true"},open:"}else if(($notnull_1) && $1a){"},html:{open:"if($notnull_1){__.push($1a);}"},"=":{_default:{$1:"$data"},open:"if($notnull_1){__.push($.encode($1a));}"},"!":{open:""}},complete:function(){b={}},afterManip:function(f,b,d){var e=b.nodeType===11?a.makeArray(b.childNodes):b.nodeType===1?[b]:[];d.call(f,b);m(e);c++}});function j(e,g,f){var b,c=f?a.map(f,function(a){return typeof a==="string"?e.key?a.replace(/(<\w+)(?=[\s>])(?![^>]*_tmplitem)([^>]*)/g,"$1 "+d+'="'+e.key+'" $2'):a:j(a,e,a._ctnt)}):e;if(g)return c;c=c.join("");c.replace(/^\s*([^<\s][^<]*)?(<[\w\W]+>)([^>]*[^>\s])?\s*$/,function(f,c,e,d){b=a(e).get();m(b);if(c)b=k(c).concat(b);if(d)b=b.concat(k(d))});return b?b:k(c)}function k(c){var b=document.createElement("div");b.innerHTML=c;return a.makeArray(b.childNodes)}function o(b){return new Function("jQuery","$item","var $=jQuery,call,__=[],$data=$item.data;with($data){__.push('"+a.trim(b).replace(/([\\'])/g,"\\$1").replace(/[\r\t\n]/g," ").replace(/\$\{([^\}]*)\}/g,"{{= $1}}").replace(/\{\{(\/?)(\w+|.)(?:\(((?:[^\}]|\}(?!\}))*?)?\))?(?:\s+(.*?)?)?(\(((?:[^\}]|\}(?!\}))*?)\))?\s*\}\}/g,function(m,l,k,g,b,c,d){var j=a.tmpl.tag[k],i,e,f;if(!j)throw"Unknown template tag: "+k;i=j._default||[];if(c&&!/\w$/.test(b)){b+=c;c=""}if(b){b=h(b);d=d?","+h(d)+")":c?")":"";e=c?b.indexOf(".")>-1?b+h(c):"("+b+").call($item"+d:b;f=c?e:"(typeof("+b+")==='function'?("+b+").call($item):("+b+"))"}else f=e=i.$1||"null";g=h(g);return"');"+j[l?"close":"open"].split("$notnull_1").join(b?"typeof("+b+")!=='undefined' && ("+b+")!=null":"true").split("$1a").join(f).split("$1").join(e).split("$2").join(g||i.$2||"")+"__.push('"})+"');}return __;")}function n(c,b){c._wrap=j(c,true,a.isArray(b)?b:[q.test(b)?b:a(b).html()]).join("")}function h(a){return a?a.replace(/\\'/g,"'").replace(/\\\\/g,"\\"):null}function s(b){var a=document.createElement("div");a.appendChild(b.cloneNode(true));return a.innerHTML}function m(o){var n="_"+c,k,j,l={},e,p,h;for(e=0,p=o.length;e<p;e++){if((k=o[e]).nodeType!==1)continue;j=k.getElementsByTagName("*");for(h=j.length-1;h>=0;h--)m(j[h]);m(k)}function m(j){var p,h=j,k,e,m;if(m=j.getAttribute(d)){while(h.parentNode&&(h=h.parentNode).nodeType===1&&!(p=h.getAttribute(d)));if(p!==m){h=h.parentNode?h.nodeType===11?0:h.getAttribute(d)||0:0;if(!(e=b[m])){e=f[m];e=g(e,b[h]||f[h]);e.key=++i;b[i]=e}c&&o(m)}j.removeAttribute(d)}else if(c&&(e=a.data(j,"tmplItem"))){o(e.key);b[e.key]=e;h=a.data(j.parentNode,"tmplItem");h=h?h.key:0}if(e){k=e;while(k&&k.key!=h){k.nodes.push(j);k=k.parent}delete e._ctnt;delete e._wrap;a.data(j,"tmplItem",e)}function o(a){a=a+n;e=l[a]=l[a]||g(e,b[e.parent.key+n]||e.parent)}}}function u(a,d,c,b){if(!a)return l.pop();l.push({_:a,tmpl:d,item:this,data:c,options:b})}function w(d,c,b){return a.tmpl(a.template(d),c,b,this)}function x(b,d){var c=b.options||{};c.wrapped=d;return a.tmpl(a.template(b.tmpl),b.data,c,b.item)}function v(d,c){var b=this._wrap;return a.map(a(a.isArray(b)?b.join(""):b).filter(d||"*"),function(a){return c?a.innerText||a.textContent:a.outerHTML||s(a)})}function t(){var b=this.nodes;a.tmpl(null,null,null,this).insertBefore(b[0]);a(b).remove()}})(jQuery);
462
463
464 /*
465 * jQuery jStorage plugin
466 * https://github.com/andris9/jStorage/
467 */
468 (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.$);
469
470
471 /*
472 * TipTip
473 * Copyright 2010 Drew Wilson
474 * www.drewwilson.com
475 * code.drewwilson.com/entry/tiptip-jquery-plugin
476 *
477 * Version 1.3 - Updated: Mar. 23, 2010
478 *
479 * This Plug-In will create a custom tooltip to replace the default
480 * browser tooltip. It is extremely lightweight and very smart in
481 * that it detects the edges of the browser window and will make sure
482 * the tooltip stays within the current window size. As a result the
483 * tooltip will adjust itself to be displayed above, below, to the left
484 * or to the right depending on what is necessary to stay within the
485 * browser window. It is completely customizable as well via CSS.
486 *
487 * This TipTip jQuery plug-in is dual licensed under the MIT and GPL licenses:
488 * http://www.opensource.org/licenses/mit-license.php
489 * http://www.gnu.org/licenses/gpl.html
490 */
491 (function($){$.fn.tipTip=function(options){var defaults={activation:"hover",keepAlive:false,maxWidth:"200px",edgeOffset:3,defaultPosition:"bottom",delay:400,fadeIn:200,fadeOut:200,attribute:"title",content:false,enter:function(){},exit:function(){}};var opts=$.extend(defaults,options);if($("#tiptip_holder").length<=0){var tiptip_holder=$('<div id="tiptip_holder" style="max-width:'+opts.maxWidth+';"></div>');var tiptip_content=$('<div id="tiptip_content"></div>');var tiptip_arrow=$('<div id="tiptip_arrow"></div>');$("body").append(tiptip_holder.html(tiptip_content).prepend(tiptip_arrow.html('<div id="tiptip_arrow_inner"></div>')))}else{var tiptip_holder=$("#tiptip_holder");var tiptip_content=$("#tiptip_content");var tiptip_arrow=$("#tiptip_arrow")}return this.each(function(){var org_elem=$(this);if(opts.content){var org_title=opts.content}else{var org_title=org_elem.attr(opts.attribute)}if(org_title!=""){if(!opts.content){org_elem.removeAttr(opts.attribute)}var timeout=false;if(opts.activation=="hover"){org_elem.hover(function(){active_tiptip()},function(){if(!opts.keepAlive){deactive_tiptip()}});if(opts.keepAlive){tiptip_holder.hover(function(){},function(){deactive_tiptip()})}}else if(opts.activation=="focus"){org_elem.focus(function(){active_tiptip()}).blur(function(){deactive_tiptip()})}else if(opts.activation=="click"){org_elem.click(function(){active_tiptip();return false}).hover(function(){},function(){if(!opts.keepAlive){deactive_tiptip()}});if(opts.keepAlive){tiptip_holder.hover(function(){},function(){deactive_tiptip()})}}function active_tiptip(){opts.enter.call(this);tiptip_content.html(org_title);tiptip_holder.hide().removeAttr("class").css("margin","0");tiptip_arrow.removeAttr("style");var top=parseInt(org_elem.offset()['top']);var left=parseInt(org_elem.offset()['left']);var org_width=parseInt(org_elem.outerWidth());var org_height=parseInt(org_elem.outerHeight());var tip_w=tiptip_holder.outerWidth();var tip_h=tiptip_holder.outerHeight();var w_compare=Math.round((org_width-tip_w)/2);var h_compare=Math.round((org_height-tip_h)/2);var marg_left=Math.round(left+w_compare);var marg_top=Math.round(top+org_height+opts.edgeOffset);var t_class="";var arrow_top="";var arrow_left=Math.round(tip_w-12)/2;if(opts.defaultPosition=="bottom"){t_class="_bottom"}else if(opts.defaultPosition=="top"){t_class="_top"}else if(opts.defaultPosition=="left"){t_class="_left"}else if(opts.defaultPosition=="right"){t_class="_right"}var right_compare=(w_compare+left)<parseInt($(window).scrollLeft());var left_compare=(tip_w+left)>parseInt($(window).width());if((right_compare&&w_compare<0)||(t_class=="_right"&&!left_compare)||(t_class=="_left"&&left<(tip_w+opts.edgeOffset+5))){t_class="_right";arrow_top=Math.round(tip_h-13)/2;arrow_left=-12;marg_left=Math.round(left+org_width+opts.edgeOffset);marg_top=Math.round(top+h_compare)}else if((left_compare&&w_compare<0)||(t_class=="_left"&&!right_compare)){t_class="_left";arrow_top=Math.round(tip_h-13)/2;arrow_left=Math.round(tip_w);marg_left=Math.round(left-(tip_w+opts.edgeOffset+5));marg_top=Math.round(top+h_compare)}var top_compare=(top+org_height+opts.edgeOffset+tip_h+8)>parseInt($(window).height()+$(window).scrollTop());var bottom_compare=((top+org_height)-(opts.edgeOffset+tip_h+8))<0;if(top_compare||(t_class=="_bottom"&&top_compare)||(t_class=="_top"&&!bottom_compare)){if(t_class=="_top"||t_class=="_bottom"){t_class="_top"}else{t_class=t_class+"_top"}arrow_top=tip_h;marg_top=Math.round(top-(tip_h+5+opts.edgeOffset))}else if(bottom_compare|(t_class=="_top"&&bottom_compare)||(t_class=="_bottom"&&!top_compare)){if(t_class=="_top"||t_class=="_bottom"){t_class="_bottom"}else{t_class=t_class+"_bottom"}arrow_top=-12;marg_top=Math.round(top+org_height+opts.edgeOffset)}if(t_class=="_right_top"||t_class=="_left_top"){marg_top=marg_top+5}else if(t_class=="_right_bottom"||t_class=="_left_bottom"){marg_top=marg_top-5}if(t_class=="_left_top"||t_class=="_left_bottom"){marg_left=marg_left+5}tiptip_arrow.css({"margin-left":arrow_left+"px","margin-top":arrow_top+"px"});tiptip_holder.css({"margin-left":marg_left+"px","margin-top":marg_top+"px"}).attr("class","tip"+t_class);if(timeout){clearTimeout(timeout)}timeout=setTimeout(function(){tiptip_holder.stop(true,true).fadeIn(opts.fadeIn)},opts.delay)}function deactive_tiptip(){opts.exit.call(this);if(timeout){clearTimeout(timeout)}tiptip_holder.fadeOut(opts.fadeOut)}}})}})(jQuery);