]> jfr.im git - irc/quakenet/qwebirc.git/blame - js/ui/qui.js
Scroll position is now locked at the bottom if it's at the bottom when resizing begins.
[irc/quakenet/qwebirc.git] / js / ui / qui.js
CommitLineData
e20e5a6b
CP
1qwebirc.ui.QUI = new Class({
2 Extends: qwebirc.ui.NewLoginUI,
3 initialize: function(parentElement, theme) {
4 this.parent(parentElement, qwebirc.ui.QUI.Window, "qui");
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));
e20e5a6b
CP
15 this.qjsui.top.addClass("tabbar");
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.tabs = this.qjsui.top;
23 this.origtopic = this.topic = this.qjsui.topic;
24 this.origlines = this.lines = this.qjsui.middle;
25 this.orignicklist = this.nicklist = this.qjsui.right;
26
27 this.input = this.qjsui.bottom;
28 this.reflow = this.qjsui.reflow.bind(this.qjsui);
29
ff4befd8
CP
30 this.tabs.addEvent("mousewheel", function(x) {
31 var event = new Event(x);
32
33 /* up */
34 if(event.wheel > 0) {
35 this.nextWindow();
36 } else if(event.wheel < 0) {
37 /* down */
38 this.prevWindow();
39 }
40 event.stop();
41 }.bind(this));
42
e20e5a6b
CP
43 this.createInput();
44 this.reflow();
45 },
46 createInput: function() {
47 var form = new Element("form");
48 this.input.appendChild(form);
49 form.addClass("input");
50
51 var inputbox = new Element("input");
52 form.appendChild(inputbox);
53 this.inputbox = inputbox;
54
55 form.addEvent("submit", function(e) {
56 new Event(e).stop();
57
58 if(inputbox.value == "")
59 return;
60
3184781b 61 this.resetTabComplete();
e20e5a6b
CP
62 this.getActiveWindow().historyExec(inputbox.value);
63 inputbox.value = "";
64 }.bind(this));
65
3184781b
CP
66 inputbox.addEvent("focus", this.resetTabComplete.bind(this));
67 inputbox.addEvent("mousedown", this.resetTabComplete.bind(this));
68
e20e5a6b
CP
69 inputbox.addEvent("keydown", function(e) {
70 var resultfn;
71 var cvalue = inputbox.value;
3184781b 72
e20e5a6b
CP
73 if(e.key == "up") {
74 resultfn = this.commandhistory.upLine;
75 } else if(e.key == "down") {
76 resultfn = this.commandhistory.downLine;
3184781b
CP
77 } else if(e.key == "tab") {
78 new Event(e).stop();
79 this.tabComplete(inputbox);
80 return;
e20e5a6b 81 } else {
3184781b
CP
82 /* ideally alt and other keys wouldn't break this */
83 this.resetTabComplete();
e20e5a6b
CP
84 return;
85 }
86
3184781b 87 this.resetTabComplete();
e20e5a6b
CP
88 if((cvalue != "") && (this.lastcvalue != cvalue))
89 this.commandhistory.addLine(cvalue, true);
90
91 var result = resultfn.bind(this.commandhistory)();
92
93 new Event(e).stop();
94 if(!result)
95 result = "";
96 this.lastcvalue = result;
97
98 inputbox.value = result;
1d6756bc 99 qwebirc.util.setAtEnd(inputbox);
e20e5a6b
CP
100 }.bind(this));
101 },
102 setLines: function(lines) {
103 this.lines.parentNode.replaceChild(lines, this.lines);
104 this.qjsui.middle = this.lines = lines;
105 },
106 setChannelItems: function(nicklist, topic) {
107 if(!$defined(nicklist)) {
108 nicklist = this.orignicklist;
109 topic = this.origtopic;
110 }
111 this.nicklist.parentNode.replaceChild(nicklist, this.nicklist);
112 this.qjsui.right = this.nicklist = nicklist;
113
114 this.topic.parentNode.replaceChild(topic, this.topic);
115 this.qjsui.topic = this.topic = topic;
116 }
117});
118
119qwebirc.ui.QUI.JSUI = new Class({
bfbe72f9 120 Implements: [Events],
b1ee83f3
CP
121 initialize: function(class_, parent, sizer) {
122 this.parent = parent;
123 this.sizer = $defined(sizer)?sizer:parent;
124
24ede2cb
CP
125 this.class_ = class_;
126 this.create();
127
6c19eb8f
CP
128 this.reflowevent = null;
129
b1ee83f3 130 window.addEvent("resize", function() {
6c19eb8f 131 this.reflow(100);
b1ee83f3
CP
132 }.bind(this));
133 },
24ede2cb 134 applyClasses: function(pos, l) {
6c19eb8f 135 l.addClass("dynamicpanel");
24ede2cb 136 l.addClass(this.class_);
6c19eb8f 137
24ede2cb
CP
138 if(pos == "middle") {
139 l.addClass("leftboundpanel");
140 } else if(pos == "top") {
141 l.addClass("topboundpanel");
142 l.addClass("widepanel");
143 } else if(pos == "topic") {
144 l.addClass("widepanel");
145 } else if(pos == "right") {
146 l.addClass("rightboundpanel");
147 } else if(pos == "bottom") {
148 l.addClass("bottomboundpanel");
149 l.addClass("widepanel");
150 }
151 },
152 create: function() {
153 var XE = function(pos) {
154 var element = new Element("div");
155 this.applyClasses(pos, element);
b1ee83f3 156
24ede2cb
CP
157 this.parent.appendChild(element);
158 return element;
b1ee83f3
CP
159 }.bind(this);
160
24ede2cb
CP
161 this.top = XE("top");
162 this.topic = XE("topic");
163 this.middle = XE("middle");
164 this.right = XE("right");
165 this.bottom = XE("bottom");
b1ee83f3 166 },
6c19eb8f
CP
167 reflow: function(delay) {
168 if(!delay)
169 delay = 1;
170
171 if(this.reflowevent)
172 $clear(this.reflowevent);
173 this.__reflow();
174 this.reflowevent = this.__reflow.delay(delay, this);
175 },
176 __reflow: function() {
b1ee83f3
CP
177 var bottom = this.bottom;
178 var middle = this.middle;
179 var right = this.right;
180 var topic = this.topic;
181 var top = this.top;
182
183 var topicsize = topic.getSize();
184 var topsize = top.getSize();
185 var rightsize = right.getSize();
186 var bottomsize = bottom.getSize();
187 var docsize = this.sizer.getSize();
188
189 var mheight = (docsize.y - topsize.y - bottomsize.y - topicsize.y);
190 var mwidth = (docsize.x - rightsize.x);
191
192 topic.setStyle("top", topsize.y + "px");
193
194 middle.setStyle("top", (topsize.y + topicsize.y) + "px");
195 if(mheight > 0) {
196 middle.setStyle("height", mheight + "px");
197 right.setStyle("height", mheight + "px");
198 }
199
6c19eb8f 200 if(mwidth > 0)
b1ee83f3 201 middle.setStyle("width", mwidth + "px");
b1ee83f3
CP
202 right.setStyle("top", (topsize.y + topicsize.y) + "px");
203 right.setStyle("left", mwidth + "px");
204
205 bottom.setStyle("top", (docsize.y - bottomsize.y) + "px");
bfbe72f9 206 this.fireEvent("reflow");
b1ee83f3
CP
207 },
208 showChannel: function(state) {
209 var display = "none";
210 if(state)
211 display = "block";
212
213 this.right.setStyle("display", display);
214 this.topic.setStyle("display", display);
6c19eb8f
CP
215 },
216 showInput: function(state) {
217 this.bottom.setStyle("display", state?"block":"none");
b1ee83f3
CP
218 }
219});
35155ba7 220
e20e5a6b
CP
221qwebirc.ui.QUI.Window = new Class({
222 Extends: qwebirc.ui.Window,
f4ae92cc
CP
223
224 initialize: function(parentObject, client, type, name) {
225 this.parent(parentObject, client, type, name);
be0bd774 226
66de775f 227 this.tab = new Element("a", {"href": "#"});
f4ae92cc 228 this.tab.addClass("tab");
fd60516d
CP
229 this.tab.addEvent("focus", function() { this.blur() }.bind(this.tab));;
230
35155ba7 231 parentObject.tabs.appendChild(this.tab);
f4ae92cc
CP
232
233 this.tab.appendText(name);
66de775f
CP
234 this.tab.addEvent("click", function(e) {
235 new Event(e).stop();
f4ae92cc
CP
236 parentObject.selectWindow(this);
237 }.bind(this));
f4ae92cc 238
e20e5a6b
CP
239 if(type != qwebirc.ui.WINDOW_STATUS && type != qwebirc.ui.WINDOW_CONNECT) {
240 var tabclose = new Element("span");
241 tabclose.set("text", "X");
f4ae92cc
CP
242 tabclose.addClass("tabclose");
243 tabclose.addEvent("click", function(e) {
244 new Event(e).stop();
245
e20e5a6b 246 if(type == qwebirc.ui.WINDOW_CHANNEL)
f4ae92cc
CP
247 this.client.exec("/PART " + name);
248
249 this.close();
3184781b
CP
250
251 parentObject.inputbox.focus();
f4ae92cc 252 }.bind(this));
52090a1f 253
f4ae92cc
CP
254 this.tab.appendChild(tabclose);
255 }
be0bd774 256
be0bd774 257 this.lines = new Element("div");
6c19eb8f 258 this.parentObject.qjsui.applyClasses("middle", this.lines);
be0bd774 259 this.lines.addClass("lines");
6c19eb8f 260
b1ee83f3
CP
261 this.lines.addEvent("scroll", function() {
262 this.scrolleddown = this.scrolledDown();
be0bd774 263 }.bind(this));
be0bd774 264
e20e5a6b 265 if(type == qwebirc.ui.WINDOW_CHANNEL) {
be0bd774
CP
266 this.topic = new Element("div");
267 this.topic.addClass("topic");
b1ee83f3 268 this.topic.addClass("tab-invisible");
be0bd774 269 this.topic.set("html", "&nbsp;");
6c19eb8f 270 this.parentObject.qjsui.applyClasses("topic", this.topic);
be0bd774 271
52090a1f 272 this.prevNick = null;
66de775f
CP
273 this.nicklist = new Element("div");
274 this.nicklist.addClass("nicklist");
b1ee83f3 275 this.nicklist.addClass("tab-invisible");
cffd43cf 276 this.nicklist.addEvent("click", this.removePrevMenu.bind(this));
6c19eb8f 277 this.parentObject.qjsui.applyClasses("nicklist", this.nicklist);
be0bd774 278 }
b1ee83f3 279
e20e5a6b 280 if(type == qwebirc.ui.WINDOW_CHANNEL) {
359b7edd
CP
281 this.updateTopic("");
282 } else {
283 this.reflow();
284 }
b1ee83f3
CP
285 },
286 reflow: function() {
287 this.parentObject.reflow();
35155ba7
CP
288 },
289 onResize: function() {
290 if(this.scrolleddown)
291 this.scrollToBottom();
359b7edd 292 },
cffd43cf 293 createMenu: function(nick, parent) {
d2512acf 294 var e = new Element("div");
cffd43cf
CP
295 parent.appendChild(e);
296 e.addClass("menu");
297
298 qwebirc.ui.MENU_ITEMS.forEach(function(x) {
d2512acf 299 var e2 = new Element("a");
cffd43cf
CP
300 e.appendChild(e2);
301
302 e2.href = "#";
303 e2.set("text", "- " + x[0]);
304
305 e2.addEvent("focus", function() { this.blur() }.bind(e2));
306 e2.addEvent("click", function(ev) { new Event(ev.stop()); this.menuClick(x[1]); }.bind(this));
307 }.bind(this));
308 return e;
309 },
310 menuClick: function(fn) {
311 /*
312 this.prevNick.removeChild(this.prevNick.menu);
313 this.prevNick.menu = null;
314 */
315 fn.bind(this)(this.prevNick.realNick);
316 this.removePrevMenu();
317 },
d8272bcb
CP
318 moveMenuClass: function() {
319 if(!this.prevNick)
320 return;
321 if(this.nicklist.firstChild == this.prevNick) {
322 this.prevNick.removeClass("selected-middle");
323 } else {
324 this.prevNick.addClass("selected-middle");
325 }
326 },
cffd43cf
CP
327 removePrevMenu: function() {
328 if(!this.prevNick)
329 return;
330
331 this.prevNick.removeClass("selected");
d8272bcb 332 this.prevNick.removeClass("selected-middle");
cffd43cf
CP
333 if(this.prevNick.menu)
334 this.prevNick.removeChild(this.prevNick.menu);
335 this.prevNick = null;
336 },
52090a1f
CP
337 nickListAdd: function(nick, position) {
338 var e = new Element("a");
339 qwebirc.ui.insertAt(position, this.nicklist, e);
f4ae92cc 340
52090a1f
CP
341 e.href = "#";
342 e.appendChild(document.createTextNode(nick));
343
344 e.realNick = this.client.stripPrefix(nick);
345
346 e.addEvent("click", function(x) {
aab6d06a
CP
347 if(this.prevNick == e) {
348 this.removePrevMenu();
349 return;
350 }
351
cffd43cf 352 this.removePrevMenu();
52090a1f
CP
353 this.prevNick = e;
354 e.addClass("selected");
d8272bcb 355 this.moveMenuClass();
cffd43cf 356 e.menu = this.createMenu(x.realNick, e);
52090a1f
CP
357 new Event(x).stop();
358 }.bind(this));
359 e.addEvent("dblclick", function(x) {
360 new Event(x).stop();
361 this.client.exec("/QUERY " + e.realNick);
362 }.bind(this));
363
fd60516d 364 e.addEvent("focus", function() { this.blur() }.bind(e));
d8272bcb 365 this.moveMenuClass();
52090a1f
CP
366 return e;
367 },
368 nickListRemove: function(nick, stored) {
369 this.nicklist.removeChild(stored);
d8272bcb 370 this.moveMenuClass();
f4ae92cc
CP
371 },
372 updateTopic: function(topic) {
f4ae92cc
CP
373 var t = this.topic;
374
375 while(t.firstChild)
376 t.removeChild(t.firstChild);
377
66de775f 378 if(topic) {
1f06a70a 379 this.parent(topic, t);
66de775f 380 } else {
359b7edd
CP
381 var e = new Element("div");
382 e.set("text", "(no topic set)");
66de775f 383 e.addClass("emptytopic");
359b7edd 384 t.appendChild(e);
66de775f 385 }
359b7edd 386 this.reflow();
f4ae92cc
CP
387 },
388 select: function() {
e20e5a6b 389 var inputVisible = this.type != qwebirc.ui.WINDOW_CONNECT && this.type != qwebirc.ui.WINDOW_CUSTOM;
6c19eb8f 390
f4ae92cc 391 this.tab.removeClass("tab-unselected");
f4ae92cc 392 this.tab.addClass("tab-selected");
359b7edd 393
6c19eb8f
CP
394 this.parentObject.setLines(this.lines);
395 this.parentObject.setChannelItems(this.nicklist, this.topic);
396 this.parentObject.qjsui.showInput(inputVisible);
397 this.parentObject.qjsui.showChannel($defined(this.nicklist));
398
399 this.reflow();
24ede2cb 400
7c633700 401 this.parent();
25be5960 402
6c19eb8f
CP
403 if(inputVisible)
404 this.parentObject.inputbox.focus();
f4ae92cc
CP
405 },
406 deselect: function() {
407 this.parent();
408
f4ae92cc
CP
409 this.tab.removeClass("tab-selected");
410 this.tab.addClass("tab-unselected");
411 },
412 close: function() {
413 this.parent();
414
f4ae92cc
CP
415 this.parentObject.tabs.removeChild(this.tab);
416 },
417 addLine: function(type, line, colour) {
f4ae92cc
CP
418 var e = new Element("div");
419
420 if(colour) {
421 e.setStyles({"background": colour});
422 } else if(this.lastcolour) {
423 e.addClass("linestyle1");
424 } else {
425 e.addClass("linestyle2");
426 }
f4ae92cc 427 this.lastcolour = !this.lastcolour;
35155ba7 428
be0bd774
CP
429 this.parent(type, line, colour, e);
430 },
431 setHilighted: function(state) {
96f28062
CP
432 laststate = this.hilighted;
433
be0bd774 434 this.parent(state);
96f28062
CP
435
436 if(state == laststate)
437 return;
438
439 this.tab.removeClass("tab-hilight-activity");
440 this.tab.removeClass("tab-hilight-us");
441 this.tab.removeClass("tab-hilight-speech");
f4ae92cc 442
96f28062
CP
443 switch(this.hilighted) {
444 case qwebirc.ui.HILIGHT_US:
445 this.tab.addClass("tab-hilight-us");
446 break;
447 case qwebirc.ui.HILIGHT_SPEECH:
448 this.tab.addClass("tab-hilight-speech");
449 break;
450 case qwebirc.ui.HILIGHT_ACTIVITY:
451 this.tab.addClass("tab-hilight-activity");
452 break;
be0bd774 453 }
f4ae92cc
CP
454 }
455});