]> jfr.im git - irc/quakenet/qwebirc.git/blame_incremental - js/ui/baseui.js
add ignore list implementation
[irc/quakenet/qwebirc.git] / js / ui / baseui.js
... / ...
CommitLineData
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;
6qwebirc.ui.WINDOW_MESSAGES = 0x20;
7
8qwebirc.ui.CUSTOM_CLIENT = "custom";
9
10qwebirc.ui.BaseUI = new Class({
11 Implements: [Events],
12 initialize: function(parentElement, windowClass, uiName, options) {
13 this.options = options;
14
15 this.windows = {};
16 this.clients = {};
17 this.windows[qwebirc.ui.CUSTOM_CLIENT] = {};
18 this.windowArray = [];
19 this.windowClass = windowClass;
20 this.parentElement = parentElement;
21 this.parentElement.addClass("qwebirc");
22 this.parentElement.addClass("qwebirc-" + uiName);
23 this.firstClient = false;
24 this.commandhistory = new qwebirc.irc.CommandHistory();
25 this.clientId = 0;
26
27 this.windowFocused = true;
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 }
50 },
51 newClient: function(client) {
52 client.id = this.clientId++;
53 client.hilightController = new qwebirc.ui.HilightController(client);
54 client.addEvent("signedOn", function() {
55 this.fireEvent("signedOn", client);
56 }.bind(this));
57 this.windows[client.id] = {}
58 this.clients[client.id] = client;
59 var w = this.newWindow(client, qwebirc.ui.WINDOW_STATUS, "Status");
60 this.selectWindow(w);
61 if(!this.firstClient) {
62 this.firstClient = true;
63 w.addLine("", "qwebirc v" + qwebirc.VERSION);
64 w.addLine("", "Copyright (C) 2008-2014 Chris Porter and the qwebirc project.");
65 w.addLine("", "http://www.qwebirc.org");
66 w.addLine("", "Licensed under the GNU General Public License, Version 2.");
67 }
68 return w;
69 },
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 },
77 getWindowIdentifier: function(client, type, name) {
78 if(type == qwebirc.ui.WINDOW_MESSAGES)
79 return "-M";
80 if(type == qwebirc.ui.WINDOW_STATUS)
81 return "";
82
83 if(client == qwebirc.ui.CUSTOM_CLIENT) /* HACK */
84 return "_" + name;
85
86 return "_" + client.toIRCLower(name);
87 },
88 newWindow: function(client, type, name) {
89 var w = this.getWindow(client, type, name);
90 if($defined(w))
91 return w;
92
93 var wId = this.getWindowIdentifier(client, type, name);
94 var w = this.windows[this.getClientId(client)][wId] = new this.windowClass(this, client, type, name, wId);
95 this.windowArray.push(w);
96
97 return w;
98 },
99 getWindow: function(client, type, name) {
100 var c = this.windows[this.getClientId(client)];
101 if(!$defined(c))
102 return null;
103
104 return c[this.getWindowIdentifier(client, type, name)];
105 },
106 getActiveWindow: function() {
107 return this.active;
108 },
109 getActiveIRCWindow: function(client) {
110 if(!this.active || this.active.type == qwebirc.ui.WINDOW_CUSTOM) {
111 return this.windows[this.getClientId(client)][this.getWindowIdentifier(client, qwebirc.ui.WINDOW_STATUS)];
112 } else {
113 return this.active;
114 }
115 },
116 __setActiveWindow: function(window) {
117 this.active = window;
118 },
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 },
142 selectWindow: function(window) {
143 if(this.active)
144 this.active.deselect();
145 window.select(); /* calls setActiveWindow */
146 this.updateTitle(window.name + " - " + this.options.appTitle);
147 },
148 updateTitle: function(text) {
149 document.title = text;
150 },
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 },
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);
181 if(index == -1) {
182 return;
183 } else if(index == 0) {
184 this.selectWindow(this.windowArray[1]);
185 } else {
186 this.selectWindow(this.windowArray[index - 1]);
187 }
188 }
189 }
190
191 this.windowArray = this.windowArray.erase(window);
192 delete this.windows[this.getClientId(window.client)][window.identifier];
193 },
194 /*
195 this shouldn't be called by overriding classes!
196 they should implement their own!
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 */
201 loginBox: function(callback, initialNickname, initialChannels, autoConnect, autoNick) {
202 qwebirc.ui.GenericLoginBox(this.parentElement, callback, initialNickname, initialChannels, autoConnect, autoNick, this.options.networkName);
203 },
204 focusChange: function(newValue) {
205 var window_ = this.getActiveWindow();
206 if($defined(window_))
207 window_.focusChange(newValue);
208 }
209});
210
211qwebirc.ui.StandardUI = new Class({
212 Extends: qwebirc.ui.BaseUI,
213 UICommands: qwebirc.ui.UI_COMMANDS,
214 initialize: function(parentElement, windowClass, uiName, options) {
215 this.parent(parentElement, windowClass, uiName, options);
216
217 this.tabCompleter = new qwebirc.ui.TabCompleterFactory(this);
218 this.uiOptions = new qwebirc.ui.DefaultOptionsClass(this, options.uiOptionsArg);
219 this.customWindows = {};
220
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;
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;
229
230 var ev;
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;
257 }
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
267
268 number = number - 1;
269
270 if(number >= this.windowArray.length)
271 return;
272
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) {
285 if($$("input").indexOf(x.target) == -1 && $$("textarea").indexOf(x.target) == -1)
286 return false;
287 return true;
288 },
289 newCustomWindow: function(name, select, type) {
290 if(!type)
291 type = qwebirc.ui.WINDOW_CUSTOM;
292
293 var w = this.newWindow(qwebirc.ui.CUSTOM_CLIENT, type, name);
294 w.addEvent("close", function(w) {
295 delete this.windows[qwebirc.ui.CUSTOM_CLIENT][w.identifier];
296 }.bind(this));
297
298 if(select)
299 this.selectWindow(w);
300
301 return w;
302 },
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]);
309 return;
310 }
311
312 var d = this.newCustomWindow(windowName, true);
313 this.customWindows[windowName] = d;
314
315 d.addEvent("close", function() {
316 this.customWindows[windowName] = null;
317 }.bind(this));
318
319 if(cssClass)
320 d.lines.addClass("qwebirc-" + cssClass);
321
322 var ew = new class_(d.lines, options);
323 ew.addEvent("close", function() {
324 d.close();
325 }.bind(this));
326
327 d.setSubWindow(ew);
328 },
329 embeddedWindow: function() {
330 this.addCustomWindow("Add webchat to your site", qwebirc.ui.EmbedWizard, "embeddedwizard", {baseURL: this.options.baseURL, uiOptions: this.uiOptions, optionsCallback: function() {
331 this.optionsWindow();
332 }.bind(this)});
333 },
334 optionsWindow: function() {
335 this.addCustomWindow("Options", qwebirc.ui.OptionsPane, "optionspane", this.uiOptions);
336 },
337 aboutWindow: function() {
338 this.addCustomWindow("About", qwebirc.ui.AboutPane, "aboutpane", this.uiOptions);
339 },
340 privacyWindow: function() {
341 this.addCustomWindow("Privacy policy", qwebirc.ui.PrivacyPolicyPane, "privacypolicypane", this.uiOptions);
342 },
343 feedbackWindow: function() {
344 this.addCustomWindow("Feedback", qwebirc.ui.FeedbackPane, "feedbackpane", this.uiOptions);
345 },
346 helpWindow: function() {
347 this.addCustomWindow("Help!", qwebirc.ui.HelpPane, "helppane", this.uiOptions);
348 },
349 urlDispatcher: function(name, window) {
350 if(name == "embedded")
351 return ["a", this.embeddedWindow.bind(this)];
352
353 if(name == "options")
354 return ["a", this.optionsWindow.bind(this)];
355
356 /* doesn't really belong here */
357 if(name == "whois") {
358 return ["span", function(nick) {
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)];
365 }
366
367 return null;
368 },
369 tabComplete: function(element) {
370 this.tabCompleter.tabComplete(element);
371 },
372 resetTabComplete: function() {
373 this.tabCompleter.reset();
374 },
375 setModifiableStylesheet: function(name) {
376 this.__styleSheet = new qwebirc.ui.style.ModifiableStylesheet(qwebirc.global.staticBaseURL + "css/" + name + qwebirc.FILE_SUFFIX + ".mcss");
377 this.setModifiableStylesheetValues({});
378 },
379 setModifiableStylesheetValues: function(values) {
380 for(var k in values)
381 this.__styleValues[k] = values[k];
382
383 if(!$defined(this.__styleSheet))
384 return;
385
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
397 this.__styleSheet.set(function() {
398 var mode = arguments[0];
399 if(mode == "c") {
400 var t = colours[arguments[2]];
401 var x = new Color(arguments[1]);
402 var c = x.setHue(t.hue).setSaturation(x.hsb[1] + t.saturation).setBrightness(x.hsb[2] + t.lightness);
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));
411 }
412});
413
414qwebirc.ui.NotificationUI = new Class({
415 Extends: qwebirc.ui.StandardUI,
416 initialize: function(parentElement, windowClass, uiName, options) {
417 this.parent(parentElement, windowClass, uiName, options);
418
419 this.__beeper = new qwebirc.ui.Beeper(this.uiOptions);
420 this.__flasher = new qwebirc.ui.Flasher(this.uiOptions);
421
422 this.beep = this.__beeper.beep.bind(this.__beeper);
423
424 this.flash = this.__flasher.flash.bind(this.__flasher);
425 this.cancelFlash = this.__flasher.cancelFlash.bind(this.__flasher);
426 },
427 setBeepOnMention: function(value) {
428 if(value)
429 this.__beeper.soundInit();
430 },
431 updateTitle: function(text) {
432 if(this.__flasher.updateTitle(text))
433 this.parent(text);
434 },
435 focusChange: function(value) {
436 this.parent(value);
437 this.__flasher.focusChange(value);
438 }
439});
440
441qwebirc.ui.NewLoginUI = new Class({
442 Extends: qwebirc.ui.NotificationUI,
443 loginBox: function(callbackfn, initialNickname, initialChannels, autoConnect, autoNick) {
444 this.postInitialize();
445
446 /* I'd prefer something shorter and snappier! */
447 var w = this.newCustomWindow("Connection details", true, qwebirc.ui.WINDOW_CONNECT);
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,
459 urlDispatcher: function(name, window) {
460 if(name == "qwhois") {
461 return ["span", function(auth) {
462 this.client.exec("/MSG Q whois #" + auth);
463 }.bind(window)];
464 }
465 return this.parent(name, window);
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 };
474
475 /* HACK */
476 var foo = function() { document.location = qwebirc.global.dynamicBaseURL + "auth?logout=1"; };
477 foo.delay(500);
478 }
479 }
480});
481
482qwebirc.ui.RootUI = qwebirc.ui.QuakeNetUI;
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