]> jfr.im git - irc/quakenet/qwebirc.git/blob - js/ui/baseui.js
deb3a04a4039ee1606856a393bd5a57acc07592a
[irc/quakenet/qwebirc.git] / js / ui / baseui.js
1 qwebirc.ui.WINDOW_STATUS = 0x01;
2 qwebirc.ui.WINDOW_QUERY = 0x02;
3 qwebirc.ui.WINDOW_CHANNEL = 0x04;
4 qwebirc.ui.WINDOW_CUSTOM = 0x08;
5 qwebirc.ui.WINDOW_CONNECT = 0x10;
6 qwebirc.ui.WINDOW_MESSAGES = 0x20;
7
8 qwebirc.ui.CUSTOM_CLIENT = "custom";
9
10 qwebirc.ui.BaseUI = new Class({
11 Implements: [Events],
12 initialize: function(parentElement, windowClass, uiName, options) {
13 this.options = options;
14
15 this.windows = {};
16 this.clients = {};
17 this.windows[qwebirc.ui.CUSTOM_CLIENT] = {};
18 this.windowArray = [];
19 this.windowClass = windowClass;
20 this.parentElement = parentElement;
21 this.parentElement.addClass("qwebirc");
22 this.parentElement.addClass("qwebirc-" + uiName);
23 this.firstClient = false;
24 this.commandhistory = new qwebirc.irc.CommandHistory();
25 this.clientId = 0;
26
27 this.windowFocused = true;
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 }
50 },
51 newClient: function(client) {
52 client.id = this.clientId++;
53 client.hilightController = new qwebirc.ui.HilightController(client);
54
55 this.windows[client.id] = {}
56 this.clients[client.id] = client;
57 var w = this.newWindow(client, qwebirc.ui.WINDOW_STATUS, "Status");
58 this.selectWindow(w);
59 if(!this.firstClient) {
60 this.firstClient = true;
61 w.addLine("", "qwebirc v" + qwebirc.VERSION);
62 w.addLine("", "Copyright (C) 2008-2011 Chris Porter and the qwebirc project.");
63 w.addLine("", "http://www.qwebirc.org");
64 w.addLine("", "Licensed under the GNU General Public License, Version 2.");
65 }
66 return w;
67 },
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 },
75 getWindowIdentifier: function(client, type, name) {
76 if(type == qwebirc.ui.WINDOW_MESSAGES)
77 return "-M";
78 if(type == qwebirc.ui.WINDOW_STATUS)
79 return "";
80
81 if(client == qwebirc.ui.CUSTOM_CLIENT) /* HACK */
82 return "_" + name;
83
84 return "_" + client.toIRCLower(name);
85 },
86 newWindow: function(client, type, name) {
87 var w = this.getWindow(client, type, name);
88 if($defined(w))
89 return w;
90
91 var wId = this.getWindowIdentifier(client, type, name);
92 var w = this.windows[this.getClientId(client)][wId] = new this.windowClass(this, client, type, name, wId);
93 this.windowArray.push(w);
94
95 return w;
96 },
97 getWindow: function(client, type, name) {
98 var c = this.windows[this.getClientId(client)];
99 if(!$defined(c))
100 return null;
101
102 return c[this.getWindowIdentifier(client, type, name)];
103 },
104 getActiveWindow: function() {
105 return this.active;
106 },
107 getActiveIRCWindow: function(client) {
108 if(!this.active || this.active.type == qwebirc.ui.WINDOW_CUSTOM) {
109 return this.windows[this.getClientId(client)][this.getWindowIdentifier(client, qwebirc.ui.WINDOW_STATUS)];
110 } else {
111 return this.active;
112 }
113 },
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 */
121 this.updateTitle(window.name + " - " + this.options.appTitle);
122 },
123 updateTitle: function(text) {
124 document.title = text;
125 },
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 },
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);
156 if(index == -1) {
157 return;
158 } else if(index == 0) {
159 this.selectWindow(this.windowArray[1]);
160 } else {
161 this.selectWindow(this.windowArray[index - 1]);
162 }
163 }
164 }
165
166 this.windowArray = this.windowArray.erase(window);
167 delete this.windows[this.getClientId(window.client)][window.identifier];
168 },
169 /*
170 this shouldn't be called by overriding classes!
171 they should implement their own!
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 */
176 loginBox: function(callback, initialNickname, initialChannels, autoConnect, autoNick) {
177 qwebirc.ui.GenericLoginBox(this.parentElement, callback, initialNickname, initialChannels, autoConnect, autoNick, this.options.networkName);
178 },
179 focusChange: function(newValue) {
180 var window_ = this.getActiveWindow();
181 if($defined(window_))
182 window_.focusChange(newValue);
183 }
184 });
185
186 qwebirc.ui.StandardUI = new Class({
187 Extends: qwebirc.ui.BaseUI,
188 UICommands: qwebirc.ui.UI_COMMANDS,
189 initialize: function(parentElement, windowClass, uiName, options) {
190 this.parent(parentElement, windowClass, uiName, options);
191
192 this.tabCompleter = new qwebirc.ui.TabCompleterFactory(this);
193 this.uiOptions = new qwebirc.ui.DefaultOptionsClass(this, options.uiOptionsArg);
194 this.customWindows = {};
195
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
201 var ev;
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;
228 }
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
238
239 number = number - 1;
240
241 if(number >= this.windowArray.length)
242 return;
243
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) {
256 if($$("input").indexOf(x.target) == -1 && $$("textarea").indexOf(x.target) == -1)
257 return false;
258 return true;
259 },
260 newCustomWindow: function(name, select, type) {
261 if(!type)
262 type = qwebirc.ui.WINDOW_CUSTOM;
263
264 var w = this.newWindow(qwebirc.ui.CUSTOM_CLIENT, type, name);
265 w.addEvent("close", function(w) {
266 delete this.windows[qwebirc.ui.CUSTOM_CLIENT][w.identifier];
267 }.bind(this));
268
269 if(select)
270 this.selectWindow(w);
271
272 return w;
273 },
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]);
280 return;
281 }
282
283 var d = this.newCustomWindow(windowName, true);
284 this.customWindows[windowName] = d;
285
286 d.addEvent("close", function() {
287 this.customWindows[windowName] = null;
288 }.bind(this));
289
290 if(cssClass)
291 d.lines.addClass("qwebirc-" + cssClass);
292
293 var ew = new class_(d.lines, options);
294 ew.addEvent("close", function() {
295 d.close();
296 }.bind(this));
297
298 d.setSubWindow(ew);
299 },
300 embeddedWindow: function() {
301 this.addCustomWindow("Add webchat to your site", qwebirc.ui.EmbedWizard, "embeddedwizard", {baseURL: this.options.baseURL, uiOptions: this.uiOptions, optionsCallback: function() {
302 this.optionsWindow();
303 }.bind(this)});
304 },
305 optionsWindow: function() {
306 this.addCustomWindow("Options", qwebirc.ui.OptionsPane, "optionspane", this.uiOptions);
307 },
308 aboutWindow: function() {
309 this.addCustomWindow("About", qwebirc.ui.AboutPane, "aboutpane", this.uiOptions);
310 },
311 privacyWindow: function() {
312 this.addCustomWindow("Privacy policy", qwebirc.ui.PrivacyPolicyPane, "privacypolicypane", this.uiOptions);
313 },
314 feedbackWindow: function() {
315 this.addCustomWindow("Feedback", qwebirc.ui.FeedbackPane, "feedbackpane", this.uiOptions);
316 },
317 faqWindow: function() {
318 this.addCustomWindow("FAQ", qwebirc.ui.FAQPane, "faqpane", this.uiOptions);
319 },
320 urlDispatcher: function(name, window) {
321 if(name == "embedded")
322 return ["a", this.embeddedWindow.bind(this)];
323
324 if(name == "options")
325 return ["a", this.optionsWindow.bind(this)];
326
327 /* doesn't really belong here */
328 if(name == "whois") {
329 return ["span", function(nick) {
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)];
336 }
337
338 return null;
339 },
340 tabComplete: function(element) {
341 this.tabCompleter.tabComplete(element);
342 },
343 resetTabComplete: function() {
344 this.tabCompleter.reset();
345 },
346 setModifiableStylesheet: function(name) {
347 this.__styleSheet = new qwebirc.ui.style.ModifiableStylesheet(qwebirc.global.staticBaseURL + "css/" + name + qwebirc.FILE_SUFFIX + ".mcss");
348 this.setModifiableStylesheetValues({});
349 },
350 setModifiableStylesheetValues: function(values) {
351 for(var k in values)
352 this.__styleValues[k] = values[k];
353
354 if(!$defined(this.__styleSheet))
355 return;
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));
372 }
373 });
374
375 qwebirc.ui.NotificationUI = new Class({
376 Extends: qwebirc.ui.StandardUI,
377 initialize: function(parentElement, windowClass, uiName, options) {
378 this.parent(parentElement, windowClass, uiName, options);
379
380 this.__beeper = new qwebirc.ui.Beeper(this.uiOptions);
381 this.__flasher = new qwebirc.ui.Flasher(this.uiOptions);
382
383 this.beep = this.__beeper.beep.bind(this.__beeper);
384
385 this.flash = this.__flasher.flash.bind(this.__flasher);
386 this.cancelFlash = this.__flasher.cancelFlash.bind(this.__flasher);
387 },
388 setBeepOnMention: function(value) {
389 if(value)
390 this.__beeper.soundInit();
391 },
392 updateTitle: function(text) {
393 if(this.__flasher.updateTitle(text))
394 this.parent(text);
395 },
396 focusChange: function(value) {
397 this.parent(value);
398 this.__flasher.focusChange(value);
399 }
400 });
401
402 qwebirc.ui.NewLoginUI = new Class({
403 Extends: qwebirc.ui.NotificationUI,
404 loginBox: function(callbackfn, initialNickname, initialChannels, autoConnect, autoNick) {
405 this.postInitialize();
406
407 /* I'd prefer something shorter and snappier! */
408 var w = this.newCustomWindow("Connection details", true, qwebirc.ui.WINDOW_CONNECT);
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
418 qwebirc.ui.QuakeNetUI = new Class({
419 Extends: qwebirc.ui.NewLoginUI,
420 urlDispatcher: function(name, window) {
421 if(name == "qwhois") {
422 return ["span", function(auth) {
423 this.client.exec("/MSG Q whois #" + auth);
424 }.bind(window)];
425 }
426 return this.parent(name, window);
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 };
435
436 /* HACK */
437 var foo = function() { document.location = qwebirc.global.dynamicBaseURL + "auth?logout=1"; };
438 foo.delay(500);
439 }
440 }
441 });
442
443 qwebirc.ui.RootUI = qwebirc.ui.QuakeNetUI;
444
445 qwebirc.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