]> jfr.im git - irc/quakenet/qwebirc.git/blame - js/ui/frontends/qui.js
Inheritance tidying + tidying!
[irc/quakenet/qwebirc.git] / js / ui / frontends / qui.js
CommitLineData
e20e5a6b
CP
1qwebirc.ui.QUI = new Class({
2 Extends: qwebirc.ui.NewLoginUI,
2cad083e
CP
3 initialize: function(parentElement, theme, options) {
4 this.parent(parentElement, qwebirc.ui.QUI.Window, "qui", options);
e20e5a6b
CP
5 this.theme = theme;
6 this.parentElement = parentElement;
7 },
8 postInitialize: function() {
9 this.qjsui = new qwebirc.ui.QUI.JSUI("qwebirc-qui", this.parentElement);
bfbe72f9
CP
10 this.qjsui.addEvent("reflow", function() {
11 var w = this.getActiveWindow();
12 if($defined(w))
13 w.onResize();
14 }.bind(this));
941e1642 15 this.qjsui.top.addClass("outertabbar");
e20e5a6b
CP
16
17 this.qjsui.bottom.addClass("input");
18 this.qjsui.right.addClass("nicklist");
19 this.qjsui.topic.addClass("topic");
20 this.qjsui.middle.addClass("lines");
21
941e1642 22 this.outerTabs = this.qjsui.top;
0989d983 23
941e1642
CP
24 this.tabs = new Element("div");
25 this.tabs.addClass("tabbar");
9da8639a
CP
26
27 this.__createDropdownMenu();
28
941e1642 29 this.outerTabs.appendChild(this.tabs);
e20e5a6b
CP
30 this.origtopic = this.topic = this.qjsui.topic;
31 this.origlines = this.lines = this.qjsui.middle;
32 this.orignicklist = this.nicklist = this.qjsui.right;
33
34 this.input = this.qjsui.bottom;
35 this.reflow = this.qjsui.reflow.bind(this.qjsui);
36
ff4befd8
CP
37 this.tabs.addEvent("mousewheel", function(x) {
38 var event = new Event(x);
39
40 /* up */
41 if(event.wheel > 0) {
42 this.nextWindow();
43 } else if(event.wheel < 0) {
44 /* down */
b35116e2 45 this.prevWindow();
ff4befd8
CP
46 }
47 event.stop();
48 }.bind(this));
49
e20e5a6b
CP
50 this.createInput();
51 this.reflow();
9da8639a
CP
52
53 /* HACK, in Chrome this should work immediately but doesn't */
54 this.__createDropdownHint.delay(100, this);
e20e5a6b 55 },
0989d983 56 __createDropdownMenu: function() {
e9837dce 57 var dropdownMenu = new Element("span");
43cb8910 58 dropdownMenu.addClass("dropdownmenu");
0989d983
CP
59
60 dropdownMenu.hide = function() {
43cb8910
CP
61 dropdownMenu.setStyle("display", "none");
62 dropdownMenu.visible = false;
e9837dce 63 document.removeEvent("mousedown", hideEvent);
43cb8910 64 }.bind(this);
e9837dce 65 var hideEvent = function() { dropdownMenu.hide(); };
0989d983
CP
66
67 dropdownMenu.hide();
43cb8910
CP
68 this.parentElement.appendChild(dropdownMenu);
69
70 this.UICommands.forEach(function(x) {
71 var text = x[0];
72 var fn = this[x[1] + "Window"].bind(this);
73 var e = new Element("a");
0989d983 74 e.addEvent("mousedown", function(e) { new Event(e).stop(); });
43cb8910
CP
75 e.addEvent("click", function() {
76 dropdownMenu.hide();
77 fn();
78 });
79 e.set("text", text);
80 dropdownMenu.appendChild(e);
81 }.bind(this));
82
941e1642 83 var dropdown = new Element("div");
43cb8910 84 dropdown.addClass("dropdown-tab");
941e1642 85 dropdown.appendChild(new Element("img", {src: "images/favicon.png", title: "menu", alt: "menu"}));
391f51ff
CP
86 dropdown.setStyle("opacity", 1);
87
88 var dropdownEffect = new Fx.Tween(dropdown, {duration: "long", property: "opacity", link: "chain"});
89 dropdownEffect.start(0.25);
90 dropdownEffect.start(1);
91 dropdownEffect.start(0.33);
92 dropdownEffect.start(1);
93
941e1642 94 this.outerTabs.appendChild(dropdown);
9da8639a 95 dropdownMenu.show = function(x) {
43cb8910 96 new Event(x).stop();
e9837dce 97 this.hideHint();
43cb8910
CP
98
99 if(dropdownMenu.visible) {
100 dropdownMenu.hide();
101 return;
102 }
e9837dce
CP
103 var top = this.outerTabs.getSize().y;
104
941e1642 105 dropdownMenu.setStyle("left", 0);
385143a6 106 dropdownMenu.setStyle("top", top-1); /* -1 == top border */
43cb8910
CP
107 dropdownMenu.setStyle("display", "inline-block");
108 dropdownMenu.visible = true;
e9837dce
CP
109
110 document.addEvent("mousedown", hideEvent);
43cb8910 111 }.bind(this);
e9837dce 112 dropdown.addEvent("mousedown", function(e) { new Event(e).stop(); });
43cb8910 113 dropdown.addEvent("click", dropdownMenu.show);
0989d983 114 },
9da8639a 115 __createDropdownHint: function() {
43cb8910
CP
116 var dropdownhint = new Element("div");
117 dropdownhint.addClass("dropdownhint");
391f51ff 118 dropdownhint.set("text", "Click the icon for the main menu.");
e9837dce
CP
119 dropdownhint.setStyle("top", this.outerTabs.getSize().y + 5);
120
121 this.parentElement.appendChild(dropdownhint);
391f51ff
CP
122 new Fx.Morph(dropdownhint, {duration: "normal", transition: Fx.Transitions.Sine.easeOut}).start({left: [900, 5]});
123
43cb8910 124 var hider = function() {
391f51ff
CP
125 new Fx.Morph(dropdownhint, {duration: "long"}).start({left: [5, -900]});
126 }.delay(4000, this);
0989d983 127
391f51ff
CP
128 var hider2 = function() {
129 if(dropdownhint.hidden)
130 return;
e9837dce 131 this.parentElement.removeChild(dropdownhint);
391f51ff
CP
132 dropdownhint.hidden = 1;
133 }.bind(this);
134 hider2.delay(4000);
e9837dce 135 this.hideHint = hider2;
391f51ff
CP
136
137 document.addEvent("mousedown", hider2);
138 document.addEvent("keypress", hider2);
139
43cb8910 140 },
e20e5a6b
CP
141 createInput: function() {
142 var form = new Element("form");
143 this.input.appendChild(form);
144 form.addClass("input");
145
146 var inputbox = new Element("input");
147 form.appendChild(inputbox);
148 this.inputbox = inputbox;
149
150 form.addEvent("submit", function(e) {
151 new Event(e).stop();
152
153 if(inputbox.value == "")
154 return;
155
3184781b 156 this.resetTabComplete();
e20e5a6b
CP
157 this.getActiveWindow().historyExec(inputbox.value);
158 inputbox.value = "";
159 }.bind(this));
160
3184781b
CP
161 inputbox.addEvent("focus", this.resetTabComplete.bind(this));
162 inputbox.addEvent("mousedown", this.resetTabComplete.bind(this));
163
e20e5a6b
CP
164 inputbox.addEvent("keydown", function(e) {
165 var resultfn;
166 var cvalue = inputbox.value;
3184781b 167
e20e5a6b
CP
168 if(e.key == "up") {
169 resultfn = this.commandhistory.upLine;
170 } else if(e.key == "down") {
171 resultfn = this.commandhistory.downLine;
3184781b
CP
172 } else if(e.key == "tab") {
173 new Event(e).stop();
174 this.tabComplete(inputbox);
175 return;
e20e5a6b 176 } else {
3184781b
CP
177 /* ideally alt and other keys wouldn't break this */
178 this.resetTabComplete();
e20e5a6b
CP
179 return;
180 }
181
3184781b 182 this.resetTabComplete();
e20e5a6b
CP
183 if((cvalue != "") && (this.lastcvalue != cvalue))
184 this.commandhistory.addLine(cvalue, true);
185
186 var result = resultfn.bind(this.commandhistory)();
187
188 new Event(e).stop();
189 if(!result)
190 result = "";
191 this.lastcvalue = result;
192
193 inputbox.value = result;
1d6756bc 194 qwebirc.util.setAtEnd(inputbox);
e20e5a6b
CP
195 }.bind(this));
196 },
197 setLines: function(lines) {
198 this.lines.parentNode.replaceChild(lines, this.lines);
199 this.qjsui.middle = this.lines = lines;
200 },
201 setChannelItems: function(nicklist, topic) {
202 if(!$defined(nicklist)) {
203 nicklist = this.orignicklist;
204 topic = this.origtopic;
205 }
206 this.nicklist.parentNode.replaceChild(nicklist, this.nicklist);
207 this.qjsui.right = this.nicklist = nicklist;
208
209 this.topic.parentNode.replaceChild(topic, this.topic);
210 this.qjsui.topic = this.topic = topic;
211 }
212});
213
214qwebirc.ui.QUI.JSUI = new Class({
bfbe72f9 215 Implements: [Events],
b1ee83f3
CP
216 initialize: function(class_, parent, sizer) {
217 this.parent = parent;
218 this.sizer = $defined(sizer)?sizer:parent;
219
24ede2cb
CP
220 this.class_ = class_;
221 this.create();
222
6c19eb8f
CP
223 this.reflowevent = null;
224
b1ee83f3 225 window.addEvent("resize", function() {
6c19eb8f 226 this.reflow(100);
b1ee83f3
CP
227 }.bind(this));
228 },
24ede2cb 229 applyClasses: function(pos, l) {
6c19eb8f 230 l.addClass("dynamicpanel");
24ede2cb 231 l.addClass(this.class_);
6c19eb8f 232
24ede2cb
CP
233 if(pos == "middle") {
234 l.addClass("leftboundpanel");
235 } else if(pos == "top") {
236 l.addClass("topboundpanel");
237 l.addClass("widepanel");
238 } else if(pos == "topic") {
239 l.addClass("widepanel");
240 } else if(pos == "right") {
241 l.addClass("rightboundpanel");
242 } else if(pos == "bottom") {
243 l.addClass("bottomboundpanel");
244 l.addClass("widepanel");
245 }
246 },
247 create: function() {
248 var XE = function(pos) {
249 var element = new Element("div");
250 this.applyClasses(pos, element);
b1ee83f3 251
24ede2cb
CP
252 this.parent.appendChild(element);
253 return element;
b1ee83f3
CP
254 }.bind(this);
255
24ede2cb
CP
256 this.top = XE("top");
257 this.topic = XE("topic");
258 this.middle = XE("middle");
259 this.right = XE("right");
260 this.bottom = XE("bottom");
b1ee83f3 261 },
6c19eb8f
CP
262 reflow: function(delay) {
263 if(!delay)
264 delay = 1;
265
266 if(this.reflowevent)
267 $clear(this.reflowevent);
268 this.__reflow();
269 this.reflowevent = this.__reflow.delay(delay, this);
270 },
271 __reflow: function() {
b1ee83f3
CP
272 var bottom = this.bottom;
273 var middle = this.middle;
274 var right = this.right;
275 var topic = this.topic;
276 var top = this.top;
277
278 var topicsize = topic.getSize();
279 var topsize = top.getSize();
280 var rightsize = right.getSize();
281 var bottomsize = bottom.getSize();
282 var docsize = this.sizer.getSize();
283
284 var mheight = (docsize.y - topsize.y - bottomsize.y - topicsize.y);
285 var mwidth = (docsize.x - rightsize.x);
286
4b9f894d 287 topic.setStyle("top", topsize.y);
b1ee83f3 288
4b9f894d 289 middle.setStyle("top", (topsize.y + topicsize.y));
b1ee83f3 290 if(mheight > 0) {
4b9f894d
CP
291 middle.setStyle("height", mheight);
292 right.setStyle("height", mheight);
b1ee83f3
CP
293 }
294
6c19eb8f 295 if(mwidth > 0)
4b9f894d
CP
296 middle.setStyle("width", mwidth);
297 right.setStyle("top", (topsize.y + topicsize.y));
298 right.setStyle("left", mwidth);
b1ee83f3 299
4b9f894d 300 bottom.setStyle("top", (docsize.y - bottomsize.y));
bfbe72f9 301 this.fireEvent("reflow");
b1ee83f3
CP
302 },
303 showChannel: function(state) {
304 var display = "none";
305 if(state)
306 display = "block";
307
308 this.right.setStyle("display", display);
309 this.topic.setStyle("display", display);
6c19eb8f
CP
310 },
311 showInput: function(state) {
941e1642 312 this.bottom.isVisible = state;
6c19eb8f 313 this.bottom.setStyle("display", state?"block":"none");
b1ee83f3
CP
314 }
315});
35155ba7 316
e20e5a6b
CP
317qwebirc.ui.QUI.Window = new Class({
318 Extends: qwebirc.ui.Window,
f4ae92cc 319
f74802c5
CP
320 initialize: function(parentObject, client, type, name, identifier) {
321 this.parent(parentObject, client, type, name, identifier);
be0bd774 322
66de775f 323 this.tab = new Element("a", {"href": "#"});
f4ae92cc 324 this.tab.addClass("tab");
fd60516d
CP
325 this.tab.addEvent("focus", function() { this.blur() }.bind(this.tab));;
326
35155ba7 327 parentObject.tabs.appendChild(this.tab);
f4ae92cc
CP
328
329 this.tab.appendText(name);
66de775f
CP
330 this.tab.addEvent("click", function(e) {
331 new Event(e).stop();
f84bf379
CP
332
333 if(this.closed)
334 return;
335
f4ae92cc
CP
336 parentObject.selectWindow(this);
337 }.bind(this));
f4ae92cc 338
e20e5a6b
CP
339 if(type != qwebirc.ui.WINDOW_STATUS && type != qwebirc.ui.WINDOW_CONNECT) {
340 var tabclose = new Element("span");
341 tabclose.set("text", "X");
f4ae92cc 342 tabclose.addClass("tabclose");
f84bf379 343 var close = function(e) {
f4ae92cc
CP
344 new Event(e).stop();
345
f84bf379
CP
346 if(this.closed)
347 return;
348
e20e5a6b 349 if(type == qwebirc.ui.WINDOW_CHANNEL)
f4ae92cc
CP
350 this.client.exec("/PART " + name);
351
352 this.close();
3184781b 353
941e1642 354 //parentObject.inputbox.focus();
f84bf379
CP
355 }.bind(this);
356
357 tabclose.addEvent("click", close);
358 this.tab.addEvent("mouseup", function(e) {
b46f79e6
CP
359 var button = 1;
360
361 if(Browser.Engine.trident)
362 button = 4;
363
364 if(e.event.button == button)
f84bf379 365 close(e);
f4ae92cc 366 }.bind(this));
52090a1f 367
f4ae92cc
CP
368 this.tab.appendChild(tabclose);
369 }
be0bd774 370
be0bd774 371 this.lines = new Element("div");
6c19eb8f 372 this.parentObject.qjsui.applyClasses("middle", this.lines);
be0bd774 373 this.lines.addClass("lines");
e82478eb
CP
374 if(type != qwebirc.ui.WINDOW_CUSTOM && type != qwebirc.ui.WINDOW_CONNECT)
375 this.lines.addClass("ircwindow");
6c19eb8f 376
b1ee83f3
CP
377 this.lines.addEvent("scroll", function() {
378 this.scrolleddown = this.scrolledDown();
ff6a32cc 379 this.scrollpos = this.getScrollParent().getScroll();
be0bd774 380 }.bind(this));
be0bd774 381
e20e5a6b 382 if(type == qwebirc.ui.WINDOW_CHANNEL) {
be0bd774
CP
383 this.topic = new Element("div");
384 this.topic.addClass("topic");
b1ee83f3 385 this.topic.addClass("tab-invisible");
be0bd774 386 this.topic.set("html", "&nbsp;");
6c19eb8f 387 this.parentObject.qjsui.applyClasses("topic", this.topic);
be0bd774 388
52090a1f 389 this.prevNick = null;
66de775f
CP
390 this.nicklist = new Element("div");
391 this.nicklist.addClass("nicklist");
b1ee83f3 392 this.nicklist.addClass("tab-invisible");
cffd43cf 393 this.nicklist.addEvent("click", this.removePrevMenu.bind(this));
6c19eb8f 394 this.parentObject.qjsui.applyClasses("nicklist", this.nicklist);
be0bd774 395 }
b1ee83f3 396
e20e5a6b 397 if(type == qwebirc.ui.WINDOW_CHANNEL) {
359b7edd
CP
398 this.updateTopic("");
399 } else {
400 this.reflow();
401 }
b1ee83f3
CP
402 },
403 reflow: function() {
404 this.parentObject.reflow();
35155ba7
CP
405 },
406 onResize: function() {
ff6a32cc
CP
407 if(this.scrolleddown) {
408 if(Browser.Engine.trident) {
409 this.scrollToBottom.delay(5, this);
410 } else {
411 this.scrollToBottom();
412 }
413 } else if($defined(this.scrollpos)) {
414 if(Browser.Engine.trident) {
415 this.getScrollParent().scrollTo(this.scrollpos.x, this.scrollpos.y);
416 } else {
417 this.getScrollParent().scrollTo.delay(5, this, [this.scrollpos.x, this.scrollpos.y]);
418 }
419 }
359b7edd 420 },
cffd43cf 421 createMenu: function(nick, parent) {
d2512acf 422 var e = new Element("div");
cffd43cf
CP
423 parent.appendChild(e);
424 e.addClass("menu");
425
426 qwebirc.ui.MENU_ITEMS.forEach(function(x) {
d2512acf 427 var e2 = new Element("a");
cffd43cf
CP
428 e.appendChild(e2);
429
430 e2.href = "#";
431 e2.set("text", "- " + x[0]);
432
433 e2.addEvent("focus", function() { this.blur() }.bind(e2));
434 e2.addEvent("click", function(ev) { new Event(ev.stop()); this.menuClick(x[1]); }.bind(this));
435 }.bind(this));
436 return e;
437 },
438 menuClick: function(fn) {
439 /*
440 this.prevNick.removeChild(this.prevNick.menu);
441 this.prevNick.menu = null;
442 */
443 fn.bind(this)(this.prevNick.realNick);
444 this.removePrevMenu();
445 },
d8272bcb
CP
446 moveMenuClass: function() {
447 if(!this.prevNick)
448 return;
449 if(this.nicklist.firstChild == this.prevNick) {
450 this.prevNick.removeClass("selected-middle");
451 } else {
452 this.prevNick.addClass("selected-middle");
453 }
454 },
cffd43cf
CP
455 removePrevMenu: function() {
456 if(!this.prevNick)
457 return;
458
459 this.prevNick.removeClass("selected");
d8272bcb 460 this.prevNick.removeClass("selected-middle");
cffd43cf
CP
461 if(this.prevNick.menu)
462 this.prevNick.removeChild(this.prevNick.menu);
463 this.prevNick = null;
464 },
52090a1f
CP
465 nickListAdd: function(nick, position) {
466 var e = new Element("a");
467 qwebirc.ui.insertAt(position, this.nicklist, e);
f4ae92cc 468
52090a1f
CP
469 e.href = "#";
470 e.appendChild(document.createTextNode(nick));
471
472 e.realNick = this.client.stripPrefix(nick);
473
474 e.addEvent("click", function(x) {
aab6d06a
CP
475 if(this.prevNick == e) {
476 this.removePrevMenu();
477 return;
478 }
479
cffd43cf 480 this.removePrevMenu();
52090a1f
CP
481 this.prevNick = e;
482 e.addClass("selected");
d8272bcb 483 this.moveMenuClass();
cffd43cf 484 e.menu = this.createMenu(x.realNick, e);
52090a1f
CP
485 new Event(x).stop();
486 }.bind(this));
52090a1f 487
fd60516d 488 e.addEvent("focus", function() { this.blur() }.bind(e));
d8272bcb 489 this.moveMenuClass();
52090a1f
CP
490 return e;
491 },
492 nickListRemove: function(nick, stored) {
493 this.nicklist.removeChild(stored);
d8272bcb 494 this.moveMenuClass();
f4ae92cc
CP
495 },
496 updateTopic: function(topic) {
f4ae92cc
CP
497 var t = this.topic;
498
499 while(t.firstChild)
500 t.removeChild(t.firstChild);
501
66de775f 502 if(topic) {
1f06a70a 503 this.parent(topic, t);
66de775f 504 } else {
359b7edd
CP
505 var e = new Element("div");
506 e.set("text", "(no topic set)");
66de775f 507 e.addClass("emptytopic");
359b7edd 508 t.appendChild(e);
66de775f 509 }
359b7edd 510 this.reflow();
f4ae92cc
CP
511 },
512 select: function() {
e20e5a6b 513 var inputVisible = this.type != qwebirc.ui.WINDOW_CONNECT && this.type != qwebirc.ui.WINDOW_CUSTOM;
6c19eb8f 514
f4ae92cc 515 this.tab.removeClass("tab-unselected");
f4ae92cc 516 this.tab.addClass("tab-selected");
359b7edd 517
6c19eb8f
CP
518 this.parentObject.setLines(this.lines);
519 this.parentObject.setChannelItems(this.nicklist, this.topic);
520 this.parentObject.qjsui.showInput(inputVisible);
521 this.parentObject.qjsui.showChannel($defined(this.nicklist));
522
523 this.reflow();
24ede2cb 524
7c633700 525 this.parent();
25be5960 526
6c19eb8f
CP
527 if(inputVisible)
528 this.parentObject.inputbox.focus();
f4ae92cc
CP
529 },
530 deselect: function() {
531 this.parent();
532
f4ae92cc
CP
533 this.tab.removeClass("tab-selected");
534 this.tab.addClass("tab-unselected");
535 },
536 close: function() {
537 this.parent();
538
f4ae92cc
CP
539 this.parentObject.tabs.removeChild(this.tab);
540 },
b35116e2 541 addLine: function(type, line, colourClass) {
f4ae92cc
CP
542 var e = new Element("div");
543
b35116e2
CP
544 if(colourClass) {
545 e.addClass(colourClass);
f4ae92cc
CP
546 } else if(this.lastcolour) {
547 e.addClass("linestyle1");
548 } else {
549 e.addClass("linestyle2");
550 }
f4ae92cc 551 this.lastcolour = !this.lastcolour;
35155ba7 552
b35116e2 553 this.parent(type, line, colourClass, e);
be0bd774
CP
554 },
555 setHilighted: function(state) {
2a802692 556 var laststate = this.hilighted;
96f28062 557
be0bd774 558 this.parent(state);
96f28062
CP
559
560 if(state == laststate)
561 return;
562
563 this.tab.removeClass("tab-hilight-activity");
564 this.tab.removeClass("tab-hilight-us");
565 this.tab.removeClass("tab-hilight-speech");
f4ae92cc 566
96f28062
CP
567 switch(this.hilighted) {
568 case qwebirc.ui.HILIGHT_US:
569 this.tab.addClass("tab-hilight-us");
570 break;
571 case qwebirc.ui.HILIGHT_SPEECH:
572 this.tab.addClass("tab-hilight-speech");
573 break;
574 case qwebirc.ui.HILIGHT_ACTIVITY:
575 this.tab.addClass("tab-hilight-activity");
576 break;
be0bd774 577 }
f4ae92cc
CP
578 }
579});