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