]> jfr.im git - irc/quakenet/qwebirc.git/blame - js/ui/baseui.js
Merge.
[irc/quakenet/qwebirc.git] / js / ui / baseui.js
CommitLineData
3e66d49c
CP
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;
8c3e644b 6qwebirc.ui.WINDOW_MESSAGES = 0x20;
3e66d49c 7
e20e5a6b 8qwebirc.ui.CUSTOM_CLIENT = "custom";
9e769c12 9
e20e5a6b 10qwebirc.ui.BaseUI = new Class({
2cad083e 11 Implements: [Events],
a59dc700 12 initialize: function(parentElement, windowClass, uiName, options) {
2cad083e 13 this.options = options;
a59dc700 14
9e769c12 15 this.windows = {};
ffbb638d 16 this.clients = {};
e20e5a6b 17 this.windows[qwebirc.ui.CUSTOM_CLIENT] = {};
9e769c12
CP
18 this.windowArray = [];
19 this.windowClass = windowClass;
20 this.parentElement = parentElement;
21 this.parentElement.addClass("qwebirc");
22 this.parentElement.addClass("qwebirc-" + uiName);
e8db8558 23 this.firstClient = false;
e20e5a6b 24 this.commandhistory = new qwebirc.irc.CommandHistory();
ffbb638d 25 this.clientId = 0;
eb271d86
CP
26
27 this.windowFocused = true;
85449eee
CP
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 }
9e769c12
CP
50 },
51 newClient: function(client) {
ffbb638d 52 client.id = this.clientId++;
96f28062
CP
53 client.hilightController = new qwebirc.ui.HilightController(client);
54
ffbb638d
CP
55 this.windows[client.id] = {}
56 this.clients[client.id] = client;
e20e5a6b 57 var w = this.newWindow(client, qwebirc.ui.WINDOW_STATUS, "Status");
9e769c12 58 this.selectWindow(w);
e8db8558
CP
59 if(!this.firstClient) {
60 this.firstClient = true;
e20e5a6b 61 w.addLine("", "qwebirc v" + qwebirc.VERSION);
f191a80b 62 w.addLine("", "Copyright (C) 2008-2012 Chris Porter and the qwebirc project.");
2dfab0e1
CP
63 w.addLine("", "http://www.qwebirc.org");
64 w.addLine("", "Licensed under the GNU General Public License, Version 2.");
e8db8558 65 }
9e769c12
CP
66 return w;
67 },
ffbb638d
CP
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 },
fd3734d4 75 getWindowIdentifier: function(client, type, name) {
f74802c5
CP
76 if(type == qwebirc.ui.WINDOW_MESSAGES)
77 return "-M";
e20e5a6b 78 if(type == qwebirc.ui.WINDOW_STATUS)
f74802c5 79 return "";
fd3734d4
CP
80
81 if(client == qwebirc.ui.CUSTOM_CLIENT) /* HACK */
82 return "_" + name;
83
84 return "_" + client.toIRCLower(name);
f74802c5
CP
85 },
86 newWindow: function(client, type, name) {
87 var w = this.getWindow(client, type, name);
88 if($defined(w))
89 return w;
9e769c12 90
fd3734d4 91 var wId = this.getWindowIdentifier(client, type, name);
f74802c5 92 var w = this.windows[this.getClientId(client)][wId] = new this.windowClass(this, client, type, name, wId);
9e769c12
CP
93 this.windowArray.push(w);
94
95 return w;
96 },
f74802c5
CP
97 getWindow: function(client, type, name) {
98 var c = this.windows[this.getClientId(client)];
99 if(!$defined(c))
100 return null;
101
fd3734d4 102 return c[this.getWindowIdentifier(client, type, name)];
f74802c5 103 },
9e769c12
CP
104 getActiveWindow: function() {
105 return this.active;
106 },
1d42a76f
CP
107 getActiveIRCWindow: function(client) {
108 if(!this.active || this.active.type == qwebirc.ui.WINDOW_CUSTOM) {
fd3734d4 109 return this.windows[this.getClientId(client)][this.getWindowIdentifier(client, qwebirc.ui.WINDOW_STATUS)];
1d42a76f
CP
110 } else {
111 return this.active;
112 }
113 },
9e769c12
CP
114 __setActiveWindow: function(window) {
115 this.active = window;
116 },
5aa173fb
CP
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 },
9e769c12
CP
140 selectWindow: function(window) {
141 if(this.active)
142 this.active.deselect();
143 window.select(); /* calls setActiveWindow */
326478c2
CP
144 this.updateTitle(window.name + " - " + this.options.appTitle);
145 },
146 updateTitle: function(text) {
147 document.title = text;
9e769c12 148 },
ff4befd8
CP
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 },
9e769c12
CP
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);
6f2e4a37
CP
179 if(index == -1) {
180 return;
181 } else if(index == 0) {
9e769c12
CP
182 this.selectWindow(this.windowArray[1]);
183 } else {
184 this.selectWindow(this.windowArray[index - 1]);
185 }
9e769c12
CP
186 }
187 }
188
404cfb58 189 this.windowArray = this.windowArray.erase(window);
ffbb638d 190 delete this.windows[this.getClientId(window.client)][window.identifier];
eb9b087b 191 },
eb9b087b
CP
192 /*
193 this shouldn't be called by overriding classes!
66de775f 194 they should implement their own!
eb9b087b
CP
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 */
66de775f 199 loginBox: function(callback, initialNickname, initialChannels, autoConnect, autoNick) {
e89c812f
CP
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);
eb271d86
CP
205 },
206 focusChange: function(newValue) {
207 var window_ = this.getActiveWindow();
208 if($defined(window_))
209 window_.focusChange(newValue);
c22afc5d
CP
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();
44c29df2 231 if($defined(w) && (w.type == qwebirc.ui.WINDOW_CHANNEL || w.type == qwebirc.ui.WINDOW_QUERY)) {
c22afc5d
CP
232 w.client.exec("/SAY " + args);
233 return;
234 }
235 }
9e769c12
CP
236 }
237});
381fddfd 238
e20e5a6b
CP
239qwebirc.ui.StandardUI = new Class({
240 Extends: qwebirc.ui.BaseUI,
f3d0c9f5 241 UICommands: qwebirc.ui.UI_COMMANDS,
381fddfd
CP
242 initialize: function(parentElement, windowClass, uiName, options) {
243 this.parent(parentElement, windowClass, uiName, options);
3184781b
CP
244
245 this.tabCompleter = new qwebirc.ui.TabCompleterFactory(this);
c0f2f367 246 this.uiOptions = new qwebirc.ui.DefaultOptionsClass(this, options.uiOptionsArg);
ebb21d2e
CP
247 this.customWindows = {};
248
6f8a20df
CP
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
2a802692 254 var ev;
20157c51
CP
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;
381fddfd 281 }
20157c51
CP
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
424608ac 291
20157c51
CP
292 number = number - 1;
293
294 if(number >= this.windowArray.length)
295 return;
381fddfd 296
20157c51
CP
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) {
deebe19a
CP
309 if($$("input").indexOf(x.target) == -1 && $$("textarea").indexOf(x.target) == -1)
310 return false;
311 return true;
841a451d 312 },
8af49135
CP
313 newCustomWindow: function(name, select, type) {
314 if(!type)
e20e5a6b 315 type = qwebirc.ui.WINDOW_CUSTOM;
e89c812f 316
e20e5a6b 317 var w = this.newWindow(qwebirc.ui.CUSTOM_CLIENT, type, name);
8af49135 318 w.addEvent("close", function(w) {
f74802c5 319 delete this.windows[qwebirc.ui.CUSTOM_CLIENT][w.identifier];
8af49135
CP
320 }.bind(this));
321
322 if(select)
323 this.selectWindow(w);
6c19eb8f 324
8af49135
CP
325 return w;
326 },
e89c812f 327 addCustomWindow: function(windowName, class_, cssClass, options, type) {
ebb21d2e
CP
328 if(!$defined(options))
329 options = {};
330
331 if(this.customWindows[windowName]) {
332 this.selectWindow(this.customWindows[windowName]);
8af49135 333 return;
841a451d 334 }
8af49135 335
e89c812f 336 var d = this.newCustomWindow(windowName, true, type);
ebb21d2e
CP
337 this.customWindows[windowName] = d;
338
339 d.addEvent("close", function() {
340 this.customWindows[windowName] = null;
8af49135
CP
341 }.bind(this));
342
ebb21d2e 343 if(cssClass)
e1a91a8a 344 d.lines.addClass("qwebirc-" + cssClass);
ebb21d2e
CP
345
346 var ew = new class_(d.lines, options);
8af49135 347 ew.addEvent("close", function() {
ebb21d2e 348 d.close();
8af49135 349 }.bind(this));
17f40fd9
CP
350
351 d.setSubWindow(ew);
841a451d 352 },
ebb21d2e 353 embeddedWindow: function() {
bcd2d24f 354 this.addCustomWindow("Add webchat to your site", qwebirc.ui.EmbedWizard, "embeddedwizard", {baseURL: this.options.baseURL, uiOptions: this.uiOptions, optionsCallback: function() {
c0f2f367
CP
355 this.optionsWindow();
356 }.bind(this)});
ebb21d2e
CP
357 },
358 optionsWindow: function() {
359 this.addCustomWindow("Options", qwebirc.ui.OptionsPane, "optionspane", this.uiOptions);
360 },
e1a91a8a
CP
361 aboutWindow: function() {
362 this.addCustomWindow("About", qwebirc.ui.AboutPane, "aboutpane", this.uiOptions);
363 },
b35116e2
CP
364 privacyWindow: function() {
365 this.addCustomWindow("Privacy policy", qwebirc.ui.PrivacyPolicyPane, "privacypolicypane", this.uiOptions);
366 },
391f51ff
CP
367 feedbackWindow: function() {
368 this.addCustomWindow("Feedback", qwebirc.ui.FeedbackPane, "feedbackpane", this.uiOptions);
369 },
f3d0c9f5
CP
370 faqWindow: function() {
371 this.addCustomWindow("FAQ", qwebirc.ui.FAQPane, "faqpane", this.uiOptions);
372 },
144ee52f 373 urlDispatcher: function(name, window) {
8af49135 374 if(name == "embedded")
925fc357 375 return ["a", this.embeddedWindow.bind(this)];
ebb21d2e
CP
376
377 if(name == "options")
378 return ["a", this.optionsWindow.bind(this)];
8af49135 379
5f2808af
CP
380 /* doesn't really belong here */
381 if(name == "whois") {
382 return ["span", function(nick) {
cbef082a
CP
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)];
5f2808af
CP
389 }
390
8af49135 391 return null;
3184781b
CP
392 },
393 tabComplete: function(element) {
394 this.tabCompleter.tabComplete(element);
395 },
396 resetTabComplete: function() {
397 this.tabCompleter.reset();
4dd199c3
CP
398 },
399 setModifiableStylesheet: function(name) {
fbe5af77 400 this.__styleSheet = new qwebirc.ui.style.ModifiableStylesheet(qwebirc.global.staticBaseURL + "css/" + name + qwebirc.FILE_SUFFIX + ".mcss");
6f8a20df 401 this.setModifiableStylesheetValues({});
4dd199c3 402 },
6f8a20df
CP
403 setModifiableStylesheetValues: function(values) {
404 for(var k in values)
405 this.__styleValues[k] = values[k];
406
4dd199c3
CP
407 if(!$defined(this.__styleSheet))
408 return;
6f8a20df
CP
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));
8af49135 425 }
381fddfd 426});
6f2e4a37 427
326478c2 428qwebirc.ui.NotificationUI = new Class({
e20e5a6b 429 Extends: qwebirc.ui.StandardUI,
fb71087a
CP
430 initialize: function(parentElement, windowClass, uiName, options) {
431 this.parent(parentElement, windowClass, uiName, options);
432
326478c2
CP
433 this.__beeper = new qwebirc.ui.Beeper(this.uiOptions);
434 this.__flasher = new qwebirc.ui.Flasher(this.uiOptions);
fb71087a 435
326478c2 436 this.beep = this.__beeper.beep.bind(this.__beeper);
127631e0 437
326478c2
CP
438 this.flash = this.__flasher.flash.bind(this.__flasher);
439 this.cancelFlash = this.__flasher.cancelFlash.bind(this.__flasher);
fb71087a 440 },
127631e0
CP
441 setBeepOnMention: function(value) {
442 if(value)
326478c2
CP
443 this.__beeper.soundInit();
444 },
445 updateTitle: function(text) {
446 if(this.__flasher.updateTitle(text))
447 this.parent(text);
eb271d86
CP
448 },
449 focusChange: function(value) {
450 this.parent(value);
451 this.__flasher.focusChange(value);
1211ddcd 452 }
fb71087a
CP
453});
454
5f2808af 455qwebirc.ui.QuakeNetUI = new Class({
e89c812f 456 Extends: qwebirc.ui.NotificationUI,
2cd9e32d
CP
457 urlDispatcher: function(name, window) {
458 if(name == "qwhois") {
7cb09779 459 return ["span", function(auth) {
2cd9e32d 460 this.client.exec("/MSG Q whois #" + auth);
925fc357
CP
461 }.bind(window)];
462 }
144ee52f 463 return this.parent(name, window);
ffbb638d
CP
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 };
4b9f894d
CP
472
473 /* HACK */
fbe5af77 474 var foo = function() { document.location = qwebirc.global.dynamicBaseURL + "auth?logout=1"; };
4b9f894d 475 foo.delay(500);
ffbb638d 476 }
2cd9e32d
CP
477 }
478});
144ee52f
CP
479
480qwebirc.ui.RootUI = qwebirc.ui.QuakeNetUI;
fbe5af77
CP
481
482qwebirc.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