2 Copyright (C) 2005 SKYRIX Software AG
4 This file is part of OpenGroupware.org.
6 OGo is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License as published by the
8 Free Software Foundation; either version 2, or (at your option) any
11 OGo is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
14 License for more details.
16 You should have received a copy of the GNU Lesser General Public
17 License along with OGo; see the file COPYING. If not, write to the
18 Free Software Foundation, 59 Temple Place - Suite 330, Boston, MA
21 /* some generic JavaScript code for SOGo */
30 var menus = new Array();
34 var lastClickedRow = null;
36 var weekStartIsMonday = true;
39 var allDocumentElements = null;
41 var userDefaults = null;
42 var userSettings = null;
44 // Ajax requests counts
45 var activeAjaxRequests = 0;
46 var removeFolderRequestCount = 0;
48 /* a W3C compliant document.all */
49 function getAllScopeElements(scope) {
50 var elements = new Array();
52 for (var i = 0; i < scope.childNodes.length; i++)
53 if (typeof(scope.childNodes[i]) == "object"
54 && scope.childNodes[i].tagName
55 && scope.childNodes[i].tagName != '')
57 elements.push(scope.childNodes[i]);
58 var childElements = getAllElements(scope.childNodes[i]);
59 if (childElements.length > 0)
60 elements.push(childElements);
66 function getAllElements(scope) {
73 && allDocumentElements != null)
74 elements = allDocumentElements;
77 elements = getAllScopeElements(scope);
78 if (scope == document)
79 allDocumentElements = elements;
86 http://www.robertnyman.com/2005/11/07/the-ultimate-getelementsbyclassname/ */
87 function getElementsByClassName2(_tag, _class, _scope) {
88 var regexp, classes, elements, element, returnElements;
90 _scope = _scope || document;
92 elements = (!_tag || _tag == "*"
93 ? getAllElements(null)
94 : _scope.getElementsByTagName(_tag));
97 classes = _class.split(/\s+/);
98 regexp = new RegExp("(^|\s+)("+ classes.join("|") +")(\s+|$)","i");
101 for(var i = 0; element = elements[i]; i++) {
102 if (regexp.test(element.className)) {
103 returnElements.push(element);
106 return returnElements;
112 function createElement(tagName, id, classes, attributes, htmlAttributes,
114 var newElement = $(document.createElement(tagName));
116 newElement.setAttribute("id", id);
118 if (typeof(classes) == "string")
119 newElement.addClassName(classes);
121 for (var i = 0; i < classes.length; i++)
122 newElement.addClassName(classes[i]);
125 for (var i in attributes)
126 newElement[i] = attributes[i];
128 for (var i in htmlAttributes)
129 newElement.setAttribute(i, htmlAttributes[i]);
131 parentNode.appendChild(newElement);
133 return $(newElement);
136 function ml_stripActionInURL(url) {
137 if (url[url.length - 1] != '/') {
140 i = url.lastIndexOf("/");
141 if (i != -1) url = url.substring(0, i);
143 if (url[url.length - 1] != '/') // ensure trailing slash
148 function URLForFolderID(folderID) {
149 var folderInfos = folderID.split(":");
151 if (folderInfos.length > 1) {
152 url = UserFolderURL + "../" + folderInfos[0];
153 if (!folderInfos[1].startsWith('/'))
155 url += folderInfos[1];
158 url = ApplicationBaseURL + folderInfos[0];
160 if (url[url.length-1] == '/')
161 url = url.substr(0, url.length-1);
166 function extractEmailAddress(mailTo) {
170 = /([a-zA-Z0-9]+[a-zA-Z0-9\._-]+[a-zA-Z0-9]+@[a-zA-Z0-9]+[a-zA-Z0-9\._-]+[a-zA-Z0-9]+)/g;
171 if (emailre.test(mailTo)) {
172 emailre.exec(mailTo);
179 function extractEmailName(mailTo) {
182 var tmpMailTo = mailTo.replace("<", "<");
183 tmpMailTo = tmpMailTo.replace(">", ">");
185 var emailNamere = /([ ]+)?(.+)\ </;
186 if (emailNamere.test(tmpMailTo)) {
187 emailNamere.exec(tmpMailTo);
188 emailName = RegExp.$2;
194 function sanitizeMailTo(dirtyMailTo) {
195 var emailName = extractEmailName(dirtyMailTo);
196 var email = "" + extractEmailAddress(dirtyMailTo);
199 if (emailName && emailName.length > 0)
200 mailto = emailName + ' <' + email + '>';
207 function openUserFolderSelector(callback, type) {
208 var urlstr = ApplicationBaseURL;
209 if (! urlstr.endsWith('/'))
211 urlstr += ("../../" + UserLogin + "/Contacts/userFolders");
212 var w = window.open(urlstr, "_blank",
213 "width=322,height=250,resizable=1,scrollbars=0,location=0");
215 window.userFolderCallback = callback;
216 window.userFolderType = type;
220 function openContactWindow(url, wId) {
222 wId = "" + (new Date().getTime());
223 var w = window.open(url, wId,
224 "width=450,height=600,resizable=0,location=0");
230 function openMailComposeWindow(url, wId) {
232 wId = "" + (new Date().getTime());
233 var w = window.open(url, wId,
234 "width=680,height=520,resizable=1,scrollbars=1,toolbar=0,"
235 + "location=0,directories=0,status=0,menubar=0"
242 function openMailTo(senderMailTo) {
243 var mailto = sanitizeMailTo(senderMailTo);
244 if (mailto.length > 0)
245 openMailComposeWindow(ApplicationBaseURL
246 + "/../Mail/compose?mailto=" + mailto);
248 return false; /* stop following the link */
251 function createHTTPClient() {
252 // http://developer.apple.com/internet/webcontent/xmlhttpreq.html
253 if (typeof XMLHttpRequest != "undefined")
254 return new XMLHttpRequest();
256 try { return new ActiveXObject("Msxml2.XMLHTTP"); }
258 try { return new ActiveXObject("Microsoft.XMLHTTP"); }
264 function appendDifferentiator(url) {
265 var url_nocache = url;
266 var position = url.indexOf('?', 0);
271 url_nocache += 'differentiator=' + Math.floor(Math.random()*50000);
276 function triggerAjaxRequest(url, callback, userdata) {
277 var http = createHTTPClient();
279 activeAjaxRequests += 1;
280 document.animTimer = setTimeout("checkAjaxRequestsState();", 200);
281 //url = appendDifferentiator(url);
284 http.open("POST", url, true);
286 http.onreadystatechange
288 //log ("state changed (" + http.readyState + "): " + url);
290 if (http.readyState == 4
291 && activeAjaxRequests > 0) {
293 http.callbackData = userdata;
296 activeAjaxRequests -= 1;
297 checkAjaxRequestsState();
301 activeAjaxRequests -= 1;
302 checkAjaxRequestsState();
303 log("AJAX Request, Caught Exception: " + e.name);
311 log("triggerAjaxRequest: error creating HTTP Client!");
317 function startAnimation(parent, nextNode) {
318 var anim = $("progressIndicator");
319 if (anim) return anim;
321 anim = document.createElement("img");
323 anim.id = "progressIndicator";
324 anim.src = ResourcesURL + "/busy.gif";
325 anim.setStyle({ visibility: "hidden" });
327 parent.insertBefore(anim, nextNode);
329 parent.appendChild(anim);
330 anim.setStyle({ visibility: "visible" });
335 function checkAjaxRequestsState() {
336 var toolbar = document.getElementById("toolbar");
338 if (activeAjaxRequests > 0
339 && !document.busyAnim) {
340 document.busyAnim = startAnimation(toolbar);
342 else if (activeAjaxRequests == 0
344 && document.busyAnim.parentNode) {
345 document.busyAnim.parentNode.removeChild(document.busyAnim);
346 document.busyAnim = null;
351 function isSafari3() {
352 return (navigator.appVersion.indexOf("Version") > -1);
355 function isSafari() {
356 //var agt = navigator.userAgent.toLowerCase();
357 //var is_safari = ((agt.indexOf('safari')!=-1)&&(agt.indexOf('mac')!=-1))?true:false;
359 return (navigator.vendor == "Apple Computer, Inc.");
362 function isHttpStatus204(status) {
363 return (status == 204 || // Firefox
364 (isSafari() && typeof(status) == 'undefined') || // Safari
365 status == 1223); // IE
368 function getTarget(event) {
369 event = event || window.event;
371 return event.target; // W3C DOM
373 return event.srcElement; // IE
376 function preventDefault(event) {
377 if (event.preventDefault)
378 event.preventDefault(); // W3C DOM
380 event.returnValue = false; // IE
383 function resetSelection(win) {
385 if (win && win.getSelection) {
386 t = win.getSelection().toString();
387 win.getSelection().removeAllRanges();
392 function refreshOpener() {
393 if (window.opener && !window.opener.closed) {
394 window.opener.location.reload();
400 function parseQueryString() {
401 var queryArray, queryDict
402 var key, value, s, idx;
403 queryDict.length = 0;
405 queryDict = new Array();
406 queryArray = location.search.substr(1).split('&');
407 for (var i in queryArray) {
408 if (!queryArray[i]) continue ;
410 idx = s.indexOf("=");
416 key = s.substr(0, idx);
417 value = unescape(s.substr(idx + 1));
420 if (typeof queryDict[key] == 'undefined')
423 queryDict[key] = value;
428 function generateQueryString(queryDict) {
430 for (var key in queryDict) {
435 s = s + key + "=" + escape(queryDict[key]);
440 function getQueryParaArray(s) {
441 if (s.charAt(0) == "?") s = s.substr(1, s.length - 1);
445 function getQueryParaValue(s, name) {
448 t = getQueryParaArray(s);
449 for (var i = 0; i < t.length; i++) {
452 if (s.indexOf(name) != 0)
455 s = s.substr(name.length, s.length - name.length);
456 return decodeURIComponent(s);
461 /* opener callback */
463 function triggerOpenerCallback() {
464 /* this code has some issue if the folder has no proper trailing slash! */
465 if (window.opener && !window.opener.closed) {
468 t = getQueryParaValue(window.location.search, "openerurl=");
469 cburl = window.opener.location.href;
470 if (cburl[cburl.length - 1] != "/") {
471 cburl = cburl.substr(0, cburl.lastIndexOf("/") + 1);
474 window.opener.location.href = cburl;
478 /* selection mechanism */
480 function deselectAll(parent) {
481 for (var i = 0; i < parent.childNodes.length; i++) {
482 var node = parent.childNodes.item(i);
483 if (node.nodeType == 1)
488 function isNodeSelected(node) {
489 return $(node).hasClassName('_selected');
492 function acceptMultiSelect(node) {
493 var response = false;
494 var attribute = node.getAttribute('multiselect');
495 if (attribute && attribute.length > 0) {
496 log("node '" + node.getAttribute("id")
497 + "' is still using old-stylemultiselect!");
498 response = (attribute.toLowerCase() == 'yes');
501 response = node.multiselect;
506 function onRowClick(event) {
507 var node = getTarget(event);
510 if (node.tagName == 'TD') {
511 node = node.parentNode; // select TR
512 rowIndex = node.rowIndex - $(node).up('table').down('thead').getElementsByTagName('tr').length;
514 else if (node.tagName == 'LI') {
515 // Find index of clicked row
516 var list = node.parentNode;
517 var items = list.childNodesWithTag("li");
518 for (var i = 0; i < items.length; i++) {
519 if (items[i] == node) {
526 var initialSelection = $(node.parentNode).getSelectedNodes();
527 if ((event.shiftKey == 1 || event.ctrlKey == 1)
529 && (acceptMultiSelect(node.parentNode)
530 || acceptMultiSelect(node.parentNode.parentNode))) {
532 $(node.parentNode).selectRange(lastClickedRow, rowIndex);
533 else if (isNodeSelected(node) == true) {
538 // At this point, should empty content of 3-pane view
540 // Single line selection
541 $(node.parentNode).deselectAll();
544 if (initialSelection != $(node.parentNode).getSelectedNodes()) {
545 // Selection has changed; fire mousedown event
546 var parentNode = node.parentNode;
547 if (parentNode.tagName == 'TBODY')
548 parentNode = parentNode.parentNode;
549 if (document.createEvent) {
550 var onSelectionChangeEvent;
552 onSelectionChangeEvent = document.createEvent("UIEvents");
554 onSelectionChangeEvent = document.createEvent("Events");
555 onSelectionChangeEvent.initEvent("mousedown", true, true);
556 parentNode.dispatchEvent(onSelectionChangeEvent);
558 else if (document.createEventObject) {
559 parentNode.fireEvent("onmousedown");
563 lastClickedRow = rowIndex;
570 // var acceptClick = false;
572 function popupMenu(event, menuId, target) {
573 document.menuTarget = target;
575 if (document.currentPopupMenu)
576 hideMenu(document.currentPopupMenu);
578 var popup = $(menuId);
579 var menuTop = Event.pointerY(event);
580 var menuLeft = Event.pointerX(event);
581 var heightDiff = (window.height()
582 - (menuTop + popup.offsetHeight));
584 menuTop += heightDiff;
586 var leftDiff = (window.width()
587 - (menuLeft + popup.offsetWidth));
589 menuLeft -= popup.offsetWidth;
591 if (popup.prepareVisibility)
592 popup.prepareVisibility();
593 popup.setStyle({ top: menuTop + "px",
594 left: menuLeft + "px",
595 visibility: "visible" });
597 document.currentPopupMenu = popup;
599 Event.observe(document.body, "click", onBodyClickMenuHandler);
601 preventDefault(event);
604 function getParentMenu(node) {
605 var currentNode, menuNode;
609 var menure = new RegExp("(^|\s+)menu(\s+|$)", "i");
611 while (menuNode == null
613 if (menure.test(currentNode.className))
614 menuNode = currentNode;
616 currentNode = currentNode.parentNode;
621 function onBodyClickMenuHandler(event) {
622 hideMenu(document.currentPopupMenu);
623 Event.stopObserving(document.body, "click", onBodyClickMenuHandler);
626 preventDefault(event);
629 function hideMenu(menuNode) {
632 if (menuNode.submenu) {
633 hideMenu(menuNode.submenu);
634 menuNode.submenu = null;
637 menuNode.setStyle({ visibility: "hidden" });
639 if (menuNode.parentMenuItem) {
640 Event.stopObserving(menuNode.parentMenuItem, "mouseover",
641 onMouseEnteredSubmenu);
642 Event.stopObserving(menuNode, "mouseover", onMouseEnteredSubmenu);
643 Event.stopObserving(menuNode.parentMenuItem, "mouseout", onMouseLeftSubmenu);
644 Event.stopObserving(menuNode, "mouseout", onMouseLeftSubmenu);
645 Event.stopObserving(menuNode.parentMenu, "mouseover",
646 onMouseEnteredParentMenu);
647 $(menuNode.parentMenuItem).removeClassName("submenu-selected");
648 menuNode.parentMenuItem.mouseInside = false;
649 menuNode.parentMenuItem = null;
650 menuNode.parentMenu.submenuItem = null;
651 menuNode.parentMenu.submenu = null;
652 menuNode.parentMenu = null;
655 if (document.createEvent) { // Safari & Mozilla
658 onhideEvent = document.createEvent("UIEvents");
660 onhideEvent = document.createEvent("Events");
661 onhideEvent.initEvent("mousedown", false, true);
662 menuNode.dispatchEvent(onhideEvent);
664 else if (document.createEventObject) { // IE
665 menuNode.fireEvent("onmousedown");
669 function onMenuEntryClick(event) {
670 var node = event.target;
672 id = getParentMenu(node).menuTarget;
677 function parseQueryParameters(url) {
678 var parameters = new Array();
680 var params = url.split("?")[1];
682 var pairs = params.split("&");
683 for (var i = 0; i < pairs.length; i++) {
684 var pair = pairs[i].split("=");
685 parameters[pair[0]] = pair[1];
692 function initLogConsole() {
693 var logConsole = $("logConsole");
695 logConsole.highlighted = false;
696 Event.observe(logConsole, "dblclick", onLogDblClick, false);
697 logConsole.innerHTML = "";
698 Event.observe(window, "keydown", onBodyKeyDown);
702 function onBodyKeyDown(event) {
703 if (event.keyCode == 27) {
705 preventDefault(event);
709 function onLogDblClick(event) {
710 var logConsole = $("logConsole");
711 logConsole.innerHTML = "";
714 function toggleLogConsole(event) {
715 var logConsole = $("logConsole");
716 var display = '' + logConsole.style.display;
717 if (display.length == 0) {
718 logConsole.setStyle({ display: 'block' });
720 logConsole.setStyle({ display: '' });
723 preventDefault(event);
726 function log(message) {
729 while (logWindow.opener)
730 logWindow = logWindow.opener;
732 var logConsole = logWindow.document.getElementById("logConsole");
734 logConsole.highlighted = !logConsole.highlighted;
735 if (message == '\c') {
736 logConsole.innerHTML = "";
739 var logMessage = message.replace("<", "<", "g");
740 logMessage = logMessage.replace(" ", " ", "g");
741 logMessage = logMessage.replace("\r\n", "<br />\n", "g");
742 logMessage = logMessage.replace("\n", "<br />\n", "g");
743 logMessage += '<br />' + "\n";
744 if (logConsole.highlighted)
745 logMessage = '<div class="highlighted">' + logMessage + '</div>';
746 logConsole.innerHTML += logMessage;
750 function backtrace() {
751 var func = backtrace.caller;
752 var str = "backtrace:\n";
758 str += " " + func.name;
760 str += " (" + this + ")";
763 str += "[anonymous]\n";
773 function popupSubmenu(event) {
774 if (this.submenu && this.submenu != "") {
775 var submenuNode = $(this.submenu);
776 var parentNode = getParentMenu(this);
777 if (parentNode.submenu)
778 hideMenu(parentNode.submenu);
779 submenuNode.parentMenuItem = this;
780 submenuNode.parentMenu = parentNode;
781 parentNode.submenuItem = this;
782 parentNode.submenu = submenuNode;
784 if (submenuNode.prepareVisibility)
785 submenuNode.prepareVisibility();
787 var menuTop = (parentNode.offsetTop - 1
790 < (menuTop + submenuNode.offsetHeight)
791 && submenuNode.offsetHeight < window.height())
792 menuTop -= submenuNode.offsetHeight - this.offsetHeight - 4;
793 var menuLeft = (parentNode.offsetLeft + parentNode.offsetWidth - 3);
795 < (menuLeft + submenuNode.offsetWidth))
796 menuLeft = parentNode.offsetLeft - submenuNode.offsetWidth + 3;
798 this.mouseInside = true;
799 Event.observe(this, "mouseover",
800 onMouseEnteredSubmenu.bindAsEventListener(this));
801 Event.observe(submenuNode, "mouseover",
802 onMouseEnteredSubmenu.bindAsEventListener(submenuNode));
803 Event.observe(this, "mouseout", onMouseLeftSubmenu.bindAsEventListener(this));
804 Event.observe(submenuNode, "mouseout",
805 onMouseLeftSubmenu.bindAsEventListener(submenuNode));
806 Event.observe(parentNode, "mouseover",
807 onMouseEnteredParentMenu.bindAsEventListener(parentNode));
808 $(this).addClassName("submenu-selected");
809 submenuNode.setStyle({ top: menuTop + "px",
810 left: menuLeft + "px",
811 visibility: "visible" });
812 preventDefault(event);
816 function onMouseEnteredParentMenu(event) {
817 if (this.submenuItem && !this.submenuItem.mouseInside)
818 hideMenu(this.submenu);
821 function onMouseEnteredSubmenu(event) {
822 $(this).mouseInside = true;
825 function onMouseLeftSubmenu(event) {
826 $(this).mouseInside = false;
830 function popupSearchMenu(event) {
831 var menuId = this.getAttribute("menuid");
832 var offset = Position.cumulativeOffset(this);
834 relX = Event.pointerX(event) - offset[0];
835 relY = Event.pointerY(event) - offset[1];
837 if (event.button == 0
839 event.cancelBubble = true;
840 event.returnValue = false;
842 if (document.currentPopupMenu)
843 hideMenu(document.currentPopupMenu);
845 var popup = $(menuId);
846 offset = Position.positionedOffset(this);
847 popup.setStyle({ top: this.offsetHeight + "px",
848 left: (offset[0] + 3) + "px",
849 visibility: "visible" });
851 document.currentPopupMenu = popup;
852 Event.observe(document.body, "click", onBodyClickMenuHandler);
856 function setSearchCriteria(event) {
857 var searchValue = $("searchValue");
858 var searchCriteria = $("searchCriteria");
860 searchValue.setAttribute("ghost-phrase", this.innerHTML);
861 searchCriteria.value = this.getAttribute('id');
863 if (this.parentNode.chosenNode)
864 this.parentNode.chosenNode.removeClassName("_chosen");
865 this.addClassName("_chosen");
866 this.parentNode.chosenNode = this;
869 function checkSearchValue(event) {
870 var form = event.target;
871 var searchValue = $("searchValue");
872 var ghostPhrase = searchValue.getAttribute('ghost-phrase');
874 if (searchValue.value == ghostPhrase)
875 searchValue.value = "";
878 function onSearchChange() {
879 log ("onSearchChange()...");
882 function configureSearchField() {
883 var searchValue = $("searchValue");
884 var searchOptions = $("searchOptions");
886 if (!searchValue) return;
888 Event.observe(searchValue, "mousedown",
889 onSearchMouseDown.bindAsEventListener(searchValue));
890 Event.observe(searchValue, "click",
891 popupSearchMenu.bindAsEventListener(searchValue));
892 Event.observe(searchValue, "blur",
893 onSearchBlur.bindAsEventListener(searchValue));
894 Event.observe(searchValue, "focus",
895 onSearchFocus.bindAsEventListener(searchValue));
896 Event.observe(searchValue, "keydown",
897 onSearchKeyDown.bindAsEventListener(searchValue));
899 if (!searchOptions) return;
901 // Set the checkmark to the first option
902 var firstOption = searchOptions.down('li');
903 firstOption.addClassName("_chosen");
904 searchOptions.chosenNode = firstOption;
907 function onSearchMouseDown(event) {
908 var superNode = this.parentNode.parentNode.parentNode;
909 relX = (Event.pointerX(event) - superNode.offsetLeft - this.offsetLeft);
910 relY = (Event.pointerY(event) - superNode.offsetTop - this.offsetTop);
913 event.cancelBubble = true;
914 event.returnValue = false;
918 function onSearchFocus() {
919 ghostPhrase = this.getAttribute("ghost-phrase");
920 if (this.value == ghostPhrase) {
922 this.setAttribute("modified", "");
927 this.setStyle({ color: "#000" });
930 function onSearchBlur(event) {
931 var ghostPhrase = this.getAttribute("ghost-phrase");
934 this.setAttribute("modified", "");
935 this.setStyle({ color: "#aaa" });
936 this.value = ghostPhrase;
937 refreshCurrentFolder();
938 } else if (this.value == ghostPhrase) {
939 this.setAttribute("modified", "");
940 this.setStyle({ color: "#aaa" });
942 this.setAttribute("modified", "yes");
943 this.setStyle({ color: "#000" });
947 function onSearchKeyDown(event) {
949 clearTimeout(this.timer);
951 this.timer = setTimeout("onSearchFormSubmit()", 1000);
954 function onSearchFormSubmit(event) {
955 var searchValue = $("searchValue");
956 var searchCriteria = $("searchCriteria");
957 var ghostPhrase = searchValue.getAttribute('ghost-phrase');
959 if (searchValue.value == ghostPhrase) return;
961 search["criteria"] = searchCriteria.value;
962 search["value"] = searchValue.value;
964 refreshCurrentFolder();
967 function initCriteria() {
968 var searchCriteria = $("searchCriteria");
969 var searchValue = $("searchValue");
971 if (!searchValue) return;
973 var searchOptions = $("searchOptions").childNodesWithTag("li");
974 if (searchOptions.length > 0) {
975 var firstChild = searchOptions[0];
976 searchCriteria.value = $(firstChild).getAttribute('id');
977 searchValue.setAttribute('ghost-phrase', firstChild.innerHTML);
978 if (searchValue.value == '') {
979 searchValue.value = firstChild.innerHTML;
980 searchValue.setAttribute("modified", "");
981 searchValue.setStyle({ color: "#aaa" });
986 /* toolbar buttons */
987 function popupToolbarMenu(node, menuId) {
988 if (document.currentPopupMenu)
989 hideMenu(document.currentPopupMenu);
991 var popup = $(menuId);
992 var top = ($(node).getStyle('top') || 0) + node.offsetHeight - 2;
993 popup.setStyle({ top: top + "px",
994 left: $(node).cascadeLeftOffset() + "px",
995 visibility: "visible" });
997 document.currentPopupMenu = popup;
998 Event.observe(document.body, "click", onBodyClickMenuHandler);
1001 /* contact selector */
1003 function folderSubscriptionCallback(http) {
1004 if (http.readyState == 4) {
1005 if (isHttpStatus204(http.status)) {
1006 if (http.callbackData)
1007 http.callbackData["method"](http.callbackData["data"]);
1010 window.alert(clabels["Unable to subscribe to that folder!"]);
1011 document.subscriptionAjaxRequest = null;
1014 log ("folderSubscriptionCallback Ajax error");
1017 function subscribeToFolder(refreshCallback, refreshCallbackData) {
1018 var folderData = refreshCallbackData["folder"].split(":");
1019 var username = folderData[0];
1020 var folderPath = folderData[1];
1021 if (username != UserLogin) {
1022 var url = (UserFolderURL + "../" + username
1023 + folderPath + "/subscribe");
1024 if (document.subscriptionAjaxRequest) {
1025 document.subscriptionAjaxRequest.aborted = true;
1026 document.subscriptionAjaxRequest.abort();
1029 var rfCbData = { method: refreshCallback, data: refreshCallbackData };
1030 document.subscriptionAjaxRequest = triggerAjaxRequest(url,
1031 folderSubscriptionCallback,
1035 refreshCallbackData["window"].alert(clabels["You cannot subscribe to a folder that you own!"]);
1038 function folderUnsubscriptionCallback(http) {
1039 if (http.readyState == 4) {
1040 removeFolderRequestCount--;
1041 if (isHttpStatus204(http.status)) {
1042 if (http.callbackData)
1043 http.callbackData["method"](http.callbackData["data"]);
1046 window.alert(clabels["Unable to unsubscribe from that folder!"]);
1050 function unsubscribeFromFolder(folder, refreshCallback, refreshCallbackData) {
1051 if (document.body.hasClassName("popup")) {
1052 window.opener.unsubscribeFromFolder(folder, refreshCallback,
1053 refreshCallbackData);
1056 var folderData = folder.split("_");
1057 var username = folderData[0];
1058 var folderPath = folderData[1];
1059 if (username.startsWith('/'))
1060 username = username.substring(1);
1061 if (username != UserLogin) {
1062 var url = (ApplicationBaseURL + folder + "/unsubscribe");
1063 removeFolderRequestCount++;
1064 var rfCbData = { method: refreshCallback, data: refreshCallbackData };
1065 triggerAjaxRequest(url, folderUnsubscriptionCallback, rfCbData);
1068 window.alert(clabels["You cannot unsubscribe from a folder that you own!"]);
1072 function accessToSubscribedFolder(serverFolder) {
1075 var parts = serverFolder.split(":");
1076 if (parts.length > 1) {
1077 var paths = parts[1].split("/");
1078 folder = "/" + parts[0] + "_" + paths[2];
1081 folder = serverFolder;
1086 function getSubscribedFolderOwner(serverFolder) {
1089 var parts = serverFolder.split(":");
1090 if (parts.length > 1) {
1097 function listRowMouseDownHandler(event) {
1098 preventDefault(event);
1099 //Event.stop(event);
1103 function initTabs() {
1104 var containers = document.getElementsByClassName("tabsContainer");
1105 for (var x = 0; x < containers.length; x++) {
1106 var container = containers[x];
1107 var firstTab = null;
1108 for (var i = 0; i < container.childNodes.length; i++) {
1109 if (container.childNodes[i].tagName == 'UL') {
1114 var nodes = container.childNodes[firstTab].childNodes;
1117 for (var i = 0; i < nodes.length; i++) {
1118 var currentNode = nodes[i];
1119 if (currentNode.tagName == 'LI') {
1122 Event.observe(currentNode, "mousedown",
1123 onTabMouseDown.bindAsEventListener(currentNode));
1124 Event.observe(currentNode, "click",
1125 onTabClick.bindAsEventListener(currentNode));
1126 //$(currentNode.getAttribute("target")).hide();
1130 nodes[firstTab].addClassName("first");
1131 nodes[firstTab].addClassName("active");
1132 container.activeTab = nodes[firstTab];
1134 var target = $(nodes[firstTab].getAttribute("target"));
1135 target.addClassName("active");
1140 function initMenus() {
1141 var menus = getMenus();
1143 for (var menuID in menus) {
1144 var menuDIV = $(menuID);
1146 initMenu(menuDIV, menus[menuID]);
1151 function initMenu(menuDIV, callbacks) {
1152 var lis = $(menuDIV.childNodesWithTag("ul")[0]).childNodesWithTag("li");
1153 for (var j = 0; j < lis.length; j++) {
1154 var node = $(lis[j]);
1155 Event.observe(node, "mousedown",
1156 listRowMouseDownHandler.bindAsEventListener(node),
1158 var callback = callbacks[j];
1160 if (typeof(callback) == "string") {
1161 if (callback == "-")
1162 node.addClassName("separator");
1164 node.submenu = callback;
1165 node.addClassName("submenu");
1166 Event.observe(node, "mouseover",
1167 popupSubmenu.bindAsEventListener(node));
1171 Event.observe(node, "mouseup",
1172 onBodyClickMenuHandler);
1173 Event.observe(node, "click",
1174 $(callback).bindAsEventListener(node));
1178 node.addClassName("disabled");
1182 function onTabMouseDown(event) {
1183 event.cancelBubble = true;
1184 preventDefault(event);
1187 function openExternalLink(anchor) {
1191 function openAclWindow(url) {
1192 var w = window.open(url, "aclWindow",
1193 "width=420,height=300,resizable=1,scrollbars=1,toolbar=0,"
1194 + "location=0,directories=0,status=0,menubar=0"
1195 + ",copyhistory=0");
1202 function getUsersRightsWindowHeight() {
1203 return usersRightsWindowHeight;
1206 function getUsersRightsWindowWidth() {
1207 return usersRightsWindowWidth;
1210 function getTopWindow() {
1211 var topWindow = null;
1212 var currentWindow = window;
1213 while (!topWindow) {
1214 if (currentWindow.document.body.hasClassName("popup")
1215 && currentWindow.opener)
1216 currentWindow = currentWindow.opener;
1218 topWindow = currentWindow;
1224 function onTabClick(event) {
1225 var node = getTarget(event); // LI element
1227 var target = node.getAttribute("target");
1229 var container = node.parentNode.parentNode;
1230 var oldTarget = container.activeTab.getAttribute("target");
1231 var content = $(target);
1232 var oldContent = $(oldTarget);
1234 oldContent.removeClassName("active");
1235 container.activeTab.removeClassName("active"); // previous LI
1236 container.activeTab = node;
1237 container.activeTab.addClassName("active"); // current LI
1238 content.addClassName("active");
1240 // Prototype alternative
1242 //oldContent.removeClassName("active");
1243 //container.activeTab.removeClassName("active"); // previous LI
1244 //container.activeTab = node;
1245 //container.activeTab.addClassName("active"); // current LI
1247 //container.activeTab.hide();
1248 //oldContent.hide();
1251 //container.activeTab = node;
1252 //container.activeTab.show();
1257 function enableAnchor(anchor) {
1258 var classStr = '' + anchor.getAttribute("class");
1259 var position = classStr.indexOf("_disabled", 0);
1260 if (position > -1) {
1261 var disabledHref = anchor.getAttribute("disabled-href");
1263 anchor.setAttribute("href", disabledHref);
1264 var disabledOnclick = anchor.getAttribute("disabled-onclick");
1265 if (disabledOnclick)
1266 anchor.setAttribute("onclick", disabledOnclick);
1267 anchor.removeClassName("_disabled");
1268 anchor.setAttribute("disabled-href", null);
1269 anchor.setAttribute("disabled-onclick", null);
1270 anchor.disabled = 0;
1275 function disableAnchor(anchor) {
1276 var classStr = '' + anchor.getAttribute("class");
1277 var position = classStr.indexOf("_disabled", 0);
1279 var href = anchor.getAttribute("href");
1281 anchor.setAttribute("disabled-href", href);
1282 var onclick = anchor.getAttribute("onclick");
1284 anchor.setAttribute("disabled-onclick", onclick);
1285 anchor.addClassName("_disabled");
1286 anchor.setAttribute("href", "#");
1287 anchor.setAttribute("onclick", "return false;");
1288 anchor.disabled = 1;
1294 var hD = "0123456789abcdef";
1295 var h = hD.substr(d & 15, 1);
1299 h = hD.substr(d & 15, 1) + h;
1305 function indexColor(number) {
1311 var colorTable = new Array(1, 1, 1);
1313 var currentValue = number;
1315 while (currentValue) {
1316 if (currentValue & 1)
1317 colorTable[index]++;
1325 + d2h((256 / colorTable[2]) - 1)
1326 + d2h((256 / colorTable[1]) - 1)
1327 + d2h((256 / colorTable[0]) - 1));
1333 function loadPreferences() {
1334 var url = UserFolderURL + "jsonDefaults";
1335 var http = createHTTPClient();
1336 http.open("GET", url, false);
1338 if (http.status == 200)
1339 userDefaults = http.responseText.evalJSON(true);
1341 url = UserFolderURL + "jsonSettings";
1342 http.open("GET", url, false);
1344 if (http.status == 200)
1345 userSettings = http.responseText.evalJSON(true);
1348 function onLoadHandler(event) {
1349 if (typeof UserLogin != "undefined")
1351 queryParameters = parseQueryParameters('' + window.location);
1352 if (!$(document.body).hasClassName("popup")) {
1356 configureSearchField();
1359 configureDragHandles();
1360 configureLinkBanner();
1361 var progressImage = $("progressIndicator");
1363 progressImage.parentNode.removeChild(progressImage);
1364 Event.observe(document.body, "contextmenu", onBodyClickContextMenu);
1367 function onBodyClickContextMenu(event) {
1368 preventDefault(event);
1371 function configureSortableTableHeaders(table) {
1372 var headers = $(table).getElementsByClassName("sortableTableHeader");
1373 for (var i = 0; i < headers.length; i++) {
1374 var header = headers[i];
1375 Event.observe(header, "click", onHeaderClick.bindAsEventListener(header))
1379 function onLinkBannerClick() {
1380 activeAjaxRequests++;
1381 checkAjaxRequestsState();
1384 function onPreferencesClick(event) {
1385 var urlstr = UserFolderURL + "preferences";
1386 var w = window.open(urlstr, "_blank",
1387 "width=430,height=250,resizable=0,scrollbars=0,location=0");
1391 preventDefault(event);
1394 function configureLinkBanner() {
1395 var linkBanner = $("linkBanner");
1397 var anchors = linkBanner.childNodesWithTag("a");
1398 for (var i = 1; i < 3; i++) {
1399 Event.observe(anchors[i], "mousedown", listRowMouseDownHandler);
1400 Event.observe(anchors[i], "click", onLinkBannerClick);
1402 Event.observe(anchors[4], "mousedown", listRowMouseDownHandler);
1403 Event.observe(anchors[4], "click", onPreferencesClick);
1404 if (anchors.length > 5)
1405 Event.observe(anchors[5], "click", toggleLogConsole);
1409 /* folder creation */
1410 function createFolder(name, okCB, notOkCB) {
1412 if (document.newFolderAjaxRequest) {
1413 document.newFolderAjaxRequest.aborted = true;
1414 document.newFolderAjaxRequest.abort();
1416 var url = ApplicationBaseURL + "/createFolder?name=" + name;
1417 document.newFolderAjaxRequest
1418 = triggerAjaxRequest(url, createFolderCallback,
1425 function createFolderCallback(http) {
1426 if (http.readyState == 4) {
1427 var data = http.callbackData;
1428 if (http.status == 201) {
1430 data.okCB(data.name, "/" + http.responseText, UserLogin);
1436 log("ajax problem:" + http.status);
1441 addEvent(window, 'load', onLoadHandler);
1443 function parent$(element) {
1444 return this.opener.document.getElementById(element);
1448 function refreshCurrentFolder() {
1451 function configureDragHandles() {
1454 function getMenus() {
1457 function onHeaderClick(event) {
1458 window.alert("generic headerClick");