]> jfr.im git - irc/quakenet/qwebirc.git/blame_incremental - js/ui/baseui.js
Missed one...
[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
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 qwebirc.ui.GenericLoginBox(this.parentElement, callback, initialNickname, initialChannels, autoConnect, autoNick, this.options.networkName);
201 },
202 focusChange: function(newValue) {
203 var window_ = this.getActiveWindow();
204 if($defined(window_))
205 window_.focusChange(newValue);
206 }
207});
208
209qwebirc.ui.StandardUI = new Class({
210 Extends: qwebirc.ui.BaseUI,
211 UICommands: qwebirc.ui.UI_COMMANDS,
212 initialize: function(parentElement, windowClass, uiName, options) {
213 this.parent(parentElement, windowClass, uiName, options);
214
215 this.tabCompleter = new qwebirc.ui.TabCompleterFactory(this);
216 this.uiOptions = new qwebirc.ui.DefaultOptionsClass(this, options.uiOptionsArg);
217 this.customWindows = {};
218
219 this.__styleValues = {hue: this.uiOptions.STYLE_HUE, saturation: 0, lightness: 0};
220 if($defined(this.options.hue)) this.__styleValues.hue = this.options.hue;
221 if($defined(this.options.saturation)) this.__styleValues.saturation = this.options.saturation;
222 if($defined(this.options.lightness)) this.__styleValues.lightness = this.options.lightness;
223
224 var ev;
225 if(Browser.Engine.trident) {
226 ev = "keydown";
227 } else {
228 ev = "keypress";
229 }
230 document.addEvent(ev, this.__handleHotkey.bind(this));
231 },
232 __handleHotkey: function(x) {
233 if(!x.alt || x.control) {
234 if(x.key == "backspace" || x.key == "/")
235 if(!this.getInputFocused(x))
236 new Event(x).stop();
237 return;
238 }
239 var success = false;
240 if(x.key == "a" || x.key == "A") {
241 var highestNum = 0;
242 var highestIndex = -1;
243 success = true;
244
245 new Event(x).stop();
246 for(var i=0;i<this.windowArray.length;i++) {
247 var h = this.windowArray[i].hilighted;
248 if(h > highestNum) {
249 highestIndex = i;
250 highestNum = h;
251 }
252 }
253 if(highestIndex > -1)
254 this.selectWindow(this.windowArray[highestIndex]);
255 } else if(x.key >= '0' && x.key <= '9') {
256 success = true;
257
258 number = x.key - '0';
259 if(number == 0)
260 number = 10
261
262 number = number - 1;
263
264 if(number >= this.windowArray.length)
265 return;
266
267 this.selectWindow(this.windowArray[number]);
268 } else if(x.key == "left") {
269 this.prevWindow();
270 success = true;
271 } else if(x.key == "right") {
272 this.nextWindow();
273 success = true;
274 }
275 if(success)
276 new Event(x).stop();
277 },
278 getInputFocused: function(x) {
279 if($$("input").indexOf(x.target) == -1 && $$("textarea").indexOf(x.target) == -1)
280 return false;
281 return true;
282 },
283 newCustomWindow: function(name, select, type) {
284 if(!type)
285 type = qwebirc.ui.WINDOW_CUSTOM;
286
287 var w = this.newWindow(qwebirc.ui.CUSTOM_CLIENT, type, name);
288 w.addEvent("close", function(w) {
289 delete this.windows[qwebirc.ui.CUSTOM_CLIENT][w.identifier];
290 }.bind(this));
291
292 if(select)
293 this.selectWindow(w);
294
295 return w;
296 },
297 addCustomWindow: function(windowName, class_, cssClass, options) {
298 if(!$defined(options))
299 options = {};
300
301 if(this.customWindows[windowName]) {
302 this.selectWindow(this.customWindows[windowName]);
303 return;
304 }
305
306 var d = this.newCustomWindow(windowName, true);
307 this.customWindows[windowName] = d;
308
309 d.addEvent("close", function() {
310 this.customWindows[windowName] = null;
311 }.bind(this));
312
313 if(cssClass)
314 d.lines.addClass("qwebirc-" + cssClass);
315
316 var ew = new class_(d.lines, options);
317 ew.addEvent("close", function() {
318 d.close();
319 }.bind(this));
320
321 d.setSubWindow(ew);
322 },
323 embeddedWindow: function() {
324 this.addCustomWindow("Add webchat to your site", qwebirc.ui.EmbedWizard, "embeddedwizard", {baseURL: this.options.baseURL, uiOptions: this.uiOptions, optionsCallback: function() {
325 this.optionsWindow();
326 }.bind(this)});
327 },
328 optionsWindow: function() {
329 this.addCustomWindow("Options", qwebirc.ui.OptionsPane, "optionspane", this.uiOptions);
330 },
331 aboutWindow: function() {
332 this.addCustomWindow("About", qwebirc.ui.AboutPane, "aboutpane", this.uiOptions);
333 },
334 privacyWindow: function() {
335 this.addCustomWindow("Privacy policy", qwebirc.ui.PrivacyPolicyPane, "privacypolicypane", this.uiOptions);
336 },
337 feedbackWindow: function() {
338 this.addCustomWindow("Feedback", qwebirc.ui.FeedbackPane, "feedbackpane", this.uiOptions);
339 },
340 faqWindow: function() {
341 this.addCustomWindow("FAQ", qwebirc.ui.FAQPane, "faqpane", this.uiOptions);
342 },
343 urlDispatcher: function(name, window) {
344 if(name == "embedded")
345 return ["a", this.embeddedWindow.bind(this)];
346
347 if(name == "options")
348 return ["a", this.optionsWindow.bind(this)];
349
350 /* doesn't really belong here */
351 if(name == "whois") {
352 return ["span", function(nick) {
353 if(this.uiOptions.QUERY_ON_NICK_CLICK) {
354 window.client.exec("/QUERY " + nick);
355 } else {
356 window.client.exec("/WHOIS " + nick);
357 }
358 }.bind(this)];
359 }
360
361 return null;
362 },
363 tabComplete: function(element) {
364 this.tabCompleter.tabComplete(element);
365 },
366 resetTabComplete: function() {
367 this.tabCompleter.reset();
368 },
369 setModifiableStylesheet: function(name) {
370 this.__styleSheet = new qwebirc.ui.style.ModifiableStylesheet(qwebirc.global.staticBaseURL + "css/" + name + qwebirc.FILE_SUFFIX + ".mcss");
371 this.setModifiableStylesheetValues({});
372 },
373 setModifiableStylesheetValues: function(values) {
374 for(var k in values)
375 this.__styleValues[k] = values[k];
376
377 if(!$defined(this.__styleSheet))
378 return;
379
380 var hue = this.__styleValues.hue, lightness = this.__styleValues.lightness, saturation = this.__styleValues.saturation;
381
382 this.__styleSheet.set(function() {
383 var mode = arguments[0];
384 if(mode == "c") {
385 var x = new Color(arguments[1]);
386 var c = x.setHue(hue).setSaturation(x.hsb[1] + saturation).setBrightness(x.hsb[2] + lightness);
387 if(c == "255,255,255") /* IE confuses white with transparent... */
388 c = "255,255,254";
389
390 return "rgb(" + c + ")";
391 } else if(mode == "o") {
392 return this.uiOptions[arguments[1]] ? arguments[2] : arguments[3];
393 }
394 }.bind(this));
395 }
396});
397
398qwebirc.ui.NotificationUI = new Class({
399 Extends: qwebirc.ui.StandardUI,
400 initialize: function(parentElement, windowClass, uiName, options) {
401 this.parent(parentElement, windowClass, uiName, options);
402
403 this.__beeper = new qwebirc.ui.Beeper(this.uiOptions);
404 this.__flasher = new qwebirc.ui.Flasher(this.uiOptions);
405
406 this.beep = this.__beeper.beep.bind(this.__beeper);
407
408 this.flash = this.__flasher.flash.bind(this.__flasher);
409 this.cancelFlash = this.__flasher.cancelFlash.bind(this.__flasher);
410 },
411 setBeepOnMention: function(value) {
412 if(value)
413 this.__beeper.soundInit();
414 },
415 updateTitle: function(text) {
416 if(this.__flasher.updateTitle(text))
417 this.parent(text);
418 },
419 focusChange: function(value) {
420 this.parent(value);
421 this.__flasher.focusChange(value);
422 }
423});
424
425qwebirc.ui.NewLoginUI = new Class({
426 Extends: qwebirc.ui.NotificationUI,
427 loginBox: function(callbackfn, initialNickname, initialChannels, autoConnect, autoNick) {
428 this.postInitialize();
429
430 /* I'd prefer something shorter and snappier! */
431 var w = this.newCustomWindow("Connection details", true, qwebirc.ui.WINDOW_CONNECT);
432 var callback = function(args) {
433 w.close();
434 callbackfn(args);
435 };
436
437 qwebirc.ui.GenericLoginBox(w.lines, callback, initialNickname, initialChannels, autoConnect, autoNick, this.options.networkName);
438 }
439});
440
441qwebirc.ui.QuakeNetUI = new Class({
442 Extends: qwebirc.ui.NewLoginUI,
443 urlDispatcher: function(name, window) {
444 if(name == "qwhois") {
445 return ["span", function(auth) {
446 this.client.exec("/MSG Q whois #" + auth);
447 }.bind(window)];
448 }
449 return this.parent(name, window);
450 },
451 logout: function() {
452 if(!qwebirc.auth.loggedin())
453 return;
454 if(confirm("Log out?")) {
455 for(var client in this.clients) {
456 this.clients[client].quit("Logged out");
457 };
458
459 /* HACK */
460 var foo = function() { document.location = qwebirc.global.dynamicBaseURL + "auth?logout=1"; };
461 foo.delay(500);
462 }
463 }
464});
465
466qwebirc.ui.RootUI = qwebirc.ui.QuakeNetUI;
467
468qwebirc.ui.RequestTransformHTML = function(options) {
469 var HREF_ELEMENTS = {
470 "IMG": 1
471 };
472
473 var update = options.update;
474 var onSuccess = options.onSuccess;
475
476 var fixUp = function(node) {
477 if(node.nodeType != 1)
478 return;
479
480 var tagName = node.nodeName.toUpperCase();
481 if(HREF_ELEMENTS[tagName]) {
482 var attr = node.getAttribute("transform_attr");
483 var value = node.getAttribute("transform_value");
484 if($defined(attr) && $defined(value)) {
485 node.removeAttribute("transform_attr");
486 node.removeAttribute("transform_value");
487 node.setAttribute(attr, qwebirc.global.staticBaseURL + value);
488 }
489 }
490
491 for(var i=0;i<node.childNodes.length;i++)
492 fixUp(node.childNodes[i]);
493 };
494
495 delete options["update"];
496 options.onSuccess = function(tree, elements, html, js) {
497 var container = new Element("div");
498 container.set("html", html);
499 fixUp(container);
500 update.empty();
501
502 while(container.childNodes.length > 0) {
503 var x = container.firstChild;
504 container.removeChild(x);
505 update.appendChild(x);
506 }
507 onSuccess();
508 };
509
510 return new Request.HTML(options);
511};
512