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