]>
Commit | Line | Data |
---|---|---|
1 | qwebirc.ui.WINDOW_STATUS = 0x01; | |
2 | qwebirc.ui.WINDOW_QUERY = 0x02; | |
3 | qwebirc.ui.WINDOW_CHANNEL = 0x04; | |
4 | qwebirc.ui.WINDOW_CUSTOM = 0x08; | |
5 | qwebirc.ui.WINDOW_CONNECT = 0x10; | |
6 | qwebirc.ui.WINDOW_MESSAGES = 0x20; | |
7 | ||
8 | qwebirc.ui.CUSTOM_CLIENT = "custom"; | |
9 | ||
10 | qwebirc.ui.BaseUI = new Class({ | |
11 | Implements: [Events], | |
12 | initialize: function(parentElement, windowClass, uiName, options) { | |
13 | this.options = options; | |
14 | ||
15 | this.windows = new QHash(); | |
16 | this.clients = new QHash(); | |
17 | this.windows.put(qwebirc.ui.CUSTOM_CLIENT, new QHash()); | |
18 | this.windowArray = []; | |
19 | this.windowClass = windowClass; | |
20 | this.parentElement = parentElement; | |
21 | this.parentElement.addClass("qwebirc"); | |
22 | this.parentElement.addClass("qwebirc-" + uiName); | |
23 | this.firstClient = false; | |
24 | this.commandhistory = new qwebirc.irc.CommandHistory(); | |
25 | this.clientId = 0; | |
26 | ||
27 | this.windowFocused = true; | |
28 | ||
29 | if(Browser.Engine.trident) { | |
30 | var checkFocus = function() { | |
31 | var hasFocus = document.hasFocus(); | |
32 | if(hasFocus != this.windowFocused) { | |
33 | this.windowFocused = hasFocus; | |
34 | this.focusChange(hasFocus); | |
35 | } | |
36 | } | |
37 | ||
38 | checkFocus.periodical(100, this); | |
39 | } else { | |
40 | var blur = function() { if(this.windowFocused) { this.windowFocused = false; this.focusChange(false); } }.bind(this); | |
41 | var focus = function() { if(!this.windowFocused) { this.windowFocused = true; this.focusChange(true); } }.bind(this); | |
42 | ||
43 | /* firefox requires both */ | |
44 | ||
45 | document.addEvent("blur", blur); | |
46 | window.addEvent("blur", blur); | |
47 | document.addEvent("focus", focus); | |
48 | window.addEvent("focus", focus); | |
49 | } | |
50 | ||
51 | qwebirc.util.__log = function(x) { | |
52 | if(QWEBIRC_DEBUG) { | |
53 | if(typeof console != "undefined") | |
54 | console.log(x); | |
55 | this.getActiveWindow().addLine(null, x); | |
56 | } | |
57 | }.bind(this); | |
58 | }, | |
59 | newClient: function(client) { | |
60 | client.id = String(this.clientId++); | |
61 | client.hilightController = new qwebirc.ui.HilightController(client); | |
62 | client.addEvent("signedOn", function() { | |
63 | this.poller = new qwebirc.xdomain.Poller(this.oobMessage.bind(this)); | |
64 | this.fireEvent("signedOn", client); | |
65 | }.bind(this)); | |
66 | this.windows.put(client.id, new QHash()); | |
67 | this.clients.put(client.id, client); | |
68 | var w = this.newWindow(client, qwebirc.ui.WINDOW_STATUS, "Status"); | |
69 | this.selectWindow(w); | |
70 | if(!this.firstClient) { | |
71 | this.firstClient = true; | |
72 | w.addLine("", "qwebirc v" + qwebirc.VERSION); | |
73 | w.addLine("", "Copyright (C) 2008-2014 Chris Porter and the qwebirc project."); | |
74 | w.addLine("", "http://www.qwebirc.org"); | |
75 | w.addLine("", "Licensed under the GNU General Public License, Version 2."); | |
76 | } | |
77 | return w; | |
78 | }, | |
79 | getClientId: function(client) { | |
80 | if(client == qwebirc.ui.CUSTOM_CLIENT) { | |
81 | return qwebirc.ui.CUSTOM_CLIENT; | |
82 | } else { | |
83 | return client.id; | |
84 | } | |
85 | }, | |
86 | getWindowIdentifier: function(client, type, name) { | |
87 | if(type == qwebirc.ui.WINDOW_MESSAGES) | |
88 | return "-M"; | |
89 | if(type == qwebirc.ui.WINDOW_STATUS) | |
90 | return ""; | |
91 | ||
92 | if(client == qwebirc.ui.CUSTOM_CLIENT) /* HACK */ | |
93 | return "_" + name; | |
94 | ||
95 | return "_" + client.toIRCLower(name); | |
96 | }, | |
97 | newWindow: function(client, type, name) { | |
98 | var w = this.getWindow(client, type, name); | |
99 | if($defined(w)) | |
100 | return w; | |
101 | ||
102 | var wId = this.getWindowIdentifier(client, type, name); | |
103 | var w = new this.windowClass(this, client, type, name, wId); | |
104 | this.windows.get(this.getClientId(client)).put(wId, w); | |
105 | this.windowArray.push(w); | |
106 | ||
107 | return w; | |
108 | }, | |
109 | getWindow: function(client, type, name) { | |
110 | var c = this.windows.get(this.getClientId(client)); | |
111 | if(!$defined(c)) | |
112 | return null; | |
113 | ||
114 | return c[this.getWindowIdentifier(client, type, name)]; | |
115 | }, | |
116 | getActiveWindow: function() { | |
117 | return this.active; | |
118 | }, | |
119 | getActiveIRCWindow: function(client) { | |
120 | if(!this.active || this.active.type == qwebirc.ui.WINDOW_CUSTOM) { | |
121 | return this.windows.get(this.getClientId(client)).get(this.getWindowIdentifier(client, qwebirc.ui.WINDOW_STATUS)); | |
122 | } else { | |
123 | return this.active; | |
124 | } | |
125 | }, | |
126 | __setActiveWindow: function(window) { | |
127 | this.active = window; | |
128 | }, | |
129 | renameWindow: function(window, name) { | |
130 | if(this.getWindow(window.client, window.type, name)) | |
131 | return null; | |
132 | ||
133 | var clientId = this.getClientId(window.client); | |
134 | var index = this.windowArray.indexOf(window); | |
135 | if(index == -1) | |
136 | return null; | |
137 | ||
138 | this.windows.get(clientId).remove(window.identifier); | |
139 | ||
140 | var window = this.windowArray[index]; | |
141 | window.name = name; | |
142 | window.identifier = this.getWindowIdentifier(window.client, window.type, window.name); | |
143 | ||
144 | this.windows.get(clientId).put(window.identifier, this.windowArray[index]); | |
145 | ||
146 | if(window.active) | |
147 | this.updateTitle(window.name + " - " + this.options.appTitle); | |
148 | ||
149 | window.rename(window.name); | |
150 | return window; | |
151 | }, | |
152 | selectWindow: function(window) { | |
153 | if(this.active) | |
154 | this.active.deselect(); | |
155 | window.select(); /* calls setActiveWindow */ | |
156 | this.updateTitle(window.name + " - " + this.options.appTitle); | |
157 | }, | |
158 | updateTitle: function(text) { | |
159 | document.title = text; | |
160 | }, | |
161 | nextWindow: function(direction) { | |
162 | if(this.windowArray.length == 0 || !this.active) | |
163 | return; | |
164 | ||
165 | if(!direction) | |
166 | direction = 1; | |
167 | ||
168 | var index = this.windowArray.indexOf(this.active); | |
169 | if(index == -1) | |
170 | return; | |
171 | ||
172 | index = index + direction; | |
173 | if(index < 0) { | |
174 | index = this.windowArray.length - 1; | |
175 | } else if(index >= this.windowArray.length) { | |
176 | index = 0; | |
177 | } | |
178 | ||
179 | this.selectWindow(this.windowArray[index]); | |
180 | }, | |
181 | prevWindow: function() { | |
182 | this.nextWindow(-1); | |
183 | }, | |
184 | __closed: function(window) { | |
185 | if(window.active) { | |
186 | this.active = undefined; | |
187 | if(this.windowArray.length == 1) { | |
188 | this.windowArray = []; | |
189 | } else { | |
190 | var index = this.windowArray.indexOf(window); | |
191 | if(index == -1) { | |
192 | return; | |
193 | } else if(index == 0) { | |
194 | this.selectWindow(this.windowArray[1]); | |
195 | } else { | |
196 | this.selectWindow(this.windowArray[index - 1]); | |
197 | } | |
198 | } | |
199 | } | |
200 | ||
201 | this.windowArray = this.windowArray.erase(window); | |
202 | this.windows.get(this.getClientId(window.client)).remove(window.identifier); | |
203 | }, | |
204 | /* | |
205 | this shouldn't be called by overriding classes! | |
206 | they should implement their own! | |
207 | some form of user input MUST be received before an | |
208 | IRC connection is made, else users are going to get | |
209 | tricked into getting themselves glined | |
210 | */ | |
211 | loginBox: function(callback, initialNickname, initialChannels, autoConnect, autoNick) { | |
212 | this.postInitialize(); | |
213 | ||
214 | this.addCustomWindow("Connect", qwebirc.ui.ConnectPane, "connectpane", { | |
215 | initialNickname: initialNickname, initialChannels: initialChannels, autoConnect: autoConnect, networkName: this.options.networkName, callback: callback, autoNick: autoNick | |
216 | }, qwebirc.ui.WINDOW_CONNECT); | |
217 | }, | |
218 | focusChange: function(newValue) { | |
219 | var window_ = this.getActiveWindow(); | |
220 | if($defined(window_)) | |
221 | window_.focusChange(newValue); | |
222 | }, | |
223 | oobMessage: function(message) { | |
224 | var c = message.splitMax(" ", 2); | |
225 | if(c.length != 2) | |
226 | return; | |
227 | ||
228 | var command = c[0]; | |
229 | if(command != "CMD") | |
230 | return; | |
231 | ||
232 | var d = c[1].splitMax(" ", 2); | |
233 | if(d.length != 2) | |
234 | return; | |
235 | ||
236 | var command = d[0]; | |
237 | var args = d[1]; | |
238 | if(command == "SAY") { | |
239 | var w = this.getActiveIRCWindow(); | |
240 | if($defined(w) && (w.type == qwebirc.ui.WINDOW_CHANNEL || w.type == qwebirc.ui.WINDOW_QUERY)) { | |
241 | w.client.exec("/SAY " + args); | |
242 | return; | |
243 | } | |
244 | } | |
245 | } | |
246 | }); | |
247 | ||
248 | qwebirc.ui.StandardUI = new Class({ | |
249 | Extends: qwebirc.ui.BaseUI, | |
250 | UICommands: qwebirc.ui.UI_COMMANDS, | |
251 | initialize: function(parentElement, windowClass, uiName, options) { | |
252 | this.parent(parentElement, windowClass, uiName, options); | |
253 | ||
254 | this.tabCompleter = new qwebirc.ui.TabCompleterFactory(this); | |
255 | this.uiOptions = new qwebirc.ui.DefaultOptionsClass(this, options.uiOptionsArg); | |
256 | this.customWindows = new QHash(); | |
257 | ||
258 | this.__styleValues = {hue: this.uiOptions.STYLE_HUE, saturation: 0, lightness: 0}; | |
259 | if($defined(this.options.hue)) this.__styleValues.hue = this.options.hue; | |
260 | if($defined(this.options.saturation)) this.__styleValues.saturation = this.options.saturation; | |
261 | if($defined(this.options.lightness)) this.__styleValues.lightness = this.options.lightness; | |
262 | ||
263 | if(this.options.thue !== null) this.__styleValues.textHue = this.options.thue; | |
264 | if(this.options.tsaturation !== null) this.__styleValues.textSaturation = this.options.tsaturation; | |
265 | if(this.options.tlightness !== null) this.__styleValues.textLightness = this.options.tlightness; | |
266 | ||
267 | document.addEvent("keydown", this.__handleHotkey.bind(this)); | |
268 | }, | |
269 | __handleHotkey: function(x) { | |
270 | var success = false; | |
271 | if(!x.alt || x.control) { | |
272 | if((x.key == "backspace" || x.key == "/") && !this.getInputFocused(x)) { | |
273 | success = true; | |
274 | } | |
275 | } else if(x.key == "a" || x.key == "A") { | |
276 | var highestNum = 0; | |
277 | var highestIndex = -1; | |
278 | success = true; | |
279 | ||
280 | for(var i=0;i<this.windowArray.length;i++) { | |
281 | var h = this.windowArray[i].hilighted; | |
282 | if(h > highestNum) { | |
283 | highestIndex = i; | |
284 | highestNum = h; | |
285 | } | |
286 | } | |
287 | if(highestIndex > -1) | |
288 | this.selectWindow(this.windowArray[highestIndex]); | |
289 | } else if(x.key >= '0' && x.key <= '9') { | |
290 | success = true; | |
291 | ||
292 | number = x.key - '0'; | |
293 | if(number == 0) | |
294 | number = 10 | |
295 | ||
296 | number = number - 1; | |
297 | ||
298 | if(number >= this.windowArray.length) | |
299 | return; | |
300 | ||
301 | this.selectWindow(this.windowArray[number]); | |
302 | } else if(x.key == "left") { | |
303 | this.prevWindow(); | |
304 | success = true; | |
305 | } else if(x.key == "right") { | |
306 | this.nextWindow(); | |
307 | success = true; | |
308 | } | |
309 | if(success) { | |
310 | new Event(x).stop(); | |
311 | x.preventDefault(); | |
312 | } | |
313 | }, | |
314 | getInputFocused: function(x) { | |
315 | if($$("input").indexOf(x.target) == -1 && $$("textarea").indexOf(x.target) == -1) | |
316 | return false; | |
317 | return true; | |
318 | }, | |
319 | newCustomWindow: function(name, select, type) { | |
320 | if(!type) | |
321 | type = qwebirc.ui.WINDOW_CUSTOM; | |
322 | ||
323 | var w = this.newWindow(qwebirc.ui.CUSTOM_CLIENT, type, name); | |
324 | w.addEvent("close", function(w) { | |
325 | this.windows.get(qwebirc.ui.CUSTOM_CLIENT).remove(w.identifier); | |
326 | }.bind(this)); | |
327 | ||
328 | if(select) | |
329 | this.selectWindow(w); | |
330 | ||
331 | return w; | |
332 | }, | |
333 | addCustomWindow: function(windowName, class_, cssClass, options, type) { | |
334 | if(!$defined(options)) | |
335 | options = {}; | |
336 | ||
337 | if(this.customWindows.contains(windowName)) { | |
338 | this.selectWindow(this.customWindows.get(windowName)); | |
339 | return; | |
340 | } | |
341 | ||
342 | var d = this.newCustomWindow(windowName, true, type); | |
343 | this.customWindows.put(windowName, d); | |
344 | ||
345 | d.addEvent("close", function() { | |
346 | this.customWindows.remove(windowName); | |
347 | }.bind(this)); | |
348 | ||
349 | if(cssClass) | |
350 | d.lines.addClass("qwebirc-" + cssClass); | |
351 | ||
352 | var ew = new class_(d.lines, options); | |
353 | ew.addEvent("close", function() { | |
354 | d.close(); | |
355 | }.bind(this)); | |
356 | ||
357 | d.setSubWindow(ew); | |
358 | }, | |
359 | embeddedWindow: function() { | |
360 | this.addCustomWindow("Add webchat to your site", qwebirc.ui.EmbedWizard, "embeddedwizard", {baseURL: this.options.baseURL, uiOptions: this.uiOptions, optionsCallback: function() { | |
361 | this.optionsWindow(); | |
362 | }.bind(this)}); | |
363 | }, | |
364 | optionsWindow: function() { | |
365 | this.addCustomWindow("Options", qwebirc.ui.OptionsPane, "optionspane", this.uiOptions); | |
366 | }, | |
367 | aboutWindow: function() { | |
368 | this.addCustomWindow("About", qwebirc.ui.AboutPane, "aboutpane", this.uiOptions); | |
369 | }, | |
370 | privacyWindow: function() { | |
371 | this.addCustomWindow("Privacy policy", qwebirc.ui.PrivacyPolicyPane, "privacypolicypane", this.uiOptions); | |
372 | }, | |
373 | feedbackWindow: function() { | |
374 | this.addCustomWindow("Feedback", qwebirc.ui.FeedbackPane, "feedbackpane", this.uiOptions); | |
375 | }, | |
376 | helpWindow: function() { | |
377 | this.addCustomWindow("Help!", qwebirc.ui.HelpPane, "helppane", this.uiOptions); | |
378 | }, | |
379 | urlDispatcher: function(name, window) { | |
380 | if(name == "embedded") | |
381 | return ["a", this.embeddedWindow.bind(this)]; | |
382 | ||
383 | if(name == "options") | |
384 | return ["a", this.optionsWindow.bind(this)]; | |
385 | ||
386 | /* doesn't really belong here */ | |
387 | if(name == "whois") { | |
388 | return ["span", function(nick) { | |
389 | if(this.uiOptions.QUERY_ON_NICK_CLICK) { | |
390 | window.client.exec("/QUERY " + nick); | |
391 | } else { | |
392 | window.client.exec("/WHOIS " + nick); | |
393 | } | |
394 | }.bind(this)]; | |
395 | } | |
396 | ||
397 | return null; | |
398 | }, | |
399 | tabComplete: function(element) { | |
400 | this.tabCompleter.tabComplete(element); | |
401 | }, | |
402 | resetTabComplete: function() { | |
403 | this.tabCompleter.reset(); | |
404 | }, | |
405 | setModifiableStylesheet: function(name) { | |
406 | this.__styleSheet = new qwebirc.ui.style.ModifiableStylesheet(qwebirc.global.staticBaseURL + "css/" + (QWEBIRC_DEBUG ? "debug/" : "") + name + qwebirc.FILE_SUFFIX + ".mcss"); | |
407 | this.setModifiableStylesheetValues({}); | |
408 | }, | |
409 | setModifiableStylesheetValues: function(values) { | |
410 | for(var k in values) | |
411 | this.__styleValues[k] = values[k]; | |
412 | ||
413 | if(!$defined(this.__styleSheet)) | |
414 | return; | |
415 | ||
416 | var back = {hue: this.__styleValues.hue, lightness: this.__styleValues.lightness, saturation: this.__styleValues.saturation}; | |
417 | var front = {hue: this.__styleValues.textHue, lightness: this.__styleValues.textLightness, saturation: this.__styleValues.textSaturation}; | |
418 | ||
419 | if(!this.__styleValues.textHue && !this.__styleValues.textLightness && !this.__styleValues.textSaturation) | |
420 | front = back; | |
421 | ||
422 | var colours = { | |
423 | back: back, | |
424 | front: front | |
425 | }; | |
426 | ||
427 | this.__styleSheet.set(function() { | |
428 | var mode = arguments[0]; | |
429 | if(mode == "c") { | |
430 | var t = colours[arguments[2]]; | |
431 | var x = new Color(arguments[1]); | |
432 | var c = x.setHue(t.hue).setSaturation(x.hsb[1] + t.saturation).setBrightness(x.hsb[2] + t.lightness); | |
433 | if(c == "255,255,255") /* IE confuses white with transparent... */ | |
434 | c = "255,255,254"; | |
435 | ||
436 | return "rgb(" + c + ")"; | |
437 | } else if(mode == "o") { | |
438 | return this.uiOptions[arguments[1]] ? arguments[2] : arguments[3]; | |
439 | } | |
440 | }.bind(this)); | |
441 | } | |
442 | }); | |
443 | ||
444 | qwebirc.ui.NotificationUI = new Class({ | |
445 | Extends: qwebirc.ui.StandardUI, | |
446 | initialize: function(parentElement, windowClass, uiName, options) { | |
447 | this.parent(parentElement, windowClass, uiName, options); | |
448 | ||
449 | this.__beeper = new qwebirc.ui.Beeper(this.uiOptions); | |
450 | this.__flasher = new qwebirc.ui.Flasher(this.uiOptions); | |
451 | this.__notifier = new qwebirc.ui.Notifier(this.uiOptions); | |
452 | ||
453 | this.cancelFlash = this.__flasher.cancelFlash.bind(this.__flasher); | |
454 | }, | |
455 | beep: function() { | |
456 | this.__beeper.beep(); | |
457 | }, | |
458 | notify: function(title, message, callback) { | |
459 | this.__beeper.beep(); | |
460 | this.__flasher.flash(); | |
461 | this.__notifier.notify(title, message, callback); | |
462 | }, | |
463 | setBeepOnMention: function(value) { | |
464 | if(value) | |
465 | this.__beeper.soundInit(); | |
466 | }, | |
467 | setNotifications: function(value) { | |
468 | this.__notifier.setEnabled(value); | |
469 | }, | |
470 | updateTitle: function(text) { | |
471 | if(this.__flasher.updateTitle(text)) | |
472 | this.parent(text); | |
473 | }, | |
474 | focusChange: function(value) { | |
475 | this.parent(value); | |
476 | this.__flasher.focusChange(value); | |
477 | this.__notifier.focusChange(value); | |
478 | } | |
479 | }); | |
480 | ||
481 | qwebirc.ui.QuakeNetUI = new Class({ | |
482 | Extends: qwebirc.ui.NotificationUI, | |
483 | urlDispatcher: function(name, window) { | |
484 | if(name == "qwhois") { | |
485 | return ["span", function(auth) { | |
486 | this.client.exec("/MSG Q whois #" + auth); | |
487 | }.bind(window)]; | |
488 | } | |
489 | return this.parent(name, window); | |
490 | }, | |
491 | logout: function() { | |
492 | if(!qwebirc.auth.loggedin()) | |
493 | return; | |
494 | if(confirm("Log out?")) { | |
495 | this.clients.each(function(k, v) { | |
496 | v.quit("Logged out"); | |
497 | }, this); | |
498 | ||
499 | /* HACK */ | |
500 | var foo = function() { document.location = qwebirc.global.dynamicBaseURL + "auth?logout=1"; }; | |
501 | foo.delay(500); | |
502 | } | |
503 | } | |
504 | }); | |
505 | ||
506 | qwebirc.ui.RootUI = qwebirc.ui.QuakeNetUI; | |
507 | ||
508 | qwebirc.ui.RequestTransformHTML = function(options) { | |
509 | var HREF_ELEMENTS = { | |
510 | "IMG": 1 | |
511 | }; | |
512 | ||
513 | var update = options.update; | |
514 | var onSuccess = options.onSuccess; | |
515 | ||
516 | var fixUp = function(node) { | |
517 | if(node.nodeType != 1) | |
518 | return; | |
519 | ||
520 | var tagName = node.nodeName.toUpperCase(); | |
521 | if(HREF_ELEMENTS[tagName]) { | |
522 | var attr = node.getAttribute("transform_attr"); | |
523 | var value = node.getAttribute("transform_value"); | |
524 | if($defined(attr) && $defined(value)) { | |
525 | node.removeAttribute("transform_attr"); | |
526 | node.removeAttribute("transform_value"); | |
527 | node.setAttribute(attr, qwebirc.global.staticBaseURL + value); | |
528 | } | |
529 | } | |
530 | ||
531 | for(var i=0;i<node.childNodes.length;i++) | |
532 | fixUp(node.childNodes[i]); | |
533 | }; | |
534 | ||
535 | delete options["update"]; | |
536 | options.onSuccess = function(tree, elements, html, js) { | |
537 | var container = new Element("div"); | |
538 | container.set("html", html); | |
539 | fixUp(container); | |
540 | update.empty(); | |
541 | ||
542 | while(container.childNodes.length > 0) { | |
543 | var x = container.firstChild; | |
544 | container.removeChild(x); | |
545 | update.appendChild(x); | |
546 | } | |
547 | onSuccess(); | |
548 | }; | |
549 | ||
550 | return new Request.HTML(options); | |
551 | }; | |
552 |