SMTPQueue: add ability to rerun the queue
[citadel.git] / webcit / static / wclib.js
1 /*
2  * JavaScript function library for WebCit.
3  *
4  * Copyright (c) 2005-2012 by the citadel.org team
5  *
6  * This program is open source software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License, version 3.
8  * the Free Software Foundation, either version 3 of the License, or
9  * 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * 
17  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19
20 var browserType;
21 var room_is_trash = 0;
22
23 var currentlyExpandedFloor = null;
24 var roomlist = null;
25 var currentDropTarget = null;
26
27 var supportsAddEventListener = (!!document.addEventListener);
28 var today = new Date();
29
30 var wc_log = "";
31 if (document.all) {browserType = "ie"}
32 if (window.navigator.userAgent.toLowerCase().match("gecko")) {
33         browserType= "gecko";
34 }
35 var ns6=document.getElementById&&!document.all;
36 Event.observe(window, 'load', ToggleTaskDateOrNoDateActivate);
37 Event.observe(window, 'load', taskViewActivate);
38 //document.observe("dom:loaded", setupPrefEngine);
39 document.observe("dom:loaded", setupIconBar);
40 function CtdlRandomString()  {
41         return((Math.random()+'').substr(3));
42 }
43 function strcmp ( str1, str2 ) {
44     // http://kevin.vanzonneveld.net
45     // +   original by: Waldo Malqui Silva
46     // +      input by: Steve Hilder
47     // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
48     // +    revised by: gorthaur
49     // *     example 1: strcmp( 'waldo', 'owald' );
50     // *     returns 1: 1
51     // *     example 2: strcmp( 'owald', 'waldo' );
52     // *     returns 2: -1
53  
54     return ( ( str1 == str2 ) ? 0 : ( ( str1 > str2 ) ? 1 : -1 ) );
55 }
56
57 function CtdlMarkLog($Which, $Status)
58 {
59     if ($Status)
60         document.getElementById($Which).checked == false;
61     else
62         document.getElementById($Which).checked == true;
63  
64 }
65 function ToggleLogEnable($Which)
66 {
67     var p;
68     var Status = !document.getElementById($Which).checked;
69     if (Status)
70         p= encodeURI('g_cmd=LOGS ' + $Which + '|0');
71     else
72         p= encodeURI('g_cmd=LOGS ' + $Which + '|1');
73     new Ajax.Request('ajax_servcmd', {
74         method: 'post',
75         parameters: p,
76         onComplete: CtdlMarkLog($Which, Status)
77     });
78 }
79
80 function SMTPRunQueue()
81 {
82     var p;
83
84     p= encodeURI('g_cmd=SMTP runqueue');
85     new Ajax.Request('ajax_servcmd', {
86         method: 'post',
87         parameters: p,
88         onComplete: function(transport) { ajax_important_message(transport.responseText.substr(4));}
89     });
90 }
91
92 function ToggleVisibility ($Which)
93 {
94         if (document.getElementById)
95         {
96                 if (document.getElementById($Which).style.display  == "none")
97                         document.getElementById($Which).style.display  = "inline";
98                 else
99                         document.getElementById($Which).style.display  = "none";
100         }
101 }
102
103 function emptyElement(element) {
104   childNodes = element.childNodes;
105   for(var i=0; i<childNodes.length; i++) {
106     try {
107     element.removeChild(childNodes[i]);
108     } catch (e) {
109       WCLog(e+"|"+e.description);
110     }
111   }
112 }
113 /** Implements superior internet explorer 'extract all child text from element' feature'. Falls back on buggy, patent violating standardized method */
114 function getTextContent(element) {
115   if (element.textContent == undefined) {
116     return element.innerText;
117   }
118   return element.textContent;
119 }
120 /** Same reasons as above */
121 function setTextContent(element, textContent) {
122   if(element.textContent == undefined) {
123     element.innerText = textContent;
124   } else {
125   element.textContent = textContent;
126   }
127 }
128
129 // We love string tokenizers.
130 function extract_token(source_string, token_num, delimiter) {
131         var i = 0;
132         var extracted_string = source_string;
133
134         if (token_num > 0) {
135                 for (i=0; i<token_num; ++i) {
136                         var j = extracted_string.indexOf(delimiter);
137                         if (j >= 0) {
138                                 extracted_string = extracted_string.substr(j+1);
139                         }
140                 }
141         }
142
143         j = extracted_string.indexOf(delimiter);
144         if (j >= 0) {
145                 extracted_string = extracted_string.substr(0, j);
146         }
147
148         return extracted_string;
149 }
150
151 function CtdlSpawnContextMenu(event, source) {
152   // remove any existing menus
153   disintergrateContextMenus(null);
154   var x = event.clientX-10; // cut a few pixels out so our mouseout works right
155   var y = event.clientY-10;
156   var contextDIV = document.createElement("div");
157   contextDIV.setAttribute("id", "ctdlContextMenu");
158   document.body.appendChild(contextDIV);
159   var sourceChildren = source.childNodes;
160   for(var j=0; j<sourceChildren.length; j++) {
161     contextDIV.appendChild(sourceChildren[j].cloneNode(true));
162   }
163   var leftRule = "left: "+x+"px;";
164   contextDIV.setAttribute("style", leftRule);
165   contextDIV.setAttribute("actual", leftRule);
166   contextDIV.style.top = y+"px";
167   contextDIV.style.display = "block";
168   $(contextDIV).observe('mouseout',disintergrateContextMenus);
169 }
170 function disintergrateContextMenus(event) {
171   var contextMenu = document.getElementById("ctdlContextMenu");
172   if (contextMenu) {
173     contextMenu.parentNode.removeChild(contextMenu);
174   }
175   Event.stopObserving(document,'click',disintergrateContextMenus);
176 }
177 // This code handles the popups for important-messages.
178 function hide_imsg_popup() {
179         if (browserType == "gecko") {
180                 document.poppedLayer = eval('document.getElementById(\'important_message\')');
181         }
182         else if (browserType == "ie") {
183                 document.poppedLayer = eval('document.all[\'important_message\']');
184         }
185         else {
186                 document.poppedLayer = eval('document.layers[\'`important_message\']');
187         }
188
189         document.poppedLayer.style.visibility = "hidden";
190 }
191
192 function unhide_imsg_popup() {
193         if (browserType == "gecko") {
194                 document.poppedLayer = eval('document.getElementById(\'important_message\')');
195         }
196         else if (browserType == "ie") {
197                 document.poppedLayer = eval('document.all[\'important_message\']');
198         }
199         else {
200                 document.poppedLayer = eval('document.layers[\'`important_message\']');
201         }
202
203         document.poppedLayer.style.visibility = "visible";
204     setTimeout('hide_imsg_popup()', 5000);
205 }
206
207 function ajax_important_message(messagetext)
208 {
209     if (browserType == "gecko") {
210         document.poppedLayer = eval('document.getElementById(\'important_message\')');
211     }
212     else if (browserType == "ie") {
213         document.poppedLayer = eval('document.all[\'important_message\']');
214     }
215     else {
216         document.poppedLayer = eval('document.layers[\'`important_message\']');
217     }
218     document.poppedLayer.style.visibility = "visible";
219     setTimeout('hide_imsg_popup()', 5000);
220     document.poppedLayer.innerHTML = messagetext;
221 }
222
223 // This function activates the ajax-powered recipient autocompleters on the message entry screen.
224 function activate_entmsg_autocompleters() {
225         new Ajax.Autocompleter('cc_id', 'cc_name_choices', 'cc_autocomplete', {} );
226         new Ajax.Autocompleter('bcc_id', 'bcc_name_choices', 'bcc_autocomplete', {} );
227         new Ajax.Autocompleter('recp_id', 'recp_name_choices', 'recp_autocomplete', {} );
228 }
229
230 function activate_iconbar_wholist_populat0r() 
231 {
232         new Ajax.PeriodicalUpdater('online_users', 'do_template?template=who_iconbar', {method: 'get', frequency: 30});
233 }
234
235 function setupIconBar() {
236
237         /* WARNING: VILE, SLEAZY HACK.  We determine the state of the box based on the image loaded. */
238         if ( $('expand_roomlist').src.substring($('expand_roomlist').src.length - 12) == "collapse.gif" ) {
239                 $('roomlist').style.display = 'block';
240                 $('roomlist').innerHTML = '';
241                 FillRooms(IconBarRoomList);
242         }
243         else {
244                 $('roomlist').style.display = 'none';
245         }
246
247         /* WARNING: VILE, SLEAZY HACK.  We determine the state of the box based on the image loaded. */
248         if ( $('expand_wholist').src.substring($('expand_wholist').src.length - 12) == "collapse.gif" ) {
249                 $('online_users').style.display = 'block';
250                 activate_iconbar_wholist_populat0r();
251         }
252         else {
253                 $('online_users').style.display = 'none';
254         }
255
256 }
257
258 function GenericTreeRoomList(roomlist) {
259   var currentExpanded = ctdlLocalPrefs.readPref("rooms_expanded");
260   var curRoomName = "";
261   if (document.getElementById("rmname")) {
262     curRoomName = getTextContent(document.getElementById("rmname"));
263   }
264   currentDropTargets = new Array();
265   var iconbar = document.getElementById("iconbar");
266   var ul = document.createElement("ul");
267   roomlist.appendChild(ul);
268   // Add mailbox, because they are special
269   var mailboxLI = document.createElement("li");
270   ul.appendChild(mailboxLI);
271   var mailboxSPAN = document.createElement("span");
272   var _mailbox = getTextContent(document.getElementById("mbox_template"));
273   mailboxSPAN.appendChild(document.createTextNode(_mailbox));
274   $(mailboxSPAN).observe('click', expandFloorEvent);
275   mailboxLI.appendChild(mailboxSPAN);
276   mailboxLI.className = "floor";
277   var mailboxUL = document.createElement("ul");
278   mailboxLI.appendChild(mailboxUL);
279   var mailboxRooms = GetMailboxRooms();
280   for(var i=0; i<mailboxRooms.length; i++) {
281           var room = mailboxRooms[i];
282           currentDropTargets.push(addRoomToList(mailboxUL, room, curRoomName));
283   }
284   if (currentExpanded != null && currentExpanded == _mailbox ) {
285           expandFloor(mailboxSPAN);
286   }
287   for(var a=0; a<floors.length; a++) {
288           var floor = floors[a];
289           var floornum = floor[0];
290     
291           if (floornum != -1)
292           {
293
294                   var name = floor[1];
295                   var floorLI = document.createElement("li");
296                   ul.appendChild(floorLI);
297                   var floorSPAN = document.createElement("span");
298                   floorSPAN.appendChild(document.createTextNode(name));
299                   $(floorSPAN).observe('click', expandFloorEvent);
300                   floorLI.appendChild(floorSPAN);
301                   floorLI.className = "floor";
302                   var floorUL = document.createElement("ul");
303                   floorLI.appendChild(floorUL);
304                   var roomsForFloor = GetRoomsByFloorNum(floornum);
305                   for(var b=0; b<roomsForFloor.length; b++) {
306                           var room = roomsForFloor[b];
307                           currentDropTargets.push(addRoomToList(floorUL, room, curRoomName));
308                   }
309                   if (currentExpanded != null && currentExpanded == name) {
310                           expandFloor(floorSPAN);
311                   }
312     }
313   }
314 }
315 function IconBarRoomList() {
316   roomlist = document.getElementById("roomlist");
317   GenericTreeRoomList(roomlist);
318 }
319 function KNRoomsRoomList() {
320   roomlist = document.getElementById("roomlist_knrooms");
321   GenericTreeRoomList(roomlist);
322 }
323
324 function addRoomToList(floorUL,room, roomToEmphasize) {
325   var roomName = room[RN_ROOM_NAME];
326   var flag = room[RN_ROOM_FLAG];
327   var curView = room[RN_CUR_VIEW];
328   var view = room[RN_DEF_VIEW];
329   var raflags = room[RN_RAFLAGS];
330   var isMailBox = ((flag & QR_MAILBOX) == QR_MAILBOX);
331   var hasNewMsgs = ((raflags & UA_HASNEWMSGS) == UA_HASNEWMSGS);
332   var roomLI = document.createElement("li");
333   var roomA = document.createElement("a");
334   roomA.setAttribute("href","dotgoto?room="+encodeURIComponent(roomName));
335   roomA.appendChild(document.createTextNode(roomName));
336   roomLI.appendChild(roomA);
337   floorUL.appendChild(roomLI);
338   var className = "room ";
339   if (view == VIEW_MAILBOX) {
340     className += "room-private"
341   } else if (view == VIEW_ADDRESSBOOK) {
342     className += "room-addr";
343   } else if (view == VIEW_CALENDAR || view == VIEW_CALBRIEF) {
344     className += "room-cal";
345   } else if (view == VIEW_TASKS) {
346     className += "room-tasks";
347   } else if (view == VIEW_NOTES) {
348     className += "room-notes";
349   } else {
350     className += "room-chat";
351   }
352   if (hasNewMsgs) {
353     className += " room-newmsgs";
354   }
355   if (roomName == roomToEmphasize) {
356     className += " room-emphasized";
357   }
358   roomLI.setAttribute("class", className);
359   roomA.dropTarget = true;
360   roomA.dropHandler = roomListDropHandler;
361   return roomLI;
362 }
363
364 function roomListDropHandler(target, dropped) {
365   if (dropped.getAttribute("citadel:msgid")) {
366       var room = getTextContent(target);
367       var msgIds = "";
368       for(msgId in currentlyMarkedRows) { //defined in summaryview.js
369           msgIds += ","+msgId;
370           if (msgIds.length > 800) {
371               var mvCommand = encodeURI("g_cmd=MOVE " + msgIds + "|"+room+"|0");
372               new Ajax.Request("ajax_servcmd", {
373                   parameters: mvCommand,
374                   method: 'post',
375               });
376               msgIds = "";
377           }
378
379       }
380       var mvCommand = encodeURI("g_cmd=MOVE " + msgIds + "|"+room+"|0");
381       new Ajax.Request('ajax_servcmd', {
382           method: 'post',
383           parameters: mvCommand,
384           onComplete: deleteAllMarkedRows()});
385   }
386 }
387 function expandFloorEvent(event) {
388   expandFloor(event.target);
389 }
390 function expandFloor(target) {
391   if (target.nodeName.toLowerCase() != "span") {
392     return; // ignore clicks on child UL
393   }
394   ctdlLocalPrefs.setPref("rooms_expanded", target.firstChild.nodeValue);
395   var parentUL = target.parentNode;
396   if (currentlyExpandedFloor != null) {
397     currentlyExpandedFloor.className = currentlyExpandedFloor.className.replace("floor-expanded","");
398   }
399   parentUL.className = parentUL.className + " floor-expanded";
400   currentlyExpandedFloor = parentUL;
401 }
402
403 // These functions handle moving sticky notes around the screen by dragging them
404
405 var uid_of_note_being_dragged = 0;
406 var saved_cursor_style = 'default';
407 var note_was_dragged = 0;
408
409 function NotesDragMouseUp(evt) {
410         document.onmouseup = null;
411         document.onmousemove = null;
412         if (document.layers) {
413                 document.releaseEvents(Event.MOUSEUP | Event.MOUSEMOVE);
414         }
415
416         d = $('note-' + uid_of_note_being_dragged);
417         d.style.cursor = saved_cursor_style;
418
419         // If any motion actually occurred, submit an ajax http call to record it to the server
420         if (note_was_dragged > 0) {
421                 p = 'note_uid=' + uid_of_note_being_dragged
422                         + '&left=' + d.style.left
423                         + '&top=' + d.style.top
424                         + '&r=' + CtdlRandomString();
425                 new Ajax.Request(
426                         'ajax_update_note',
427                         {
428                                 method: 'post',
429                                 parameters: p
430                         }
431                 );
432         }
433
434         uid_of_note_being_dragged = '';
435         return true;
436 }
437
438 function NotesDragMouseMove(evt) {
439         x = (ns6 ? evt.clientX : event.clientX);
440         x_increment = x - saved_x;
441         y = (ns6 ? evt.clientY : event.clientY);
442         y_increment = y - saved_y;
443
444         // Move the div
445         d = $('note-' + uid_of_note_being_dragged);
446
447         divTop = parseInt(d.style.top);
448         divLeft = parseInt(d.style.left);
449
450         d.style.top = (divTop + y_increment) + 'px';
451         d.style.left = (divLeft + x_increment) + 'px';
452
453         saved_x = x;
454         saved_y = y;
455         note_was_dragged = 1;
456         return true;
457 }
458
459
460 function NotesDragMouseDown(evt, uid) {
461         saved_x = (ns6 ? evt.clientX : event.clientX);
462         saved_y = (ns6 ? evt.clientY : event.clientY);
463         document.onmouseup = NotesDragMouseUp;
464         document.onmousemove = NotesDragMouseMove;
465         if (document.layers) {
466                 document.captureEvents(Event.MOUSEUP | Event.MOUSEMOVE);
467         }
468         uid_of_note_being_dragged = uid;
469         d = $('note-' + uid_of_note_being_dragged);
470         saved_cursor_style = d.style.cursor;
471         d.style.cursor = 'move';
472         return false;           // disable the default action
473 }
474
475
476 // Called when the user clicks on the palette icon of a sticky note to change its color.
477 // It toggles the color selector visible or invisible.
478
479 function NotesClickPalette(evt, uid) {
480         uid_of_note_being_colored = uid;
481         d = $('palette-' + uid_of_note_being_colored);
482
483         if (d.style.display) {
484                 if (d.style.display == 'none') {
485                         d.style.display = 'block';
486                 }
487                 else {
488                         d.style.display = 'none';
489                 }
490         }
491         else {
492                 d.style.display = 'block';
493         }
494
495         return true;
496 }
497
498
499 // Called when the user clicks on one of the colors in an open color selector.
500 // Sets the desired color and then closes the color selector.
501
502 function NotesClickColor(evt, uid, red, green, blue, notecolor, titlecolor) {
503         uid_of_note_being_colored = uid;
504         palette_button = $('palette-' + uid_of_note_being_colored);
505         note_div = $('note-' + uid_of_note_being_colored);
506         titlebar_div = $('titlebar-' + uid_of_note_being_colored);
507
508         // alert('FIXME red=' + red + ' green=' + green + ' blue=' + blue);
509
510         note_div.style.backgroundColor = notecolor;
511         titlebar_div.style.backgroundColor = titlecolor;
512         palette_button.style.display = 'none';
513
514         // submit an ajax http call to record it to the server
515         p = 'note_uid=' + uid_of_note_being_colored
516                 + '&red=' + red
517                 + '&green=' + green
518                 + '&blue=' + blue
519                 + '&r=' + CtdlRandomString();
520         new Ajax.Request(
521                 'ajax_update_note',
522                 {
523                         method: 'post',
524                         parameters: p
525                 }
526         );
527 }
528
529
530
531
532 // These functions handle resizing sticky notes by dragging the resize handle
533
534 var uid_of_note_being_resized = 0;
535 var saved_cursor_style = 'default';
536 var note_was_resized = 0;
537
538 function NotesResizeMouseUp(evt) {
539         document.onmouseup = null;
540         document.onmousemove = null;
541         if (document.layers) {
542                 document.releaseEvents(Event.MOUSEUP | Event.MOUSEMOVE);
543         }
544
545         d = $('note-' + uid_of_note_being_resized);
546         d.style.cursor = saved_cursor_style;
547
548         // If any motion actually occurred, submit an ajax http call to record it to the server
549         if (note_was_resized > 0) {
550                 p = 'note_uid=' + uid_of_note_being_resized
551                         + '&width=' + d.style.width
552                         + '&height=' + d.style.height
553                         + '&r=' + CtdlRandomString();
554                 new Ajax.Request(
555                         'ajax_update_note',
556                         {
557                                 method: 'post',
558                                 parameters: p
559                         }
560                 );
561         }
562
563         uid_of_note_being_resized = '';
564         return false;           // disable the default action
565 }
566
567 function NotesResizeMouseMove(evt) {
568         x = (ns6 ? evt.clientX : event.clientX);
569         x_increment = x - saved_x;
570         y = (ns6 ? evt.clientY : event.clientY);
571         y_increment = y - saved_y;
572
573         // Move the div
574         d = $('note-' + uid_of_note_being_resized);
575
576         divTop = parseInt(d.style.height);
577         divLeft = parseInt(d.style.width);
578
579         newHeight = divTop + y_increment;
580         if (newHeight < 50) newHeight = 50;
581
582         newWidth = divLeft + x_increment;
583         if (newWidth < 50) newWidth = 50;
584
585         d.style.height = newHeight + 'px';
586         d.style.width = newWidth + 'px';
587
588         saved_x = x;
589         saved_y = y;
590         note_was_resized = 1;
591         return false;           // disable the default action
592 }
593
594
595 function NotesResizeMouseDown(evt, uid) {
596         saved_x = (ns6 ? evt.clientX : event.clientX);
597         saved_y = (ns6 ? evt.clientY : event.clientY);
598         document.onmouseup = NotesResizeMouseUp;
599         document.onmousemove = NotesResizeMouseMove;
600         if (document.layers) {
601                 document.captureEvents(Event.MOUSEUP | Event.MOUSEMOVE);
602         }
603         uid_of_note_being_resized = uid;
604         d = $('note-' + uid_of_note_being_resized);
605         saved_cursor_style = d.style.cursor;
606         d.style.cursor = 'move';
607         return false;           // disable the default action
608 }
609
610
611 function DeleteStickyNote(evt, uid, confirmation_prompt) {
612         uid_of_note_being_deleted = uid;
613         d = $('note-' + uid_of_note_being_deleted);
614
615         if (confirm(confirmation_prompt)) {
616                 new Effect.Puff(d);
617
618                 // submit an ajax http call to delete it on the server
619                 p = 'note_uid=' + uid_of_note_being_deleted
620                         + '&deletenote=yes'
621                         + '&r=' + CtdlRandomString();
622                 new Ajax.Request(
623                         'ajax_update_note',
624                         {
625                                 method: 'post',
626                                 parameters: p
627                         }
628                 );
629         }
630 }
631
632 function ctdl_ts_getInnerText(el) {
633         if (typeof el == "string") return el;
634         if (typeof el == "undefined") { return el };
635         if (el.innerText) return el.innerText;  //Not needed but it is faster
636         var str = "";
637         
638         var cs = el.childNodes;
639         var l = cs.length;
640         for (var i = 0; i < l; i++) {
641                 switch (cs[i].nodeType) {
642                         case 1: //ELEMENT_NODE
643                                 str += ts_getInnerText(cs[i]);
644                                 break;
645                         case 3: //TEXT_NODE
646                                 str += cs[i].nodeValue;
647                                 break;
648                 }
649         }
650         return str;
651 }
652
653
654 // Place a gradient loadscreen on an element, e.g to use before Ajax.updater
655 function CtdlLoadScreen(elementid) {
656 var elem = document.getElementById(elementid);
657 elem.innerHTML = "<div align=center><br><table border=0 cellpadding=10 bgcolor=\"#ffffff\"><tr><td><img src=\"static/throbber.gif\" /><font color=\"#AAAAAA\">&nbsp;&nbsp;Loading....</font></td></tr></table><br></div>";
658 }
659
660
661
662 // Pop open the address book (target_input is the INPUT field to populate)
663
664 function PopOpenAddressBook(target_input) {
665         $('address_book_popup').style.display = 'block';
666         p = 'target_input=' + target_input + '&r=' + CtdlRandomString();
667         new Ajax.Updater(
668                 'address_book_popup_middle_div',
669                 'display_address_book_middle_div',
670                 {
671                         method: 'get',
672                         parameters: p,
673                         evalScripts: true
674                 }
675         );
676 }
677
678 function PopulateAddressBookInnerDiv(which_addr_book, target_input) {
679         $('address_book_inner_div').innerHTML = "<div align=center><br><table border=0 cellpadding=10 bgcolor=\"#ffffff\"><tr><td><img src=\"static/throbber.gif\" /><font color=\"#AAAAAA\">&nbsp;&nbsp;Loading....</font></td></tr></table><br></div>";
680         p = 'which_addr_book=' + which_addr_book
681           + '&target_input=' + target_input
682           + '&r=' + CtdlRandomString();
683         new Ajax.Updater(
684                 'address_book_inner_div',
685                 'display_address_book_inner_div',
686                 {
687                         method: 'get',
688                         parameters: p
689                 }
690         );
691 }
692
693 // What happens when a contact is selected from the address book popup
694 // (populate the specified target)
695
696 function AddContactsToTarget(target, whichaddr) {
697         while (whichaddr.selectedIndex != -1) {
698                 if (target.value.length > 0) {
699                         target.value = target.value + ', ';
700                 }
701                 target.value = target.value + whichaddr.value;
702                 whichaddr.options[whichaddr.selectedIndex].selected = false;
703         }
704 }
705
706 // Respond to a meeting invitation
707 function RespondToInvitation(question_divname, title_divname, msgnum, cal_partnum, sc) {
708         p = 'msgnum=' + msgnum + '&cal_partnum=' + cal_partnum + '&sc=' + sc ;
709         new Ajax.Updater(title_divname, 'respond_to_request', { method: 'post', parameters: p } );
710         Effect.Fade(question_divname, { duration: 0.5 });
711 }
712
713 // Handle a received RSVP
714 function HandleRSVP(question_divname, title_divname, msgnum, cal_partnum, sc) {
715         p = 'msgnum=' + msgnum + '&cal_partnum=' + cal_partnum + '&sc=' + sc ;
716         new Ajax.Updater(title_divname, 'handle_rsvp', { method: 'post', parameters: p } );
717         Effect.Fade(question_divname, { duration: 0.5 });
718 }
719 /* var fakeMouse = document.createEvent("MouseEvents");
720  fakeMouse.initMouseEvent("click", true, true, window, 
721    0,0,0,0,0, false, false, false, false, 0, null); */
722 // TODO: Collapse into one function
723 function toggleTaskDtStart(event) {
724         var checkBox = $('nodtstart');
725         var checkBoxTime = $('dtstart_time_assoc');
726         var dtstart = document.getElementById("dtstart");
727         var dtstart_date = document.getElementById("dtstart_date");
728         var dtstart_time = document.getElementById("dtstart_time");
729         if (checkBox.checked) {
730                 dtstart_date.style.visibility = "hidden";
731                 dtstart_time.style.visibility = "hidden";
732         } else {
733                 if (checkBoxTime.checked) {
734                         dtstart_time.style.visibility = "visible";
735                 } else {
736                         dtstart_time.style.visibility = "hidden";
737                 }
738                 dtstart_date.style.visibility = "visible";
739                 if (dtstart.value.length == 0)
740                         dtstart.dpck._initCurrentDate();
741         }
742 }
743 function toggleTaskDue(event) {
744         var checkBox = $('nodue');
745         var checkBoxTime = $('due_time_assoc');
746         var due = document.getElementById("due");
747         var due_date = document.getElementById("due_date");
748         var due_time = document.getElementById("due_time");
749         if (checkBox.checked) {
750                 due_date.style.visibility = "hidden";
751                 due_time.style.visibility = "hidden";
752         } else {
753                 if (checkBoxTime.checked) {
754                         due_time.style.visibility = "visible";
755                 } else {
756                         due_time.style.visibility = "hidden";
757                 }
758                 due_date.style.visibility = "visible";
759                 if (due.value.length == 0)
760                         due.dpck._initCurrentDate();
761         }
762 }
763 function ToggleTaskDateOrNoDateActivate(event) {
764         var dtstart = document.getElementById("nodtstart");
765         if (dtstart != null) {
766                 toggleTaskDtStart(null);
767                 toggleTaskDue(null);
768                 $('nodtstart').observe('click', toggleTaskDtStart);
769                 $('dtstart_time_assoc').observe('click', toggleTaskDtStart);
770                 $('nodue').observe('click', toggleTaskDue);
771                 $('due_time_assoc').observe('click', toggleTaskDue);
772         } 
773 }
774 function TaskViewGatherCategoriesFromTable() {
775         var table = $('taskview');
776         
777 }
778 function attachDatePicker(relative) {
779         var dpck = new DatePicker({
780         relative: relative,
781               language: 'en', //wclang.substr(0,2),
782               disableFutureDate: false,
783               dateFormat: [ ["yyyy", "mm", "dd"], "-"],
784               showDuration: 0.2
785         });
786         document.getElementById(relative).dpck = dpck; // attach a ref to it
787 }
788 function eventEditAllDay() {
789         var allDayCheck = document.getElementById("alldayevent");
790         var dtend_time = document.getElementById("dtend_time");
791         var dtstart_time = document.getElementById("dtstart_time");
792         if(allDayCheck.checked) {
793                 dtstart_time.style.visibility = "hidden";
794                 dtend_time.style.visibility = "hidden";
795         } else {
796                 dtstart_time.style.visibility = "visible";
797                 dtend_time.style.visibility = "visible";
798         }
799 }
800
801 // Functions which handle show/hide of various elements in the recurrence editor
802
803 function RecurrenceShowHide() {
804
805         if ($('is_recur').checked) {
806                 $('rrule_div').style.display = 'block';
807         }
808         else {
809                 $('rrule_div').style.display = 'none';
810         }
811
812         if ($('freq_selector').selectedIndex == 4) {
813                 $('weekday_selector').style.display = 'block';
814         }
815         else {
816                 $('weekday_selector').style.display = 'none';
817         }
818
819         if ($('freq_selector').selectedIndex == 5) {
820                 $('monthday_selector').style.display = 'block';
821         }
822         else {
823                 $('monthday_selector').style.display = 'none';
824         }
825
826         if ($('rrend_count').checked) {
827                 $('rrcount').disabled = false;
828         }
829         else {
830                 $('rrcount').disabled = true;
831         }
832
833         if ($('rrend_until').checked) {
834                 $('rruntil').disabled = false;
835         }
836         else {
837                 $('rruntil').disabled = true;
838         }
839
840         if ($('rrmonthtype_mday').checked) {
841                 $('rrmday').disabled = false;
842         }
843         else {
844                 $('rrmday').disabled = true;
845         }
846
847         if ($('rrmonthtype_wday').checked) {
848                 $('rrmweek').disabled = false;
849                 $('rrmweekday').disabled = false;
850         }
851         else {
852                 $('rrmweek').disabled = true;
853                 $('rrmweekday').disabled = true;
854         }
855
856         if ($('freq_selector').selectedIndex == 6) {
857                 $('yearday_selector').style.display = 'block';
858         }
859         else {
860                 $('yearday_selector').style.display = 'none';
861         }
862
863         $('ymday').innerHTML = 'XXXX-' + $('dtstart').value.substr(5);
864         $('rrmday').innerHTML = $('dtstart').value.substr(8);
865
866         if ($('rryeartype_ywday').checked) {
867                 $('rrymweek').disabled = false;
868                 $('rrymweekday').disabled = false;
869                 $('rrymonth').disabled = false;
870         }
871         else {
872                 $('rrymweek').disabled = true;
873                 $('rrymweekday').disabled = true;
874                 $('rrymonth').disabled = true;
875         }
876
877 }
878
879
880 // Enable or disable the 'check attendee availability' button depending on whether
881 // the attendees list is empty
882 function EnableOrDisableCheckButton()
883 {
884         if ($('attendees_box').value.length == 0) {
885                 $('check_button').disabled = true;
886         }
887         else {
888                 $('check_button').disabled = false;
889         }
890 }
891
892
893
894
895 function launchChat(event) {
896 window.open('chat', 'ctdl_chat_window', 'toolbar=no,location=no,directories=no,copyhistory=no,status=no,scrollbars=yes,resizable=yes');
897 }
898 // logger
899 function WCLog(msg) {
900   if (!!window.console && !!console.log) {
901     console.log(msg);
902   } else if (!!window.opera && !!opera.postError) {
903     opera.postError(msg);
904   } else {
905     wc_log += msg + "\r\n";
906   }
907 }
908
909 function RefreshSMTPqueueDisplay() {
910         new Ajax.Updater('smtpqueue_inner_div',
911         'display_smtpqueue_inner_div', { method: 'get',
912                 parameters: Math.random() } );
913 }
914
915 function DeleteSMTPqueueMsg(msgnum1, msgnum2) {
916         var p = encodeURI('g_cmd=DELE ' + msgnum1 + ',' + msgnum2);
917         new Ajax.Request(
918                 'ajax_servcmd', {
919                         method: 'post',
920                         parameters: p,
921                         onComplete: RefreshSMTPqueueDisplay()
922                 }
923         );
924 }
925
926
927 function ConfirmLogoff() {
928         new Ajax.Updater(
929                 'md-content',
930                 'do_template?template=confirmlogoff',
931                 {
932                         method: 'get',
933                         evalScripts: true,
934                         onSuccess: function(cl_success) {
935                                 toggleModal(1);
936                         }
937                 }
938         );
939 }
940
941
942 function switch_to_lang(new_lang) {
943         p = 'push?url=' + encodeURI(window.location);
944         new Ajax.Request(p, { method: 'get' } );
945         window.location = 'switch_language?lang=' + new_lang ;
946 }
947
948
949 function toggle_roomlist() 
950 {
951         /* WARNING: VILE, SLEAZY HACK.  We determine the state of the box based on the image loaded. */
952         if ( $('expand_roomlist').src.substring($('expand_roomlist').src.length - 12) == "collapse.gif" ) {
953                 $('roomlist').style.display = 'none';
954                 $('expand_roomlist').src = 'static/webcit_icons/expand.gif';
955                 wstate=0;
956         }
957
958         else {
959                 $('roomlist').style.display = 'block';
960                 $('expand_roomlist').src = 'static/webcit_icons/collapse.gif';
961                 $('roomlist').innerHTML = '';
962                 FillRooms(IconBarRoomList);
963                 wstate=1;
964         }
965
966         // tell the server what I did
967         p = 'toggle_roomlist_expanded_state?wstate=' + wstate + '?rand=' + Math.random() ;
968         new Ajax.Request(p, { method: 'get' } );
969
970         return false;   /* this prevents the click from registering as a roomlist button press */
971 }
972
973
974 function toggle_wholist() 
975 {
976         /* WARNING: VILE, SLEAZY HACK.  We determine the state of the box based on the image loaded. */
977         if ( $('expand_wholist').src.substring($('expand_wholist').src.length - 12) == "collapse.gif" ) {
978                 $('online_users').style.display = 'none';
979                 $('expand_wholist').src = 'static/webcit_icons/expand.gif';
980                 wstate=0;
981         }
982
983         else {
984                 $('online_users').style.display = 'block';
985                 $('expand_wholist').src = 'static/webcit_icons/collapse.gif';
986                 activate_iconbar_wholist_populat0r();
987                 wstate=1;
988         }
989
990         // tell the server what I did
991         p = 'toggle_wholist_expanded_state?wstate=' + wstate + '?rand=' + Math.random() ;
992         new Ajax.Request(p, { method: 'get' } );
993
994         return false;   /* this prevents the click from registering as a wholist button press */
995 }
996
997