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