]> err.no Git - scalable-opengroupware.org/blobdiff - UI/WebServerResources/generic.js
git-svn-id: http://svn.opengroupware.org/SOGo/inverse/trunk@1277 d1b88da0-ebda-0310...
[scalable-opengroupware.org] / UI / WebServerResources / generic.js
index 25e8a488179c23b7eab9f26cddd91b1743169ee4..ce1bace1bb87a762e93cf3d805451994461ccd54 100644 (file)
@@ -20,8 +20,6 @@
 */
 /* some generic JavaScript code for SOGo */
 
-// TODO: replace things with Prototype where applicable
-
 /* generic stuff */
 
 var logConsole;
@@ -29,14 +27,26 @@ var logWindow = null;
 
 var queryParameters;
 
-var activeAjaxRequests = 0;
+var menus = new Array();
+var search = {};
+var sorting = {};
+
+var lastClickedRow = -1;
+
+var weekStartIsMonday = true;
 
 // logArea = null;
 var allDocumentElements = null;
 
+var userDefaults = null;
+var userSettings = null;
+
+// Ajax requests counts
+var activeAjaxRequests = 0;
+var removeFolderRequestCount = 0;
+
 /* a W3C compliant document.all */
-function getAllScopeElements(scope)
-{
+function getAllScopeElements(scope) {
   var elements = new Array();
 
   for (var i = 0; i < scope.childNodes.length; i++)
@@ -53,8 +63,7 @@ function getAllScopeElements(scope)
   return elements;
 }
 
-function getAllElements(scope)
-{
+function getAllElements(scope) {
   var elements;
 
   if (scope == null)
@@ -100,6 +109,30 @@ function getElementsByClassName2(_tag, _class, _scope) {
   }
 }
 
+function createElement(tagName, id, classes, attributes, htmlAttributes,
+                      parentNode) {
+  var newElement = $(document.createElement(tagName));
+  if (id)
+    newElement.setAttribute("id", id);
+  if (classes) {
+    if (typeof(classes) == "string")
+      newElement.addClassName(classes);
+    else
+      for (var i = 0; i < classes.length; i++)
+       newElement.addClassName(classes[i]);
+  }
+  if (attributes)
+    for (var i in attributes)
+      newElement[i] = attributes[i];
+  if (htmlAttributes)
+    for (var i in htmlAttributes)
+      newElement.setAttribute(i, htmlAttributes[i]);
+  if (parentNode)
+    parentNode.appendChild(newElement);
+
+  return $(newElement);
+}
+
 function ml_stripActionInURL(url) {
   if (url[url.length - 1] != '/') {
     var i;
@@ -112,6 +145,25 @@ function ml_stripActionInURL(url) {
   return url;
 }
 
+function URLForFolderID(folderID) {
+  var folderInfos = folderID.split(":");
+  var url;
+  if (folderInfos.length > 1) {
+    url = UserFolderURL + "../" + folderInfos[0];
+    if (!(folderInfos[0].endsWith('/')
+         || folderInfos[1].startsWith('/')))
+      url += '/';
+    url += folderInfos[1];
+  }
+  else
+    url = ApplicationBaseURL + folderInfos[0];
+   
+  if (url[url.length-1] == '/')
+    url = url.substr(0, url.length-1);
+
+  return url;
+}
+
 function extractEmailAddress(mailTo) {
   var email = "";
 
@@ -128,17 +180,22 @@ function extractEmailAddress(mailTo) {
 function extractEmailName(mailTo) {
   var emailName = "";
 
-  var emailNamere = /(\w[\w\ _-]+)\ (&lt;|<)/;
-  if (emailNamere.test(mailTo)) {
-    emailNamere.exec(mailTo);
-    emailName = RegExp.$1;
+  var tmpMailTo = mailTo.replace("&lt;", "<");
+  tmpMailTo = tmpMailTo.replace("&gt;", ">");
+
+  var emailNamere = /([        ]+)?(.+)\ </;
+  if (emailNamere.test(tmpMailTo)) {
+    emailNamere.exec(tmpMailTo);
+    emailName = RegExp.$2;
   }
+   
+  return emailName;
 }
 
 function sanitizeMailTo(dirtyMailTo) {
   var emailName = extractEmailName(dirtyMailTo);
   var email = "" + extractEmailAddress(dirtyMailTo);
-
+   
   var mailto = "";
   if (emailName && emailName.length > 0)
     mailto = emailName + ' <' + email + '>';
@@ -148,22 +205,63 @@ function sanitizeMailTo(dirtyMailTo) {
   return mailto;
 }
 
-function openMailComposeWindow(url) {
-  var w = window.open(url, null,
+function openUserFolderSelector(callback, type) {
+  var urlstr = ApplicationBaseURL;
+  if (! urlstr.endsWith('/'))
+    urlstr += '/';
+  urlstr += ("../../" + UserLogin + "/Contacts/userFolders");
+  var w = window.open(urlstr, "_blank",
+                     "width=322,height=250,resizable=1,scrollbars=0,location=0");
+  w.opener = window;
+  window.userFolderCallback = callback;
+  window.userFolderType = type;
+  w.focus();
+}
+
+function openContactWindow(url, wId) {
+  if (typeof wId == "undefined")
+    wId = "_blank";
+  else {
+    var r = new RegExp("[\.\/-]", "g");
+    wId = wId.replace(r, "_");
+  }
+
+  var w = window.open(url, wId,
+                     "width=450,height=600,resizable=0,location=0");
+  w.focus();
+
+  return w;
+}
+
+function openMailComposeWindow(url, wId) {
+  var parentWindow = this;
+
+  if (typeof wId == "undefined")
+    wId = "_blank";
+  else {
+    var r = new RegExp("[\.\/-]", "g");
+    wId = wId.replace(r, "_");
+  }
+  
+  if (document.body.hasClassName("popup"))
+    parentWindow = window.opener;
+
+  var w = parentWindow.open(url, wId,
                       "width=680,height=520,resizable=1,scrollbars=1,toolbar=0,"
                       + "location=0,directories=0,status=0,menubar=0"
                       + ",copyhistory=0");
+
   w.focus();
 
   return w;
 }
 
-function openMailTo(senderMailto) {
-  var mailto = sanitizeMailTo(senderMailto);
+function openMailTo(senderMailTo) {
+  var mailto = sanitizeMailTo(senderMailTo);
 
   if (mailto.length > 0)
     openMailComposeWindow(ApplicationBaseURL
-                          + "/../Mail/compose?mailto=" + mailto);
+                         + "../Mail/compose?mailto=" + mailto);
 
   return false; /* stop following the link */
 }
@@ -172,7 +270,7 @@ function createHTTPClient() {
   // http://developer.apple.com/internet/webcontent/xmlhttpreq.html
   if (typeof XMLHttpRequest != "undefined")
     return new XMLHttpRequest();
-  
+
   try { return new ActiveXObject("Msxml2.XMLHTTP"); } 
   catch (e) { }
   try { return new ActiveXObject("Microsoft.XMLHTTP"); } 
@@ -181,63 +279,130 @@ function createHTTPClient() {
   return null;
 }
 
-function triggerAjaxRequest(url, callback, userdata) {
+function appendDifferentiator(url) {
+  var url_nocache = url;
+  var position = url.indexOf('?', 0);
+  if (position < 0)
+    url_nocache += '?';
+  else
+    url_nocache += '&';
+  url_nocache += 'differentiator=' + Math.floor(Math.random()*50000);
+
+  return url_nocache;
+}
+
+function triggerAjaxRequest(url, callback, userdata, content, headers) {
   var http = createHTTPClient();
 
   activeAjaxRequests += 1;
-  document.animTimer = setTimeout("checkAjaxRequestsState();", 200);
+  document.animTimer = setTimeout("checkAjaxRequestsState();", 50);
+  //url = appendDifferentiator(url);
 
   if (http) {
+    http.open("POST", url, true);
+    http.url = url;
     http.onreadystatechange
       = function() {
-//         log ("state changed (" + http.readyState + "): " + url);
-        try {
-          if (http.readyState == 4
-              && activeAjaxRequests > 0) {
-                if (!http.aborted) {
-                  http.callbackData = userdata;
-                  callback(http);
-                }
-                activeAjaxRequests -= 1;
-                checkAjaxRequestsState();
-              }
-        }
-        catch( e ) {
-          activeAjaxRequests -= 1;
-          checkAjaxRequestsState();
-          log("AJAX Request, Caught Exception: " + e.name);
-          log(e.message);
-        }
-      };
-    http.url = url;
-    http.open("GET", url, true);
-    http.send("");
+//       log ("state changed (" + http.readyState + "): " + url);
+      try {
+       if (http.readyState == 4
+           && activeAjaxRequests > 0) {
+         if (!http.aborted) {
+           if (userdata)
+             http.callbackData = userdata;
+           callback(http);
+         }
+         activeAjaxRequests -= 1;
+         checkAjaxRequestsState();
+       }
+      }
+      catch( e ) {
+       activeAjaxRequests -= 1;
+       checkAjaxRequestsState();
+       log("AJAX Request, Caught Exception: " + e.name);
+       log(e.message);
+       log(backtrace());
+      }
+    };
+    if (headers) {
+      for (var i in headers)
+       http.setRequestHeader(i, headers[i]);
+    }
+    http.send(content);
+  }
+  else {
+    log("triggerAjaxRequest: error creating HTTP Client!");
   }
 
   return http;
 }
 
+function startAnimation(parent, nextNode) {
+  var anim = $("progressIndicator");
+  if (anim) return anim;
+  
+  anim = document.createElement("img");
+  anim = $(anim);
+  anim.id = "progressIndicator";
+  anim.src = ResourcesURL + "/busy.gif";
+  anim.setStyle({ visibility: "hidden" });
+  if (nextNode)
+    parent.insertBefore(anim, nextNode);
+  else
+    parent.appendChild(anim);
+  anim.setStyle({ visibility: "visible" });
+
+  return anim;
+}
+
 function checkAjaxRequestsState() {
   var toolbar = document.getElementById("toolbar");
   if (toolbar) {
     if (activeAjaxRequests > 0
         && !document.busyAnim) {
-      var anim = document.createElement("img");
-      document.busyAnim = anim;
-      anim.id = "progressIndicator";
-      anim.src = ResourcesURL + "/busy.gif";
-      anim.style.visibility = "hidden;";
-      toolbar.appendChild(anim);
-      anim.style.visibility = "visible;";
+      document.busyAnim = startAnimation(toolbar);
     }
     else if (activeAjaxRequests == 0
-            && document.busyAnim) {
+            && document.busyAnim
+            && document.busyAnim.parentNode) {
       document.busyAnim.parentNode.removeChild(document.busyAnim);
       document.busyAnim = null;
     }
   }
 }
 
+function isSafari3() {
+  return (navigator.appVersion.indexOf("Version") > -1);
+}
+
+function isSafari() {
+  //var agt = navigator.userAgent.toLowerCase();
+  //var is_safari = ((agt.indexOf('safari')!=-1)&&(agt.indexOf('mac')!=-1))?true:false;
+
+  return (navigator.vendor == "Apple Computer, Inc.");
+}
+
+function isHttpStatus204(status) {
+  return (status == 204 ||                                  // Firefox
+         (isSafari() && typeof(status) == 'undefined') ||  // Safari
+          status == 1223);                                  // IE
+}
+
+function getTarget(event) {
+  event = event || window.event;
+  if (event.target)
+    return event.target; // W3C DOM
+  else
+    return event.srcElement; // IE
+}
+
+function preventDefault(event) {
+  if (event.preventDefault)
+    event.preventDefault(); // W3C DOM
+  else
+    event.returnValue = false; // IE
+}
+
 function resetSelection(win) {
   var t = "";
   if (win && win.getSelection) {
@@ -257,7 +422,7 @@ function refreshOpener() {
 
 function parseQueryString() {
   var queryArray, queryDict
-  var key, value, s, idx;
+    var key, value, s, idx;
   queryDict.length = 0;
   
   queryDict  = new Array();
@@ -295,149 +460,140 @@ function generateQueryString(queryDict) {
   return s;
 }
 
-function getQueryParaArray(s) {
-  if (s.charAt(0) == "?") s = s.substr(1, s.length - 1);
-  return s.split("&");
-}
-
-function getQueryParaValue(s, name) {
-  var t;
-  
-  t = getQueryParaArray(s);
-  for (var i = 0; i < t.length; i++) {
-    var s = t[i];
-    
-    if (s.indexOf(name) != 0)
-      continue;
-    
-    s = s.substr(name.length, s.length - name.length);
-    return decodeURIComponent(s);
-  }
-  return null;
-}
-
-/* opener callback */
-
-function triggerOpenerCallback() {
-  /* this code has some issue if the folder has no proper trailing slash! */
-  if (window.opener && !window.opener.closed) {
-    var t, cburl;
-    
-    t = getQueryParaValue(window.location.search, "openerurl=");
-    cburl = window.opener.location.href;
-    if (cburl[cburl.length - 1] != "/") {
-      cburl = cburl.substr(0, cburl.lastIndexOf("/") + 1);
-    }
-    cburl = cburl + t;
-    window.opener.location.href = cburl;
-  }
-}
-
 /* selection mechanism */
 
 function deselectAll(parent) {
   for (var i = 0; i < parent.childNodes.length; i++) {
     var node = parent.childNodes.item(i);
     if (node.nodeType == 1)
-      node.deselect();
+      $(node).deselect();
   }
 }
 
 function isNodeSelected(node) {
-  var classStr = '' + node.getAttribute('class');
-  var position = classStr.indexOf('_selected', 0);
-
-  return (position > -1);
+  return $(node).hasClassName('_selected');
 }
 
 function acceptMultiSelect(node) {
-  var accept = ('' + node.getAttribute('multiselect')).toLowerCase();
+  var response = false;
+  var attribute = node.getAttribute('multiselect');
+  if (attribute && attribute.length > 0) {
+    log("node '" + node.getAttribute("id")
+       + "' is still using old-stylemultiselect!");
+    response = (attribute.toLowerCase() == 'yes');
+  }
+  else
+    response = node.multiselect;
 
-  return (accept == 'yes');
+  return response;
 }
 
 function onRowClick(event) {
-  var node = event.target;
+  var node = getTarget(event);
+  var rowIndex = null;
+
+  if (node.tagName == 'TD') {
+    node = node.parentNode; // select TR
+    rowIndex = node.rowIndex - $(node).up('table').down('thead').getElementsByTagName('tr').length;  
+  }
+  else if (node.tagName == 'LI') {
+    // Find index of clicked row
+    var list = node.parentNode;
+    var items = list.childNodesWithTag("li");
+    for (var i = 0; i < items.length; i++) {
+      if (items[i] == node) {
+       rowIndex = i;
+       break;
+      }
+    }
+  }
 
-  if (node.tagName == 'TD')
-    node = node.parentNode;
+  var initialSelection = $(node.parentNode).getSelectedNodes();
 
-  var startSelection = node.parentNode.getSelectedNodes();
-  if (event.shiftKey == 1
+  if (initialSelection.length > 0 && !Event.isLeftClick(event))
+    // Ignore non primary-click (ie right-click)
+    return true;
+  
+  if ((event.shiftKey == 1 || event.ctrlKey == 1)
+      && (lastClickedRow >= 0)
       && (acceptMultiSelect(node.parentNode)
          || acceptMultiSelect(node.parentNode.parentNode))) {
-    if (isNodeSelected(node) == true) {
-      node.deselect();
+    if (event.shiftKey)
+      $(node.parentNode).selectRange(lastClickedRow, rowIndex);
+    else if (isNodeSelected(node) == true) {
+      $(node).deselect();
     } else {
-      node.select();
+      $(node).select();
     }
+    // At this point, should empty content of 3-pane view
   } else {
-    deselectAll(node.parentNode);
-    node.select();
-  }
-
-  if (startSelection != node.parentNode.getSelectedNodes()) {
-    var parentNode = node.parentNode;
-    if (parentNode instanceof HTMLTableSectionElement)
-      parentNode = parentNode.parentNode;
-    var onSelectionChangeEvent = document.createEvent("Event");
-    onSelectionChangeEvent.initEvent("selectionchange", true, true);
-    parentNode.dispatchEvent(onSelectionChangeEvent);
+    // Single line selection
+    $(node.parentNode).deselectAll();
+    $(node).select();
+  
+    if (initialSelection != $(node.parentNode).getSelectedNodes()) {
+      // Selection has changed; fire mousedown event
+      var parentNode = node.parentNode;
+      if (parentNode.tagName == 'TBODY')
+       parentNode = parentNode.parentNode;
+      parentNode.fire("mousedown");
+    }
   }
+  lastClickedRow = rowIndex;
+  
+  return true;
 }
 
 /* popup menus */
 
-var bodyOnClick = "";
 // var acceptClick = false;
 
-function onMenuClick(event, menuId)
-{
-  var node = event.target;
+function popupMenu(event, menuId, target) {
+  document.menuTarget = target;
 
   if (document.currentPopupMenu)
-    hideMenu(event, document.currentPopupMenu);
+    hideMenu(document.currentPopupMenu);
+
+  var popup = $(menuId);
+
+  var deltaX = 0;
+  var deltaY = 0;
 
-  var popup = document.getElementById(menuId);
+  var pageContent = $("pageContent");
+  if (popup.parentNode.tagName != "BODY") {
+    var offset = pageContent.cascadeLeftOffset();
+    deltaX = -($(popup.parentNode).cascadeLeftOffset() - offset);
+    offset = pageContent.cascadeTopOffset();
+    deltaY = -($(popup.parentNode).cascadeTopOffset() - offset);
+  }
 
-  var menuTop = event.pageY;
-  var menuLeft = event.pageX;
-  var heightDiff = (window.innerHeight
+  var menuTop = Event.pointerY(event) + deltaY;
+  var menuLeft = Event.pointerX(event) + deltaX;
+  var heightDiff = (window.height()
                    - (menuTop + popup.offsetHeight));
   if (heightDiff < 0)
     menuTop += heightDiff;
-
-  var leftDiff = (window.innerWidth
+  
+  var leftDiff = (window.width()
                  - (menuLeft + popup.offsetWidth));
   if (leftDiff < 0)
     menuLeft -= popup.offsetWidth;
 
-  popup.style.top = menuTop + "px;";
-  popup.style.left = menuLeft + "px;";
-  popup.style.visibility = "visible;";
-  setupMenuTarget(popup, node);
-
-  bodyOnClick = "" + document.body.getAttribute("onclick");
-  document.body.setAttribute("onclick", "onBodyClick(event);");
+  if (popup.prepareVisibility)
+    popup.prepareVisibility();
+  
+  popup.setStyle({ top: menuTop + "px",
+                  left: menuLeft + "px",
+                  visibility: "visible" });
+  
   document.currentPopupMenu = popup;
 
-  event.cancelBubble = true;
-  event.returnValue = false;
-
-  return false;
-}
+  $(document.body).observe("click", onBodyClickMenuHandler);
 
-function setupMenuTarget(menu, target)
-{
-  menu.menuTarget = target;
-  var menus = document.getElementsByClassName("menu", menu);
-  for (var i = 0; i < menus.length; i++) {
-    menus[i].menuTarget = target;
-  }
+  preventDefault(event);
 }
 
-function getParentMenu(node)
-{
+function getParentMenu(node) {
   var currentNode, menuNode;
 
   menuNode = null;
@@ -454,48 +610,44 @@ function getParentMenu(node)
   return menuNode;
 }
 
-function onBodyClick(event)
-{
-  document.currentPopupMenu.menuTarget = null;
-  hideMenu(event, document.currentPopupMenu);
-  document.body.setAttribute("onclick", bodyOnClick);
+function onBodyClickMenuHandler(event) {
+  hideMenu(document.currentPopupMenu);
+  document.body.stopObserving("click", onBodyClickMenuHandler);
 
-  return false;
+  if (event)
+    preventDefault(event);
 }
 
-function hideMenu(event, menuNode)
-{
+function hideMenu(menuNode) {
   var onHide;
 
-//   log('hiding menu "' + menuNode.getAttribute('id') + '"');
-  if (menuNode.submenu)
-    {
-      hideMenu(event, menuNode.submenu);
-      menuNode.submenu = null;
-    }
+  if (menuNode.submenu) {
+    hideMenu(menuNode.submenu);
+    menuNode.submenu = null;
+  }
 
-  menuNode.style.visibility = "hidden";
-  if (menuNode.parentMenuItem)
-    {
-      menuNode.parentMenuItem.setAttribute('class', 'submenu');
-      menuNode.parentMenuItem = null;
-      menuNode.parentMenu.setAttribute('onmousemove', null);
-      menuNode.parentMenu.submenuItem = null;
-      menuNode.parentMenu.submenu = null;
-      menuNode.parentMenu = null;
-    }
+  menuNode.setStyle({ visibility: "hidden" });
+  if (menuNode.parentMenuItem) {
+    menuNode.parentMenuItem.stopObserving("mouseover",onMouseEnteredSubmenu);
+    menuNode.stopObserving("mouseover", onMouseEnteredSubmenu);
+    menuNode.parentMenuItem.stopObserving("mouseout", onMouseLeftSubmenu);
+    menuNode.stopObserving("mouseout", onMouseLeftSubmenu);
+    menuNode.parentMenu.stopObserving("mouseover", onMouseEnteredParentMenu);
+    $(menuNode.parentMenuItem).removeClassName("submenu-selected");
+    menuNode.parentMenuItem.mouseInside = false;
+    menuNode.parentMenuItem = null;
+    menuNode.parentMenu.submenuItem = null;
+    menuNode.parentMenu.submenu = null;
+    menuNode.parentMenu = null;
+  }
 
-  var onhideEvent = document.createEvent("Event");
-  onhideEvent.initEvent("hideMenu", false, true);
-  menuNode.dispatchEvent(onhideEvent);
+  $(menuNode).fire("mousedown");
 }
 
-function onMenuEntryClick(event, menuId)
-{
+function onMenuEntryClick(event) {
   var node = event.target;
 
   id = getParentMenu(node).menuTarget;
-//   log("clicked " + id + "/" + id.tagName);
 
   return false;
 }
@@ -518,24 +670,21 @@ function parseQueryParameters(url) {
 function initLogConsole() {
   var logConsole = $("logConsole");
   if (logConsole) {
-    logConsole.addEventListener("dblclick", onLogDblClick, false);
-    logConsole.innerHTML = "";
-    node = document.getElementsByTagName('body')[0];
-    node.addEventListener("keydown", onBodyKeyDown, true);
+    logConsole.highlighted = false;
+    logConsole.observe("dblclick", onLogDblClick, false);
+    logConsole.update();
+    Event.observe(window, "keydown", onBodyKeyDown);
   }
 }
 
-function onBodyKeyDown(event)
-{
+function onBodyKeyDown(event) {
   if (event.keyCode == 27) {
     toggleLogConsole();
-    event.cancelBubble = true;
-    event.returnValue = false;
+    preventDefault(event);
   }
 }
 
-function onLogDblClick(event)
-{
+function onLogDblClick(event) {
   var logConsole = $("logConsole");
   logConsole.innerHTML = "";
 }
@@ -544,13 +693,12 @@ function toggleLogConsole(event) {
   var logConsole = $("logConsole");
   var display = '' + logConsole.style.display;
   if (display.length == 0) {
-    logConsole.style.display = 'block;';
+    logConsole.setStyle({ display: 'block' });
   } else {
-    logConsole.style.display = '';
+    logConsole.setStyle({ display: '' });
   }
-  event.cancelBubble = true;
-  event.returnValue = false;
-  event.preventDefault();
+  if (event)
+    preventDefault(event);
 }
 
 function log(message) {
@@ -559,77 +707,110 @@ function log(message) {
     while (logWindow.opener)
       logWindow = logWindow.opener;
   }
-  var logConsole = logWindow.document.getElementById('logConsole');
-  if (logConsole)
-    logConsole.innerHTML += message + '<br />' + "\n";
-}
-
-function dropDownSubmenu(event)
-{
-  var node = event.target;
-  var submenu = node.getAttribute("submenu");
-  if (submenu && submenu != "")
-    {
-      var submenuNode = document.getElementById(submenu);
-      var parentNode = getParentMenu(node);
-      if (parentNode.submenu)
-       hideMenu(event, parentNode.submenu);
-      submenuNode.parentMenuItem = node;
-      submenuNode.parentMenu = parentNode;
-      parentNode.submenuItem = node;
-      parentNode.submenu = submenuNode;
-
-      var menuTop = (node.offsetTop - 2);
-      
-      var heightDiff = (window.innerHeight
-                       - (menuTop + submenuNode.offsetHeight));
-      if (heightDiff < 0)
-       menuTop += heightDiff;
-
-      var menuLeft = parentNode.offsetWidth - 3;
-      if (window.innerWidth
-          < (menuLeft + submenuNode.offsetWidth
-             + parentNode.cascadeLeftOffset()))
-       menuLeft = -submenuNode.offsetWidth + 3;
-
-      parentNode.setAttribute('onmousemove', 'checkDropDown(event);');
-      node.setAttribute('class', 'submenu-selected');
-      submenuNode.style.top = menuTop + "px;";
-      submenuNode.style.left = menuLeft + "px;";
-      submenuNode.style.visibility = "visible;";
+  var logConsole = logWindow.document.getElementById("logConsole");
+  if (logConsole) {
+    logConsole.highlighted = !logConsole.highlighted;
+    if (message == '\c') {
+      logConsole.innerHTML = "";
+      return;
     }
+    var logMessage = message.replace("<", "&lt;", "g");
+    logMessage = logMessage.replace(" ", "&nbsp;", "g");
+    logMessage = logMessage.replace("\r\n", "<br />\n", "g");
+    logMessage = logMessage.replace("\n", "<br />\n", "g");
+    logMessage += '<br />' + "\n";
+    if (logConsole.highlighted)
+      logMessage = '<div class="highlighted">' + logMessage + '</div>';
+    logConsole.innerHTML += logMessage;
+  }
 }
 
-function checkDropDown(event)
-{
-  var parentMenu = getParentMenu(event.target);
-  var submenuItem = parentMenu.submenuItem;
-  if (submenuItem)
+function backtrace() {
+  var func = backtrace.caller;
+  var str = "backtrace:\n";
+
+  while (func)
     {
-      var menuX = event.clientX - parentMenu.cascadeLeftOffset();
-      var menuY = event.clientY - parentMenu.cascadeTopOffset();
-      var itemX = submenuItem.offsetLeft;
-      var itemY = submenuItem.offsetTop - 75;
-
-      if (menuX >= itemX
-          && menuX < itemX + submenuItem.offsetWidth
-          && (menuY < itemY
-              || menuY > (itemY + submenuItem.offsetHeight)))
+      if (func.name)
        {
-         hideMenu(event, parentMenu.submenu);
-         parentMenu.submenu = null;
-         parentMenu.submenuItem = null;
-         parentMenu.setAttribute('onmousemove', null);
+         str += "  " + func.name;
+         if (this)
+            str += " (" + this + ")";
        }
+      else
+       str += "[anonymous]\n";
+
+      str += "\n";
+      func = func.caller;
     }
+  str += "--\n";
+
+  return str;
+}
+
+function popupSubmenu(event) {
+  if (this.submenu && this.submenu != "") {
+    var submenuNode = $(this.submenu);
+    var parentNode = getParentMenu(this);
+    if (parentNode.submenu)
+      hideMenu(parentNode.submenu);
+    submenuNode.parentMenuItem = this;
+    submenuNode.parentMenu = parentNode;
+    parentNode.submenuItem = this;
+    parentNode.submenu = submenuNode;
+
+    if (submenuNode.prepareVisibility)
+      submenuNode.prepareVisibility();
+
+    var menuTop = (parentNode.offsetTop - 1
+                  + this.offsetTop);
+
+    if (window.height()
+       < (menuTop + submenuNode.offsetHeight))
+      if (submenuNode.offsetHeight < window.height())
+       menuTop = window.height() - submenuNode.offsetHeight;
+      else
+       menuTop = 0;
+
+    var menuLeft = (parentNode.offsetLeft + parentNode.offsetWidth - 3);
+    if (window.width()
+       < (menuLeft + submenuNode.offsetWidth))
+      menuLeft = parentNode.offsetLeft - submenuNode.offsetWidth + 3;
+
+    this.mouseInside = true;
+    this.observe("mouseover", onMouseEnteredSubmenu);
+    submenuNode.observe("mouseover", onMouseEnteredSubmenu);
+    this.observe("mouseout", onMouseLeftSubmenu);
+    submenuNode.observe("mouseout", onMouseLeftSubmenu);
+    parentNode.observe("mouseover", onMouseEnteredParentMenu);
+    $(this).addClassName("submenu-selected");
+    submenuNode.setStyle({ top: menuTop + "px",
+                          left: menuLeft + "px",
+                          visibility: "visible" });
+    preventDefault(event);
+  }
+}
+
+function onMouseEnteredParentMenu(event) {
+  if (this.submenuItem && !this.submenuItem.mouseInside)
+    hideMenu(this.submenu);
+}
+
+function onMouseEnteredSubmenu(event) {
+  $(this).mouseInside = true;
+}
+
+function onMouseLeftSubmenu(event) {
+  $(this).mouseInside = false;
 }
 
 /* search field */
-function popupSearchMenu(event, menuId)
-{
-  var node = event.target;
-  relX = event.pageX - node.cascadeLeftOffset();
-  relY = event.pageY - node.cascadeTopOffset();
+function popupSearchMenu(event) {
+  var menuId = this.getAttribute("menuid");
+  var offset = Position.cumulativeOffset(this);
+
+  relX = Event.pointerX(event) - offset[0];
+  relY = Event.pointerY(event) - offset[1];
 
   if (event.button == 0
       && relX < 24) {
@@ -637,49 +818,63 @@ function popupSearchMenu(event, menuId)
     event.returnValue = false;
 
     if (document.currentPopupMenu)
-      hideMenu(event, document.currentPopupMenu);
+      hideMenu(document.currentPopupMenu);
 
-    var popup = document.getElementById(menuId);
-    popup.style.top = node.offsetHeight + "px";
-    popup.style.left = (node.offsetLeft + 3) + "px";
-    popup.style.visibility = "visible";
+    var popup = $(menuId);
+    offset = Position.positionedOffset(this);
+    popup.setStyle({ top: this.offsetHeight + "px",
+         left: (offset[0] + 3) + "px",
+         visibility: "visible" });
   
-    bodyOnClick = "" + document.body.getAttribute("onclick");
-    document.body.setAttribute("onclick", "onBodyClick('" + menuId + "');");
     document.currentPopupMenu = popup;
+    $(document.body).observe("click", onBodyClickMenuHandler);
   }
 }
 
-function setSearchCriteria(event)
-{
-  searchValue = document.getElementById('searchValue');
-  searchCriteria = document.getElementById('searchCriteria');
+function setSearchCriteria(event) {
+  var searchValue = $("searchValue");
+  var searchCriteria = $("searchCriteria");
+
+  searchValue.ghostPhrase = this.innerHTML;
+  searchCriteria.value = this.getAttribute('id');
   
-  var node = event.target;
-  searchValue.setAttribute("ghost-phrase", node.innerHTML);
-  searchCriteria = node.getAttribute('id');
+  if (this.parentNode.chosenNode)
+    this.parentNode.chosenNode.removeClassName("_chosen");
+  this.addClassName("_chosen");
+  this.parentNode.chosenNode = this;
 }
 
-function checkSearchValue(event)
-{
-  var form = event.target;
-  var searchValue = document.getElementById('searchValue');
-  var ghostPhrase = searchValue.getAttribute('ghost-phrase');
+function checkSearchValue(event) {
+  var searchValue = $("searchValue");
 
-  if (searchValue.value == ghostPhrase)
+  if (searchValue.value == searchValue.ghostPhrase)
     searchValue.value = "";
 }
 
-function onSearchChange()
-{
-  log ("onSearchChange()...");
+function configureSearchField() {
+  var searchValue = $("searchValue");
+  var searchOptions = $("searchOptions");
+
+  if (!searchValue) return;
+
+  searchValue.observe("click", popupSearchMenu);
+  searchValue.observe("blur", onSearchBlur);
+  searchValue.observe("focus", onSearchFocus);
+  searchValue.observe("keydown", onSearchKeyDown);
+  searchValue.observe("mousedown", onSearchMouseDown);
+  
+  if (!searchOptions) return;
+   
+  // Set the checkmark to the first option
+  var firstOption = searchOptions.down('li');
+  firstOption.addClassName("_chosen");
+  searchOptions.chosenNode = firstOption;
 }
 
-function onSearchMouseDown(event, searchValue)
-{
-  superNode = searchValue.parentNode.parentNode.parentNode;
-  relX = (event.pageX - superNode.offsetLeft - searchValue.offsetLeft);
-  relY = (event.pageY - superNode.offsetTop - searchValue.offsetTop);
+function onSearchMouseDown(event) {
+  var superNode = this.parentNode.parentNode.parentNode;
+  relX = (Event.pointerX(event) - superNode.offsetLeft - this.offsetLeft);
+  relY = (Event.pointerY(event) - superNode.offsetTop - this.offsetTop);
 
   if (relY < 24) {
     event.cancelBubble = true;
@@ -687,186 +882,310 @@ function onSearchMouseDown(event, searchValue)
   }
 }
 
-function onSearchFocus(searchValue)
-{
-  ghostPhrase = searchValue.getAttribute("ghost-phrase");
-  if (searchValue.value == ghostPhrase) {
-    searchValue.value = "";
-    searchValue.setAttribute("modified", "");
+function onSearchFocus() {
+  ghostPhrase = this.ghostPhrase;
+  if (this.value == ghostPhrase) {
+    this.value = "";
+    this.setAttribute("modified", "");
   } else {
-    searchValue.select();
+    this.select();
   }
 
-  searchValue.style.color = "#000";
+  this.setStyle({ color: "#000" });
 }
 
-function onSearchBlur(searchValue)
-{
-  var ghostPhrase = searchValue.getAttribute("ghost-phrase");
-//   log ("search blur: '" + searchValue.value + "'");
-  if (!searchValue.value) {
-    searchValue.setAttribute("modified", "");
-    searchValue.style.color = "#aaa";
-    searchValue.value = ghostPhrase;
-  } else if (searchValue.value == ghostPhrase) {
-    searchValue.setAttribute("modified", "");
-    searchValue.style.color = "#aaa";
+function onSearchBlur(event) {
+  if (!this.value) {
+    this.setAttribute("modified", "");
+    this.setStyle({ color: "#aaa" });
+    this.value = this.ghostPhrase;
+    search["value"] = "";
+    if (searchValue.lastSearch != "") {
+      searchValue.lastSearch = "";
+      refreshCurrentFolder();
+    }
+  } else if (this.value == this.ghostPhrase) {
+    this.setAttribute("modified", "");
+    this.setStyle({ color: "#aaa" });
   } else {
-    searchValue.setAttribute("modified", "yes");
-    searchValue.style.color = "#000";
+    this.setAttribute("modified", "yes");
+    this.setStyle({ color: "#000" });
   }
 }
 
-function onSearchKeyDown(searchValue)
-{
-  if (searchValue.timer)
-    clearTimeout(searchValue.timer);
+function onSearchKeyDown(event) {
+  if (this.timer)
+    clearTimeout(this.timer);
 
-  searchValue.timer = setTimeout("onSearchFormSubmit()", 1000);
+  this.timer = setTimeout("onSearchFormSubmit()", 1000);
 }
 
-function initCriteria()
-{
-  var searchCriteria = document.getElementById('searchCriteria');
-  var searchValue = document.getElementById('searchValue');
-  var firstOption;
-  firstOption = document.getElementById('searchOptions').childNodes[1];
-  searchCriteria.value = firstOption.getAttribute('id');
-  searchValue.setAttribute('ghost-phrase', firstOption.innerHTML);
-  if (searchValue.value == '') {
-    searchValue.value = firstOption.innerHTML;
-    searchValue.setAttribute("modified", "");
-    searchValue.style.color = "#aaa";
+function onSearchFormSubmit(event) {
+  var searchValue = $("searchValue");
+  var searchCriteria = $("searchCriteria");
+   
+  if (searchValue.value != searchValue.ghostPhrase
+      && searchValue.value != searchValue.lastSearch) {
+    search["criteria"] = searchCriteria.value;
+    search["value"] = searchValue.value;
+    searchValue.lastSearch = searchValue.value;
+    refreshCurrentFolder();
   }
 }
+
+function initCriteria() {
+  var searchCriteria = $("searchCriteria");
+  var searchValue = $("searchValue");
  
+  if (searchValue) {
+    var searchOptions = $("searchOptions").childNodesWithTag("li");
+    if (searchOptions.length > 0) {
+      var firstChild = searchOptions[0];
+      searchCriteria.value = $(firstChild).getAttribute('id');
+      searchValue.ghostPhrase = firstChild.innerHTML;
+      searchValue.lastSearch = "";
+      if (searchValue.value == '') {
+       searchValue.value = firstChild.innerHTML;
+       searchValue.setAttribute("modified", "");
+       searchValue.setStyle({ color: "#aaa" });
+      }
+    }
+  }
+}
+
+/* toolbar buttons */
+function popupToolbarMenu(node, menuId) {
+  if (document.currentPopupMenu)
+    hideMenu(document.currentPopupMenu);
+
+  var popup = $(menuId);
+  var top = ($(node).getStyle('top') || 0) + node.offsetHeight - 2;
+  popup.setStyle({ top: top + "px",
+       left: $(node).cascadeLeftOffset() + "px",
+       visibility: "visible" });
+
+  document.currentPopupMenu = popup;
+  $(document.body).observe("click", onBodyClickMenuHandler);
+}
+
 /* contact selector */
 
-function onContactAdd(node)
-{
-  var selector = null;
-  var selectorURL = '?popup=YES';
-  if (node) {
-    selector = node.parentNode.parentNode;
-    selectorURL += ("&selectorId=" + selector.getAttribute("id"));
+function folderSubscriptionCallback(http) {
+  if (http.readyState == 4) {
+    if (isHttpStatus204(http.status)) {
+      if (http.callbackData)
+       http.callbackData["method"](http.callbackData["data"]);
+    }
+    else
+      window.alert(clabels["Unable to subscribe to that folder!"]);
+    document.subscriptionAjaxRequest = null;
   }
+  else
+    log ("folderSubscriptionCallback Ajax error");
+}
+
+function subscribeToFolder(refreshCallback, refreshCallbackData) {
+  var folderData = refreshCallbackData["folder"].split(":");
+  var username = folderData[0];
+  var folderPath = folderData[1];
+  if (username != UserLogin) {
+    var url = (UserFolderURL + "../" + username
+              + folderPath + "/subscribe");
+    if (document.subscriptionAjaxRequest) {
+      document.subscriptionAjaxRequest.aborted = true;
+      document.subscriptionAjaxRequest.abort();
+    }
 
-  urlstr = ApplicationBaseURL;
-  if (urlstr[urlstr.length-1] != '/')
-    urlstr += '/';
-  urlstr += ("../../" + UserLogin + "/Contacts/"
-             + contactSelectorAction + selectorURL);
-//   log (urlstr);
-  var w = window.open(urlstr, "Addressbook",
-                      "width=640,height=400,resizable=1,scrollbars=0");
-  w.selector = selector;
-  w.opener = this;
-  w.focus();
-
-  return false;
+    var rfCbData = { method: refreshCallback, data: refreshCallbackData };
+    document.subscriptionAjaxRequest = triggerAjaxRequest(url,
+                                                         folderSubscriptionCallback,
+                                                         rfCbData);
+  }
+  else
+    refreshCallbackData["window"].alert(clabels["You cannot subscribe to a folder that you own!"]);
 }
 
-function onContactRemove(node) {
-  var selector = node.parentNode.parentNode;
-  var selectorId = selector.getAttribute("id");
-  var hasChanged = false;
+function folderUnsubscriptionCallback(http) {
+  if (http.readyState == 4) {
+    removeFolderRequestCount--;
+    if (isHttpStatus204(http.status)) {
+      if (http.callbackData)
+       http.callbackData["method"](http.callbackData["data"]);
+    }
+    else
+      window.alert(clabels["Unable to unsubscribe from that folder!"]);
+  }
+}
 
-  var names = $('uixselector-' + selectorId + '-display');
-  var nodes = names.getSelectedNodes();
-  hasChanged = (nodes.length > 0);
-  for (var i = 0; i < nodes.length; i++) {
-    var currentNode = nodes[i];
-    currentNode.parentNode.removeChild(currentNode);
+function unsubscribeFromFolder(folder, refreshCallback, refreshCallbackData) {
+  if (document.body.hasClassName("popup")) {
+    window.opener.unsubscribeFromFolder(folder, refreshCallback,
+                                       refreshCallbackData);
   }
+  else {
+    var folderData = folder.split("_");
+    var username = folderData[0];
+    var folderPath = folderData[1];
+    if (username.startsWith('/'))
+      username = username.substring(1);
+    if (username != UserLogin) {
+      var url = (ApplicationBaseURL + folder + "/unsubscribe");
+      removeFolderRequestCount++;
+      var rfCbData = { method: refreshCallback, data: refreshCallbackData };
+      triggerAjaxRequest(url, folderUnsubscriptionCallback, rfCbData);
+    }
+    else
+      window.alert(clabels["You cannot unsubscribe from a folder that you own!"]);
+  }
+}
 
-  var uids = $('uixselector-' + selectorId + '-uidList');
-  nodes = node.parentNode.childNodes;
-  var ids = new Array();
-  for (var i = 0; i < nodes.length; i++)
-    if (nodes[i] instanceof HTMLLIElement)
-      ids.push(nodes[i].getAttribute("uid"));
-  uids.value = ids.join(",");
+function accessToSubscribedFolder(serverFolder) {
+  var folder;
 
-  if (selector.changeNotification && hasChanged)
-    selector.changeNotification("removal");
+  var parts = serverFolder.split(":");
+  if (parts.length > 1) {
+    var paths = parts[1].split("/");
+    folder = "/" + parts[0] + "_" + paths[2];
+  }
+  else
+    folder = serverFolder;
+  
+  return folder;
+}
 
-  return false;
+function getSubscribedFolderOwner(serverFolder) {
+  var owner;
+  
+  var parts = serverFolder.split(":");
+  if (parts.length > 1) {
+    owner = parts[0];
+  }
+  
+  return owner;
 }
 
 function listRowMouseDownHandler(event) {
-  event.preventDefault();
+  preventDefault(event);
+  //Event.stop(event); 
 }
 
 /* tabs */
-function initTabs()
-{
+function initTabs() {
   var containers = document.getElementsByClassName("tabsContainer");
   for (var x = 0; x < containers.length; x++) {
     var container = containers[x];
-    var nodes = container.childNodes[1].childNodes;
-
-    var firstTab;
+    var firstTab = null;
+    for (var i = 0; i < container.childNodes.length; i++) {
+      if (container.childNodes[i].tagName == 'UL') {
+       if (!firstTab)
+         firstTab = i;
+      }
+    }
+    var nodes = container.childNodes[firstTab].childNodes;
+    
+    firstTab = null;
     for (var i = 0; i < nodes.length; i++) {
-      if (nodes[i] instanceof HTMLLIElement) {
-        if (!firstTab) {
-          firstTab = nodes[i];
-        }
-        nodes[i].addEventListener("mousedown", onTabMouseDown, true);
-        nodes[i].addEventListener("click", onTabClick, true);
+      var currentNode = nodes[i];
+      if (currentNode.tagName == 'LI') {
+       if (!firstTab)
+         firstTab = i;
+       $(currentNode).observe("mousedown", onTabMouseDown);
+       $(currentNode).observe("click", onTabClick);
+       //$(currentNode.getAttribute("target")).hide();
       }
     }
 
-    firstTab.addClassName("first");
-    firstTab.addClassName("active");
-    container.activeTab = firstTab;
+    nodes[firstTab].addClassName("first");
+    nodes[firstTab].addClassName("active");
+    container.activeTab = nodes[firstTab];
 
-    var target = $(firstTab.getAttribute("target"));
+    var target = $(nodes[firstTab].getAttribute("target"));
     target.addClassName("active");
+    //target.show();
   }
 }
 
-function initMenusNamed(menuDivNames) {
-  for (var i = 0; i < menuDivNames.length; i++) {
-    var menuDIV = $(menuDivNames[i]);
-    if (menuDIV)
-      initMenu(menuDIV);
-    else
-      log("menu named '" + menuDivNames[i] + "' not found");
+function initMenus() {
+  var menus = getMenus();
+  if (menus) {
+    for (var menuID in menus) {
+      var menuDIV = $(menuID);
+      if (menuDIV)
+       initMenu(menuDIV, menus[menuID]);
+    }
   }
 }
 
-function initMenu(menuDIV) {
-  var lis = menuDIV.childNodesWithTag("ul")[0].childNodesWithTag("li");
-  for (var j = 0; j < lis.length; j++)
-    lis[j].addEventListener("mousedown", listRowMouseDownHandler, false);
-  var subMenus = menuDIV.childNodesWithTag("div");
-  for (var i = 0; i < subMenus.length; i++)
-    initMenu(subMenus[i]);
+function initMenu(menuDIV, callbacks) {
+  var lis = $(menuDIV.down("ul")).childNodesWithTag("li");
+  for (var j = 0; j < lis.length; j++) {
+    var node = $(lis[j]);
+    node.observe("mousedown", listRowMouseDownHandler, false);
+    var callback = callbacks[j];
+    if (callback) {
+      if (typeof(callback) == "string") {
+       if (callback == "-")
+         node.addClassName("separator");
+       else {
+         node.submenu = callback;
+         node.addClassName("submenu");
+         node.observe("mouseover", popupSubmenu);
+       }
+      }
+      else {
+       node.observe("mouseup", onBodyClickMenuHandler);
+       node.observe("click", callback);
+      }
+    }
+    else
+      node.addClassName("disabled");
+  }
 }
 
 function onTabMouseDown(event) {
   event.cancelBubble = true;
-  event.preventDefault();
+  preventDefault(event);
 }
 
 function openExternalLink(anchor) {
   return false;
 }
 
-function openAclWindow(url, objectTitle) {
+function openAclWindow(url) {
   var w = window.open(url, "aclWindow",
-                      "width=300,height=300,resizable=1,scrollbars=1,toolbar=0,"
+                      "width=420,height=300,resizable=1,scrollbars=1,toolbar=0,"
                       + "location=0,directories=0,status=0,menubar=0"
                       + ",copyhistory=0");
+  w.opener = window;
   w.focus();
-  w.title = "Poil: " + objectTitle;
 
   return w;
 }
 
+function getUsersRightsWindowHeight() {
+  return usersRightsWindowHeight;
+}
+
+function getUsersRightsWindowWidth() {
+  return usersRightsWindowWidth;
+}
+
+function getTopWindow() {
+  var topWindow = null;
+  var currentWindow = window;
+  while (!topWindow) {
+    if (currentWindow.document.body.hasClassName("popup")
+       && currentWindow.opener)
+      currentWindow = currentWindow.opener;
+    else
+      topWindow = currentWindow;
+  }
+
+  return topWindow;
+}
+
 function onTabClick(event) {
-  var node = event.target;
+  var node = getTarget(event); // LI element
 
   var target = node.getAttribute("target");
 
@@ -876,10 +1195,24 @@ function onTabClick(event) {
   var oldContent = $(oldTarget);
 
   oldContent.removeClassName("active");
-  container.activeTab.removeClassName("active");
+  container.activeTab.removeClassName("active"); // previous LI
   container.activeTab = node;
-  container.activeTab.addClassName("active");
+  container.activeTab.addClassName("active"); // current LI
   content.addClassName("active");
+  
+  // Prototype alternative
+
+  //oldContent.removeClassName("active");
+  //container.activeTab.removeClassName("active"); // previous LI
+  //container.activeTab = node;
+  //container.activeTab.addClassName("active"); // current LI
+
+  //container.activeTab.hide();
+  //oldContent.hide();
+  //content.show();
+
+  //container.activeTab = node;
+  //container.activeTab.show();
 
   return false;
 }
@@ -922,11 +1255,13 @@ function disableAnchor(anchor) {
 
 function d2h(d) {
   var hD = "0123456789abcdef";
-  var h = hD.substr(d&15,1);
-  while (d>15) {
-    d>>=4;
-    h=hD.substr(d&15,1)+h;
+  var h = hD.substr(d & 15, 1);
+
+  while (d > 15) {
+    d >>= 4;
+    h = hD.substr(d & 15, 1) + h;
   }
+
   return h;
 }
 
@@ -940,15 +1275,14 @@ function indexColor(number) {
     
     var currentValue = number;
     var index = 0;
-    while (currentValue)
-      {
-        if (currentValue & 1)
-          colorTable[index]++;
+    while (currentValue) {
+      if (currentValue & 1)
+       colorTable[index]++;
       if (index == 3)
-        index = 0;
+       index = 0;
       currentValue >>= 1;
       index++;
-      }
+    }
     
     color = ("#"
              + d2h((256 / colorTable[2]) - 1)
@@ -959,33 +1293,57 @@ function indexColor(number) {
   return color;
 }
 
-var onLoadHandler = {
-  handleEvent: function (event) {
-    queryParameters = parseQueryParameters('' + window.location);
-    if (!document.body.hasClassName("popup")) {
-      initLogConsole();
-      initializeMenus();
-      initCriteria();
-    }
-    initTabs();
-    configureDragHandles();
-    configureSortableTableHeaders();
-    configureLinkBanner();
-    var progressImage = $("progressIndicator");
-    if (progressImage)
-      progressImage.parentNode.removeChild(progressImage);
+function loadPreferences() {
+  var url = UserFolderURL + "jsonDefaults";
+  var http = createHTTPClient();
+  http.open("GET", url, false);
+  http.send("");
+  if (http.status == 200) {
+    if (http.responseText.length > 0)
+      userDefaults = http.responseText.evalJSON(true);
+    else
+      userDefaults = {};
   }
+
+  url = UserFolderURL + "jsonSettings";
+  http.open("GET", url, false);
+  http.send("");
+  if (http.status == 200) {
+    if (http.responseText.length > 0)
+      userSettings = http.responseText.evalJSON(true);
+    else
+      userSettings = {};
+  }
+}
+
+function onLoadHandler(event) {
+  if (typeof UserLogin != "undefined")
+    loadPreferences();
+  queryParameters = parseQueryParameters('' + window.location);
+  if (!$(document.body).hasClassName("popup")) {
+    initLogConsole();
+  }
+  initCriteria();
+  configureSearchField();
+  initMenus();
+  initTabs();
+  configureDragHandles();
+  configureLinkBanner();
+  var progressImage = $("progressIndicator");
+  if (progressImage)
+    progressImage.parentNode.removeChild(progressImage);
+  $(document.body).observe("contextmenu", onBodyClickContextMenu);
+}
+
+function onBodyClickContextMenu(event) {
+  preventDefault(event);
 }
 
-function configureSortableTableHeaders() {
-  var headers = document.getElementsByClassName("sortableTableHeader");
+function configureSortableTableHeaders(table) {
+  var headers = $(table).getElementsByClassName("sortableTableHeader");
   for (var i = 0; i < headers.length; i++) {
-    var anchor = headers[i].childNodesWithTag("a")[0];
-    if (!anchor.link) {
-      anchor.link = anchor.getAttribute("href");
-      anchor.href = "#";
-      anchor.addEventListener("click", onHeaderClick, true);
-    }
+    var header = headers[i];
+    $(header).observe("click", onHeaderClick);
   }
 }
 
@@ -994,27 +1352,92 @@ function onLinkBannerClick() {
   checkAjaxRequestsState();
 }
 
+function onPreferencesClick(event) {
+  var urlstr = UserFolderURL + "preferences";
+  var w = window.open(urlstr, "_blank",
+                     "width=430,height=250,resizable=0,scrollbars=0,location=0");
+  w.opener = window;
+  w.focus();
+
+  preventDefault(event);
+}
+
 function configureLinkBanner() {
   var linkBanner = $("linkBanner");
   if (linkBanner) {
-    var anchors = linkBanner.childNodesWithTag("a");
-    for (var i = 0; i < 4; i++) {
-      anchors[i].addEventListener("mousedown", listRowMouseDownHandler,
-                                  false);
-      anchors[i].addEventListener("click", onLinkBannerClick, false);
+    var moduleLinks = [ "calendar", "contacts", "mail" ];
+    for (var i = 0; i < moduleLinks.length; i++) {
+      var link = $(moduleLinks[i] + "BannerLink");
+      if (link) {
+       link.observe("mousedown", listRowMouseDownHandler);
+       link.observe("click", onLinkBannerClick);
+      }
+    }
+    link = $("preferencesBannerLink");
+    if (link) {
+      link.observe("mousedown", listRowMouseDownHandler);
+      link.observe("click", onPreferencesClick);
+    }
+    link = $("consoleBannerLink");
+    if (link) {
+      link.observe("mousedown", listRowMouseDownHandler);
+      link.observe("click", toggleLogConsole);
     }
-    if (anchors.length > 5)
-      anchors[5].addEventListener("click", toggleLogConsole, true);
   }
 }
 
-window.addEventListener("load", onLoadHandler, false);
+/* folder creation */
+function createFolder(name, okCB, notOkCB) {
+  if (name) {
+    if (document.newFolderAjaxRequest) {
+      document.newFolderAjaxRequest.aborted = true;
+      document.newFolderAjaxRequest.abort();
+    }
+    var url = ApplicationBaseURL + "/createFolder?name=" + name;
+    document.newFolderAjaxRequest
+      = triggerAjaxRequest(url, createFolderCallback,
+                          {name: name,
+                           okCB: okCB,
+                           notOkCB: notOkCB});
+  }
+}
+
+function createFolderCallback(http) {
+  if (http.readyState == 4) {
+    var data = http.callbackData;
+    if (http.status == 201) {
+      if (data.okCB)
+       data.okCB(data.name, "/" + http.responseText, UserLogin);
+    }
+    else {
+      if (data.notOkCB)
+       data.notOkCB(name);
+      else
+       log("ajax problem:" + http.status);
+    }
+  }
+}
+
+function onFinalLoadHandler(event) {
+  var safetyNet = $("javascriptSafetyNet");
+  if (safetyNet)
+    safetyNet.parentNode.removeChild(safetyNet);
+}
+
+FastInit.addOnLoad(onLoadHandler);
+
+function parent$(element) {
+  return this.opener.document.getElementById(element);
+}
 
 /* stubs */
+function refreshCurrentFolder() {
+}
+
 function configureDragHandles() {
 }
 
-function initializeMenus() {
+function getMenus() {
 }
 
 function onHeaderClick(event) {