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