]> jfr.im git - irc/quakenet/qwebirc.git/blame - js/ui/baseui.js
Add cross-domain /SAY.
[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) {
2cad083e 177 qwebirc.ui.GenericLoginBox(this.parentElement, callback, initialNickname, initialChannels, autoConnect, autoNick, this.options.networkName);
eb271d86
CP
178 },
179 focusChange: function(newValue) {
180 var window_ = this.getActiveWindow();
181 if($defined(window_))
182 window_.focusChange(newValue);
c22afc5d
CP
183 },
184 signedOn: function() {
185 this.poller = new qwebirc.xdomain.Poller(this.oobMessage.bind(this));
186 },
187 oobMessage: function(message) {
188 var c = message.splitMax(" ", 2);
189 if(c.length != 2)
190 return;
191
192 var command = c[0];
193 if(command != "CMD")
194 return;
195
196 var d = c[1].splitMax(" ", 2);
197 if(d.length != 2)
198 return;
199
200 var command = d[0];
201 var args = d[1];
202 if(command == "SAY") {
203 var w = this.getActiveIRCWindow();
204 if($defined(w) && w.type == qwebirc.ui.WINDOW_CHANNEL) {
205 w.client.exec("/SAY " + args);
206 return;
207 }
208 }
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);
ebb21d2e
CP
220 this.customWindows = {};
221
2a802692 222 var ev;
20157c51
CP
223 if(Browser.Engine.trident) {
224 ev = "keydown";
225 } else {
226 ev = "keypress";
227 }
228 document.addEvent(ev, this.__handleHotkey.bind(this));
229 },
230 __handleHotkey: function(x) {
231 if(!x.alt || x.control) {
232 if(x.key == "backspace" || x.key == "/")
233 if(!this.getInputFocused(x))
234 new Event(x).stop();
235 return;
236 }
237 var success = false;
238 if(x.key == "a" || x.key == "A") {
239 var highestNum = 0;
240 var highestIndex = -1;
241 success = true;
242
243 new Event(x).stop();
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 }
273 if(success)
274 new Event(x).stop();
275 },
276 getInputFocused: function(x) {
deebe19a
CP
277 if($$("input").indexOf(x.target) == -1 && $$("textarea").indexOf(x.target) == -1)
278 return false;
279 return true;
841a451d 280 },
8af49135
CP
281 newCustomWindow: function(name, select, type) {
282 if(!type)
e20e5a6b 283 type = qwebirc.ui.WINDOW_CUSTOM;
8af49135 284
e20e5a6b 285 var w = this.newWindow(qwebirc.ui.CUSTOM_CLIENT, type, name);
8af49135 286 w.addEvent("close", function(w) {
f74802c5 287 delete this.windows[qwebirc.ui.CUSTOM_CLIENT][w.identifier];
8af49135
CP
288 }.bind(this));
289
290 if(select)
291 this.selectWindow(w);
6c19eb8f 292
8af49135
CP
293 return w;
294 },
ebb21d2e
CP
295 addCustomWindow: function(windowName, class_, cssClass, options) {
296 if(!$defined(options))
297 options = {};
298
299 if(this.customWindows[windowName]) {
300 this.selectWindow(this.customWindows[windowName]);
8af49135 301 return;
841a451d 302 }
8af49135 303
ebb21d2e
CP
304 var d = this.newCustomWindow(windowName, true);
305 this.customWindows[windowName] = d;
306
307 d.addEvent("close", function() {
308 this.customWindows[windowName] = null;
8af49135
CP
309 }.bind(this));
310
ebb21d2e 311 if(cssClass)
e1a91a8a 312 d.lines.addClass("qwebirc-" + cssClass);
ebb21d2e
CP
313
314 var ew = new class_(d.lines, options);
8af49135 315 ew.addEvent("close", function() {
ebb21d2e 316 d.close();
8af49135 317 }.bind(this));
17f40fd9
CP
318
319 d.setSubWindow(ew);
841a451d 320 },
ebb21d2e 321 embeddedWindow: function() {
bcd2d24f 322 this.addCustomWindow("Add webchat to your site", qwebirc.ui.EmbedWizard, "embeddedwizard", {baseURL: this.options.baseURL, uiOptions: this.uiOptions, optionsCallback: function() {
c0f2f367
CP
323 this.optionsWindow();
324 }.bind(this)});
ebb21d2e
CP
325 },
326 optionsWindow: function() {
327 this.addCustomWindow("Options", qwebirc.ui.OptionsPane, "optionspane", this.uiOptions);
328 },
e1a91a8a
CP
329 aboutWindow: function() {
330 this.addCustomWindow("About", qwebirc.ui.AboutPane, "aboutpane", this.uiOptions);
331 },
b35116e2
CP
332 privacyWindow: function() {
333 this.addCustomWindow("Privacy policy", qwebirc.ui.PrivacyPolicyPane, "privacypolicypane", this.uiOptions);
334 },
391f51ff
CP
335 feedbackWindow: function() {
336 this.addCustomWindow("Feedback", qwebirc.ui.FeedbackPane, "feedbackpane", this.uiOptions);
337 },
f3d0c9f5
CP
338 faqWindow: function() {
339 this.addCustomWindow("FAQ", qwebirc.ui.FAQPane, "faqpane", this.uiOptions);
340 },
144ee52f 341 urlDispatcher: function(name, window) {
8af49135 342 if(name == "embedded")
925fc357 343 return ["a", this.embeddedWindow.bind(this)];
ebb21d2e
CP
344
345 if(name == "options")
346 return ["a", this.optionsWindow.bind(this)];
8af49135 347
5f2808af
CP
348 /* doesn't really belong here */
349 if(name == "whois") {
350 return ["span", function(nick) {
cbef082a
CP
351 if(this.uiOptions.QUERY_ON_NICK_CLICK) {
352 window.client.exec("/QUERY " + nick);
353 } else {
354 window.client.exec("/WHOIS " + nick);
355 }
356 }.bind(this)];
5f2808af
CP
357 }
358
8af49135 359 return null;
3184781b
CP
360 },
361 tabComplete: function(element) {
362 this.tabCompleter.tabComplete(element);
363 },
364 resetTabComplete: function() {
365 this.tabCompleter.reset();
4dd199c3
CP
366 },
367 setModifiableStylesheet: function(name) {
fbe5af77 368 this.__styleSheet = new qwebirc.ui.style.ModifiableStylesheet(qwebirc.global.staticBaseURL + "css/" + name + qwebirc.FILE_SUFFIX + ".mcss");
4dd199c3
CP
369
370 if($defined(this.options.hue)) {
371 this.setModifiableStylesheetValues(this.options.hue, 0, 0);
372 } else {
889ecb33 373 this.setModifiableStylesheetValues(this.uiOptions.STYLE_HUE, 0, 0);
4dd199c3
CP
374 }
375 },
376 setModifiableStylesheetValues: function(hue, saturation, lightness) {
377 if(!$defined(this.__styleSheet))
378 return;
379 this.__styleSheet.set(function(x) {
380 return x.setHue(hue).setSaturation(x.hsb[1] + saturation).setBrightness(x.hsb[2] + lightness);
381 });
8af49135 382 }
381fddfd 383});
6f2e4a37 384
326478c2 385qwebirc.ui.NotificationUI = new Class({
e20e5a6b 386 Extends: qwebirc.ui.StandardUI,
fb71087a
CP
387 initialize: function(parentElement, windowClass, uiName, options) {
388 this.parent(parentElement, windowClass, uiName, options);
389
326478c2
CP
390 this.__beeper = new qwebirc.ui.Beeper(this.uiOptions);
391 this.__flasher = new qwebirc.ui.Flasher(this.uiOptions);
fb71087a 392
326478c2 393 this.beep = this.__beeper.beep.bind(this.__beeper);
127631e0 394
326478c2
CP
395 this.flash = this.__flasher.flash.bind(this.__flasher);
396 this.cancelFlash = this.__flasher.cancelFlash.bind(this.__flasher);
fb71087a 397 },
127631e0
CP
398 setBeepOnMention: function(value) {
399 if(value)
326478c2
CP
400 this.__beeper.soundInit();
401 },
402 updateTitle: function(text) {
403 if(this.__flasher.updateTitle(text))
404 this.parent(text);
eb271d86
CP
405 },
406 focusChange: function(value) {
407 this.parent(value);
408 this.__flasher.focusChange(value);
1211ddcd 409 }
fb71087a
CP
410});
411
5f2808af 412qwebirc.ui.NewLoginUI = new Class({
326478c2 413 Extends: qwebirc.ui.NotificationUI,
5f2808af
CP
414 loginBox: function(callbackfn, initialNickname, initialChannels, autoConnect, autoNick) {
415 this.postInitialize();
416
c837b844
CP
417 /* I'd prefer something shorter and snappier! */
418 var w = this.newCustomWindow("Connection details", true, qwebirc.ui.WINDOW_CONNECT);
5f2808af
CP
419 var callback = function(args) {
420 w.close();
421 callbackfn(args);
422 };
423
424 qwebirc.ui.GenericLoginBox(w.lines, callback, initialNickname, initialChannels, autoConnect, autoNick, this.options.networkName);
425 }
426});
427
428qwebirc.ui.QuakeNetUI = new Class({
429 Extends: qwebirc.ui.NewLoginUI,
2cd9e32d
CP
430 urlDispatcher: function(name, window) {
431 if(name == "qwhois") {
7cb09779 432 return ["span", function(auth) {
2cd9e32d 433 this.client.exec("/MSG Q whois #" + auth);
925fc357
CP
434 }.bind(window)];
435 }
144ee52f 436 return this.parent(name, window);
ffbb638d
CP
437 },
438 logout: function() {
439 if(!qwebirc.auth.loggedin())
440 return;
441 if(confirm("Log out?")) {
442 for(var client in this.clients) {
443 this.clients[client].quit("Logged out");
444 };
4b9f894d
CP
445
446 /* HACK */
fbe5af77 447 var foo = function() { document.location = qwebirc.global.dynamicBaseURL + "auth?logout=1"; };
4b9f894d 448 foo.delay(500);
ffbb638d 449 }
2cd9e32d
CP
450 }
451});
144ee52f
CP
452
453qwebirc.ui.RootUI = qwebirc.ui.QuakeNetUI;
fbe5af77
CP
454
455qwebirc.ui.RequestTransformHTML = function(options) {
456 var HREF_ELEMENTS = {
457 "IMG": 1
458 };
459
460 var update = options.update;
461 var onSuccess = options.onSuccess;
462
463 var fixUp = function(node) {
464 if(node.nodeType != 1)
465 return;
466
467 var tagName = node.nodeName.toUpperCase();
468 if(HREF_ELEMENTS[tagName]) {
469 var attr = node.getAttribute("transform_attr");
470 var value = node.getAttribute("transform_value");
471 if($defined(attr) && $defined(value)) {
472 node.removeAttribute("transform_attr");
473 node.removeAttribute("transform_value");
474 node.setAttribute(attr, qwebirc.global.staticBaseURL + value);
475 }
476 }
477
478 for(var i=0;i<node.childNodes.length;i++)
479 fixUp(node.childNodes[i]);
480 };
481
482 delete options["update"];
483 options.onSuccess = function(tree, elements, html, js) {
484 var container = new Element("div");
485 container.set("html", html);
486 fixUp(container);
487 update.empty();
488
489 while(container.childNodes.length > 0) {
490 var x = container.firstChild;
491 container.removeChild(x);
492 update.appendChild(x);
493 }
494 onSuccess();
495 };
496
497 return new Request.HTML(options);
498};
499