Commit | Line | Data |
---|---|---|
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 | ||
2dd6a025 D |
6 | /** |
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 | |
10 | */ | |
11 | function randomString(string_length) { | |
12 | var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZabcdefghiklmnopqrstuvwxyz", | |
13 | randomstring = '', | |
14 | i, | |
15 | rnum; | |
16 | for (i = 0; i < string_length; i++) { | |
17 | rnum = Math.floor(Math.random() * chars.length); | |
18 | randomstring += chars.substring(rnum, rnum + 1); | |
19 | } | |
20 | return randomstring; | |
21 | } | |
22 | ||
23 | /** | |
24 | * String.trim shim | |
25 | */ | |
26 | if (typeof String.prototype.trim === 'undefined') { | |
27 | String.prototype.trim = function () { | |
28 | return this.replace(/^\s+|\s+$/g, ""); | |
29 | }; | |
30 | } | |
31 | ||
32 | /** | |
33 | * String.lpad shim | |
34 | * @param {Number} length The length of padding | |
35 | * @param {String} characher The character to pad with | |
36 | * @returns {String} The padded string | |
37 | */ | |
38 | if (typeof String.prototype.lpad === 'undefined') { | |
39 | String.prototype.lpad = function (length, character) { | |
40 | var padding = "", | |
41 | i; | |
42 | for (i = 0; i < length; i++) { | |
43 | padding += character; | |
44 | } | |
45 | return (padding + this).slice(-length); | |
46 | }; | |
47 | } | |
48 | ||
49 | ||
50 | /** | |
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 | |
54 | */ | |
55 | function secondsToTime(secs) { | |
56 | var hours, minutes, seconds, divisor_for_minutes, divisor_for_seconds, obj; | |
57 | hours = Math.floor(secs / (60 * 60)); | |
58 | ||
59 | divisor_for_minutes = secs % (60 * 60); | |
60 | minutes = Math.floor(divisor_for_minutes / 60); | |
61 | ||
62 | divisor_for_seconds = divisor_for_minutes % 60; | |
63 | seconds = Math.ceil(divisor_for_seconds); | |
64 | ||
65 | obj = { | |
66 | "h": hours, | |
67 | "m": minutes, | |
68 | "s": seconds | |
69 | }; | |
70 | return obj; | |
71 | } | |
72 | ||
73 | ||
64c6bcb4 D |
74 | /* Command input Alias + re-writing */ |
75 | function InputPreProcessor () { | |
76 | this.recursive_depth = 3; | |
77 | ||
78 | this.aliases = {}; | |
79 | this.vars = {version: 1}; | |
80 | ||
81 | // Current recursive depth | |
82 | var depth = 0; | |
83 | ||
84 | ||
85 | // Takes an array of words to process! | |
86 | this.processInput = function (input) { | |
87 | var words = input || [], | |
88 | alias = this.aliases[words[0]], | |
89 | alias_len, | |
90 | current_alias_word = '', | |
91 | compiled = []; | |
92 | ||
93 | // If an alias wasn't found, return the original input | |
94 | if (!alias) return input; | |
95 | ||
96 | // Split the alias up into useable words | |
97 | alias = alias.split(' '); | |
98 | alias_len = alias.length; | |
99 | ||
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]; | |
104 | ||
105 | // Non $ word | |
106 | if (current_alias_word[0] !== '$') { | |
107 | compiled.push(current_alias_word); | |
108 | continue; | |
109 | } | |
110 | ||
111 | // Refering to an input word ($N) | |
112 | if (!isNaN(current_alias_word[1])) { | |
113 | var num = current_alias_word.match(/\$(\d+)(\+)?(\d+)?/); | |
114 | ||
115 | // Did we find anything or does the word it refers to non-existant? | |
116 | if (!num || !words[num[1]]) continue; | |
64bdb2ff | 117 | |
64c6bcb4 D |
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))); | |
124 | } else { | |
125 | // Add a single word | |
126 | compiled.push(words[parseInt(num[1], 10)]); | |
127 | } | |
128 | ||
129 | continue; | |
130 | } | |
131 | ||
132 | ||
133 | // Refering to a variable | |
134 | if (typeof this.vars[current_alias_word.substr(1)] !== 'undefined') { | |
135 | ||
136 | // Get the variable | |
137 | compiled.push(this.vars[current_alias_word.substr(1)]); | |
138 | ||
139 | continue; | |
140 | } | |
141 | ||
142 | } | |
143 | ||
144 | return compiled; | |
145 | }; | |
146 | ||
147 | ||
148 | this.process = function (input) { | |
149 | input = input || ''; | |
150 | ||
151 | var words = input.split(' '); | |
152 | ||
153 | depth++; | |
154 | if (depth >= this.recursive_depth) { | |
155 | depth--; | |
156 | return input; | |
157 | } | |
158 | ||
159 | if (this.aliases[words[0]]) { | |
160 | words = this.processInput(words); | |
64bdb2ff | 161 | |
64c6bcb4 D |
162 | if (this.aliases[words[0]]) { |
163 | words = this.process(words.join(' ')).split(' '); | |
164 | } | |
165 | ||
166 | } | |
167 | ||
168 | depth--; | |
169 | return words.join(' '); | |
170 | }; | |
171 | } | |
172 | ||
173 | ||
1167a85d D |
174 | /** |
175 | * Convert HSL to RGB formatted colour | |
176 | */ | |
177 | function hsl2rgb(h, s, l) { | |
178 | var m1, m2, hue; | |
179 | var r, g, b | |
180 | s /=100; | |
181 | l /= 100; | |
182 | if (s == 0) | |
183 | r = g = b = (l * 255); | |
184 | else { | |
185 | function HueToRgb(m1, m2, hue) { | |
186 | var v; | |
187 | if (hue < 0) | |
188 | hue += 1; | |
189 | else if (hue > 1) | |
190 | hue -= 1; | |
191 | ||
192 | if (6 * hue < 1) | |
193 | v = m1 + (m2 - m1) * hue * 6; | |
194 | else if (2 * hue < 1) | |
195 | v = m2; | |
196 | else if (3 * hue < 2) | |
197 | v = m1 + (m2 - m1) * (2/3 - hue) * 6; | |
198 | else | |
199 | v = m1; | |
200 | ||
201 | return 255 * v; | |
202 | } | |
203 | if (l <= 0.5) | |
204 | m2 = l * (s + 1); | |
205 | else | |
206 | m2 = l + s - l * s; | |
207 | m1 = l * 2 - m2; | |
208 | hue = h / 360; | |
209 | r = HueToRgb(m1, m2, hue + 1/3); | |
210 | g = HueToRgb(m1, m2, hue); | |
211 | b = HueToRgb(m1, m2, hue - 1/3); | |
212 | } | |
213 | return [r,g,b]; | |
214 | } | |
215 | ||
216 | ||
b166c1ac D |
217 | /** |
218 | * Formats a kiwi message to IRC format | |
219 | */ | |
220 | function formatToIrcMsg(message) { | |
221 | // Format any colour codes (eg. $c4) | |
a2127d40 | 222 | message = message.replace(/%C(\d)/g, function(match, colour_number) { |
b166c1ac D |
223 | return String.fromCharCode(3) + colour_number.toString(); |
224 | }); | |
225 | ||
226 | var formatters = { | |
227 | B: '\x02', // Bold | |
228 | I: '\x1D', // Italics | |
229 | U: '\x1F', // Underline | |
230 | O: '\x0F' // Out / Clear formatting | |
231 | }; | |
a2127d40 | 232 | message = message.replace(/%([BIUO])/g, function(match, format_code) { |
b166c1ac D |
233 | if (typeof formatters[format_code.toUpperCase()] !== 'undefined') |
234 | return formatters[format_code.toUpperCase()]; | |
235 | }); | |
236 | ||
237 | return message; | |
238 | } | |
239 | ||
240 | ||
2dd6a025 D |
241 | /** |
242 | * Formats a message. Adds bold, underline and colouring | |
243 | * @param {String} msg The message to format | |
244 | * @returns {String} The HTML formatted message | |
245 | */ | |
246 | function formatIRCMsg (msg) { | |
f47955d3 JA |
247 | "use strict"; |
248 | var out = '', | |
249 | currentTag = '', | |
250 | openTags = { | |
251 | bold: false, | |
252 | italic: false, | |
253 | underline: false, | |
254 | colour: false | |
255 | }, | |
f47955d3 JA |
256 | spanFromOpen = function () { |
257 | var style = '', | |
258 | colours; | |
643ca730 | 259 | if (!(openTags.bold || openTags.italic || openTags.underline || openTags.colour)) { |
f47955d3 JA |
260 | return ''; |
261 | } else { | |
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] + ';' : ''); | |
268 | } | |
9d8f8dfe | 269 | return '<span class="format_span" style="' + style + '">'; |
f47955d3 JA |
270 | } |
271 | }, | |
2dd6a025 | 272 | colourMatch = function (str) { |
f47955d3 | 273 | var re = /^\x03(([0-9][0-9]?)(,([0-9][0-9]?))?)/; |
2dd6a025 | 274 | return re.exec(str); |
f47955d3 JA |
275 | }, |
276 | hexFromNum = function (num) { | |
2dd6a025 D |
277 | switch (parseInt(num, 10)) { |
278 | case 0: | |
279 | return '#FFFFFF'; | |
280 | case 1: | |
281 | return '#000000'; | |
282 | case 2: | |
283 | return '#000080'; | |
284 | case 3: | |
285 | return '#008000'; | |
286 | case 4: | |
287 | return '#FF0000'; | |
288 | case 5: | |
289 | return '#800040'; | |
290 | case 6: | |
291 | return '#800080'; | |
292 | case 7: | |
293 | return '#FF8040'; | |
294 | case 8: | |
295 | return '#FFFF00'; | |
296 | case 9: | |
297 | return '#80FF00'; | |
298 | case 10: | |
299 | return '#008080'; | |
300 | case 11: | |
301 | return '#00FFFF'; | |
302 | case 12: | |
303 | return '#0000FF'; | |
304 | case 13: | |
305 | return '#FF55FF'; | |
306 | case 14: | |
307 | return '#808080'; | |
308 | case 15: | |
309 | return '#C0C0C0'; | |
310 | default: | |
311 | return null; | |
312 | } | |
f47955d3 JA |
313 | }, |
314 | i = 0, | |
315 | colours = [], | |
316 | match; | |
317 | ||
318 | for (i = 0; i < msg.length; i++) { | |
319 | switch (msg[i]) { | |
320 | case '\x02': | |
643ca730 | 321 | if ((openTags.bold || openTags.italic || openTags.underline || openTags.colour)) { |
f47955d3 JA |
322 | out += currentTag + '</span>'; |
323 | } | |
324 | openTags.bold = !openTags.bold; | |
325 | currentTag = spanFromOpen(); | |
326 | break; | |
327 | case '\x1D': | |
2cb3c82e | 328 | if ((openTags.bold || openTags.italic || openTags.underline || openTags.colour)) { |
f47955d3 JA |
329 | out += currentTag + '</span>'; |
330 | } | |
331 | openTags.italic = !openTags.italic; | |
332 | currentTag = spanFromOpen(); | |
333 | break; | |
334 | case '\x1F': | |
643ca730 | 335 | if ((openTags.bold || openTags.italic || openTags.underline || openTags.colour)) { |
f47955d3 JA |
336 | out += currentTag + '</span>'; |
337 | } | |
338 | openTags.underline = !openTags.underline; | |
339 | currentTag = spanFromOpen(); | |
340 | break; | |
341 | case '\x03': | |
643ca730 | 342 | if ((openTags.bold || openTags.italic || openTags.underline || openTags.colour)) { |
f47955d3 JA |
343 | out += currentTag + '</span>'; |
344 | } | |
345 | match = colourMatch(msg.substr(i, 6)); | |
346 | if (match) { | |
f47955d3 JA |
347 | i += match[1].length; |
348 | // 2 & 4 | |
349 | colours[0] = hexFromNum(match[2]); | |
350 | if (match[4]) { | |
351 | colours[1] = hexFromNum(match[4]); | |
2dd6a025 | 352 | } |
f47955d3 JA |
353 | openTags.colour = colours.join(','); |
354 | } else { | |
355 | openTags.colour = false; | |
356 | } | |
357 | currentTag = spanFromOpen(); | |
358 | break; | |
359 | case '\x0F': | |
643ca730 | 360 | if ((openTags.bold || openTags.italic || openTags.underline || openTags.colour)) { |
f47955d3 | 361 | out += currentTag + '</span>'; |
2dd6a025 | 362 | } |
f47955d3 JA |
363 | openTags.bold = openTags.italic = openTags.underline = openTags.colour = false; |
364 | break; | |
365 | default: | |
643ca730 | 366 | if ((openTags.bold || openTags.italic || openTags.underline || openTags.colour)) { |
f47955d3 JA |
367 | currentTag += msg[i]; |
368 | } else { | |
369 | out += msg[i]; | |
370 | } | |
371 | break; | |
2dd6a025 | 372 | } |
f47955d3 | 373 | } |
643ca730 | 374 | if ((openTags.bold || openTags.italic || openTags.underline || openTags.colour)) { |
f47955d3 JA |
375 | out += currentTag + '</span>'; |
376 | } | |
377 | return out; | |
2dd6a025 D |
378 | } |
379 | ||
0260a968 JA |
380 | function escapeRegex (str) { |
381 | return str.replace(/[\[\\\^\$\.\|\?\*\+\(\)]/g, '\\$&'); | |
382 | } | |
2eacc942 JA |
383 | |
384 | function emoticonFromText(str) { | |
385 | var words_in = str.split(' '), | |
386 | words_out = [], | |
387 | i, | |
e62f5be1 D |
388 | pushEmoticon = function (alt, emote_name) { |
389 | words_out.push('<i class="emoticon ' + emote_name + '">' + alt + '</i>'); | |
2eacc942 JA |
390 | }; |
391 | ||
392 | for (i = 0; i < words_in.length; i++) { | |
393 | switch(words_in[i]) { | |
394 | case ':)': | |
e62f5be1 | 395 | pushEmoticon(':)', 'smile'); |
2eacc942 JA |
396 | break; |
397 | case ':(': | |
e62f5be1 | 398 | pushEmoticon(':(', 'sad'); |
2eacc942 JA |
399 | break; |
400 | case ':3': | |
e62f5be1 | 401 | pushEmoticon(':3', 'lion'); |
2eacc942 JA |
402 | break; |
403 | case ';3': | |
e62f5be1 | 404 | pushEmoticon(';3', 'winky_lion'); |
2eacc942 JA |
405 | break; |
406 | case ':s': | |
e62f5be1 D |
407 | case ':S': |
408 | pushEmoticon(':s', 'confused'); | |
2eacc942 JA |
409 | break; |
410 | case ';(': | |
e62f5be1 D |
411 | case ';_;': |
412 | pushEmoticon(';(', 'cry'); | |
2eacc942 JA |
413 | break; |
414 | case ';)': | |
e62f5be1 | 415 | pushEmoticon(';)', 'wink'); |
2eacc942 JA |
416 | break; |
417 | case ';D': | |
b2bb27e7 | 418 | pushEmoticon(';D', 'wink_happy'); |
2eacc942 JA |
419 | break; |
420 | case ':P': | |
e62f5be1 D |
421 | case ':p': |
422 | pushEmoticon(':P', 'tongue'); | |
2eacc942 JA |
423 | break; |
424 | case 'xP': | |
e62f5be1 | 425 | pushEmoticon('xP', 'cringe_tongue'); |
2eacc942 JA |
426 | break; |
427 | case ':o': | |
428 | case ':O': | |
e62f5be1 D |
429 | case ':0': |
430 | pushEmoticon(':o', 'shocked'); | |
2eacc942 JA |
431 | break; |
432 | case ':D': | |
e62f5be1 | 433 | pushEmoticon(':D', 'happy'); |
2eacc942 | 434 | break; |
e62f5be1 D |
435 | case '^^': |
436 | case '^.^': | |
437 | pushEmoticon('^^,', 'eyebrows'); | |
2eacc942 JA |
438 | break; |
439 | case '<3': | |
e62f5be1 | 440 | pushEmoticon('<3', 'heart'); |
2eacc942 JA |
441 | break; |
442 | case '>_<': | |
e62f5be1 D |
443 | case '>.<': |
444 | pushEmoticon('>_<', 'doh'); | |
2eacc942 JA |
445 | break; |
446 | case 'XD': | |
447 | case 'xD': | |
e62f5be1 | 448 | pushEmoticon('xD', 'big_grin'); |
2eacc942 JA |
449 | break; |
450 | case 'o.0': | |
e62f5be1 D |
451 | case 'o.O': |
452 | pushEmoticon('o.0', 'wide_eye_right'); | |
2eacc942 JA |
453 | break; |
454 | case '0.o': | |
e62f5be1 D |
455 | case 'O.o': |
456 | pushEmoticon('0.o', 'wide_eye_left'); | |
2eacc942 JA |
457 | break; |
458 | case ':\\': | |
459 | case '=\\': | |
2eacc942 JA |
460 | case ':/': |
461 | case '=/': | |
e62f5be1 | 462 | pushEmoticon(':\\', 'unsure'); |
2eacc942 JA |
463 | break; |
464 | default: | |
465 | words_out.push(words_in[i]); | |
466 | } | |
467 | } | |
468 | ||
469 | return words_out.join(' '); | |
470 | } | |
697a76c5 JA |
471 | |
472 | // Code based on http://anentropic.wordpress.com/2009/06/25/javascript-iso8601-parser-and-pretty-dates/#comment-154 | |
473 | function parseISO8601(str) { | |
474 | if (Date.prototype.toISOString) { | |
475 | return new Date(str); | |
476 | } else { | |
477 | var parts = str.split('T'), | |
478 | dateParts = parts[0].split('-'), | |
479 | timeParts = parts[1].split('Z'), | |
480 | timeSubParts = timeParts[0].split(':'), | |
481 | timeSecParts = timeSubParts[2].split('.'), | |
482 | timeHours = Number(timeSubParts[0]), | |
483 | _date = new Date(); | |
484 | ||
485 | _date.setUTCFullYear(Number(dateParts[0])); | |
486 | _date.setUTCDate(1); | |
487 | _date.setUTCMonth(Number(dateParts[1])-1); | |
488 | _date.setUTCDate(Number(dateParts[2])); | |
489 | _date.setUTCHours(Number(timeHours)); | |
490 | _date.setUTCMinutes(Number(timeSubParts[1])); | |
491 | _date.setUTCSeconds(Number(timeSecParts[0])); | |
492 | if (timeSecParts[1]) { | |
493 | _date.setUTCMilliseconds(Number(timeSecParts[1])); | |
494 | } | |
495 | ||
496 | return _date; | |
497 | } | |
530f55dc CC |
498 | } |
499 | ||
500 | // Simplyfy the translation syntax | |
501 | function translateText(string_id, params) { | |
67791db1 D |
502 | params = params || ''; |
503 | ||
530f55dc CC |
504 | return _kiwi.global.i18n.translate(string_id).fetch(params); |
505 | } | |
67791db1 D |
506 | |
507 | /** | |
508 | * Simplyfy the text styling syntax | |
509 | * | |
510 | * Syntax: | |
9ec48c54 D |
511 | * %nick: nickname |
512 | * %channel: channel | |
513 | * %ident: ident | |
514 | * %host: host | |
515 | * %realname: realname | |
516 | * %text: translated text | |
67791db1 | 517 | * %C[digit]: color |
9ec48c54 D |
518 | * %B: bold |
519 | * %I: italic | |
520 | * %U: underline | |
521 | * %O: cancel styles | |
67791db1 | 522 | **/ |
530f55dc | 523 | function styleText(string_id, params) { |
67791db1 D |
524 | var style, text; |
525 | ||
9ec48c54 D |
526 | //style = formatToIrcMsg(_kiwi.app.text_theme[string_id]); |
527 | style = _kiwi.app.text_theme[string_id]; | |
2d6e0505 | 528 | style = formatToIrcMsg(style); |
67791db1 | 529 | |
cba6f47f | 530 | // Expand a member mask into its individual parts (nick, ident, hostname) |
9ec48c54 | 531 | if (params.member) { |
f16a42bd D |
532 | params.nick = params.member.nick || ''; |
533 | params.ident = params.member.ident || ''; | |
534 | params.host = params.member.hostname || ''; | |
535 | params.prefix = params.member.prefix || ''; | |
67791db1 D |
536 | } |
537 | ||
9ec48c54 D |
538 | // Do the magic. Use the %shorthand syntax to produce output. |
539 | text = style.replace(/%([A-Z]{2,})/ig, function(match, key) { | |
540 | if (typeof params[key] !== 'undefined') | |
541 | return params[key]; | |
67791db1 D |
542 | }); |
543 | ||
544 | return text; | |
b2bb27e7 | 545 | } |