]> 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);
fbe5af77 62 w.addLine("", "Copyright (C) 2008-2010 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 },
117 selectWindow: function(window) {
118 if(this.active)
119 this.active.deselect();
120 window.select(); /* calls setActiveWindow */
326478c2
CP
121 this.updateTitle(window.name + " - " + this.options.appTitle);
122 },
123 updateTitle: function(text) {
124 document.title = text;
9e769c12 125 },
ff4befd8
CP
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 },
9e769c12
CP
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);
6f2e4a37
CP
156 if(index == -1) {
157 return;
158 } else if(index == 0) {
9e769c12
CP
159 this.selectWindow(this.windowArray[1]);
160 } else {
161 this.selectWindow(this.windowArray[index - 1]);
162 }
9e769c12
CP
163 }
164 }
165
404cfb58 166 this.windowArray = this.windowArray.erase(window);
ffbb638d 167 delete this.windows[this.getClientId(window.client)][window.identifier];
eb9b087b 168 },
eb9b087b
CP
169 /*
170 this shouldn't be called by overriding classes!
66de775f 171 they should implement their own!
eb9b087b
CP
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 */
66de775f 176 loginBox: function(callback, initialNickname, initialChannels, autoConnect, autoNick) {
e89c812f
CP
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);
eb271d86
CP
182 },
183 focusChange: function(newValue) {
184 var window_ = this.getActiveWindow();
185 if($defined(window_))
186 window_.focusChange(newValue);
c22afc5d
CP
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) {
209 w.client.exec("/SAY " + args);
210 return;
211 }
212 }
9e769c12
CP
213 }
214});
381fddfd 215
e20e5a6b
CP
216qwebirc.ui.StandardUI = new Class({
217 Extends: qwebirc.ui.BaseUI,
f3d0c9f5 218 UICommands: qwebirc.ui.UI_COMMANDS,
381fddfd
CP
219 initialize: function(parentElement, windowClass, uiName, options) {
220 this.parent(parentElement, windowClass, uiName, options);
3184781b
CP
221
222 this.tabCompleter = new qwebirc.ui.TabCompleterFactory(this);
c0f2f367 223 this.uiOptions = new qwebirc.ui.DefaultOptionsClass(this, options.uiOptionsArg);
ebb21d2e
CP
224 this.customWindows = {};
225
2a802692 226 var ev;
20157c51
CP
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;
381fddfd 253 }
20157c51
CP
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
424608ac 263
20157c51
CP
264 number = number - 1;
265
266 if(number >= this.windowArray.length)
267 return;
381fddfd 268
20157c51
CP
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) {
deebe19a
CP
281 if($$("input").indexOf(x.target) == -1 && $$("textarea").indexOf(x.target) == -1)
282 return false;
283 return true;
841a451d 284 },
8af49135
CP
285 newCustomWindow: function(name, select, type) {
286 if(!type)
e20e5a6b 287 type = qwebirc.ui.WINDOW_CUSTOM;
e89c812f 288
e20e5a6b 289 var w = this.newWindow(qwebirc.ui.CUSTOM_CLIENT, type, name);
8af49135 290 w.addEvent("close", function(w) {
f74802c5 291 delete this.windows[qwebirc.ui.CUSTOM_CLIENT][w.identifier];
8af49135
CP
292 }.bind(this));
293
294 if(select)
295 this.selectWindow(w);
6c19eb8f 296
8af49135
CP
297 return w;
298 },
e89c812f 299 addCustomWindow: function(windowName, class_, cssClass, options, type) {
ebb21d2e
CP
300 if(!$defined(options))
301 options = {};
302
303 if(this.customWindows[windowName]) {
304 this.selectWindow(this.customWindows[windowName]);
8af49135 305 return;
841a451d 306 }
8af49135 307
e89c812f 308 var d = this.newCustomWindow(windowName, true, type);
ebb21d2e
CP
309 this.customWindows[windowName] = d;
310
311 d.addEvent("close", function() {
312 this.customWindows[windowName] = null;
8af49135
CP
313 }.bind(this));
314
ebb21d2e 315 if(cssClass)
e1a91a8a 316 d.lines.addClass("qwebirc-" + cssClass);
ebb21d2e
CP
317
318 var ew = new class_(d.lines, options);
8af49135 319 ew.addEvent("close", function() {
ebb21d2e 320 d.close();
8af49135 321 }.bind(this));
17f40fd9
CP
322
323 d.setSubWindow(ew);
841a451d 324 },
ebb21d2e 325 embeddedWindow: function() {
bcd2d24f 326 this.addCustomWindow("Add webchat to your site", qwebirc.ui.EmbedWizard, "embeddedwizard", {baseURL: this.options.baseURL, uiOptions: this.uiOptions, optionsCallback: function() {
c0f2f367
CP
327 this.optionsWindow();
328 }.bind(this)});
ebb21d2e
CP
329 },
330 optionsWindow: function() {
331 this.addCustomWindow("Options", qwebirc.ui.OptionsPane, "optionspane", this.uiOptions);
332 },
e1a91a8a
CP
333 aboutWindow: function() {
334 this.addCustomWindow("About", qwebirc.ui.AboutPane, "aboutpane", this.uiOptions);
335 },
b35116e2
CP
336 privacyWindow: function() {
337 this.addCustomWindow("Privacy policy", qwebirc.ui.PrivacyPolicyPane, "privacypolicypane", this.uiOptions);
338 },
391f51ff
CP
339 feedbackWindow: function() {
340 this.addCustomWindow("Feedback", qwebirc.ui.FeedbackPane, "feedbackpane", this.uiOptions);
341 },
f3d0c9f5
CP
342 faqWindow: function() {
343 this.addCustomWindow("FAQ", qwebirc.ui.FAQPane, "faqpane", this.uiOptions);
344 },
144ee52f 345 urlDispatcher: function(name, window) {
8af49135 346 if(name == "embedded")
925fc357 347 return ["a", this.embeddedWindow.bind(this)];
ebb21d2e
CP
348
349 if(name == "options")
350 return ["a", this.optionsWindow.bind(this)];
8af49135 351
5f2808af
CP
352 /* doesn't really belong here */
353 if(name == "whois") {
354 return ["span", function(nick) {
cbef082a
CP
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)];
5f2808af
CP
361 }
362
8af49135 363 return null;
3184781b
CP
364 },
365 tabComplete: function(element) {
366 this.tabCompleter.tabComplete(element);
367 },
368 resetTabComplete: function() {
369 this.tabCompleter.reset();
4dd199c3
CP
370 },
371 setModifiableStylesheet: function(name) {
fbe5af77 372 this.__styleSheet = new qwebirc.ui.style.ModifiableStylesheet(qwebirc.global.staticBaseURL + "css/" + name + qwebirc.FILE_SUFFIX + ".mcss");
4dd199c3
CP
373
374 if($defined(this.options.hue)) {
375 this.setModifiableStylesheetValues(this.options.hue, 0, 0);
376 } else {
889ecb33 377 this.setModifiableStylesheetValues(this.uiOptions.STYLE_HUE, 0, 0);
4dd199c3
CP
378 }
379 },
380 setModifiableStylesheetValues: function(hue, saturation, lightness) {
381 if(!$defined(this.__styleSheet))
382 return;
383 this.__styleSheet.set(function(x) {
384 return x.setHue(hue).setSaturation(x.hsb[1] + saturation).setBrightness(x.hsb[2] + lightness);
385 });
8af49135 386 }
381fddfd 387});
6f2e4a37 388
326478c2 389qwebirc.ui.NotificationUI = new Class({
e20e5a6b 390 Extends: qwebirc.ui.StandardUI,
fb71087a
CP
391 initialize: function(parentElement, windowClass, uiName, options) {
392 this.parent(parentElement, windowClass, uiName, options);
393
326478c2
CP
394 this.__beeper = new qwebirc.ui.Beeper(this.uiOptions);
395 this.__flasher = new qwebirc.ui.Flasher(this.uiOptions);
fb71087a 396
326478c2 397 this.beep = this.__beeper.beep.bind(this.__beeper);
127631e0 398
326478c2
CP
399 this.flash = this.__flasher.flash.bind(this.__flasher);
400 this.cancelFlash = this.__flasher.cancelFlash.bind(this.__flasher);
fb71087a 401 },
127631e0
CP
402 setBeepOnMention: function(value) {
403 if(value)
326478c2
CP
404 this.__beeper.soundInit();
405 },
406 updateTitle: function(text) {
407 if(this.__flasher.updateTitle(text))
408 this.parent(text);
eb271d86
CP
409 },
410 focusChange: function(value) {
411 this.parent(value);
412 this.__flasher.focusChange(value);
1211ddcd 413 }
fb71087a
CP
414});
415
5f2808af 416qwebirc.ui.QuakeNetUI = new Class({
e89c812f 417 Extends: qwebirc.ui.NotificationUI,
2cd9e32d
CP
418 urlDispatcher: function(name, window) {
419 if(name == "qwhois") {
7cb09779 420 return ["span", function(auth) {
2cd9e32d 421 this.client.exec("/MSG Q whois #" + auth);
925fc357
CP
422 }.bind(window)];
423 }
144ee52f 424 return this.parent(name, window);
ffbb638d
CP
425 },
426 logout: function() {
427 if(!qwebirc.auth.loggedin())
428 return;
429 if(confirm("Log out?")) {
430 for(var client in this.clients) {
431 this.clients[client].quit("Logged out");
432 };
4b9f894d
CP
433
434 /* HACK */
fbe5af77 435 var foo = function() { document.location = qwebirc.global.dynamicBaseURL + "auth?logout=1"; };
4b9f894d 436 foo.delay(500);
ffbb638d 437 }
2cd9e32d
CP
438 }
439});
144ee52f
CP
440
441qwebirc.ui.RootUI = qwebirc.ui.QuakeNetUI;
fbe5af77
CP
442
443qwebirc.ui.RequestTransformHTML = function(options) {
444 var HREF_ELEMENTS = {
445 "IMG": 1
446 };
447
448 var update = options.update;
449 var onSuccess = options.onSuccess;
450
451 var fixUp = function(node) {
452 if(node.nodeType != 1)
453 return;
454
455 var tagName = node.nodeName.toUpperCase();
456 if(HREF_ELEMENTS[tagName]) {
457 var attr = node.getAttribute("transform_attr");
458 var value = node.getAttribute("transform_value");
459 if($defined(attr) && $defined(value)) {
460 node.removeAttribute("transform_attr");
461 node.removeAttribute("transform_value");
462 node.setAttribute(attr, qwebirc.global.staticBaseURL + value);
463 }
464 }
465
466 for(var i=0;i<node.childNodes.length;i++)
467 fixUp(node.childNodes[i]);
468 };
469
470 delete options["update"];
471 options.onSuccess = function(tree, elements, html, js) {
472 var container = new Element("div");
473 container.set("html", html);
474 fixUp(container);
475 update.empty();
476
477 while(container.childNodes.length > 0) {
478 var x = container.firstChild;
479 container.removeChild(x);
480 update.appendChild(x);
481 }
482 onSuccess();
483 };
484
485 return new Request.HTML(options);
486};
487