]> jfr.im git - irc/quakenet/qwebirc.git/blob - js/ui/baseui.js
Fix ticket expirations.
[irc/quakenet/qwebirc.git] / js / ui / baseui.js
1 qwebirc.ui.WINDOW_STATUS = 0x01;
2 qwebirc.ui.WINDOW_QUERY = 0x02;
3 qwebirc.ui.WINDOW_CHANNEL = 0x04;
4 qwebirc.ui.WINDOW_CUSTOM = 0x08;
5 qwebirc.ui.WINDOW_CONNECT = 0x10;
6 qwebirc.ui.WINDOW_MESSAGES = 0x20;
7
8 qwebirc.ui.CUSTOM_CLIENT = "custom";
9
10 qwebirc.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
55 this.windows[client.id] = {}
56 this.clients[client.id] = client;
57 var w = this.newWindow(client, qwebirc.ui.WINDOW_STATUS, "Status");
58 this.selectWindow(w);
59 if(!this.firstClient) {
60 this.firstClient = true;
61 w.addLine("", "qwebirc v" + qwebirc.VERSION);
62 w.addLine("", "Copyright (C) 2008-2012 Chris Porter and the qwebirc project.");
63 w.addLine("", "http://www.qwebirc.org");
64 w.addLine("", "Licensed under the GNU General Public License, Version 2.");
65 }
66 return w;
67 },
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 },
75 getWindowIdentifier: function(client, type, name) {
76 if(type == qwebirc.ui.WINDOW_MESSAGES)
77 return "-M";
78 if(type == qwebirc.ui.WINDOW_STATUS)
79 return "";
80
81 if(client == qwebirc.ui.CUSTOM_CLIENT) /* HACK */
82 return "_" + name;
83
84 return "_" + client.toIRCLower(name);
85 },
86 newWindow: function(client, type, name) {
87 var w = this.getWindow(client, type, name);
88 if($defined(w))
89 return w;
90
91 var wId = this.getWindowIdentifier(client, type, name);
92 var w = this.windows[this.getClientId(client)][wId] = new this.windowClass(this, client, type, name, wId);
93 this.windowArray.push(w);
94
95 return w;
96 },
97 getWindow: function(client, type, name) {
98 var c = this.windows[this.getClientId(client)];
99 if(!$defined(c))
100 return null;
101
102 return c[this.getWindowIdentifier(client, type, name)];
103 },
104 getActiveWindow: function() {
105 return this.active;
106 },
107 getActiveIRCWindow: function(client) {
108 if(!this.active || this.active.type == qwebirc.ui.WINDOW_CUSTOM) {
109 return this.windows[this.getClientId(client)][this.getWindowIdentifier(client, qwebirc.ui.WINDOW_STATUS)];
110 } else {
111 return this.active;
112 }
113 },
114 __setActiveWindow: function(window) {
115 this.active = window;
116 },
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 },
140 selectWindow: function(window) {
141 if(this.active)
142 this.active.deselect();
143 window.select(); /* calls setActiveWindow */
144 this.updateTitle(window.name + " - " + this.options.appTitle);
145 },
146 updateTitle: function(text) {
147 document.title = text;
148 },
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 },
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);
179 if(index == -1) {
180 return;
181 } else if(index == 0) {
182 this.selectWindow(this.windowArray[1]);
183 } else {
184 this.selectWindow(this.windowArray[index - 1]);
185 }
186 }
187 }
188
189 this.windowArray = this.windowArray.erase(window);
190 delete this.windows[this.getClientId(window.client)][window.identifier];
191 },
192 /*
193 this shouldn't be called by overriding classes!
194 they should implement their own!
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 */
199 loginBox: function(callback, initialNickname, initialChannels, autoConnect, autoNick) {
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);
205 },
206 focusChange: function(newValue) {
207 var window_ = this.getActiveWindow();
208 if($defined(window_))
209 window_.focusChange(newValue);
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();
231 if($defined(w) && (w.type == qwebirc.ui.WINDOW_CHANNEL || w.type == qwebirc.ui.WINDOW_QUERY)) {
232 w.client.exec("/SAY " + args);
233 return;
234 }
235 }
236 }
237 });
238
239 qwebirc.ui.StandardUI = new Class({
240 Extends: qwebirc.ui.BaseUI,
241 UICommands: qwebirc.ui.UI_COMMANDS,
242 initialize: function(parentElement, windowClass, uiName, options) {
243 this.parent(parentElement, windowClass, uiName, options);
244
245 this.tabCompleter = new qwebirc.ui.TabCompleterFactory(this);
246 this.uiOptions = new qwebirc.ui.DefaultOptionsClass(this, options.uiOptionsArg);
247 this.customWindows = {};
248
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;
253
254 var ev;
255 if(Browser.Engine.trident) {
256 ev = "keydown";
257 } else {
258 ev = "keypress";
259 }
260 document.addEvent(ev, this.__handleHotkey.bind(this));
261 },
262 __handleHotkey: function(x) {
263 if(!x.alt || x.control) {
264 if(x.key == "backspace" || x.key == "/")
265 if(!this.getInputFocused(x))
266 new Event(x).stop();
267 return;
268 }
269 var success = false;
270 if(x.key == "a" || x.key == "A") {
271 var highestNum = 0;
272 var highestIndex = -1;
273 success = true;
274
275 new Event(x).stop();
276 for(var i=0;i<this.windowArray.length;i++) {
277 var h = this.windowArray[i].hilighted;
278 if(h > highestNum) {
279 highestIndex = i;
280 highestNum = h;
281 }
282 }
283 if(highestIndex > -1)
284 this.selectWindow(this.windowArray[highestIndex]);
285 } else if(x.key >= '0' && x.key <= '9') {
286 success = true;
287
288 number = x.key - '0';
289 if(number == 0)
290 number = 10
291
292 number = number - 1;
293
294 if(number >= this.windowArray.length)
295 return;
296
297 this.selectWindow(this.windowArray[number]);
298 } else if(x.key == "left") {
299 this.prevWindow();
300 success = true;
301 } else if(x.key == "right") {
302 this.nextWindow();
303 success = true;
304 }
305 if(success)
306 new Event(x).stop();
307 },
308 getInputFocused: function(x) {
309 if($$("input").indexOf(x.target) == -1 && $$("textarea").indexOf(x.target) == -1)
310 return false;
311 return true;
312 },
313 newCustomWindow: function(name, select, type) {
314 if(!type)
315 type = qwebirc.ui.WINDOW_CUSTOM;
316
317 var w = this.newWindow(qwebirc.ui.CUSTOM_CLIENT, type, name);
318 w.addEvent("close", function(w) {
319 delete this.windows[qwebirc.ui.CUSTOM_CLIENT][w.identifier];
320 }.bind(this));
321
322 if(select)
323 this.selectWindow(w);
324
325 return w;
326 },
327 addCustomWindow: function(windowName, class_, cssClass, options, type) {
328 if(!$defined(options))
329 options = {};
330
331 if(this.customWindows[windowName]) {
332 this.selectWindow(this.customWindows[windowName]);
333 return;
334 }
335
336 var d = this.newCustomWindow(windowName, true, type);
337 this.customWindows[windowName] = d;
338
339 d.addEvent("close", function() {
340 this.customWindows[windowName] = null;
341 }.bind(this));
342
343 if(cssClass)
344 d.lines.addClass("qwebirc-" + cssClass);
345
346 var ew = new class_(d.lines, options);
347 ew.addEvent("close", function() {
348 d.close();
349 }.bind(this));
350
351 d.setSubWindow(ew);
352 },
353 embeddedWindow: function() {
354 this.addCustomWindow("Add webchat to your site", qwebirc.ui.EmbedWizard, "embeddedwizard", {baseURL: this.options.baseURL, uiOptions: this.uiOptions, optionsCallback: function() {
355 this.optionsWindow();
356 }.bind(this)});
357 },
358 optionsWindow: function() {
359 this.addCustomWindow("Options", qwebirc.ui.OptionsPane, "optionspane", this.uiOptions);
360 },
361 aboutWindow: function() {
362 this.addCustomWindow("About", qwebirc.ui.AboutPane, "aboutpane", this.uiOptions);
363 },
364 privacyWindow: function() {
365 this.addCustomWindow("Privacy policy", qwebirc.ui.PrivacyPolicyPane, "privacypolicypane", this.uiOptions);
366 },
367 feedbackWindow: function() {
368 this.addCustomWindow("Feedback", qwebirc.ui.FeedbackPane, "feedbackpane", this.uiOptions);
369 },
370 faqWindow: function() {
371 this.addCustomWindow("FAQ", qwebirc.ui.FAQPane, "faqpane", this.uiOptions);
372 },
373 urlDispatcher: function(name, window) {
374 if(name == "embedded")
375 return ["a", this.embeddedWindow.bind(this)];
376
377 if(name == "options")
378 return ["a", this.optionsWindow.bind(this)];
379
380 /* doesn't really belong here */
381 if(name == "whois") {
382 return ["span", function(nick) {
383 if(this.uiOptions.QUERY_ON_NICK_CLICK) {
384 window.client.exec("/QUERY " + nick);
385 } else {
386 window.client.exec("/WHOIS " + nick);
387 }
388 }.bind(this)];
389 }
390
391 return null;
392 },
393 tabComplete: function(element) {
394 this.tabCompleter.tabComplete(element);
395 },
396 resetTabComplete: function() {
397 this.tabCompleter.reset();
398 },
399 setModifiableStylesheet: function(name) {
400 this.__styleSheet = new qwebirc.ui.style.ModifiableStylesheet(qwebirc.global.staticBaseURL + "css/" + name + qwebirc.FILE_SUFFIX + ".mcss");
401 this.setModifiableStylesheetValues({});
402 },
403 setModifiableStylesheetValues: function(values) {
404 for(var k in values)
405 this.__styleValues[k] = values[k];
406
407 if(!$defined(this.__styleSheet))
408 return;
409
410 var hue = this.__styleValues.hue, lightness = this.__styleValues.lightness, saturation = this.__styleValues.saturation;
411
412 this.__styleSheet.set(function() {
413 var mode = arguments[0];
414 if(mode == "c") {
415 var x = new Color(arguments[1]);
416 var c = x.setHue(hue).setSaturation(x.hsb[1] + saturation).setBrightness(x.hsb[2] + lightness);
417 if(c == "255,255,255") /* IE confuses white with transparent... */
418 c = "255,255,254";
419
420 return "rgb(" + c + ")";
421 } else if(mode == "o") {
422 return this.uiOptions[arguments[1]] ? arguments[2] : arguments[3];
423 }
424 }.bind(this));
425 }
426 });
427
428 qwebirc.ui.NotificationUI = new Class({
429 Extends: qwebirc.ui.StandardUI,
430 initialize: function(parentElement, windowClass, uiName, options) {
431 this.parent(parentElement, windowClass, uiName, options);
432
433 this.__beeper = new qwebirc.ui.Beeper(this.uiOptions);
434 this.__flasher = new qwebirc.ui.Flasher(this.uiOptions);
435
436 this.beep = this.__beeper.beep.bind(this.__beeper);
437
438 this.flash = this.__flasher.flash.bind(this.__flasher);
439 this.cancelFlash = this.__flasher.cancelFlash.bind(this.__flasher);
440 },
441 setBeepOnMention: function(value) {
442 if(value)
443 this.__beeper.soundInit();
444 },
445 updateTitle: function(text) {
446 if(this.__flasher.updateTitle(text))
447 this.parent(text);
448 },
449 focusChange: function(value) {
450 this.parent(value);
451 this.__flasher.focusChange(value);
452 }
453 });
454
455 qwebirc.ui.QuakeNetUI = new Class({
456 Extends: qwebirc.ui.NotificationUI,
457 urlDispatcher: function(name, window) {
458 if(name == "qwhois") {
459 return ["span", function(auth) {
460 this.client.exec("/MSG Q whois #" + auth);
461 }.bind(window)];
462 }
463 return this.parent(name, window);
464 },
465 logout: function() {
466 if(!qwebirc.auth.loggedin())
467 return;
468 if(confirm("Log out?")) {
469 for(var client in this.clients) {
470 this.clients[client].quit("Logged out");
471 };
472
473 /* HACK */
474 var foo = function() { document.location = qwebirc.global.dynamicBaseURL + "auth?logout=1"; };
475 foo.delay(500);
476 }
477 }
478 });
479
480 qwebirc.ui.RootUI = qwebirc.ui.QuakeNetUI;
481
482 qwebirc.ui.RequestTransformHTML = function(options) {
483 var HREF_ELEMENTS = {
484 "IMG": 1
485 };
486
487 var update = options.update;
488 var onSuccess = options.onSuccess;
489
490 var fixUp = function(node) {
491 if(node.nodeType != 1)
492 return;
493
494 var tagName = node.nodeName.toUpperCase();
495 if(HREF_ELEMENTS[tagName]) {
496 var attr = node.getAttribute("transform_attr");
497 var value = node.getAttribute("transform_value");
498 if($defined(attr) && $defined(value)) {
499 node.removeAttribute("transform_attr");
500 node.removeAttribute("transform_value");
501 node.setAttribute(attr, qwebirc.global.staticBaseURL + value);
502 }
503 }
504
505 for(var i=0;i<node.childNodes.length;i++)
506 fixUp(node.childNodes[i]);
507 };
508
509 delete options["update"];
510 options.onSuccess = function(tree, elements, html, js) {
511 var container = new Element("div");
512 container.set("html", html);
513 fixUp(container);
514 update.empty();
515
516 while(container.childNodes.length > 0) {
517 var x = container.firstChild;
518 container.removeChild(x);
519 update.appendChild(x);
520 }
521 onSuccess();
522 };
523
524 return new Request.HTML(options);
525 };
526