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