]> 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
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 }
9e769c12
CP
50 },
51 newClient: function(client) {
ffbb638d 52 client.id = this.clientId++;
96f28062
CP
53 client.hilightController = new qwebirc.ui.HilightController(client);
54
ffbb638d
CP
55 this.windows[client.id] = {}
56 this.clients[client.id] = client;
e20e5a6b 57 var w = this.newWindow(client, qwebirc.ui.WINDOW_STATUS, "Status");
9e769c12 58 this.selectWindow(w);
e8db8558
CP
59 if(!this.firstClient) {
60 this.firstClient = true;
e20e5a6b 61 w.addLine("", "qwebirc v" + qwebirc.VERSION);
f191a80b 62 w.addLine("", "Copyright (C) 2008-2012 Chris Porter and the qwebirc project.");
2dfab0e1
CP
63 w.addLine("", "http://www.qwebirc.org");
64 w.addLine("", "Licensed under the GNU General Public License, Version 2.");
e8db8558 65 }
9e769c12
CP
66 return w;
67 },
ffbb638d
CP
68 getClientId: function(client) {
69 if(client == qwebirc.ui.CUSTOM_CLIENT) {
70 return qwebirc.ui.CUSTOM_CLIENT;
71 } else {
72 return client.id;
73 }
74 },
fd3734d4 75 getWindowIdentifier: function(client, type, name) {
f74802c5
CP
76 if(type == qwebirc.ui.WINDOW_MESSAGES)
77 return "-M";
e20e5a6b 78 if(type == qwebirc.ui.WINDOW_STATUS)
f74802c5 79 return "";
fd3734d4
CP
80
81 if(client == qwebirc.ui.CUSTOM_CLIENT) /* HACK */
82 return "_" + name;
83
84 return "_" + client.toIRCLower(name);
f74802c5
CP
85 },
86 newWindow: function(client, type, name) {
87 var w = this.getWindow(client, type, name);
88 if($defined(w))
89 return w;
9e769c12 90
fd3734d4 91 var wId = this.getWindowIdentifier(client, type, name);
f74802c5 92 var w = this.windows[this.getClientId(client)][wId] = new this.windowClass(this, client, type, name, wId);
9e769c12
CP
93 this.windowArray.push(w);
94
95 return w;
96 },
f74802c5
CP
97 getWindow: function(client, type, name) {
98 var c = this.windows[this.getClientId(client)];
99 if(!$defined(c))
100 return null;
101
fd3734d4 102 return c[this.getWindowIdentifier(client, type, name)];
f74802c5 103 },
9e769c12
CP
104 getActiveWindow: function() {
105 return this.active;
106 },
1d42a76f
CP
107 getActiveIRCWindow: function(client) {
108 if(!this.active || this.active.type == qwebirc.ui.WINDOW_CUSTOM) {
fd3734d4 109 return this.windows[this.getClientId(client)][this.getWindowIdentifier(client, qwebirc.ui.WINDOW_STATUS)];
1d42a76f
CP
110 } else {
111 return this.active;
112 }
113 },
9e769c12
CP
114 __setActiveWindow: function(window) {
115 this.active = window;
116 },
5aa173fb
CP
117 renameWindow: function(window, name) {
118 if(this.getWindow(window.client, window.type, name))
119 return null;
120
121 var clientId = this.getClientId(window.client);
122 var index = this.windowArray.indexOf(window);
123 if(index == -1)
124 return null;
125
126 delete this.windows[clientId][window.identifier];
127
128 var window = this.windowArray[index];
129 window.name = name;
130 window.identifier = this.getWindowIdentifier(window.client, window.type, window.name);
131
132 this.windows[clientId][window.identifier] = this.windowArray[index];
133
134 if(window.active)
135 this.updateTitle(window.name + " - " + this.options.appTitle);
136
137 window.rename(window.name);
138 return window;
139 },
9e769c12
CP
140 selectWindow: function(window) {
141 if(this.active)
142 this.active.deselect();
143 window.select(); /* calls setActiveWindow */
326478c2
CP
144 this.updateTitle(window.name + " - " + this.options.appTitle);
145 },
146 updateTitle: function(text) {
147 document.title = text;
9e769c12 148 },
ff4befd8
CP
149 nextWindow: function(direction) {
150 if(this.windowArray.length == 0 || !this.active)
151 return;
152
153 if(!direction)
154 direction = 1;
155
156 var index = this.windowArray.indexOf(this.active);
157 if(index == -1)
158 return;
159
160 index = index + direction;
161 if(index < 0) {
162 index = this.windowArray.length - 1;
163 } else if(index >= this.windowArray.length) {
164 index = 0;
165 }
166
167 this.selectWindow(this.windowArray[index]);
168 },
169 prevWindow: function() {
170 this.nextWindow(-1);
171 },
9e769c12
CP
172 __closed: function(window) {
173 if(window.active) {
174 this.active = undefined;
175 if(this.windowArray.length == 1) {
176 this.windowArray = [];
177 } else {
178 var index = this.windowArray.indexOf(window);
6f2e4a37
CP
179 if(index == -1) {
180 return;
181 } else if(index == 0) {
9e769c12
CP
182 this.selectWindow(this.windowArray[1]);
183 } else {
184 this.selectWindow(this.windowArray[index - 1]);
185 }
9e769c12
CP
186 }
187 }
188
404cfb58 189 this.windowArray = this.windowArray.erase(window);
ffbb638d 190 delete this.windows[this.getClientId(window.client)][window.identifier];
eb9b087b 191 },
eb9b087b
CP
192 /*
193 this shouldn't be called by overriding classes!
66de775f 194 they should implement their own!
eb9b087b
CP
195 some form of user input MUST be received before an
196 IRC connection is made, else users are going to get
197 tricked into getting themselves glined
198 */
66de775f 199 loginBox: function(callback, initialNickname, initialChannels, autoConnect, autoNick) {
e89c812f
CP
200 this.postInitialize();
201
202 this.addCustomWindow("Connection details", qwebirc.ui.ConnectPane, "connectpane", {
203 initialNickname: initialNickname, initialChannels: initialChannels, autoConnect: autoConnect, networkName: this.options.networkName, callback: callback, autoNick: autoNick
204 }, qwebirc.ui.WINDOW_CONNECT);
eb271d86
CP
205 },
206 focusChange: function(newValue) {
207 var window_ = this.getActiveWindow();
208 if($defined(window_))
209 window_.focusChange(newValue);
c22afc5d
CP
210 },
211 signedOn: function() {
212 this.poller = new qwebirc.xdomain.Poller(this.oobMessage.bind(this));
213 },
214 oobMessage: function(message) {
215 var c = message.splitMax(" ", 2);
216 if(c.length != 2)
217 return;
218
219 var command = c[0];
220 if(command != "CMD")
221 return;
222
223 var d = c[1].splitMax(" ", 2);
224 if(d.length != 2)
225 return;
226
227 var command = d[0];
228 var args = d[1];
229 if(command == "SAY") {
230 var w = this.getActiveIRCWindow();
44c29df2 231 if($defined(w) && (w.type == qwebirc.ui.WINDOW_CHANNEL || w.type == qwebirc.ui.WINDOW_QUERY)) {
c22afc5d
CP
232 w.client.exec("/SAY " + args);
233 return;
234 }
235 }
9e769c12
CP
236 }
237});
381fddfd 238
e20e5a6b
CP
239qwebirc.ui.StandardUI = new Class({
240 Extends: qwebirc.ui.BaseUI,
f3d0c9f5 241 UICommands: qwebirc.ui.UI_COMMANDS,
381fddfd
CP
242 initialize: function(parentElement, windowClass, uiName, options) {
243 this.parent(parentElement, windowClass, uiName, options);
3184781b
CP
244
245 this.tabCompleter = new qwebirc.ui.TabCompleterFactory(this);
c0f2f367 246 this.uiOptions = new qwebirc.ui.DefaultOptionsClass(this, options.uiOptionsArg);
ebb21d2e
CP
247 this.customWindows = {};
248
6f8a20df
CP
249 this.__styleValues = {hue: this.uiOptions.STYLE_HUE, saturation: 0, lightness: 0};
250 if($defined(this.options.hue)) this.__styleValues.hue = this.options.hue;
251 if($defined(this.options.saturation)) this.__styleValues.saturation = this.options.saturation;
252 if($defined(this.options.lightness)) this.__styleValues.lightness = this.options.lightness;
656385a2
CP
253
254 if(this.options.thue !== null) this.__styleValues.textHue = this.options.thue;
255 if(this.options.tsaturation !== null) this.__styleValues.textSaturation = this.options.tsaturation;
256 if(this.options.tlightness !== null) this.__styleValues.textLightness = this.options.tlightness;
6f8a20df 257
2a802692 258 var ev;
20157c51
CP
259 if(Browser.Engine.trident) {
260 ev = "keydown";
261 } else {
262 ev = "keypress";
263 }
264 document.addEvent(ev, this.__handleHotkey.bind(this));
265 },
266 __handleHotkey: function(x) {
267 if(!x.alt || x.control) {
268 if(x.key == "backspace" || x.key == "/")
269 if(!this.getInputFocused(x))
270 new Event(x).stop();
271 return;
272 }
273 var success = false;
274 if(x.key == "a" || x.key == "A") {
275 var highestNum = 0;
276 var highestIndex = -1;
277 success = true;
278
279 new Event(x).stop();
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;
381fddfd 285 }
20157c51
CP
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
424608ac 295
20157c51
CP
296 number = number - 1;
297
298 if(number >= this.windowArray.length)
299 return;
381fddfd 300
20157c51
CP
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 },
312 getInputFocused: function(x) {
deebe19a
CP
313 if($$("input").indexOf(x.target) == -1 && $$("textarea").indexOf(x.target) == -1)
314 return false;
315 return true;
841a451d 316 },
8af49135
CP
317 newCustomWindow: function(name, select, type) {
318 if(!type)
e20e5a6b 319 type = qwebirc.ui.WINDOW_CUSTOM;
e89c812f 320
e20e5a6b 321 var w = this.newWindow(qwebirc.ui.CUSTOM_CLIENT, type, name);
8af49135 322 w.addEvent("close", function(w) {
f74802c5 323 delete this.windows[qwebirc.ui.CUSTOM_CLIENT][w.identifier];
8af49135
CP
324 }.bind(this));
325
326 if(select)
327 this.selectWindow(w);
6c19eb8f 328
8af49135
CP
329 return w;
330 },
e89c812f 331 addCustomWindow: function(windowName, class_, cssClass, options, type) {
ebb21d2e
CP
332 if(!$defined(options))
333 options = {};
334
335 if(this.customWindows[windowName]) {
336 this.selectWindow(this.customWindows[windowName]);
8af49135 337 return;
841a451d 338 }
8af49135 339
e89c812f 340 var d = this.newCustomWindow(windowName, true, type);
ebb21d2e
CP
341 this.customWindows[windowName] = d;
342
343 d.addEvent("close", function() {
344 this.customWindows[windowName] = null;
8af49135
CP
345 }.bind(this));
346
ebb21d2e 347 if(cssClass)
e1a91a8a 348 d.lines.addClass("qwebirc-" + cssClass);
ebb21d2e
CP
349
350 var ew = new class_(d.lines, options);
8af49135 351 ew.addEvent("close", function() {
ebb21d2e 352 d.close();
8af49135 353 }.bind(this));
17f40fd9
CP
354
355 d.setSubWindow(ew);
841a451d 356 },
ebb21d2e 357 embeddedWindow: function() {
bcd2d24f 358 this.addCustomWindow("Add webchat to your site", qwebirc.ui.EmbedWizard, "embeddedwizard", {baseURL: this.options.baseURL, uiOptions: this.uiOptions, optionsCallback: function() {
c0f2f367
CP
359 this.optionsWindow();
360 }.bind(this)});
ebb21d2e
CP
361 },
362 optionsWindow: function() {
363 this.addCustomWindow("Options", qwebirc.ui.OptionsPane, "optionspane", this.uiOptions);
364 },
e1a91a8a
CP
365 aboutWindow: function() {
366 this.addCustomWindow("About", qwebirc.ui.AboutPane, "aboutpane", this.uiOptions);
367 },
b35116e2
CP
368 privacyWindow: function() {
369 this.addCustomWindow("Privacy policy", qwebirc.ui.PrivacyPolicyPane, "privacypolicypane", this.uiOptions);
370 },
391f51ff
CP
371 feedbackWindow: function() {
372 this.addCustomWindow("Feedback", qwebirc.ui.FeedbackPane, "feedbackpane", this.uiOptions);
373 },
f3d0c9f5
CP
374 faqWindow: function() {
375 this.addCustomWindow("FAQ", qwebirc.ui.FAQPane, "faqpane", this.uiOptions);
376 },
144ee52f 377 urlDispatcher: function(name, window) {
8af49135 378 if(name == "embedded")
925fc357 379 return ["a", this.embeddedWindow.bind(this)];
ebb21d2e
CP
380
381 if(name == "options")
382 return ["a", this.optionsWindow.bind(this)];
8af49135 383
5f2808af
CP
384 /* doesn't really belong here */
385 if(name == "whois") {
386 return ["span", function(nick) {
cbef082a
CP
387 if(this.uiOptions.QUERY_ON_NICK_CLICK) {
388 window.client.exec("/QUERY " + nick);
389 } else {
390 window.client.exec("/WHOIS " + nick);
391 }
392 }.bind(this)];
5f2808af
CP
393 }
394
8af49135 395 return null;
3184781b
CP
396 },
397 tabComplete: function(element) {
398 this.tabCompleter.tabComplete(element);
399 },
400 resetTabComplete: function() {
401 this.tabCompleter.reset();
4dd199c3
CP
402 },
403 setModifiableStylesheet: function(name) {
fbe5af77 404 this.__styleSheet = new qwebirc.ui.style.ModifiableStylesheet(qwebirc.global.staticBaseURL + "css/" + name + qwebirc.FILE_SUFFIX + ".mcss");
6f8a20df 405 this.setModifiableStylesheetValues({});
4dd199c3 406 },
6f8a20df
CP
407 setModifiableStylesheetValues: function(values) {
408 for(var k in values)
409 this.__styleValues[k] = values[k];
410
4dd199c3
CP
411 if(!$defined(this.__styleSheet))
412 return;
6f8a20df 413
656385a2
CP
414 var back = {hue: this.__styleValues.hue, lightness: this.__styleValues.lightness, saturation: this.__styleValues.saturation};
415 var front = {hue: this.__styleValues.textHue, lightness: this.__styleValues.textLightness, saturation: this.__styleValues.textSaturation};
416
417 if(!this.__styleValues.textHue && !this.__styleValues.textLightness && !this.__styleValues.textSaturation)
418 front = back;
419
420 var colours = {
421 back: back,
422 front: front
423 };
424
6f8a20df
CP
425 this.__styleSheet.set(function() {
426 var mode = arguments[0];
427 if(mode == "c") {
656385a2 428 var t = colours[arguments[2]];
6f8a20df 429 var x = new Color(arguments[1]);
656385a2 430 var c = x.setHue(t.hue).setSaturation(x.hsb[1] + t.saturation).setBrightness(x.hsb[2] + t.lightness);
6f8a20df
CP
431 if(c == "255,255,255") /* IE confuses white with transparent... */
432 c = "255,255,254";
433
434 return "rgb(" + c + ")";
435 } else if(mode == "o") {
436 return this.uiOptions[arguments[1]] ? arguments[2] : arguments[3];
437 }
438 }.bind(this));
8af49135 439 }
381fddfd 440});
6f2e4a37 441
326478c2 442qwebirc.ui.NotificationUI = new Class({
e20e5a6b 443 Extends: qwebirc.ui.StandardUI,
fb71087a
CP
444 initialize: function(parentElement, windowClass, uiName, options) {
445 this.parent(parentElement, windowClass, uiName, options);
446
326478c2
CP
447 this.__beeper = new qwebirc.ui.Beeper(this.uiOptions);
448 this.__flasher = new qwebirc.ui.Flasher(this.uiOptions);
fb71087a 449
326478c2 450 this.beep = this.__beeper.beep.bind(this.__beeper);
127631e0 451
326478c2
CP
452 this.flash = this.__flasher.flash.bind(this.__flasher);
453 this.cancelFlash = this.__flasher.cancelFlash.bind(this.__flasher);
fb71087a 454 },
127631e0
CP
455 setBeepOnMention: function(value) {
456 if(value)
326478c2
CP
457 this.__beeper.soundInit();
458 },
459 updateTitle: function(text) {
460 if(this.__flasher.updateTitle(text))
461 this.parent(text);
eb271d86
CP
462 },
463 focusChange: function(value) {
464 this.parent(value);
465 this.__flasher.focusChange(value);
1211ddcd 466 }
fb71087a
CP
467});
468
5f2808af 469qwebirc.ui.QuakeNetUI = new Class({
e89c812f 470 Extends: qwebirc.ui.NotificationUI,
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?")) {
483 for(var client in this.clients) {
484 this.clients[client].quit("Logged out");
485 };
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