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