]> jfr.im git - irc/quakenet/qwebirc.git/blame - js/ui/baseui.js
Missed one...
[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) {
2cad083e 200 qwebirc.ui.GenericLoginBox(this.parentElement, callback, initialNickname, initialChannels, autoConnect, autoNick, this.options.networkName);
eb271d86
CP
201 },
202 focusChange: function(newValue) {
203 var window_ = this.getActiveWindow();
204 if($defined(window_))
205 window_.focusChange(newValue);
9e769c12
CP
206 }
207});
381fddfd 208
e20e5a6b
CP
209qwebirc.ui.StandardUI = new Class({
210 Extends: qwebirc.ui.BaseUI,
f3d0c9f5 211 UICommands: qwebirc.ui.UI_COMMANDS,
381fddfd
CP
212 initialize: function(parentElement, windowClass, uiName, options) {
213 this.parent(parentElement, windowClass, uiName, options);
3184781b
CP
214
215 this.tabCompleter = new qwebirc.ui.TabCompleterFactory(this);
c0f2f367 216 this.uiOptions = new qwebirc.ui.DefaultOptionsClass(this, options.uiOptionsArg);
ebb21d2e
CP
217 this.customWindows = {};
218
6f8a20df
CP
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
2a802692 224 var ev;
20157c51
CP
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;
381fddfd 251 }
20157c51
CP
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
424608ac 261
20157c51
CP
262 number = number - 1;
263
264 if(number >= this.windowArray.length)
265 return;
381fddfd 266
20157c51
CP
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) {
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) {
f74802c5 289 delete this.windows[qwebirc.ui.CUSTOM_CLIENT][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
301 if(this.customWindows[windowName]) {
302 this.selectWindow(this.customWindows[windowName]);
8af49135 303 return;
841a451d 304 }
8af49135 305
ebb21d2e
CP
306 var d = this.newCustomWindow(windowName, true);
307 this.customWindows[windowName] = d;
308
309 d.addEvent("close", function() {
310 this.customWindows[windowName] = null;
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 },
f3d0c9f5
CP
340 faqWindow: function() {
341 this.addCustomWindow("FAQ", qwebirc.ui.FAQPane, "faqpane", this.uiOptions);
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
CP
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));
8af49135 395 }
381fddfd 396});
6f2e4a37 397
326478c2 398qwebirc.ui.NotificationUI = new Class({
e20e5a6b 399 Extends: qwebirc.ui.StandardUI,
fb71087a
CP
400 initialize: function(parentElement, windowClass, uiName, options) {
401 this.parent(parentElement, windowClass, uiName, options);
402
326478c2
CP
403 this.__beeper = new qwebirc.ui.Beeper(this.uiOptions);
404 this.__flasher = new qwebirc.ui.Flasher(this.uiOptions);
fb71087a 405
326478c2 406 this.beep = this.__beeper.beep.bind(this.__beeper);
127631e0 407
326478c2
CP
408 this.flash = this.__flasher.flash.bind(this.__flasher);
409 this.cancelFlash = this.__flasher.cancelFlash.bind(this.__flasher);
fb71087a 410 },
127631e0
CP
411 setBeepOnMention: function(value) {
412 if(value)
326478c2
CP
413 this.__beeper.soundInit();
414 },
415 updateTitle: function(text) {
416 if(this.__flasher.updateTitle(text))
417 this.parent(text);
eb271d86
CP
418 },
419 focusChange: function(value) {
420 this.parent(value);
421 this.__flasher.focusChange(value);
1211ddcd 422 }
fb71087a
CP
423});
424
5f2808af 425qwebirc.ui.NewLoginUI = new Class({
326478c2 426 Extends: qwebirc.ui.NotificationUI,
5f2808af
CP
427 loginBox: function(callbackfn, initialNickname, initialChannels, autoConnect, autoNick) {
428 this.postInitialize();
429
c837b844
CP
430 /* I'd prefer something shorter and snappier! */
431 var w = this.newCustomWindow("Connection details", true, qwebirc.ui.WINDOW_CONNECT);
5f2808af
CP
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,
2cd9e32d
CP
443 urlDispatcher: function(name, window) {
444 if(name == "qwhois") {
7cb09779 445 return ["span", function(auth) {
2cd9e32d 446 this.client.exec("/MSG Q whois #" + auth);
925fc357
CP
447 }.bind(window)];
448 }
144ee52f 449 return this.parent(name, window);
ffbb638d
CP
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 };
4b9f894d
CP
458
459 /* HACK */
fbe5af77 460 var foo = function() { document.location = qwebirc.global.dynamicBaseURL + "auth?logout=1"; };
4b9f894d 461 foo.delay(500);
ffbb638d 462 }
2cd9e32d
CP
463 }
464});
144ee52f
CP
465
466qwebirc.ui.RootUI = qwebirc.ui.QuakeNetUI;
fbe5af77
CP
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