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