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