]> 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 || w.type == qwebirc.ui.WINDOW_QUERY)) {
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 this.setModifiableStylesheetValues($defined(this.options.hue) ? this.options.hue : this.uiOptions.STYLE_HUE, $defined(this.options.saturation) ? this.options.saturation : 0, $defined(this.options.lightness) ? this.options.lightness : 0);
375 },
376 setModifiableStylesheetValues: function(hue, saturation, lightness) {
377 if(!$defined(this.__styleSheet))
378 return;
379 this.__styleSheet.set(function(x) {
380 return x.setHue(hue).setSaturation(x.hsb[1] + saturation).setBrightness(x.hsb[2] + lightness);
381 });
382 }
383 });
384
385 qwebirc.ui.NotificationUI = new Class({
386 Extends: qwebirc.ui.StandardUI,
387 initialize: function(parentElement, windowClass, uiName, options) {
388 this.parent(parentElement, windowClass, uiName, options);
389
390 this.__beeper = new qwebirc.ui.Beeper(this.uiOptions);
391 this.__flasher = new qwebirc.ui.Flasher(this.uiOptions);
392
393 this.beep = this.__beeper.beep.bind(this.__beeper);
394
395 this.flash = this.__flasher.flash.bind(this.__flasher);
396 this.cancelFlash = this.__flasher.cancelFlash.bind(this.__flasher);
397 },
398 setBeepOnMention: function(value) {
399 if(value)
400 this.__beeper.soundInit();
401 },
402 updateTitle: function(text) {
403 if(this.__flasher.updateTitle(text))
404 this.parent(text);
405 },
406 focusChange: function(value) {
407 this.parent(value);
408 this.__flasher.focusChange(value);
409 }
410 });
411
412 qwebirc.ui.QuakeNetUI = new Class({
413 Extends: qwebirc.ui.NotificationUI,
414 urlDispatcher: function(name, window) {
415 if(name == "qwhois") {
416 return ["span", function(auth) {
417 this.client.exec("/MSG Q whois #" + auth);
418 }.bind(window)];
419 }
420 return this.parent(name, window);
421 },
422 logout: function() {
423 if(!qwebirc.auth.loggedin())
424 return;
425 if(confirm("Log out?")) {
426 for(var client in this.clients) {
427 this.clients[client].quit("Logged out");
428 };
429
430 /* HACK */
431 var foo = function() { document.location = qwebirc.global.dynamicBaseURL + "auth?logout=1"; };
432 foo.delay(500);
433 }
434 }
435 });
436
437 qwebirc.ui.RootUI = qwebirc.ui.QuakeNetUI;
438
439 qwebirc.ui.RequestTransformHTML = function(options) {
440 var HREF_ELEMENTS = {
441 "IMG": 1
442 };
443
444 var update = options.update;
445 var onSuccess = options.onSuccess;
446
447 var fixUp = function(node) {
448 if(node.nodeType != 1)
449 return;
450
451 var tagName = node.nodeName.toUpperCase();
452 if(HREF_ELEMENTS[tagName]) {
453 var attr = node.getAttribute("transform_attr");
454 var value = node.getAttribute("transform_value");
455 if($defined(attr) && $defined(value)) {
456 node.removeAttribute("transform_attr");
457 node.removeAttribute("transform_value");
458 node.setAttribute(attr, qwebirc.global.staticBaseURL + value);
459 }
460 }
461
462 for(var i=0;i<node.childNodes.length;i++)
463 fixUp(node.childNodes[i]);
464 };
465
466 delete options["update"];
467 options.onSuccess = function(tree, elements, html, js) {
468 var container = new Element("div");
469 container.set("html", html);
470 fixUp(container);
471 update.empty();
472
473 while(container.childNodes.length > 0) {
474 var x = container.firstChild;
475 container.removeChild(x);
476 update.appendChild(x);
477 }
478 onSuccess();
479 };
480
481 return new Request.HTML(options);
482 };
483