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 */
7 * Generate a random string of given length
8 * @param {Number} string_length The length of the random string
9 * @returns {String} The random string
11 function randomString(string_length
) {
12 var chars
= "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz",
16 for (i
= 0; i
< string_length
; i
++) {
17 rnum
= Math
.floor(Math
.random() * chars
.length
);
18 randomstring
+= chars
.substring(rnum
, rnum
+ 1);
26 if (typeof String
.prototype.trim
=== 'undefined') {
27 String
.prototype.trim = function () {
28 return this.replace(/^\s+|\s+$/g, "");
34 * @param {Number} length The length of padding
35 * @param {String} characher The character to pad with
36 * @returns {String} The padded string
38 if (typeof String
.prototype.lpad
=== 'undefined') {
39 String
.prototype.lpad = function (length
, character
) {
42 for (i
= 0; i
< length
; i
++) {
45 return (padding
+ this).slice(-length
);
51 * Convert seconds into hours:minutes:seconds
52 * @param {Number} secs The number of seconds to converts
53 * @returns {Object} An object representing the hours/minutes/second conversion of secs
55 function secondsToTime(secs
) {
56 var hours
, minutes
, seconds
, divisor_for_minutes
, divisor_for_seconds
, obj
;
57 hours
= Math
.floor(secs
/ (60 * 60));
59 divisor_for_minutes
= secs
% (60 * 60);
60 minutes
= Math
.floor(divisor_for_minutes
/ 60);
62 divisor_for_seconds
= divisor_for_minutes
% 60;
63 seconds
= Math
.ceil(divisor_for_seconds
);
74 /* Command input Alias + re-writing */
75 function InputPreProcessor () {
76 this.recursive_depth
= 3;
79 this.vars
= {version
: 1};
81 // Current recursive depth
85 // Takes an array of words to process!
86 this.processInput = function (input
) {
87 var words
= input
|| [],
88 alias
= this.aliases
[words
[0]],
90 current_alias_word
= '',
93 // If an alias wasn't found, return the original input
94 if (!alias
) return input
;
96 // Split the alias up into useable words
97 alias
= alias
.split(' ');
98 alias_len
= alias
.length
;
100 // Iterate over each word and pop them into the final compiled array.
101 // Any $ words are processed with the result ending into the compiled array.
102 for (var i
=0; i
<alias_len
; i
++) {
103 current_alias_word
= alias
[i
];
106 if (current_alias_word
[0] !== '$') {
107 compiled
.push(current_alias_word
);
111 // Refering to an input word ($N)
112 if (!isNaN(current_alias_word
[1])) {
113 var num
= current_alias_word
.match(/\$(\d+)(\+)?(\d+)?/);
115 // Did we find anything or does the word it refers to non-existant?
116 if (!num
|| !words
[num
[1]]) continue;
118 if (num
[2] === '+' && num
[3]) {
119 // Add X number of words
120 compiled
= compiled
.concat(words
.slice(parseInt(num
[1], 10), parseInt(num
[1], 10) + parseInt(num
[3], 10)));
121 } else if (num
[2] === '+') {
122 // Add the remaining of the words
123 compiled
= compiled
.concat(words
.slice(parseInt(num
[1], 10)));
126 compiled
.push(words
[parseInt(num
[1], 10)]);
133 // Refering to a variable
134 if (typeof this.vars
[current_alias_word
.substr(1)] !== 'undefined') {
137 compiled
.push(this.vars
[current_alias_word
.substr(1)]);
148 this.process = function (input
) {
151 var words
= input
.split(' ');
154 if (depth
>= this.recursive_depth
) {
159 if (this.aliases
[words
[0]]) {
160 words
= this.processInput(words
);
162 if (this.aliases
[words
[0]]) {
163 words
= this.process(words
.join(' ')).split(' ');
169 return words
.join(' ');
175 * Convert HSL to RGB formatted colour
177 function hsl2rgb(h
, s
, l
) {
183 r
= g
= b
= (l
* 255);
185 function HueToRgb(m1
, m2
, hue
) {
193 v
= m1
+ (m2
- m1
) * hue
* 6;
194 else if (2 * hue
< 1)
196 else if (3 * hue
< 2)
197 v
= m1
+ (m2
- m1
) * (2/3 - hue
) * 6;
209 r
= HueToRgb(m1
, m2
, hue
+ 1/3);
210 g
= HueToRgb(m1
, m2
, hue
);
211 b
= HueToRgb(m1
, m2
, hue
- 1/3);
218 * Formats a kiwi message to IRC format
220 function formatToIrcMsg(message
) {
221 // Format any colour codes (eg. $c4)
222 message
= message
.replace(/%C(\d)/ig, function(match
, colour_number
) {
223 return String
.fromCharCode(3) + colour_number
.toString();
228 I
: '\x1D', // Italics
229 U
: '\x1F', // Underline
230 O
: '\x0F' // Out / Clear formatting
232 message
= message
.replace(/%([BIUO])/ig, function(match
, format_code
) {
233 if (typeof formatters
[format_code
.toUpperCase()] !== 'undefined')
234 return formatters
[format_code
.toUpperCase()];
242 * Formats a message. Adds bold, underline and colouring
243 * @param {String} msg The message to format
244 * @returns {String} The HTML formatted message
246 function formatIRCMsg (msg
) {
256 spanFromOpen = function () {
259 if (!(openTags
.bold
|| openTags
.italic
|| openTags
.underline
|| openTags
.colour
)) {
262 style
+= (openTags
.bold
) ? 'font-weight: bold; ' : '';
263 style
+= (openTags
.italic
) ? 'font-style: italic; ' : '';
264 style
+= (openTags
.underline
) ? 'text-decoration: underline; ' : '';
265 if (openTags
.colour
) {
266 colours
= openTags
.colour
.split(',');
267 style
+= 'color: ' + colours
[0] + ((colours
[1]) ? '; background-color: ' + colours
[1] + ';' : '');
269 return '<span class="format_span" style="' + style
+ '">';
272 colourMatch = function (str
) {
273 var re
= /^\x03(([0-9][0-9]?)(,([0-9][0-9]?))?)/;
276 hexFromNum = function (num
) {
277 switch (parseInt(num
, 10)) {
318 for (i
= 0; i
< msg
.length
; i
++) {
321 if ((openTags
.bold
|| openTags
.italic
|| openTags
.underline
|| openTags
.colour
)) {
322 out
+= currentTag
+ '</span>';
324 openTags
.bold
= !openTags
.bold
;
325 currentTag
= spanFromOpen();
328 if ((openTags
.bold
|| openTags
.italic
|| openTags
.underline
|| openTags
.colour
)) {
329 out
+= currentTag
+ '</span>';
331 openTags
.italic
= !openTags
.italic
;
332 currentTag
= spanFromOpen();
335 if ((openTags
.bold
|| openTags
.italic
|| openTags
.underline
|| openTags
.colour
)) {
336 out
+= currentTag
+ '</span>';
338 openTags
.underline
= !openTags
.underline
;
339 currentTag
= spanFromOpen();
342 if ((openTags
.bold
|| openTags
.italic
|| openTags
.underline
|| openTags
.colour
)) {
343 out
+= currentTag
+ '</span>';
345 match
= colourMatch(msg
.substr(i
, 6));
347 i
+= match
[1].length
;
349 colours
[0] = hexFromNum(match
[2]);
351 colours
[1] = hexFromNum(match
[4]);
353 openTags
.colour
= colours
.join(',');
355 openTags
.colour
= false;
357 currentTag
= spanFromOpen();
360 if ((openTags
.bold
|| openTags
.italic
|| openTags
.underline
|| openTags
.colour
)) {
361 out
+= currentTag
+ '</span>';
363 openTags
.bold
= openTags
.italic
= openTags
.underline
= openTags
.colour
= false;
366 if ((openTags
.bold
|| openTags
.italic
|| openTags
.underline
|| openTags
.colour
)) {
367 currentTag
+= msg
[i
];
374 if ((openTags
.bold
|| openTags
.italic
|| openTags
.underline
|| openTags
.colour
)) {
375 out
+= currentTag
+ '</span>';
381 function formatDate (d
) {
383 return d
.toLocaleDateString() + ', ' + d
.getHours().toString() + ':' + d
.getMinutes().toString() + ':' + d
.getSeconds().toString();
386 function escapeRegex (str
) {
387 return str
.replace(/[\[\\\^\$\.\|\?\*\+\(\)]/g, '\\$&');
390 function emoticonFromText(str
) {
391 var words_in
= str
.split(' '),
394 pushEmoticon = function (alt
, emote_name
) {
395 words_out
.push('<i class="emoticon ' + emote_name
+ '">' + alt
+ '</i>');
398 for (i
= 0; i
< words_in
.length
; i
++) {
399 switch(words_in
[i
]) {
401 pushEmoticon(':)', 'smile');
404 pushEmoticon(':(', 'sad');
407 pushEmoticon(':3', 'lion');
410 pushEmoticon(';3', 'winky_lion');
414 pushEmoticon(':s', 'confused');
418 pushEmoticon(';(', 'cry');
421 pushEmoticon(';)', 'wink');
424 pushEmoticon(';D"', 'wink_happy');
428 pushEmoticon(':P', 'tongue');
431 pushEmoticon('xP', 'cringe_tongue');
436 pushEmoticon(':o', 'shocked');
439 pushEmoticon(':D', 'happy');
443 pushEmoticon('^^,', 'eyebrows');
446 pushEmoticon('<3', 'heart');
450 pushEmoticon('>_<', 'doh');
454 pushEmoticon('xD', 'big_grin');
458 pushEmoticon('o.0', 'wide_eye_right');
462 pushEmoticon('0.o', 'wide_eye_left');
468 pushEmoticon(':\\', 'unsure');
471 words_out
.push(words_in
[i
]);
475 return words_out
.join(' ');
478 // Code based on http://anentropic.wordpress.com/2009/06/25/javascript-iso8601-parser-and-pretty-dates/#comment-154
479 function parseISO8601(str
) {
480 if (Date
.prototype.toISOString
) {
481 return new Date(str
);
483 var parts
= str
.split('T'),
484 dateParts
= parts
[0].split('-'),
485 timeParts
= parts
[1].split('Z'),
486 timeSubParts
= timeParts
[0].split(':'),
487 timeSecParts
= timeSubParts
[2].split('.'),
488 timeHours
= Number(timeSubParts
[0]),
491 _date
.setUTCFullYear(Number(dateParts
[0]));
493 _date
.setUTCMonth(Number(dateParts
[1])-1);
494 _date
.setUTCDate(Number(dateParts
[2]));
495 _date
.setUTCHours(Number(timeHours
));
496 _date
.setUTCMinutes(Number(timeSubParts
[1]));
497 _date
.setUTCSeconds(Number(timeSecParts
[0]));
498 if (timeSecParts
[1]) {
499 _date
.setUTCMilliseconds(Number(timeSecParts
[1]));
506 // Simplyfy the translation syntax
507 function translateText(string_id
, params
) {
508 params
= params
|| '';
510 return _kiwi
.global
.i18n
.translate(string_id
).fetch(params
);
514 * Simplyfy the text styling syntax
527 * %T: translated text
529 function styleText(string_id
, params
) {
532 style
= formatToIrcMsg(_kiwi
.app
.text_theme
[string_id
]);
534 // Bring member info back to first level of params
536 _
.each(params
['%M'], function(val
, key
) {
541 // Do the magic. Use the shorthand syntax to produce output.
542 text
= style
.replace(/%([TJHNCR])/g, function(match
, key
) {
545 if (typeof params
[key
.toUpperCase()] !== 'undefined')
546 return params
[key
.toUpperCase()];