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