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