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