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