]> jfr.im git - irc/quakenet/qwebirc.git/blob - js/ui/baseui.js
Merge.
[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-2010 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 selectWindow: function(window) {
118 if(this.active)
119 this.active.deselect();
120 window.select(); /* calls setActiveWindow */
121 this.updateTitle(window.name + " - " + this.options.appTitle);
122 },
123 updateTitle: function(text) {
124 document.title = text;
125 },
126 nextWindow: function(direction) {
127 if(this.windowArray.length == 0 || !this.active)
128 return;
129
130 if(!direction)
131 direction = 1;
132
133 var index = this.windowArray.indexOf(this.active);
134 if(index == -1)
135 return;
136
137 index = index + direction;
138 if(index < 0) {
139 index = this.windowArray.length - 1;
140 } else if(index >= this.windowArray.length) {
141 index = 0;
142 }
143
144 this.selectWindow(this.windowArray[index]);
145 },
146 prevWindow: function() {
147 this.nextWindow(-1);
148 },
149 __closed: function(window) {
150 if(window.active) {
151 this.active = undefined;
152 if(this.windowArray.length == 1) {
153 this.windowArray = [];
154 } else {
155 var index = this.windowArray.indexOf(window);
156 if(index == -1) {
157 return;
158 } else if(index == 0) {
159 this.selectWindow(this.windowArray[1]);
160 } else {
161 this.selectWindow(this.windowArray[index - 1]);
162 }
163 }
164 }
165
166 this.windowArray = this.windowArray.erase(window);
167 delete this.windows[this.getClientId(window.client)][window.identifier];
168 },
169 /*
170 this shouldn't be called by overriding classes!
171 they should implement their own!
172 some form of user input MUST be received before an
173 IRC connection is made, else users are going to get
174 tricked into getting themselves glined
175 */
176 loginBox: function(callback, initialNickname, initialChannels, autoConnect, autoNick) {
177 this.postInitialize();
178
179 this.addCustomWindow("Connection details", qwebirc.ui.ConnectPane, "connectpane", {
180 initialNickname: initialNickname, initialChannels: initialChannels, autoConnect: autoConnect, networkName: this.options.networkName, callback: callback, autoNick: autoNick
181 }, qwebirc.ui.WINDOW_CONNECT);
182 },
183 focusChange: function(newValue) {
184 var window_ = this.getActiveWindow();
185 if($defined(window_))
186 window_.focusChange(newValue);
187 },
188 signedOn: function() {
189 this.poller = new qwebirc.xdomain.Poller(this.oobMessage.bind(this));
190 },
191 oobMessage: function(message) {
192 var c = message.splitMax(" ", 2);
193 if(c.length != 2)
194 return;
195
196 var command = c[0];
197 if(command != "CMD")
198 return;
199
200 var d = c[1].splitMax(" ", 2);
201 if(d.length != 2)
202 return;
203
204 var command = d[0];
205 var args = d[1];
206 if(command == "SAY") {
207 var w = this.getActiveIRCWindow();
208 if($defined(w) && w.type == qwebirc.ui.WINDOW_CHANNEL) {
209 w.client.exec("/SAY " + args);
210 return;
211 }
212 }
213 }
214 });
215
216 qwebirc.ui.StandardUI = new Class({
217 Extends: qwebirc.ui.BaseUI,
218 UICommands: qwebirc.ui.UI_COMMANDS,
219 initialize: function(parentElement, windowClass, uiName, options) {
220 this.parent(parentElement, windowClass, uiName, options);
221
222 this.tabCompleter = new qwebirc.ui.TabCompleterFactory(this);
223 this.uiOptions = new qwebirc.ui.DefaultOptionsClass(this, options.uiOptionsArg);
224 this.customWindows = {};
225
226 var ev;
227 if(Browser.Engine.trident) {
228 ev = "keydown";
229 } else {
230 ev = "keypress";
231 }
232 document.addEvent(ev, this.__handleHotkey.bind(this));
233 },
234 __handleHotkey: function(x) {
235 if(!x.alt || x.control) {
236 if(x.key == "backspace" || x.key == "/")
237 if(!this.getInputFocused(x))
238 new Event(x).stop();
239 return;
240 }
241 var success = false;
242 if(x.key == "a" || x.key == "A") {
243 var highestNum = 0;
244 var highestIndex = -1;
245 success = true;
246
247 new Event(x).stop();
248 for(var i=0;i<this.windowArray.length;i++) {
249 var h = this.windowArray[i].hilighted;
250 if(h > highestNum) {
251 highestIndex = i;
252 highestNum = h;
253 }
254 }
255 if(highestIndex > -1)
256 this.selectWindow(this.windowArray[highestIndex]);
257 } else if(x.key >= '0' && x.key <= '9') {
258 success = true;
259
260 number = x.key - '0';
261 if(number == 0)
262 number = 10
263
264 number = number - 1;
265
266 if(number >= this.windowArray.length)
267 return;
268
269 this.selectWindow(this.windowArray[number]);
270 } else if(x.key == "left") {
271 this.prevWindow();
272 success = true;
273 } else if(x.key == "right") {
274 this.nextWindow();
275 success = true;
276 }
277 if(success)
278 new Event(x).stop();
279 },
280 getInputFocused: function(x) {
281 if($$("input").indexOf(x.target) == -1 && $$("textarea").indexOf(x.target) == -1)
282 return false;
283 return true;
284 },
285 newCustomWindow: function(name, select, type) {
286 if(!type)
287 type = qwebirc.ui.WINDOW_CUSTOM;
288
289 var w = this.newWindow(qwebirc.ui.CUSTOM_CLIENT, type, name);
290 w.addEvent("close", function(w) {
291 delete this.windows[qwebirc.ui.CUSTOM_CLIENT][w.identifier];
292 }.bind(this));
293
294 if(select)
295 this.selectWindow(w);
296
297 return w;
298 },
299 addCustomWindow: function(windowName, class_, cssClass, options, type) {
300 if(!$defined(options))
301 options = {};
302
303 if(this.customWindows[windowName]) {
304 this.selectWindow(this.customWindows[windowName]);
305 return;
306 }
307
308 var d = this.newCustomWindow(windowName, true, type);
309 this.customWindows[windowName] = d;
310
311 d.addEvent("close", function() {
312 this.customWindows[windowName] = null;
313 }.bind(this));
314
315 if(cssClass)
316 d.lines.addClass("qwebirc-" + cssClass);
317
318 var ew = new class_(d.lines, options);
319 ew.addEvent("close", function() {
320 d.close();
321 }.bind(this));
322
323 d.setSubWindow(ew);
324 },
325 embeddedWindow: function() {
326 this.addCustomWindow("Add webchat to your site", qwebirc.ui.EmbedWizard, "embeddedwizard", {baseURL: this.options.baseURL, uiOptions: this.uiOptions, optionsCallback: function() {
327 this.optionsWindow();
328 }.bind(this)});
329 },
330 optionsWindow: function() {
331 this.addCustomWindow("Options", qwebirc.ui.OptionsPane, "optionspane", this.uiOptions);
332 },
333 aboutWindow: function() {
334 this.addCustomWindow("About", qwebirc.ui.AboutPane, "aboutpane", this.uiOptions);
335 },
336 privacyWindow: function() {
337 this.addCustomWindow("Privacy policy", qwebirc.ui.PrivacyPolicyPane, "privacypolicypane", this.uiOptions);
338 },
339 feedbackWindow: function() {
340 this.addCustomWindow("Feedback", qwebirc.ui.FeedbackPane, "feedbackpane", this.uiOptions);
341 },
342 faqWindow: function() {
343 this.addCustomWindow("FAQ", qwebirc.ui.FAQPane, "faqpane", this.uiOptions);
344 },
345 urlDispatcher: function(name, window) {
346 if(name == "embedded")
347 return ["a", this.embeddedWindow.bind(this)];
348
349 if(name == "options")
350 return ["a", this.optionsWindow.bind(this)];
351
352 /* doesn't really belong here */
353 if(name == "whois") {
354 return ["span", function(nick) {
355 if(this.uiOptions.QUERY_ON_NICK_CLICK) {
356 window.client.exec("/QUERY " + nick);
357 } else {
358 window.client.exec("/WHOIS " + nick);
359 }
360 }.bind(this)];
361 }
362
363 return null;
364 },
365 tabComplete: function(element) {
366 this.tabCompleter.tabComplete(element);
367 },
368 resetTabComplete: function() {
369 this.tabCompleter.reset();
370 },
371 setModifiableStylesheet: function(name) {
372 this.__styleSheet = new qwebirc.ui.style.ModifiableStylesheet(qwebirc.global.staticBaseURL + "css/" + name + qwebirc.FILE_SUFFIX + ".mcss");
373
374 if($defined(this.options.hue)) {
375 this.setModifiableStylesheetValues(this.options.hue, 0, 0);
376 } else {
377 this.setModifiableStylesheetValues(this.uiOptions.STYLE_HUE, 0, 0);
378 }
379 },
380 setModifiableStylesheetValues: function(hue, saturation, lightness) {
381 if(!$defined(this.__styleSheet))
382 return;
383 this.__styleSheet.set(function(x) {
384 return x.setHue(hue).setSaturation(x.hsb[1] + saturation).setBrightness(x.hsb[2] + lightness);
385 });
386 }
387 });
388
389 qwebirc.ui.NotificationUI = new Class({
390 Extends: qwebirc.ui.StandardUI,
391 initialize: function(parentElement, windowClass, uiName, options) {
392 this.parent(parentElement, windowClass, uiName, options);
393
394 this.__beeper = new qwebirc.ui.Beeper(this.uiOptions);
395 this.__flasher = new qwebirc.ui.Flasher(this.uiOptions);
396
397 this.beep = this.__beeper.beep.bind(this.__beeper);
398
399 this.flash = this.__flasher.flash.bind(this.__flasher);
400 this.cancelFlash = this.__flasher.cancelFlash.bind(this.__flasher);
401 },
402 setBeepOnMention: function(value) {
403 if(value)
404 this.__beeper.soundInit();
405 },
406 updateTitle: function(text) {
407 if(this.__flasher.updateTitle(text))
408 this.parent(text);
409 },
410 focusChange: function(value) {
411 this.parent(value);
412 this.__flasher.focusChange(value);
413 }
414 });
415
416 qwebirc.ui.QuakeNetUI = new Class({
417 Extends: qwebirc.ui.NotificationUI,
418 urlDispatcher: function(name, window) {
419 if(name == "qwhois") {
420 return ["span", function(auth) {
421 this.client.exec("/MSG Q whois #" + auth);
422 }.bind(window)];
423 }
424 return this.parent(name, window);
425 },
426 logout: function() {
427 if(!qwebirc.auth.loggedin())
428 return;
429 if(confirm("Log out?")) {
430 for(var client in this.clients) {
431 this.clients[client].quit("Logged out");
432 };
433
434 /* HACK */
435 var foo = function() { document.location = qwebirc.global.dynamicBaseURL + "auth?logout=1"; };
436 foo.delay(500);
437 }
438 }
439 });
440
441 qwebirc.ui.RootUI = qwebirc.ui.QuakeNetUI;
442
443 qwebirc.ui.RequestTransformHTML = function(options) {
444 var HREF_ELEMENTS = {
445 "IMG": 1
446 };
447
448 var update = options.update;
449 var onSuccess = options.onSuccess;
450
451 var fixUp = function(node) {
452 if(node.nodeType != 1)
453 return;
454
455 var tagName = node.nodeName.toUpperCase();
456 if(HREF_ELEMENTS[tagName]) {
457 var attr = node.getAttribute("transform_attr");
458 var value = node.getAttribute("transform_value");
459 if($defined(attr) && $defined(value)) {
460 node.removeAttribute("transform_attr");
461 node.removeAttribute("transform_value");
462 node.setAttribute(attr, qwebirc.global.staticBaseURL + value);
463 }
464 }
465
466 for(var i=0;i<node.childNodes.length;i++)
467 fixUp(node.childNodes[i]);
468 };
469
470 delete options["update"];
471 options.onSuccess = function(tree, elements, html, js) {
472 var container = new Element("div");
473 container.set("html", html);
474 fixUp(container);
475 update.empty();
476
477 while(container.childNodes.length > 0) {
478 var x = container.firstChild;
479 container.removeChild(x);
480 update.appendChild(x);
481 }
482 onSuccess();
483 };
484
485 return new Request.HTML(options);
486 };
487