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