]> code.citadel.org Git - citadel.git/blob - webcit/static/wclib.js
b56ab0bfa62fbba83933bd566da54aa52a1bbb68
[citadel.git] / webcit / static / wclib.js
1 //
2 // $Id: wclib.js,v 625.2 2005/09/18 04:04:32 ajc Exp $
3 //
4 // JavaScript function library for WebCit.
5 //
6 //
7
8
9 var browserType;
10 var room_is_trash = 0;
11
12 if (document.layers) {browserType = "nn4"}
13 if (document.all) {browserType = "ie"}
14 if (window.navigator.userAgent.toLowerCase().match("gecko")) {
15         browserType= "gecko"
16 }
17
18 var ns6=document.getElementById&&!document.all;
19
20
21 //
22 // This code handles the popups for instant messages.
23 //
24
25
26 function hide_page_popup() {
27         if (browserType == "gecko" )
28                 document.poppedLayer = eval('document.getElementById(\'page_popup\')');
29         else if (browserType == "ie")
30                 document.poppedLayer = eval('document.all[\'page_popup\']');
31         else
32                 document.poppedLayer = eval('document.layers[\'`page_popup\']');
33
34         document.poppedLayer.style.visibility = "hidden";
35 }
36
37 function hide_imsg_popup() {
38         if (browserType == "gecko" )
39                 document.poppedLayer = eval('document.getElementById(\'important_message\')');
40         else if (browserType == "ie")
41                 document.poppedLayer = eval('document.all[\'important_message\']');
42         else
43                 document.poppedLayer = eval('document.layers[\'`important_message\']');
44
45         document.poppedLayer.style.visibility = "hidden";
46 }
47
48 // This function activates the ajax-powered recipient autocompleters on the message entry screen.
49 function activate_entmsg_autocompleters() {
50         new Ajax.Autocompleter('cc_id', 'cc_name_choices', 'cc_autocomplete', {} );
51         new Ajax.Autocompleter('bcc_id', 'bcc_name_choices', 'bcc_autocomplete', {} );
52         new Ajax.Autocompleter('recp_id', 'recp_name_choices', 'recp_autocomplete', {} );
53 }
54
55
56
57 // Toggle the icon bar between menu/roomlist...
58 var which_div_expanded = null;
59 var num_drop_targets = 0;
60 var drop_targets_elements = new Array();
61 var drop_targets_roomnames = new Array();
62
63 function switch_to_room_list() {
64         $('iconbar').innerHTML = $('iconbar').innerHTML.substr(0, $('iconbar').innerHTML.indexOf('switch'));
65         new Ajax.Updater('iconbar', 'iconbar_ajax_rooms', { method: 'get' } );
66 }
67
68 function expand_floor(floor_div) {
69         if (which_div_expanded != null) {
70                 if ($(which_div_expanded) != null) {
71                         $(which_div_expanded).style.display = 'none' ;
72                 }
73         }
74
75         // clicking on the already-expanded floor causes the whole list to collapse
76         if (which_div_expanded == floor_div) {
77                 which_div_expanded = null;
78
79                 // notify the server that no floors are expanded
80                 new Ajax.Request(
81                         'set_floordiv_expanded/-1', {
82                                 method: 'post'
83                         }
84                 );
85                 return true;
86         }
87
88         // expand the requested floor
89         $(floor_div).style.display = 'block';
90         which_div_expanded = floor_div;
91
92         // notify the server of which floor is expanded
93         new Ajax.Request(
94                 'set_floordiv_expanded/'+floor_div, {
95                         method: 'post'
96                 }
97         );
98 }
99
100 function switch_to_menu_buttons() {
101         which_div_expanded = null;
102         num_drop_targets = 0;
103         new Ajax.Updater('iconbar', 'iconbar_ajax_menu', { method: 'get' } );
104 }
105
106
107 // Static variables for mailbox view...
108 //
109 var CtdlNumMsgsSelected = 0;
110 var CtdlMsgsSelected = new Array();
111
112 // This gets called when you single click on a message in the mailbox view.
113 // We know that the element id of the table row will be the letter 'm' plus the message number.
114 //
115 function CtdlSingleClickMsg(evt, msgnum) {
116
117         // Clear the preview pane until we load the new message
118         $('preview_pane').innerHTML = '';
119
120         // De-select any messages that were already selected, *unless* the Ctrl key
121         // is being pressed, in which case the user wants multi select.
122         if (!evt.ctrlKey) {
123                 if (CtdlNumMsgsSelected > 0) {
124                         for (i=0; i<CtdlNumMsgsSelected; ++i) {
125                                 $('m'+CtdlMsgsSelected[i]).style.backgroundColor = '#fff';
126                                 $('m'+CtdlMsgsSelected[i]).style.color = '#000';
127                         }
128                         CtdlNumMsgsSelected = 0;
129                 }
130         }
131
132         // For multi select ... is the message being clicked already selected?
133         already_selected = 0;
134         if ( (evt.ctrlKey) && (CtdlNumMsgsSelected > 0) ) {
135                 for (i=0; i<CtdlNumMsgsSelected; ++i) {
136                         if (CtdlMsgsSelected[i] == msgnum) {
137                                 already_selected = 1;
138                         }
139                 }
140         }
141
142         // Now select (or de-select) the message
143         if ( (evt.ctrlKey) && (already_selected == 1) ) {
144                 $('m'+msgnum).style.backgroundColor = '#fff';
145                 $('m'+msgnum).style.color = '#000';
146         }
147         else {
148                 $('m'+msgnum).style.backgroundColor='#69aaff';
149                 $('m'+msgnum).style.color='#fff';
150                 CtdlNumMsgsSelected = CtdlNumMsgsSelected + 1;
151                 CtdlMsgsSelected[CtdlNumMsgsSelected-1] = msgnum;
152         }
153
154         // Update the preview pane
155         new Ajax.Updater('preview_pane', 'msg/'+msgnum, { method: 'get' } );
156
157         // Mark the message as read
158         new Ajax.Request(
159                 'ajax_servcmd', {
160                         method: 'post',
161                         parameters: 'g_cmd=SEEN '+msgnum+'|1',
162                         onComplete: CtdlRemoveTheUnseenBold(msgnum)
163                 }
164         );
165
166         return false;           // try to defeat the default click behavior
167 }
168
169 // Delete selected messages.
170 function CtdlDeleteSelectedMessages(evt) {
171         
172         if (CtdlNumMsgsSelected < 1) {
173                 // Nothing to delete, so exit silently.
174                 return false;
175         }
176         for (i=0; i<CtdlNumMsgsSelected; ++i) {
177                 if (parseInt(room_is_trash) > 0) {
178                         new Ajax.Request(
179                                 'ajax_servcmd', {
180                                         method: 'post',
181                                         parameters: 'g_cmd=DELE ' + CtdlMsgsSelected[i],
182                                         onComplete: CtdlClearDeletedMsg(CtdlMsgsSelected[i])
183                                 }
184                         );
185                 }
186                 else {
187                         new Ajax.Request(
188                                 'ajax_servcmd', {
189                                         method: 'post',
190                                         parameters: 'g_cmd=MOVE ' + CtdlMsgsSelected[i] + '|_TRASH_|0',
191                                         onComplete: CtdlClearDeletedMsg(CtdlMsgsSelected[i])
192                                 }
193                         );
194                 }
195         }
196         CtdlNumMsgsSelected = 0;
197
198         // Clear the preview pane too.
199         $('preview_pane').innerHTML = '';
200 }
201
202
203 // Move selected messages.
204 function CtdlMoveSelectedMessages(evt, target_roomname) {
205         
206         if (CtdlNumMsgsSelected < 1) {
207                 // Nothing to delete, so exit silently.
208                 return false;
209         }
210         for (i=0; i<CtdlNumMsgsSelected; ++i) {
211                 new Ajax.Request(
212                         'ajax_servcmd', {
213                                 method:'post',
214                                 parameters:'g_cmd=MOVE ' + CtdlMsgsSelected[i] + '|' + target_roomname + '|0',
215                                 onComplete:CtdlClearDeletedMsg(CtdlMsgsSelected[i])
216                         }
217                 );
218         }
219         CtdlNumMsgsSelected = 0;
220
221         // Clear the preview pane too.
222         $('preview_pane').innerHTML = '';
223 }
224
225
226
227 // This gets called when the user touches the keyboard after selecting messages...
228 function CtdlMsgListKeyPress(evt) {
229         if(document.all) {                              // aIEeee
230                 var whichKey = window.event.keyCode;
231         }
232         else {                                          // non-sux0r browsers
233                 var whichKey = evt.which;
234         }
235         if (whichKey == 46) {                           // DELETE key
236                 CtdlDeleteSelectedMessages(evt);
237         }
238         return true;
239 }
240
241 // Take the boldface away from a message to indicate that it has been seen.
242 function CtdlRemoveTheUnseenBold(msgnum) {
243         $('m'+msgnum).style.fontWeight='normal';
244 }
245
246 // A message has been deleted, so yank it from the list.
247 // (IE barfs on m9999.innerHTML='' so we use a script.aculo.us effect instead.)
248 function CtdlClearDeletedMsg(msgnum) {
249         new Effect.Squish('m'+msgnum);
250 }
251
252
253 // These functions called when the user down-clicks on the message list resizer bar
254
255 var saved_x = 0;
256 var saved_y = 0;
257
258 function CtdlResizeMsgListMouseUp(evt) {
259         document.onmouseup = null;
260         document.onmousemove = null;
261         if (document.layers) {
262                 document.releaseEvents(Event.MOUSEUP | Event.MOUSEMOVE);
263         }
264         return true;
265 }
266
267 function CtdlResizeMsgListMouseMove(evt) {
268         y = (ns6 ? evt.clientY : event.clientY);
269         increment = y - saved_y;
270
271         // First move the bottom of the message list...
272         d = $('message_list');
273         if (d.offsetHeight){
274                 divHeight = d.offsetHeight;
275         }
276         else if (d.style.pixelHeight) {
277                 divHeight = d.style.pixelHeight;
278         }
279         d.style.height = (divHeight + increment) + 'px';
280
281         // Then move the top of the preview pane...
282         d = $('preview_pane');
283         if (d.offsetTop){
284                 divTop = d.offsetTop;
285         }
286         else if (d.style.pixelTop) {
287                 divTop = d.style.pixelTop;
288         }
289         d.style.top = (divTop + increment) + 'px';
290
291         // Resize the bottom of the preview pane...
292         d = $('preview_pane');
293         if (d.offsetHeight){
294                 divHeight = d.offsetHeight;
295         }
296         else if (d.style.pixelHeight) {
297                 divHeight = d.style.pixelHeight;
298         }
299         d.style.height = (divHeight - increment) + 'px';
300
301         // Then move the top of the slider bar.
302         d = $('resize_msglist');
303         if (d.offsetTop){
304                 divTop = d.offsetTop;
305         }
306         else if (d.style.pixelTop) {
307                 divTop = d.style.pixelTop;
308         }
309         d.style.top = (divTop + increment) + 'px';
310
311         saved_y = y;
312         return true;
313 }
314
315 function CtdlResizeMsgListMouseDown(evt) {
316         saved_y = (ns6 ? evt.clientY : event.clientY);
317         document.onmouseup = CtdlResizeMsgListMouseUp;
318         document.onmousemove = CtdlResizeMsgListMouseMove;
319         if (document.layers) {
320                 document.captureEvents(Event.MOUSEUP | Event.MOUSEMOVE);
321         }
322         return false;           // disable the default action
323 }
324
325
326
327 // These functions handle drag and drop message moving
328
329 var mm_div = null;
330
331 function CtdlMoveMsgMouseDown(evt, msgnum) {
332
333         // do the highlight first
334         CtdlSingleClickMsg(evt, msgnum);
335
336         // Now handle the possibility of dragging
337         saved_x = (ns6 ? evt.clientX : event.clientX);
338         saved_y = (ns6 ? evt.clientY : event.clientY);
339         document.onmouseup = CtdlMoveMsgMouseUp;
340         document.onmousemove = CtdlMoveMsgMouseMove;
341         if (document.layers) {
342                 document.captureEvents(Event.MOUSEUP | Event.MOUSEMOVE);
343         }
344
345         return false;
346 }
347
348 function CtdlMoveMsgMouseMove(evt) {
349         x = (ns6 ? evt.clientX : event.clientX);
350         y = (ns6 ? evt.clientY : event.clientY);
351
352         if ( (x == saved_x) && (y == saved_y) ) {
353                 return true;
354         }
355
356         if (CtdlNumMsgsSelected < 1) { 
357                 return true;
358         }
359
360         if (!mm_div) {
361
362
363                 drag_o_text = "<div style=\"overflow:none; background-color:#fff; color:#000; border: 1px solid black; filter:alpha(opacity=75); -moz-opacity:.75; opacity:.75;\"><tr><td>";
364                 for (i=0; i<CtdlNumMsgsSelected; ++i) {
365                         drag_o_text = drag_o_text + 
366                                 ctdl_ts_getInnerText(
367                                         $('m'+CtdlMsgsSelected[i]).cells[0]
368                                 ) + '<br>';
369                 }
370                 drag_o_text = drag_o_text + "<div>";
371
372                 mm_div = document.createElement("DIV");
373                 mm_div.style.position='absolute';
374                 mm_div.style.top = y + 'px';
375                 mm_div.style.left = x + 'px';
376                 mm_div.style.pixelHeight = '300';
377                 mm_div.style.pixelWidth = '300';
378                 mm_div.innerHTML = drag_o_text;
379                 document.body.appendChild(mm_div);
380         }
381         else {
382                 mm_div.style.top = y + 'px';
383                 mm_div.style.left = x + 'px';
384         }
385
386         return false;   // prevent the default mouse action from happening?
387 }
388
389 function CtdlMoveMsgMouseUp(evt) {
390         document.onmouseup = null;
391         document.onmousemove = null;
392         if (document.layers) {
393                 document.releaseEvents(Event.MOUSEUP | Event.MOUSEMOVE);
394         }
395
396         if (mm_div) {
397                 document.body.removeChild(mm_div);      
398                 mm_div = null;
399         }
400
401         if (num_drop_targets < 1) {     // nowhere to drop
402                 return true;
403         }
404
405         // Did we release the mouse button while hovering over a drop target?
406         // NOTE: this only works cross-browser because the iconbar div is always
407         //      positioned at 0,0.  Browsers differ in whether the 'offset'
408         //      functions return pos relative to the document or parent.
409
410         for (i=0; i<num_drop_targets; ++i) {
411
412                 x = (ns6 ? evt.clientX : event.clientX);
413                 y = (ns6 ? evt.clientY : event.clientY);
414
415                 l = parseInt(drop_targets_elements[i].offsetLeft);
416                 t = parseInt(drop_targets_elements[i].offsetTop);
417                 r = parseInt(drop_targets_elements[i].offsetLeft)
418                   + parseInt(drop_targets_elements[i].offsetWidth);
419                 b = parseInt(drop_targets_elements[i].offsetTop)
420                   + parseInt(drop_targets_elements[i].offsetHeight);
421
422                 /* alert('Offsets are: ' + l + ' ' + t + ' ' + r + ' ' + b + '.'); */
423         
424                 if ( (x >= l) && (x <= r) && (y >= t) && (y <= b) ) {
425                         // Yes, we dropped it on a hotspot.
426                         CtdlMoveSelectedMessages(evt, drop_targets_roomnames[i]);
427                         return true;
428                 }
429         }
430
431         return true;
432 }
433
434
435 function ctdl_ts_getInnerText(el) {
436         if (typeof el == "string") return el;
437         if (typeof el == "undefined") { return el };
438         if (el.innerText) return el.innerText;  //Not needed but it is faster
439         var str = "";
440         
441         var cs = el.childNodes;
442         var l = cs.length;
443         for (var i = 0; i < l; i++) {
444                 switch (cs[i].nodeType) {
445                         case 1: //ELEMENT_NODE
446                                 str += ts_getInnerText(cs[i]);
447                                 break;
448                         case 3: //TEXT_NODE
449                                 str += cs[i].nodeValue;
450                                 break;
451                 }
452         }
453         return str;
454 }
455
456