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