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