]> jfr.im git - irc/quakenet/qwebirc.git/blame - js/ui/baseui.js
fix hotkeys
[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
ea29e3d7
CP
15 this.windows = new QHash();
16 this.clients = new QHash();
17 this.windows.put(qwebirc.ui.CUSTOM_CLIENT, new QHash());
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) {
ea29e3d7 52 client.id = String(this.clientId++);
96f28062 53 client.hilightController = new qwebirc.ui.HilightController(client);
fc38a626
CP
54 client.addEvent("signedOn", function() {
55 this.fireEvent("signedOn", client);
56 }.bind(this));
ea29e3d7
CP
57 this.windows.put(client.id, new QHash());
58 this.clients.put(client.id, client);
e20e5a6b 59 var w = this.newWindow(client, qwebirc.ui.WINDOW_STATUS, "Status");
9e769c12 60 this.selectWindow(w);
e8db8558
CP
61 if(!this.firstClient) {
62 this.firstClient = true;
e20e5a6b 63 w.addLine("", "qwebirc v" + qwebirc.VERSION);
13828a8d 64 w.addLine("", "Copyright (C) 2008-2014 Chris Porter and the qwebirc project.");
2dfab0e1
CP
65 w.addLine("", "http://www.qwebirc.org");
66 w.addLine("", "Licensed under the GNU General Public License, Version 2.");
e8db8558 67 }
9e769c12
CP
68 return w;
69 },
ffbb638d
CP
70 getClientId: function(client) {
71 if(client == qwebirc.ui.CUSTOM_CLIENT) {
72 return qwebirc.ui.CUSTOM_CLIENT;
73 } else {
74 return client.id;
75 }
76 },
fd3734d4 77 getWindowIdentifier: function(client, type, name) {
f74802c5
CP
78 if(type == qwebirc.ui.WINDOW_MESSAGES)
79 return "-M";
e20e5a6b 80 if(type == qwebirc.ui.WINDOW_STATUS)
f74802c5 81 return "";
fd3734d4
CP
82
83 if(client == qwebirc.ui.CUSTOM_CLIENT) /* HACK */
84 return "_" + name;
85
86 return "_" + client.toIRCLower(name);
f74802c5
CP
87 },
88 newWindow: function(client, type, name) {
89 var w = this.getWindow(client, type, name);
90 if($defined(w))
91 return w;
9e769c12 92
fd3734d4 93 var wId = this.getWindowIdentifier(client, type, name);
ea29e3d7
CP
94 var w = new this.windowClass(this, client, type, name, wId);
95 this.windows.get(this.getClientId(client)).put(wId, w);
9e769c12
CP
96 this.windowArray.push(w);
97
98 return w;
99 },
f74802c5 100 getWindow: function(client, type, name) {
ea29e3d7 101 var c = this.windows.get(this.getClientId(client));
f74802c5
CP
102 if(!$defined(c))
103 return null;
104
fd3734d4 105 return c[this.getWindowIdentifier(client, type, name)];
f74802c5 106 },
9e769c12
CP
107 getActiveWindow: function() {
108 return this.active;
109 },
1d42a76f
CP
110 getActiveIRCWindow: function(client) {
111 if(!this.active || this.active.type == qwebirc.ui.WINDOW_CUSTOM) {
ea29e3d7 112 return this.windows.get(this.getClientId(client)).get(this.getWindowIdentifier(client, qwebirc.ui.WINDOW_STATUS));
1d42a76f
CP
113 } else {
114 return this.active;
115 }
116 },
9e769c12
CP
117 __setActiveWindow: function(window) {
118 this.active = window;
119 },
5aa173fb
CP
120 renameWindow: function(window, name) {
121 if(this.getWindow(window.client, window.type, name))
122 return null;
123
124 var clientId = this.getClientId(window.client);
125 var index = this.windowArray.indexOf(window);
126 if(index == -1)
127 return null;
128
ea29e3d7 129 this.windows.get(clientId).remove(window.identifier);
5aa173fb
CP
130
131 var window = this.windowArray[index];
132 window.name = name;
133 window.identifier = this.getWindowIdentifier(window.client, window.type, window.name);
134
ea29e3d7 135 this.windows.get(clientId).put(window.identifier, this.windowArray[index]);
5aa173fb
CP
136
137 if(window.active)
138 this.updateTitle(window.name + " - " + this.options.appTitle);
139
140 window.rename(window.name);
141 return window;
142 },
9e769c12
CP
143 selectWindow: function(window) {
144 if(this.active)
145 this.active.deselect();
146 window.select(); /* calls setActiveWindow */
326478c2
CP
147 this.updateTitle(window.name + " - " + this.options.appTitle);
148 },
149 updateTitle: function(text) {
150 document.title = text;
9e769c12 151 },
ff4befd8
CP
152 nextWindow: function(direction) {
153 if(this.windowArray.length == 0 || !this.active)
154 return;
155
156 if(!direction)
157 direction = 1;
158
159 var index = this.windowArray.indexOf(this.active);
160 if(index == -1)
161 return;
162
163 index = index + direction;
164 if(index < 0) {
165 index = this.windowArray.length - 1;
166 } else if(index >= this.windowArray.length) {
167 index = 0;
168 }
169
170 this.selectWindow(this.windowArray[index]);
171 },
172 prevWindow: function() {
173 this.nextWindow(-1);
174 },
9e769c12
CP
175 __closed: function(window) {
176 if(window.active) {
177 this.active = undefined;
178 if(this.windowArray.length == 1) {
179 this.windowArray = [];
180 } else {
181 var index = this.windowArray.indexOf(window);
6f2e4a37
CP
182 if(index == -1) {
183 return;
184 } else if(index == 0) {
9e769c12
CP
185 this.selectWindow(this.windowArray[1]);
186 } else {
187 this.selectWindow(this.windowArray[index - 1]);
188 }
9e769c12
CP
189 }
190 }
191
404cfb58 192 this.windowArray = this.windowArray.erase(window);
ea29e3d7 193 this.windows.get(this.getClientId(window.client)).remove(window.identifier);
eb9b087b 194 },
eb9b087b
CP
195 /*
196 this shouldn't be called by overriding classes!
66de775f 197 they should implement their own!
eb9b087b
CP
198 some form of user input MUST be received before an
199 IRC connection is made, else users are going to get
200 tricked into getting themselves glined
201 */
66de775f 202 loginBox: function(callback, initialNickname, initialChannels, autoConnect, autoNick) {
2cad083e 203 qwebirc.ui.GenericLoginBox(this.parentElement, callback, initialNickname, initialChannels, autoConnect, autoNick, this.options.networkName);
eb271d86
CP
204 },
205 focusChange: function(newValue) {
206 var window_ = this.getActiveWindow();
207 if($defined(window_))
208 window_.focusChange(newValue);
9e769c12
CP
209 }
210});
381fddfd 211
e20e5a6b
CP
212qwebirc.ui.StandardUI = new Class({
213 Extends: qwebirc.ui.BaseUI,
f3d0c9f5 214 UICommands: qwebirc.ui.UI_COMMANDS,
381fddfd
CP
215 initialize: function(parentElement, windowClass, uiName, options) {
216 this.parent(parentElement, windowClass, uiName, options);
3184781b
CP
217
218 this.tabCompleter = new qwebirc.ui.TabCompleterFactory(this);
c0f2f367 219 this.uiOptions = new qwebirc.ui.DefaultOptionsClass(this, options.uiOptionsArg);
ea29e3d7 220 this.customWindows = new QHash();
ebb21d2e 221
6f8a20df
CP
222 this.__styleValues = {hue: this.uiOptions.STYLE_HUE, saturation: 0, lightness: 0};
223 if($defined(this.options.hue)) this.__styleValues.hue = this.options.hue;
224 if($defined(this.options.saturation)) this.__styleValues.saturation = this.options.saturation;
225 if($defined(this.options.lightness)) this.__styleValues.lightness = this.options.lightness;
656385a2
CP
226
227 if(this.options.thue !== null) this.__styleValues.textHue = this.options.thue;
228 if(this.options.tsaturation !== null) this.__styleValues.textSaturation = this.options.tsaturation;
229 if(this.options.tlightness !== null) this.__styleValues.textLightness = this.options.tlightness;
6f8a20df 230
83d21243 231 document.addEvent("keydown", this.__handleHotkey.bind(this));
20157c51
CP
232 },
233 __handleHotkey: function(x) {
20157c51 234 var success = false;
83d21243
CP
235 if(!x.alt || x.control) {
236 if((x.key == "backspace" || x.key == "/") && !this.getInputFocused(x)) {
237 success = true;
238 }
239 } else if(x.key == "a" || x.key == "A") {
20157c51
CP
240 var highestNum = 0;
241 var highestIndex = -1;
242 success = true;
83d21243 243
20157c51
CP
244 for(var i=0;i<this.windowArray.length;i++) {
245 var h = this.windowArray[i].hilighted;
246 if(h > highestNum) {
247 highestIndex = i;
248 highestNum = h;
381fddfd 249 }
20157c51
CP
250 }
251 if(highestIndex > -1)
252 this.selectWindow(this.windowArray[highestIndex]);
253 } else if(x.key >= '0' && x.key <= '9') {
254 success = true;
255
256 number = x.key - '0';
257 if(number == 0)
258 number = 10
424608ac 259
20157c51
CP
260 number = number - 1;
261
262 if(number >= this.windowArray.length)
263 return;
381fddfd 264
20157c51
CP
265 this.selectWindow(this.windowArray[number]);
266 } else if(x.key == "left") {
267 this.prevWindow();
268 success = true;
269 } else if(x.key == "right") {
270 this.nextWindow();
271 success = true;
272 }
83d21243 273 if(success) {
20157c51 274 new Event(x).stop();
83d21243
CP
275 x.preventDefault();
276 }
20157c51
CP
277 },
278 getInputFocused: function(x) {
deebe19a
CP
279 if($$("input").indexOf(x.target) == -1 && $$("textarea").indexOf(x.target) == -1)
280 return false;
281 return true;
841a451d 282 },
8af49135
CP
283 newCustomWindow: function(name, select, type) {
284 if(!type)
e20e5a6b 285 type = qwebirc.ui.WINDOW_CUSTOM;
8af49135 286
e20e5a6b 287 var w = this.newWindow(qwebirc.ui.CUSTOM_CLIENT, type, name);
8af49135 288 w.addEvent("close", function(w) {
ea29e3d7 289 this.windows.get(qwebirc.ui.CUSTOM_CLIENT).remove(w.identifier);
8af49135
CP
290 }.bind(this));
291
292 if(select)
293 this.selectWindow(w);
6c19eb8f 294
8af49135
CP
295 return w;
296 },
ebb21d2e
CP
297 addCustomWindow: function(windowName, class_, cssClass, options) {
298 if(!$defined(options))
299 options = {};
300
ea29e3d7
CP
301 if(this.customWindows.contains(windowName)) {
302 this.selectWindow(this.customWindows.get(windowName));
8af49135 303 return;
841a451d 304 }
8af49135 305
ebb21d2e 306 var d = this.newCustomWindow(windowName, true);
ea29e3d7 307 this.customWindows.put(windowName, d);
ebb21d2e
CP
308
309 d.addEvent("close", function() {
ea29e3d7 310 this.customWindows.remove(windowName);
8af49135
CP
311 }.bind(this));
312
ebb21d2e 313 if(cssClass)
e1a91a8a 314 d.lines.addClass("qwebirc-" + cssClass);
ebb21d2e
CP
315
316 var ew = new class_(d.lines, options);
8af49135 317 ew.addEvent("close", function() {
ebb21d2e 318 d.close();
8af49135 319 }.bind(this));
17f40fd9
CP
320
321 d.setSubWindow(ew);
841a451d 322 },
ebb21d2e 323 embeddedWindow: function() {
bcd2d24f 324 this.addCustomWindow("Add webchat to your site", qwebirc.ui.EmbedWizard, "embeddedwizard", {baseURL: this.options.baseURL, uiOptions: this.uiOptions, optionsCallback: function() {
c0f2f367
CP
325 this.optionsWindow();
326 }.bind(this)});
ebb21d2e
CP
327 },
328 optionsWindow: function() {
329 this.addCustomWindow("Options", qwebirc.ui.OptionsPane, "optionspane", this.uiOptions);
330 },
e1a91a8a
CP
331 aboutWindow: function() {
332 this.addCustomWindow("About", qwebirc.ui.AboutPane, "aboutpane", this.uiOptions);
333 },
b35116e2
CP
334 privacyWindow: function() {
335 this.addCustomWindow("Privacy policy", qwebirc.ui.PrivacyPolicyPane, "privacypolicypane", this.uiOptions);
336 },
391f51ff
CP
337 feedbackWindow: function() {
338 this.addCustomWindow("Feedback", qwebirc.ui.FeedbackPane, "feedbackpane", this.uiOptions);
339 },
355dbcb7
CP
340 helpWindow: function() {
341 this.addCustomWindow("Help!", qwebirc.ui.HelpPane, "helppane", this.uiOptions);
f3d0c9f5 342 },
144ee52f 343 urlDispatcher: function(name, window) {
8af49135 344 if(name == "embedded")
925fc357 345 return ["a", this.embeddedWindow.bind(this)];
ebb21d2e
CP
346
347 if(name == "options")
348 return ["a", this.optionsWindow.bind(this)];
8af49135 349
5f2808af
CP
350 /* doesn't really belong here */
351 if(name == "whois") {
352 return ["span", function(nick) {
cbef082a
CP
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)];
5f2808af
CP
359 }
360
8af49135 361 return null;
3184781b
CP
362 },
363 tabComplete: function(element) {
364 this.tabCompleter.tabComplete(element);
365 },
366 resetTabComplete: function() {
367 this.tabCompleter.reset();
4dd199c3
CP
368 },
369 setModifiableStylesheet: function(name) {
fbe5af77 370 this.__styleSheet = new qwebirc.ui.style.ModifiableStylesheet(qwebirc.global.staticBaseURL + "css/" + name + qwebirc.FILE_SUFFIX + ".mcss");
6f8a20df 371 this.setModifiableStylesheetValues({});
4dd199c3 372 },
6f8a20df
CP
373 setModifiableStylesheetValues: function(values) {
374 for(var k in values)
375 this.__styleValues[k] = values[k];
376
4dd199c3
CP
377 if(!$defined(this.__styleSheet))
378 return;
6f8a20df 379
656385a2
CP
380 var back = {hue: this.__styleValues.hue, lightness: this.__styleValues.lightness, saturation: this.__styleValues.saturation};
381 var front = {hue: this.__styleValues.textHue, lightness: this.__styleValues.textLightness, saturation: this.__styleValues.textSaturation};
382
383 if(!this.__styleValues.textHue && !this.__styleValues.textLightness && !this.__styleValues.textSaturation)
384 front = back;
385
386 var colours = {
387 back: back,
388 front: front
389 };
390
6f8a20df
CP
391 this.__styleSheet.set(function() {
392 var mode = arguments[0];
393 if(mode == "c") {
656385a2 394 var t = colours[arguments[2]];
6f8a20df 395 var x = new Color(arguments[1]);
656385a2 396 var c = x.setHue(t.hue).setSaturation(x.hsb[1] + t.saturation).setBrightness(x.hsb[2] + t.lightness);
6f8a20df
CP
397 if(c == "255,255,255") /* IE confuses white with transparent... */
398 c = "255,255,254";
399
400 return "rgb(" + c + ")";
401 } else if(mode == "o") {
402 return this.uiOptions[arguments[1]] ? arguments[2] : arguments[3];
403 }
404 }.bind(this));
8af49135 405 }
381fddfd 406});
6f2e4a37 407
326478c2 408qwebirc.ui.NotificationUI = new Class({
e20e5a6b 409 Extends: qwebirc.ui.StandardUI,
fb71087a
CP
410 initialize: function(parentElement, windowClass, uiName, options) {
411 this.parent(parentElement, windowClass, uiName, options);
412
326478c2
CP
413 this.__beeper = new qwebirc.ui.Beeper(this.uiOptions);
414 this.__flasher = new qwebirc.ui.Flasher(this.uiOptions);
fb71087a 415
326478c2 416 this.beep = this.__beeper.beep.bind(this.__beeper);
127631e0 417
326478c2
CP
418 this.flash = this.__flasher.flash.bind(this.__flasher);
419 this.cancelFlash = this.__flasher.cancelFlash.bind(this.__flasher);
fb71087a 420 },
127631e0
CP
421 setBeepOnMention: function(value) {
422 if(value)
326478c2
CP
423 this.__beeper.soundInit();
424 },
425 updateTitle: function(text) {
426 if(this.__flasher.updateTitle(text))
427 this.parent(text);
eb271d86
CP
428 },
429 focusChange: function(value) {
430 this.parent(value);
431 this.__flasher.focusChange(value);
1211ddcd 432 }
fb71087a
CP
433});
434
5f2808af 435qwebirc.ui.NewLoginUI = new Class({
326478c2 436 Extends: qwebirc.ui.NotificationUI,
5f2808af
CP
437 loginBox: function(callbackfn, initialNickname, initialChannels, autoConnect, autoNick) {
438 this.postInitialize();
439
c837b844 440 /* I'd prefer something shorter and snappier! */
a4a71818 441 var w = this.newCustomWindow("Connect", true, qwebirc.ui.WINDOW_CONNECT);
5f2808af
CP
442 var callback = function(args) {
443 w.close();
444 callbackfn(args);
445 };
446
447 qwebirc.ui.GenericLoginBox(w.lines, callback, initialNickname, initialChannels, autoConnect, autoNick, this.options.networkName);
448 }
449});
450
451qwebirc.ui.QuakeNetUI = new Class({
452 Extends: qwebirc.ui.NewLoginUI,
2cd9e32d
CP
453 urlDispatcher: function(name, window) {
454 if(name == "qwhois") {
7cb09779 455 return ["span", function(auth) {
2cd9e32d 456 this.client.exec("/MSG Q whois #" + auth);
925fc357
CP
457 }.bind(window)];
458 }
144ee52f 459 return this.parent(name, window);
ffbb638d
CP
460 },
461 logout: function() {
462 if(!qwebirc.auth.loggedin())
463 return;
464 if(confirm("Log out?")) {
ea29e3d7
CP
465 this.clients.each(function(k, v) {
466 v.quit("Logged out");
467 }, this);
4b9f894d
CP
468
469 /* HACK */
fbe5af77 470 var foo = function() { document.location = qwebirc.global.dynamicBaseURL + "auth?logout=1"; };
4b9f894d 471 foo.delay(500);
ffbb638d 472 }
2cd9e32d
CP
473 }
474});
144ee52f
CP
475
476qwebirc.ui.RootUI = qwebirc.ui.QuakeNetUI;
fbe5af77
CP
477
478qwebirc.ui.RequestTransformHTML = function(options) {
479 var HREF_ELEMENTS = {
480 "IMG": 1
481 };
482
483 var update = options.update;
484 var onSuccess = options.onSuccess;
485
486 var fixUp = function(node) {
487 if(node.nodeType != 1)
488 return;
489
490 var tagName = node.nodeName.toUpperCase();
491 if(HREF_ELEMENTS[tagName]) {
492 var attr = node.getAttribute("transform_attr");
493 var value = node.getAttribute("transform_value");
494 if($defined(attr) && $defined(value)) {
495 node.removeAttribute("transform_attr");
496 node.removeAttribute("transform_value");
497 node.setAttribute(attr, qwebirc.global.staticBaseURL + value);
498 }
499 }
500
501 for(var i=0;i<node.childNodes.length;i++)
502 fixUp(node.childNodes[i]);
503 };
504
505 delete options["update"];
506 options.onSuccess = function(tree, elements, html, js) {
507 var container = new Element("div");
508 container.set("html", html);
509 fixUp(container);
510 update.empty();
511
512 while(container.childNodes.length > 0) {
513 var x = container.firstChild;
514 container.removeChild(x);
515 update.appendChild(x);
516 }
517 onSuccess();
518 };
519
520 return new Request.HTML(options);
521};
522