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