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 = -1;
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[0].endsWith('/')
154 || folderInfos[1].startsWith('/')))
156 url += folderInfos[1];
159 url = ApplicationBaseURL + folderInfos[0];
161 if (url[url.length-1] == '/')
162 url = url.substr(0, url.length-1);
167 function extractEmailAddress(mailTo) {
171 = /([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;
172 if (emailre.test(mailTo)) {
173 emailre.exec(mailTo);
180 function extractEmailName(mailTo) {
183 var tmpMailTo = mailTo.replace("<", "<");
184 tmpMailTo = tmpMailTo.replace(">", ">");
186 var emailNamere = /([ ]+)?(.+)\ </;
187 if (emailNamere.test(tmpMailTo)) {
188 emailNamere.exec(tmpMailTo);
189 emailName = RegExp.$2;
195 function sanitizeMailTo(dirtyMailTo) {
196 var emailName = extractEmailName(dirtyMailTo);
197 var email = "" + extractEmailAddress(dirtyMailTo);
200 if (emailName && emailName.length > 0)
201 mailto = emailName + ' <' + email + '>';
208 function openUserFolderSelector(callback, type) {
209 var urlstr = ApplicationBaseURL;
210 if (! urlstr.endsWith('/'))
212 urlstr += ("../../" + UserLogin + "/Contacts/userFolders");
213 var w = window.open(urlstr, "_blank",
214 "width=322,height=250,resizable=1,scrollbars=0,location=0");
216 window.userFolderCallback = callback;
217 window.userFolderType = type;
221 function openContactWindow(url, wId) {
222 if (typeof wId == "undefined")
225 var r = new RegExp("[\.\/-]", "g");
226 wId = wId.replace(r, "_");
229 var w = window.open(url, wId,
230 "width=450,height=600,resizable=0,location=0");
236 function openMailComposeWindow(url, wId) {
237 var parentWindow = this;
239 if (typeof wId == "undefined")
242 var r = new RegExp("[\.\/-]", "g");
243 wId = wId.replace(r, "_");
244 if (document.body.hasClassName("popup"))
245 parentWindow = window.opener;
248 var w = parentWindow.open(url, wId,
249 "width=680,height=520,resizable=1,scrollbars=1,toolbar=0,"
250 + "location=0,directories=0,status=0,menubar=0"
258 function openMailTo(senderMailTo) {
259 var mailto = sanitizeMailTo(senderMailTo);
260 if (mailto.length > 0)
261 openMailComposeWindow(ApplicationBaseURL
262 + "/../Mail/compose?mailto=" + mailto);
264 return false; /* stop following the link */
267 function createHTTPClient() {
268 // http://developer.apple.com/internet/webcontent/xmlhttpreq.html
269 if (typeof XMLHttpRequest != "undefined")
270 return new XMLHttpRequest();
272 try { return new ActiveXObject("Msxml2.XMLHTTP"); }
274 try { return new ActiveXObject("Microsoft.XMLHTTP"); }
280 function appendDifferentiator(url) {
281 var url_nocache = url;
282 var position = url.indexOf('?', 0);
287 url_nocache += 'differentiator=' + Math.floor(Math.random()*50000);
292 function triggerAjaxRequest(url, callback, userdata) {
293 var http = createHTTPClient();
295 activeAjaxRequests += 1;
296 document.animTimer = setTimeout("checkAjaxRequestsState();", 50);
297 //url = appendDifferentiator(url);
300 http.open("POST", url, true);
302 http.onreadystatechange
304 //log ("state changed (" + http.readyState + "): " + url);
306 if (http.readyState == 4
307 && activeAjaxRequests > 0) {
310 http.callbackData = userdata;
313 activeAjaxRequests -= 1;
314 checkAjaxRequestsState();
318 activeAjaxRequests -= 1;
319 checkAjaxRequestsState();
320 log("AJAX Request, Caught Exception: " + e.name);
328 log("triggerAjaxRequest: error creating HTTP Client!");
334 function startAnimation(parent, nextNode) {
335 var anim = $("progressIndicator");
336 if (anim) return anim;
338 anim = document.createElement("img");
340 anim.id = "progressIndicator";
341 anim.src = ResourcesURL + "/busy.gif";
342 anim.setStyle({ visibility: "hidden" });
344 parent.insertBefore(anim, nextNode);
346 parent.appendChild(anim);
347 anim.setStyle({ visibility: "visible" });
352 function checkAjaxRequestsState() {
353 var toolbar = document.getElementById("toolbar");
355 if (activeAjaxRequests > 0
356 && !document.busyAnim) {
357 document.busyAnim = startAnimation(toolbar);
359 else if (activeAjaxRequests == 0
361 && document.busyAnim.parentNode) {
362 document.busyAnim.parentNode.removeChild(document.busyAnim);
363 document.busyAnim = null;
368 function isSafari3() {
369 return (navigator.appVersion.indexOf("Version") > -1);
372 function isSafari() {
373 //var agt = navigator.userAgent.toLowerCase();
374 //var is_safari = ((agt.indexOf('safari')!=-1)&&(agt.indexOf('mac')!=-1))?true:false;
376 return (navigator.vendor == "Apple Computer, Inc.");
379 function isHttpStatus204(status) {
380 return (status == 204 || // Firefox
381 (isSafari() && typeof(status) == 'undefined') || // Safari
382 status == 1223); // IE
385 function getTarget(event) {
386 event = event || window.event;
388 return event.target; // W3C DOM
390 return event.srcElement; // IE
393 function preventDefault(event) {
394 if (event.preventDefault)
395 event.preventDefault(); // W3C DOM
397 event.returnValue = false; // IE
400 function resetSelection(win) {
402 if (win && win.getSelection) {
403 t = win.getSelection().toString();
404 win.getSelection().removeAllRanges();
409 function refreshOpener() {
410 if (window.opener && !window.opener.closed) {
411 window.opener.location.reload();
417 function parseQueryString() {
418 var queryArray, queryDict
419 var key, value, s, idx;
420 queryDict.length = 0;
422 queryDict = new Array();
423 queryArray = location.search.substr(1).split('&');
424 for (var i in queryArray) {
425 if (!queryArray[i]) continue ;
427 idx = s.indexOf("=");
433 key = s.substr(0, idx);
434 value = unescape(s.substr(idx + 1));
437 if (typeof queryDict[key] == 'undefined')
440 queryDict[key] = value;
445 function generateQueryString(queryDict) {
447 for (var key in queryDict) {
452 s = s + key + "=" + escape(queryDict[key]);
457 /* selection mechanism */
459 function deselectAll(parent) {
460 for (var i = 0; i < parent.childNodes.length; i++) {
461 var node = parent.childNodes.item(i);
462 if (node.nodeType == 1)
467 function isNodeSelected(node) {
468 return $(node).hasClassName('_selected');
471 function acceptMultiSelect(node) {
472 var response = false;
473 var attribute = node.getAttribute('multiselect');
474 if (attribute && attribute.length > 0) {
475 log("node '" + node.getAttribute("id")
476 + "' is still using old-stylemultiselect!");
477 response = (attribute.toLowerCase() == 'yes');
480 response = node.multiselect;
485 function onRowClick(event) {
486 var node = getTarget(event);
489 if (node.tagName == 'TD') {
490 node = node.parentNode; // select TR
491 rowIndex = node.rowIndex - $(node).up('table').down('thead').getElementsByTagName('tr').length;
493 else if (node.tagName == 'LI') {
494 // Find index of clicked row
495 var list = node.parentNode;
496 var items = list.childNodesWithTag("li");
497 for (var i = 0; i < items.length; i++) {
498 if (items[i] == node) {
505 var initialSelection = $(node.parentNode).getSelectedNodes();
506 if ((event.shiftKey == 1 || event.ctrlKey == 1)
507 && (lastClickedRow >= 0)
508 && (acceptMultiSelect(node.parentNode)
509 || acceptMultiSelect(node.parentNode.parentNode))) {
511 $(node.parentNode).selectRange(lastClickedRow, rowIndex);
512 else if (isNodeSelected(node) == true) {
517 // At this point, should empty content of 3-pane view
519 // Single line selection
520 $(node.parentNode).deselectAll();
523 if (initialSelection != $(node.parentNode).getSelectedNodes()) {
524 // Selection has changed; fire mousedown event
525 var parentNode = node.parentNode;
526 if (parentNode.tagName == 'TBODY')
527 parentNode = parentNode.parentNode;
528 if (document.createEvent) {
529 var onSelectionChangeEvent;
531 onSelectionChangeEvent = document.createEvent("UIEvents");
533 onSelectionChangeEvent = document.createEvent("Events");
534 onSelectionChangeEvent.initEvent("mousedown", true, true);
535 parentNode.dispatchEvent(onSelectionChangeEvent);
537 else if (document.createEventObject) {
538 parentNode.fireEvent("onmousedown");
542 lastClickedRow = rowIndex;
549 // var acceptClick = false;
551 function popupMenu(event, menuId, target) {
552 document.menuTarget = target;
554 if (document.currentPopupMenu)
555 hideMenu(document.currentPopupMenu);
557 var popup = $(menuId);
562 var pageContent = $("pageContent");
563 if (popup.parentNode.tagName != "BODY") {
564 var offset = pageContent.cascadeLeftOffset();
565 deltaX = -($(popup.parentNode).cascadeLeftOffset() - offset);
566 offset = pageContent.cascadeTopOffset();
567 deltaY = -($(popup.parentNode).cascadeTopOffset() - offset);
570 var menuTop = Event.pointerY(event) + deltaY;
571 var menuLeft = Event.pointerX(event) + deltaX;
572 var heightDiff = (window.height()
573 - (menuTop + popup.offsetHeight));
575 menuTop += heightDiff;
577 var leftDiff = (window.width()
578 - (menuLeft + popup.offsetWidth));
580 menuLeft -= popup.offsetWidth;
582 if (popup.prepareVisibility)
583 popup.prepareVisibility();
584 popup.setStyle({ top: menuTop + "px",
585 left: menuLeft + "px",
586 visibility: "visible" });
588 document.currentPopupMenu = popup;
590 Event.observe(document.body, "click", onBodyClickMenuHandler);
592 preventDefault(event);
595 function getParentMenu(node) {
596 var currentNode, menuNode;
600 var menure = new RegExp("(^|\s+)menu(\s+|$)", "i");
602 while (menuNode == null
604 if (menure.test(currentNode.className))
605 menuNode = currentNode;
607 currentNode = currentNode.parentNode;
612 function onBodyClickMenuHandler(event) {
613 hideMenu(document.currentPopupMenu);
614 Event.stopObserving(document.body, "click", onBodyClickMenuHandler);
617 preventDefault(event);
620 function hideMenu(menuNode) {
623 if (menuNode.submenu) {
624 hideMenu(menuNode.submenu);
625 menuNode.submenu = null;
628 menuNode.setStyle({ visibility: "hidden" });
630 if (menuNode.parentMenuItem) {
631 Event.stopObserving(menuNode.parentMenuItem, "mouseover",
632 onMouseEnteredSubmenu);
633 Event.stopObserving(menuNode, "mouseover", onMouseEnteredSubmenu);
634 Event.stopObserving(menuNode.parentMenuItem, "mouseout", onMouseLeftSubmenu);
635 Event.stopObserving(menuNode, "mouseout", onMouseLeftSubmenu);
636 Event.stopObserving(menuNode.parentMenu, "mouseover",
637 onMouseEnteredParentMenu);
638 $(menuNode.parentMenuItem).removeClassName("submenu-selected");
639 menuNode.parentMenuItem.mouseInside = false;
640 menuNode.parentMenuItem = null;
641 menuNode.parentMenu.submenuItem = null;
642 menuNode.parentMenu.submenu = null;
643 menuNode.parentMenu = null;
646 if (document.createEvent) { // Safari & Mozilla
649 onhideEvent = document.createEvent("UIEvents");
651 onhideEvent = document.createEvent("Events");
652 onhideEvent.initEvent("mousedown", false, true);
653 menuNode.dispatchEvent(onhideEvent);
655 else if (document.createEventObject) { // IE
656 menuNode.fireEvent("onmousedown");
660 function onMenuEntryClick(event) {
661 var node = event.target;
663 id = getParentMenu(node).menuTarget;
668 function parseQueryParameters(url) {
669 var parameters = new Array();
671 var params = url.split("?")[1];
673 var pairs = params.split("&");
674 for (var i = 0; i < pairs.length; i++) {
675 var pair = pairs[i].split("=");
676 parameters[pair[0]] = pair[1];
683 function initLogConsole() {
684 var logConsole = $("logConsole");
686 logConsole.highlighted = false;
687 Event.observe(logConsole, "dblclick", onLogDblClick, false);
688 logConsole.innerHTML = "";
689 Event.observe(window, "keydown", onBodyKeyDown);
693 function onBodyKeyDown(event) {
694 if (event.keyCode == 27) {
696 preventDefault(event);
700 function onLogDblClick(event) {
701 var logConsole = $("logConsole");
702 logConsole.innerHTML = "";
705 function toggleLogConsole(event) {
706 var logConsole = $("logConsole");
707 var display = '' + logConsole.style.display;
708 if (display.length == 0) {
709 logConsole.setStyle({ display: 'block' });
711 logConsole.setStyle({ display: '' });
714 preventDefault(event);
717 function log(message) {
720 while (logWindow.opener)
721 logWindow = logWindow.opener;
723 var logConsole = logWindow.document.getElementById("logConsole");
725 logConsole.highlighted = !logConsole.highlighted;
726 if (message == '\c') {
727 logConsole.innerHTML = "";
730 var logMessage = message.replace("<", "<", "g");
731 logMessage = logMessage.replace(" ", " ", "g");
732 logMessage = logMessage.replace("\r\n", "<br />\n", "g");
733 logMessage = logMessage.replace("\n", "<br />\n", "g");
734 logMessage += '<br />' + "\n";
735 if (logConsole.highlighted)
736 logMessage = '<div class="highlighted">' + logMessage + '</div>';
737 logConsole.innerHTML += logMessage;
741 function backtrace() {
742 var func = backtrace.caller;
743 var str = "backtrace:\n";
749 str += " " + func.name;
751 str += " (" + this + ")";
754 str += "[anonymous]\n";
764 function popupSubmenu(event) {
765 if (this.submenu && this.submenu != "") {
766 var submenuNode = $(this.submenu);
767 var parentNode = getParentMenu(this);
768 if (parentNode.submenu)
769 hideMenu(parentNode.submenu);
770 submenuNode.parentMenuItem = this;
771 submenuNode.parentMenu = parentNode;
772 parentNode.submenuItem = this;
773 parentNode.submenu = submenuNode;
775 if (submenuNode.prepareVisibility)
776 submenuNode.prepareVisibility();
778 var menuTop = (parentNode.offsetTop - 1
781 < (menuTop + submenuNode.offsetHeight)
782 && submenuNode.offsetHeight < window.height())
783 menuTop -= submenuNode.offsetHeight - this.offsetHeight - 4;
784 var menuLeft = (parentNode.offsetLeft + parentNode.offsetWidth - 3);
786 < (menuLeft + submenuNode.offsetWidth))
787 menuLeft = parentNode.offsetLeft - submenuNode.offsetWidth + 3;
789 this.mouseInside = true;
790 Event.observe(this, "mouseover",
791 onMouseEnteredSubmenu.bindAsEventListener(this));
792 Event.observe(submenuNode, "mouseover",
793 onMouseEnteredSubmenu.bindAsEventListener(submenuNode));
794 Event.observe(this, "mouseout", onMouseLeftSubmenu.bindAsEventListener(this));
795 Event.observe(submenuNode, "mouseout",
796 onMouseLeftSubmenu.bindAsEventListener(submenuNode));
797 Event.observe(parentNode, "mouseover",
798 onMouseEnteredParentMenu.bindAsEventListener(parentNode));
799 $(this).addClassName("submenu-selected");
800 submenuNode.setStyle({ top: menuTop + "px",
801 left: menuLeft + "px",
802 visibility: "visible" });
803 preventDefault(event);
807 function onMouseEnteredParentMenu(event) {
808 if (this.submenuItem && !this.submenuItem.mouseInside)
809 hideMenu(this.submenu);
812 function onMouseEnteredSubmenu(event) {
813 $(this).mouseInside = true;
816 function onMouseLeftSubmenu(event) {
817 $(this).mouseInside = false;
821 function popupSearchMenu(event) {
822 var menuId = this.getAttribute("menuid");
823 var offset = Position.cumulativeOffset(this);
825 relX = Event.pointerX(event) - offset[0];
826 relY = Event.pointerY(event) - offset[1];
828 if (event.button == 0
830 event.cancelBubble = true;
831 event.returnValue = false;
833 if (document.currentPopupMenu)
834 hideMenu(document.currentPopupMenu);
836 var popup = $(menuId);
837 offset = Position.positionedOffset(this);
838 popup.setStyle({ top: this.offsetHeight + "px",
839 left: (offset[0] + 3) + "px",
840 visibility: "visible" });
842 document.currentPopupMenu = popup;
843 Event.observe(document.body, "click", onBodyClickMenuHandler);
847 function setSearchCriteria(event) {
848 var searchValue = $("searchValue");
849 var searchCriteria = $("searchCriteria");
851 searchValue.setAttribute("ghost-phrase", this.innerHTML);
852 searchCriteria.value = this.getAttribute('id');
854 if (this.parentNode.chosenNode)
855 this.parentNode.chosenNode.removeClassName("_chosen");
856 this.addClassName("_chosen");
857 this.parentNode.chosenNode = this;
860 function checkSearchValue(event) {
861 var form = event.target;
862 var searchValue = $("searchValue");
863 var ghostPhrase = searchValue.getAttribute('ghost-phrase');
865 if (searchValue.value == ghostPhrase)
866 searchValue.value = "";
869 function onSearchChange() {
870 log ("onSearchChange()...");
873 function configureSearchField() {
874 var searchValue = $("searchValue");
875 var searchOptions = $("searchOptions");
877 if (!searchValue) return;
879 Event.observe(searchValue, "mousedown",
880 onSearchMouseDown.bindAsEventListener(searchValue));
881 Event.observe(searchValue, "click",
882 popupSearchMenu.bindAsEventListener(searchValue));
883 Event.observe(searchValue, "blur",
884 onSearchBlur.bindAsEventListener(searchValue));
885 Event.observe(searchValue, "focus",
886 onSearchFocus.bindAsEventListener(searchValue));
887 Event.observe(searchValue, "keydown",
888 onSearchKeyDown.bindAsEventListener(searchValue));
890 if (!searchOptions) return;
892 // Set the checkmark to the first option
893 var firstOption = searchOptions.down('li');
894 firstOption.addClassName("_chosen");
895 searchOptions.chosenNode = firstOption;
898 function onSearchMouseDown(event) {
899 var superNode = this.parentNode.parentNode.parentNode;
900 relX = (Event.pointerX(event) - superNode.offsetLeft - this.offsetLeft);
901 relY = (Event.pointerY(event) - superNode.offsetTop - this.offsetTop);
904 event.cancelBubble = true;
905 event.returnValue = false;
909 function onSearchFocus() {
910 ghostPhrase = this.getAttribute("ghost-phrase");
911 if (this.value == ghostPhrase) {
913 this.setAttribute("modified", "");
918 this.setStyle({ color: "#000" });
921 function onSearchBlur(event) {
922 var ghostPhrase = this.getAttribute("ghost-phrase");
925 this.setAttribute("modified", "");
926 this.setStyle({ color: "#aaa" });
927 this.value = ghostPhrase;
928 refreshCurrentFolder();
929 } else if (this.value == ghostPhrase) {
930 this.setAttribute("modified", "");
931 this.setStyle({ color: "#aaa" });
933 this.setAttribute("modified", "yes");
934 this.setStyle({ color: "#000" });
938 function onSearchKeyDown(event) {
940 clearTimeout(this.timer);
942 this.timer = setTimeout("onSearchFormSubmit()", 1000);
945 function onSearchFormSubmit(event) {
946 var searchValue = $("searchValue");
947 var searchCriteria = $("searchCriteria");
948 var ghostPhrase = searchValue.getAttribute('ghost-phrase');
950 if (searchValue.value == ghostPhrase) return;
952 search["criteria"] = searchCriteria.value;
953 search["value"] = searchValue.value;
955 refreshCurrentFolder();
958 function initCriteria() {
959 var searchCriteria = $("searchCriteria");
960 var searchValue = $("searchValue");
962 if (!searchValue) return;
964 var searchOptions = $("searchOptions").childNodesWithTag("li");
965 if (searchOptions.length > 0) {
966 var firstChild = searchOptions[0];
967 searchCriteria.value = $(firstChild).getAttribute('id');
968 searchValue.setAttribute('ghost-phrase', firstChild.innerHTML);
969 if (searchValue.value == '') {
970 searchValue.value = firstChild.innerHTML;
971 searchValue.setAttribute("modified", "");
972 searchValue.setStyle({ color: "#aaa" });
977 /* toolbar buttons */
978 function popupToolbarMenu(node, menuId) {
979 if (document.currentPopupMenu)
980 hideMenu(document.currentPopupMenu);
982 var popup = $(menuId);
983 var top = ($(node).getStyle('top') || 0) + node.offsetHeight - 2;
984 popup.setStyle({ top: top + "px",
985 left: $(node).cascadeLeftOffset() + "px",
986 visibility: "visible" });
988 document.currentPopupMenu = popup;
989 Event.observe(document.body, "click", onBodyClickMenuHandler);
992 /* contact selector */
994 function folderSubscriptionCallback(http) {
995 if (http.readyState == 4) {
996 if (isHttpStatus204(http.status)) {
997 if (http.callbackData)
998 http.callbackData["method"](http.callbackData["data"]);
1001 window.alert(clabels["Unable to subscribe to that folder!"]);
1002 document.subscriptionAjaxRequest = null;
1005 log ("folderSubscriptionCallback Ajax error");
1008 function subscribeToFolder(refreshCallback, refreshCallbackData) {
1009 var folderData = refreshCallbackData["folder"].split(":");
1010 var username = folderData[0];
1011 var folderPath = folderData[1];
1012 if (username != UserLogin) {
1013 var url = (UserFolderURL + "../" + username
1014 + folderPath + "/subscribe");
1015 if (document.subscriptionAjaxRequest) {
1016 document.subscriptionAjaxRequest.aborted = true;
1017 document.subscriptionAjaxRequest.abort();
1020 var rfCbData = { method: refreshCallback, data: refreshCallbackData };
1021 document.subscriptionAjaxRequest = triggerAjaxRequest(url,
1022 folderSubscriptionCallback,
1026 refreshCallbackData["window"].alert(clabels["You cannot subscribe to a folder that you own!"]);
1029 function folderUnsubscriptionCallback(http) {
1030 if (http.readyState == 4) {
1031 removeFolderRequestCount--;
1032 if (isHttpStatus204(http.status)) {
1033 if (http.callbackData)
1034 http.callbackData["method"](http.callbackData["data"]);
1037 window.alert(clabels["Unable to unsubscribe from that folder!"]);
1041 function unsubscribeFromFolder(folder, refreshCallback, refreshCallbackData) {
1042 if (document.body.hasClassName("popup")) {
1043 window.opener.unsubscribeFromFolder(folder, refreshCallback,
1044 refreshCallbackData);
1047 var folderData = folder.split("_");
1048 var username = folderData[0];
1049 var folderPath = folderData[1];
1050 if (username.startsWith('/'))
1051 username = username.substring(1);
1052 if (username != UserLogin) {
1053 var url = (ApplicationBaseURL + folder + "/unsubscribe");
1054 removeFolderRequestCount++;
1055 var rfCbData = { method: refreshCallback, data: refreshCallbackData };
1056 triggerAjaxRequest(url, folderUnsubscriptionCallback, rfCbData);
1059 window.alert(clabels["You cannot unsubscribe from a folder that you own!"]);
1063 function accessToSubscribedFolder(serverFolder) {
1066 var parts = serverFolder.split(":");
1067 if (parts.length > 1) {
1068 var paths = parts[1].split("/");
1069 folder = "/" + parts[0] + "_" + paths[2];
1072 folder = serverFolder;
1077 function getSubscribedFolderOwner(serverFolder) {
1080 var parts = serverFolder.split(":");
1081 if (parts.length > 1) {
1088 function listRowMouseDownHandler(event) {
1089 preventDefault(event);
1090 //Event.stop(event);
1094 function initTabs() {
1095 var containers = document.getElementsByClassName("tabsContainer");
1096 for (var x = 0; x < containers.length; x++) {
1097 var container = containers[x];
1098 var firstTab = null;
1099 for (var i = 0; i < container.childNodes.length; i++) {
1100 if (container.childNodes[i].tagName == 'UL') {
1105 var nodes = container.childNodes[firstTab].childNodes;
1108 for (var i = 0; i < nodes.length; i++) {
1109 var currentNode = nodes[i];
1110 if (currentNode.tagName == 'LI') {
1113 Event.observe(currentNode, "mousedown",
1114 onTabMouseDown.bindAsEventListener(currentNode));
1115 Event.observe(currentNode, "click",
1116 onTabClick.bindAsEventListener(currentNode));
1117 //$(currentNode.getAttribute("target")).hide();
1121 nodes[firstTab].addClassName("first");
1122 nodes[firstTab].addClassName("active");
1123 container.activeTab = nodes[firstTab];
1125 var target = $(nodes[firstTab].getAttribute("target"));
1126 target.addClassName("active");
1131 function initMenus() {
1132 var menus = getMenus();
1134 for (var menuID in menus) {
1135 var menuDIV = $(menuID);
1137 initMenu(menuDIV, menus[menuID]);
1142 function initMenu(menuDIV, callbacks) {
1143 var lis = $(menuDIV.childNodesWithTag("ul")[0]).childNodesWithTag("li");
1144 for (var j = 0; j < lis.length; j++) {
1145 var node = $(lis[j]);
1146 Event.observe(node, "mousedown",
1147 listRowMouseDownHandler.bindAsEventListener(node),
1149 var callback = callbacks[j];
1151 if (typeof(callback) == "string") {
1152 if (callback == "-")
1153 node.addClassName("separator");
1155 node.submenu = callback;
1156 node.addClassName("submenu");
1157 Event.observe(node, "mouseover",
1158 popupSubmenu.bindAsEventListener(node));
1162 Event.observe(node, "mouseup",
1163 onBodyClickMenuHandler);
1164 Event.observe(node, "click",
1165 $(callback).bindAsEventListener(node));
1169 node.addClassName("disabled");
1173 function onTabMouseDown(event) {
1174 event.cancelBubble = true;
1175 preventDefault(event);
1178 function openExternalLink(anchor) {
1182 function openAclWindow(url) {
1183 var w = window.open(url, "aclWindow",
1184 "width=420,height=300,resizable=1,scrollbars=1,toolbar=0,"
1185 + "location=0,directories=0,status=0,menubar=0"
1186 + ",copyhistory=0");
1193 function getUsersRightsWindowHeight() {
1194 return usersRightsWindowHeight;
1197 function getUsersRightsWindowWidth() {
1198 return usersRightsWindowWidth;
1201 function getTopWindow() {
1202 var topWindow = null;
1203 var currentWindow = window;
1204 while (!topWindow) {
1205 if (currentWindow.document.body.hasClassName("popup")
1206 && currentWindow.opener)
1207 currentWindow = currentWindow.opener;
1209 topWindow = currentWindow;
1215 function onTabClick(event) {
1216 var node = getTarget(event); // LI element
1218 var target = node.getAttribute("target");
1220 var container = node.parentNode.parentNode;
1221 var oldTarget = container.activeTab.getAttribute("target");
1222 var content = $(target);
1223 var oldContent = $(oldTarget);
1225 oldContent.removeClassName("active");
1226 container.activeTab.removeClassName("active"); // previous LI
1227 container.activeTab = node;
1228 container.activeTab.addClassName("active"); // current LI
1229 content.addClassName("active");
1231 // Prototype alternative
1233 //oldContent.removeClassName("active");
1234 //container.activeTab.removeClassName("active"); // previous LI
1235 //container.activeTab = node;
1236 //container.activeTab.addClassName("active"); // current LI
1238 //container.activeTab.hide();
1239 //oldContent.hide();
1242 //container.activeTab = node;
1243 //container.activeTab.show();
1248 function enableAnchor(anchor) {
1249 var classStr = '' + anchor.getAttribute("class");
1250 var position = classStr.indexOf("_disabled", 0);
1251 if (position > -1) {
1252 var disabledHref = anchor.getAttribute("disabled-href");
1254 anchor.setAttribute("href", disabledHref);
1255 var disabledOnclick = anchor.getAttribute("disabled-onclick");
1256 if (disabledOnclick)
1257 anchor.setAttribute("onclick", disabledOnclick);
1258 anchor.removeClassName("_disabled");
1259 anchor.setAttribute("disabled-href", null);
1260 anchor.setAttribute("disabled-onclick", null);
1261 anchor.disabled = 0;
1266 function disableAnchor(anchor) {
1267 var classStr = '' + anchor.getAttribute("class");
1268 var position = classStr.indexOf("_disabled", 0);
1270 var href = anchor.getAttribute("href");
1272 anchor.setAttribute("disabled-href", href);
1273 var onclick = anchor.getAttribute("onclick");
1275 anchor.setAttribute("disabled-onclick", onclick);
1276 anchor.addClassName("_disabled");
1277 anchor.setAttribute("href", "#");
1278 anchor.setAttribute("onclick", "return false;");
1279 anchor.disabled = 1;
1285 var hD = "0123456789abcdef";
1286 var h = hD.substr(d & 15, 1);
1290 h = hD.substr(d & 15, 1) + h;
1296 function indexColor(number) {
1302 var colorTable = new Array(1, 1, 1);
1304 var currentValue = number;
1306 while (currentValue) {
1307 if (currentValue & 1)
1308 colorTable[index]++;
1316 + d2h((256 / colorTable[2]) - 1)
1317 + d2h((256 / colorTable[1]) - 1)
1318 + d2h((256 / colorTable[0]) - 1));
1324 function loadPreferences() {
1325 var url = UserFolderURL + "jsonDefaults";
1326 var http = createHTTPClient();
1327 http.open("GET", url, false);
1329 if (http.status == 200) {
1330 if (http.responseText.length > 0)
1331 userDefaults = http.responseText.evalJSON(true);
1336 url = UserFolderURL + "jsonSettings";
1337 http.open("GET", url, false);
1339 if (http.status == 200) {
1340 if (http.responseText.length > 0)
1341 userSettings = http.responseText.evalJSON(true);
1347 function onLoadHandler(event) {
1348 if (typeof UserLogin != "undefined")
1350 queryParameters = parseQueryParameters('' + window.location);
1351 if (!$(document.body).hasClassName("popup")) {
1355 configureSearchField();
1358 configureDragHandles();
1359 configureLinkBanner();
1360 var progressImage = $("progressIndicator");
1362 progressImage.parentNode.removeChild(progressImage);
1363 Event.observe(document.body, "contextmenu", onBodyClickContextMenu);
1366 function onBodyClickContextMenu(event) {
1367 preventDefault(event);
1370 function configureSortableTableHeaders(table) {
1371 var headers = $(table).getElementsByClassName("sortableTableHeader");
1372 for (var i = 0; i < headers.length; i++) {
1373 var header = headers[i];
1374 Event.observe(header, "click", onHeaderClick.bindAsEventListener(header))
1378 function onLinkBannerClick() {
1379 activeAjaxRequests++;
1380 checkAjaxRequestsState();
1383 function onPreferencesClick(event) {
1384 var urlstr = UserFolderURL + "preferences";
1385 var w = window.open(urlstr, "_blank",
1386 "width=430,height=250,resizable=0,scrollbars=0,location=0");
1390 preventDefault(event);
1393 function configureLinkBanner() {
1394 var linkBanner = $("linkBanner");
1396 var anchors = linkBanner.childNodesWithTag("a");
1397 for (var i = 1; i < 3; i++) {
1398 Event.observe(anchors[i], "mousedown", listRowMouseDownHandler);
1399 Event.observe(anchors[i], "click", onLinkBannerClick);
1401 Event.observe(anchors[4], "mousedown", listRowMouseDownHandler);
1402 Event.observe(anchors[4], "click", onPreferencesClick);
1403 if (anchors.length > 5)
1404 Event.observe(anchors[5], "click", toggleLogConsole);
1408 /* folder creation */
1409 function createFolder(name, okCB, notOkCB) {
1411 if (document.newFolderAjaxRequest) {
1412 document.newFolderAjaxRequest.aborted = true;
1413 document.newFolderAjaxRequest.abort();
1415 var url = ApplicationBaseURL + "/createFolder?name=" + name;
1416 document.newFolderAjaxRequest
1417 = triggerAjaxRequest(url, createFolderCallback,
1424 function createFolderCallback(http) {
1425 if (http.readyState == 4) {
1426 var data = http.callbackData;
1427 if (http.status == 201) {
1429 data.okCB(data.name, "/" + http.responseText, UserLogin);
1435 log("ajax problem:" + http.status);
1440 addEvent(window, 'load', onLoadHandler);
1442 function parent$(element) {
1443 return this.opener.document.getElementById(element);
1447 function refreshCurrentFolder() {
1450 function configureDragHandles() {
1453 function getMenus() {
1456 function onHeaderClick(event) {
1457 window.alert("generic headerClick");