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