(feature/cleanup) Refactored clickmenu to speed up the BE
authorBenni Mack <benni.mack@typo3.org>
Fri, 9 Nov 2007 20:57:42 +0000 (20:57 +0000)
committerBenni Mack <benni.mack@typo3.org>
Fri, 9 Nov 2007 20:57:42 +0000 (20:57 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@2682 709f56b5-9817-0410-a4d7-c38de5d9e867

20 files changed:
ChangeLog
typo3/alt_clickmenu.php
typo3/alt_db_navframe.php
typo3/alt_doc.php
typo3/alt_file_navframe.php
typo3/db_list.php
typo3/file_list.php
typo3/js/clickmenu.js [new file with mode: 0644]
typo3/mod/user/ws/class.wslib_gui.php
typo3/mod/user/ws/index.php
typo3/mod/user/ws/workspaceforms.php
typo3/mod/web/func/index.php
typo3/mod/web/info/index.php
typo3/mod/web/perm/index.php
typo3/stylesheet.css
typo3/sysext/cms/layout/db_layout.php
typo3/sysext/tstemplate/ts/index.php
typo3/sysext/version/cm1/index.php
typo3/template.php
typo3/tree.js

index b19d113..d9f75a0 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,6 @@
 2007-11-09  Benjamin Mack  <mack@xnos.org>
 
+       * (feature/cleanup) Refactored clickmenu to speed up the BE
        * (bugfix) Fixed Image Generation bug. Call in t3lib_div now uses the IM wrapper to render gifs/pngs
 
 2007-11-08  Ingo Renner        <ingo@typo3.org>
index 46f3e40..2f966d7 100755 (executable)
@@ -1208,8 +1208,8 @@ class clickMenu {
                                        // Create JavaScript section:
                                $script=$GLOBALS['TBE_TEMPLATE']->wrapScriptTags('
 
-                               if (top.content && top.content'.$frameName.' && top.content'.$frameName.'.setLayerObj)  {
-                                       top.content'.$frameName.'.setLayerObj(unescape("'.t3lib_div::rawurlencodeJS($CMtable).'"),'.$this->cmLevel.');
+                               if (top.content && top.content'.$frameName.' && top.content'.$frameName.'.Clickmenu)    {
+                                       top.content'.$frameName.'.Clickmenu.populateData(unescape("'.t3lib_div::rawurlencodeJS($CMtable).'"),'.$this->cmLevel.');
                                }
                                '.(!$this->doDisplayTopFrameCM()?'hideCM();':'')
                                );
@@ -1279,7 +1279,7 @@ class clickMenu {
                                $onClick=eregi_replace('return[[:space:]]+hideCM\(\)[[:space:]]*;','',$onClick);
                                $onClick=eregi_replace('return[[:space:]]+false[[:space:]]*;','',$onClick);
                                $onClick=eregi_replace('hideCM\(\);','',$onClick);
-                               if (!$i[5])     $onClick.='hideEmpty();';
+                               if (!$i[5])     $onClick.='Clickmenu.hideAll();';
 
                                if ($GLOBALS['TYPO3_CONF_VARS']['BE']['useOnContextMenuHandler'])   {
                                        $CSM = ' oncontextmenu="'.htmlspecialchars($onClick).';return false;"';
@@ -1736,4 +1736,4 @@ foreach($SOBE->include_once as $INC_FILE) include_once($INC_FILE);
 
 $SOBE->main();
 $SOBE->printContent();
-?>
\ No newline at end of file
+?>
index 96dd198..86a9480 100755 (executable)
@@ -169,11 +169,8 @@ class SC_alt_db_navframe {
                        ');
 
                                // Click menu code is added:
-                       $CMparts=$this->doc->getContextMenuCode();
-                       $this->doc->bodyTagAdditions = $CMparts[1];
+                       $this->doc->getContextMenuCode();
                        $this->doc->bodyTagId = 'bodyTag';
-                       $this->doc->JScode.= $CMparts[0];
-                       $this->doc->postCode.= $CMparts[2];
                }
        }
 
index af34411..95a5e5f 100755 (executable)
@@ -490,10 +490,8 @@ class SC_alt_doc {
                ).$this->doc->getDynTabMenuJScode();
 
                        // Setting up the context sensitive menu:
-               $CMparts = $this->doc->getContextMenuCode();
-               $this->doc->JScode.= $CMparts[0];
-               $this->doc->bodyTagAdditions = str_replace('onload="','onload="window.scrollTo(0,'.t3lib_div::intInRange(t3lib_div::_GP('_scrollPosition'),0,10000).');',$CMparts[1]);
-               $this->doc->postCode.= $CMparts[2];
+               $this->doc->getContextMenuCode();
+               $this->doc->bodyTagAdditions = 'onload="window.scrollTo(0,'.t3lib_div::intInRange(t3lib_div::_GP('_scrollPosition'),0,10000).');"';
        }
 
        /**
index 3e2aae4..c8ebef1 100755 (executable)
@@ -149,10 +149,7 @@ class SC_alt_file_navframe {
                        );
 
                                // Click menu code is added:
-                       $CMparts=$this->doc->getContextMenuCode();
-                       $this->doc->bodyTagAdditions = $CMparts[1];
-                       $this->doc->JScode.= $CMparts[0];
-                       $this->doc->postCode.= $CMparts[2];
+                       $this->doc->getContextMenuCode();
                }
        }
 
index 0d8695f..0655f1e 100755 (executable)
@@ -349,10 +349,7 @@ class SC_db_list {
                        ');
 
                                // Setting up the context sensitive menu:
-                       $CMparts=$this->doc->getContextMenuCode();
-                       $this->doc->bodyTagAdditions = $CMparts[1];
-                       $this->doc->JScode.=$CMparts[0];
-                       $this->doc->postCode.= $CMparts[2];
+                       $this->doc->getContextMenuCode();
                } // access
 
 
index 5f26922..64222bf 100755 (executable)
@@ -246,10 +246,7 @@ class SC_file_list {
                        );
 
                                // This will return content necessary for the context sensitive clickmenus to work: bodytag events, JavaScript functions and DIV-layers.
-                       $CMparts=$this->doc->getContextMenuCode();
-                       $this->doc->bodyTagAdditions = $CMparts[1];
-                       $this->doc->JScode.=$CMparts[0];
-                       $this->doc->postCode.= $CMparts[2];
+                       $this->doc->getContextMenuCode();
 
 
                                // Create output
@@ -367,4 +364,4 @@ $SOBE->printContent();
 if ($TYPO3_CONF_VARS['BE']['compressionLevel'])        {
        new gzip_encode($TYPO3_CONF_VARS['BE']['compressionLevel']);
 }
-?>
\ No newline at end of file
+?>
diff --git a/typo3/js/clickmenu.js b/typo3/js/clickmenu.js
new file mode 100644 (file)
index 0000000..d29a6ef
--- /dev/null
@@ -0,0 +1,273 @@
+/**
+ * Javascript functions regarding the clickmenu
+ * relies on the javascript library "prototype"
+ *
+ * (c) 2007 Benjamin Mack <www.xnos.org>
+ * All rights reserved
+ *
+ * This script is part of TYPO3 by
+ * Kasper Skaarhoj <kasperYYYYY@typo3.com>
+ *
+ * Released under GNU/GPL (see license file in tslib/)
+ *
+ * This script is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ *
+ * This copyright notice MUST APPEAR in all copies of this script
+ */
+
+
+/**
+ * extends the window object to get cross-browser window dimensions
+ * 
+ * @return     an object with a width and height property
+ */
+window.getDimensions = function() {
+       var w = window.innerWidth
+                       || document.documentElement.clientWidth
+                       || document.body.clientWidth
+                       || 0;
+       var h = window.innerHeight
+                       || document.documentElement.clientHeight
+                       || document.body.clientHeight
+                       || 0;
+       return { width: w, height: h };
+}
+
+
+/**
+ * extends prototype's Position object 
+ *
+ * @return     an object with a top and a left position property
+ */
+Position.getScrollOffset = function() {
+       this.prepare();
+       return { top: this.deltaY, left: this.deltaX };
+}
+
+/**
+ * new clickmenu code to make an AJAX call and render the 
+ * AJAX result in a layer next to the mouse cursor
+ */
+var Clickmenu = {
+       clickURL: 'alt_clickmenu.php',  // URL to the clickmenu.php file, see template.php
+       ajax: true,     // template.php -> isCMLayers check
+       mousePos: { X: null, Y: null },
+
+
+       /**
+        * main function, called from most clickmenu links
+        * @param       table           table from where info should be fetched
+        * @param       uid             the UID of the item
+        * @param       listFr          list Frame?
+        * @param       enDisItems      Items to disable / enable
+        * @param       backPath        TYPO3 backPath
+        * @param       addParams       additional params
+        * @return      nothing
+        */
+       show: function(table, uid, listFr, enDisItems, backPath, addParams) {
+               var params = 'table=' + encodeURIComponent(table)
+                       + '&uid=' + uid
+                       + '&listFr=' + listFr
+                       + '&enDisItems=' + enDisItems
+                       + '&backPath=' + backPath
+                       + '&addParams=' + addParams;
+               this.callURL(params);
+       },
+
+
+       /**
+        * switch function that either makes an AJAX call
+        * or loads the request in the top frame
+        *
+        * @param       params  parameters added to the URL
+        * @return      nothing
+        */ 
+       callURL: function(params) {     
+               if (this.ajax && Ajax.getTransport()) { // run with AJAX
+                       params += '&ajax=1';
+                       new Ajax.Request(this.clickURL, {
+                               method: 'get',
+                               parameters: params,
+                               onComplete: function(xhr) {
+                                       var response = xhr.responseXML;
+                                       if (!response.getElementsByTagName('data')[0]) return;
+                                       var menu  = response.getElementsByTagName('data')[0].getElementsByTagName('clickmenu')[0];
+                                       var data  = menu.getElementsByTagName('htmltable')[0].firstChild.data;
+                                       var level = menu.getElementsByTagName('cmlevel')[0].firstChild.data;
+                                       this.populateData(data, level);
+                               }.bind(this)
+                       });
+               } else { // fallback with no AJAX, no isCMLayers
+                       top.loadTopMenu(this.clickURL + '?' + params);
+               }
+       },
+
+
+       /**
+        * fills the clickmenu with content and displays it correctly
+        * depending on the mouse position
+        * @param       data    the data that will be put in the menu
+        * @param       level   the depth of the clickmenu
+        */
+       populateData: function(data, level) {
+               if (!$('contentMenu0')) this.addClickmenuItem();
+               level = parseInt(level) || 0;
+               var obj = $('contentMenu' + level);
+
+               if (obj && (level == 0 || Element.visible('contentMenu' + (level-1)))) {
+                       obj.innerHTML = data;
+                       var x = this.mousePos.X;
+                       var y = this.mousePos.Y;
+                       var dimsWindow = window.getDimensions();
+                       dimsWindow.width = dimsWindow.width-20; // saving margin for scrollbars
+
+                       var dims = Element.getDimensions(obj); // dimensions for the clickmenu
+                       var offset = Position.getScrollOffset();
+                       var relative = { X: this.mousePos.X - offset.left, Y: this.mousePos.Y - offset.top };
+
+                       // adjusting the Y position of the layer to fit it into the window frame
+                       // if there is enough space above then put it upwards,
+                       // otherwise adjust it to the bottom of the window
+                       if (dimsWindow.height - dims.height < relative.Y) {
+                               if (relative.Y > dims.height) {
+                                       y -= (dims.height - 10);
+                               } else {
+                                       y += (dimsWindow.height - dims.height - relative.Y);
+                               }
+                       }
+                       // adjusting the X position like Y above
+                       if (dimsWindow.width - dims.width < relative.X) {
+                               if (relative.X > dims.width) {
+                                       x -= (dims.width - 10);
+                               } else {
+                                       x += (dimsWindow.width - dims.width - relative.X);
+                               }
+                       }
+
+                       obj.style.left = x + 'px';
+                       obj.style.top  = y + 'px';
+                       Element.show(obj);
+               }
+               if (/MSIE5/.test(navigator.userAgent)) {
+                       this._toggleSelectorBoxes('hidden');
+               }
+       },
+
+       /**
+        * event handler function that saves the actual position of the mouse
+        * in the Clickmenu object
+        * @param       event   the event object
+        */
+       calcMousePosEvent: function(event) {
+               if (!event) {
+                       event = window.event;
+               }
+               this.mousePos.X = Event.pointerX(event);
+               this.mousePos.Y = Event.pointerY(event);
+               this.mouseOutFromMenu('contentMenu0');
+               this.mouseOutFromMenu('contentMenu1');
+       },
+
+
+       /**
+        * hides a visible menu if the mouse has moved outside
+        * of the object
+        * @param       obj     the object to hide
+        * @result      nothing
+        */
+       mouseOutFromMenu: function(obj) {
+               obj = $(obj);
+               if (obj && Element.visible(obj) && !Position.within(obj, this.mousePos.X, this.mousePos.Y)) {
+                       this.hide(obj);
+                       if (/MSIE5/.test(navigator.userAgent) && obj.id == 'contentMenu0') {
+                               this._toggleSelectorBoxes('visible');
+                       }
+               }
+       },
+
+       /**
+        * hides a clickmenu
+        *
+        * @param       obj     the clickmenu object to hide
+        * @result      nothing
+        */
+       hide: function(obj) {
+               Element.hide(obj);
+       },
+
+       /**
+        * hides all clickmenus
+        */
+       hideAll: function() {
+               this.hide('contentMenu0');
+               this.hide('contentMenu1');
+       },
+
+
+       /**
+        * hides / displays all selector boxes in a page, fixes an IE 5 selector problem
+        * originally by Michiel van Leening
+        *
+        * @param       action  hide (= "hidden") or show (= "visible")
+        * @result      nothing
+        */
+       _toggleSelectorBoxes: function(action) {
+               for (i = 0; i < document.forms.length; i++) {
+                       for (j = 0; j < document.forms[i].elements.length; j++) {
+                               if (document.forms[i].elements[j].type == 'select-one') {
+                                       document.forms[i].elements[j].style.visibility = action;
+                               }
+                       }
+               }
+       },
+
+
+       /**
+        * manipulates the DOM to add the divs needed for clickmenu at the bottom of the <body>-tag
+        *
+        * @return      nothing
+        */
+       addClickmenuItem: function() {
+               var code = '<div id="contentMenu0" style="display: block;"></div><div id="contentMenu1" style="display: block;"></div>';
+               new Insertion.Bottom(document.getElementsByTagName('body')[0], code);
+       }
+}
+
+// register mouse movement inside the document
+Event.observe(document, 'mousemove', Clickmenu.calcMousePosEvent.bindAsEventListener(Clickmenu), true);
+
+
+// deprecated functions since 4.2, here for compatibility, remove in 4.4
+function showClickmenu(table, uid, listFr, enDisItems, backPath, addParams)    {
+       Clickmenu.show(table, uid, listFr, enDisItems, backPath, addParams);
+}
+
+function showClickmenu_raw(url) {
+       var parts = url.split('?');
+       if (parts.length == 2) {
+               Clickmenu.clickURL = parts[0];
+               Clickmenu.callURL(parts[1]);
+       } else {
+               Clickmenu.callURL(url);
+       }
+}
+function showClickmenu_noajax(url) {
+       Clickmenu.ajax = false; showClickmenu_raw(url);
+}
+function setLayerObj(tableData, cmLevel) {
+       Clickmenu.populateData(tableData, cmLevel);
+}
+function hideEmpty() {
+       Clickmenu.hideAll();
+       return false;
+}
+function hideSpecific(level) {
+       if (level == 0 || level == 1)   {
+               Clickmenu.hide('contentMenu'+level);
+       }
+} 
+function showHideSelectorBoxes(action) {
+       toggleSelectorBoxes(action);
+}
index a33a38a..ac3e250 100644 (file)
@@ -116,12 +116,9 @@ class wslib_gui {
         *
         * The following code is <strong>required</strong> in BE module when this function is used:
         * <code>
-        *      $CMparts = $this->doc->getContextMenuCode();
-        *      $this->doc->JScode.= $CMparts[0];
-        *      $this->doc->bodyTagAdditions = $CMparts[1];
-        *      $this->doc->postCode.= $CMparts[2];
+        *      $this->doc->getContextMenuCode();
         * </code>
-        * or click-menu will not be gerated properly!
+        * or click-menu will not be generated properly!
         *
         * @param       object          $doc    Document (to use for formatting)
         * @param       int             $wsid   Workspace ID, If <code>null</code>, the value is obtained from current BE user
@@ -1303,4 +1300,4 @@ if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/mod/u
        include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['typo3/mod/user/ws/class.wslib_gui.php']);
 }
 
-?>
\ No newline at end of file
+?>
index 2299136..ec01b61 100755 (executable)
@@ -282,10 +282,7 @@ class SC_mod_user_ws_index extends t3lib_SCbase {
                $this->doc->form = '<form action="index.php" method="post" name="pageform">';
 
                        // Setting up the context sensitive menu:
-               $CMparts = $this->doc->getContextMenuCode();
-               $this->doc->JScode.= $CMparts[0];
-               $this->doc->bodyTagAdditions = $CMparts[1];
-               $this->doc->postCode.= $CMparts[2];
+               $this->doc->getContextMenuCode();
 
                        // Add JS for dynamic tabs:
                $this->doc->JScode.= $this->doc->getDynTabMenuJScode();
index 760fc61..6489cbd 100644 (file)
@@ -142,11 +142,8 @@ class SC_mod_user_ws_workspaceForms extends t3lib_SCbase {
                $this->doc->docType = 'xhtml_trans';
                $this->doc->form = '<form action="' . t3lib_div::getIndpEnv('SCRIPT_NAME').'" method="post" enctype="'.$GLOBALS['TYPO3_CONF_VARS']['SYS']['form_enctype'].'" name="editform" onsubmit="return TBE_EDITOR.checkSubmit(1);">';
 
-               $CMparts = $this->doc->getContextMenuCode();
-               $this->doc->JScode.= $CMparts[0];
+               $this->doc->getContextMenuCode();
                $this->doc->JScode.= $this->doc->getDynTabMenuJScode();
-               $this->doc->bodyTagAdditions = $CMparts[1];
-               $this->doc->postCode.= $CMparts[2];
 
                // Parent initialization:
                t3lib_SCbase::init();
@@ -666,4 +663,4 @@ $SOBE = t3lib_div::makeInstance('SC_mod_user_ws_workspaceForms');
 $SOBE->init();
 $SOBE->main();
 $SOBE->printContent();
-?>
\ No newline at end of file
+?>
index e0adc44..faa1ff0 100755 (executable)
@@ -119,10 +119,7 @@ class SC_mod_web_func_index extends t3lib_SCbase {
 
 
                                // Setting up the context sensitive menu:
-                       $CMparts=$this->doc->getContextMenuCode();
-                       $this->doc->bodyTagAdditions = $CMparts[1];
-                       $this->doc->JScode.=$CMparts[0];
-                       $this->doc->postCode.= $CMparts[2];
+                       $this->doc->getContextMenuCode();
 
                        $this->doc->form='<form action="index.php" method="post"><input type="hidden" name="id" value="'.$this->id.'" />';
 
index 1d0d877..75bc3d4 100755 (executable)
@@ -128,10 +128,7 @@ class SC_mod_web_info_index extends t3lib_SCbase {
 
 
                                // Setting up the context sensitive menu:
-                       $CMparts=$this->doc->getContextMenuCode();
-                       $this->doc->bodyTagAdditions = $CMparts[1];
-                       $this->doc->JScode.=$CMparts[0];
-                       $this->doc->postCode.= $CMparts[2];
+                       $this->doc->getContextMenuCode();
 
                        $headerSection = $this->doc->getHeader('pages',$this->pageinfo,$this->pageinfo['_thePath']).'<br />'.
                                $LANG->sL('LLL:EXT:lang/locallang_core.php:labels.path',1).': '.
index 4e58ed6..ccdd69e 100755 (executable)
@@ -172,10 +172,7 @@ class SC_mod_web_perm_index {
                ');
 
                        // Setting up the context sensitive menu:
-               $CMparts=$this->doc->getContextMenuCode();
-               $this->doc->bodyTagAdditions = $CMparts[1];
-               $this->doc->JScode.=$CMparts[0];
-               $this->doc->postCode.= $CMparts[2];
+               $this->doc->getContextMenuCode();
 
                        // Set up menus:
                $this->menuConfig();
index d242114..9268959 100755 (executable)
@@ -539,6 +539,10 @@ TABLE.ver-subtree TR.typo3-ver-noComp TD { font-style: italic; }
  * VARIOUS STAND-ALONE classes:
  *********************************************/
 
+/* context menus */
+div#contentMenu0 { z-index: 1; position: absolute; }
+div#contentMenu1 { z-index: 2; position: absolute; }
+
 /* Dimmed span tag color (disabled) */
 .typo3-dimmed { color: #666; }
 .c-na { color: #666; font-style: italic; }
index 69b3a87..c896a59 100755 (executable)
@@ -499,10 +499,7 @@ class SC_db_layout {
                $this->doc->form='<form action="'.htmlspecialchars($BACK_PATH.'tce_db.php?&prErr=1&uPT=1').'" method="post" enctype="'.$GLOBALS['TYPO3_CONF_VARS']['SYS']['form_enctype'].'" name="editform" onsubmit="return TBE_EDITOR.checkSubmit(1);">';
 
                        // Setting up the context sensitive menu:
-               $CMparts = $this->doc->getContextMenuCode();
-               $this->doc->JScode.= $CMparts[0];
-               $this->doc->bodyTagAdditions = $CMparts[1];
-               $this->doc->postCode.= $CMparts[2];
+               $this->doc->getContextMenuCode();
 
                        // Set the edit_record value for internal use in this function:
                $edit_record = $this->edit_record;
@@ -1035,10 +1032,7 @@ class SC_db_layout {
 
 
                        // For Context Sensitive Menus:
-               $CMparts = $this->doc->getContextMenuCode();
-               $this->doc->bodyTagAdditions = $CMparts[1];
-               $this->doc->JScode.= $CMparts[0];
-               $this->doc->postCode.= $CMparts[2];
+               $this->doc->getContextMenuCode();
 
 
                        // Draw the page properties.
index 1d46995..10d59dc 100644 (file)
@@ -131,10 +131,7 @@ class SC_mod_web_ts_index extends t3lib_SCbase {
 
 
                                // Setting up the context sensitive menu:
-                       $CMparts=$this->doc->getContextMenuCode();
-                       $this->doc->bodyTagAdditions = $CMparts[1];
-                       $this->doc->JScode.=$CMparts[0];
-                       $this->doc->postCode.= $CMparts[2];
+                       $this->doc->getContextMenuCode();
 
 
                        $headerSection = $this->doc->getHeader("pages",$pageinfo,$pageinfo["_thePath"]).'<br>'.
index 75b476c..71d7673 100755 (executable)
@@ -199,10 +199,7 @@ class tx_version_cm1 extends t3lib_SCbase {
 ';
 
                        // Setting up the context sensitive menu:
-               $CMparts = $this->doc->getContextMenuCode();
-               $this->doc->JScode.= $CMparts[0];
-               $this->doc->bodyTagAdditions = $CMparts[1];
-               $this->doc->postCode.= $CMparts[2];
+               $this->doc->getContextMenuCode();
 
                        // Getting input data:
                $this->id = intval(t3lib_div::_GP('id'));               // Page id. If set, indicates activation from Web>Versioning module
index 6d1288d..9676055 100755 (executable)
@@ -1263,326 +1263,23 @@ $str.=$this->docBodyTagBegin().
 
 
        /**
-        * Returns an array with parts (JavaScript, init-functions, <div>-layers) for use on pages which displays the clickmenu layers (context sensitive menus)
+        * Includes the necessary Javascript function for the clickmenu (context sensitive menus) in the document
         *
-        * @return      array           If values are present: [0] = A <script> section for the HTML page header, [1] = onmousemove/onload handler for HTML tag or alike, [2] = Two empty <div> layers for the context menu
+        * @return      array   Deprecated: Includes the code already in the doc, so the return array is always empty.
+        *                      Please just call this function without expecting a return value for future calls
         */
-       function getContextMenuCode()   {
-               $content = '
-                       <script type="text/javascript">
-                       /*<![CDATA[*/
-                                       // is called from most clickmenu links
-                               function showClickmenu(table, uid, listFr, enDisItems, backPath, addParams)     {
-                                       var url = "'.$this->backPath.'alt_clickmenu.php?table=" + encodeURIComponent(table)
-                                                 + "&uid=" + uid
-                                                                               + "&listFr=" + listFr
-                                                                               + "&enDisItems=" + enDisItems
-                                                                               + "&backPath=" + backPath
-                                                                               + "&addParams=" + addParams;
-
-                                       showClickmenu_raw(url);
-                               }
-                                       // switch - either forwards call to ajax or does the request in the top frame
-                               function showClickmenu_raw(url) {';
-               if ($this->isCMlayers())        { // AJAX
-                       $content.= '
-                                       url += "&ajax=1";
-                                       ajax_doRequest(url);';
-               } else { // no AJAX
-                       $content.= '
-                                       showClickmenu_noajax(url);';
-               }
-               $content.= '
-                               }
+       function getContextMenuCode()   {
+              $this->loadJavascriptLib('contrib/prototype/prototype.js');
+              $this->loadJavascriptLib('js/clickmenu.js');
 
-                               function showClickmenu_noajax(url)      {
-                                       top.loadTopMenu(url);
-                               }';
-               if ($this->isCMlayers())        {
-                       $content.= t3lib_ajax::getJScode('showClickmenu_ajax', 'showClickmenu_noajax');
-                       $content.='
-                                       // opens the clickmenu, is called from ajax_doRequest
-                               function showClickmenu_ajax(t3ajax)     {
-                                       if (t3ajax.getElementsByTagName("data")[0])     {
-                                               var clickmenu = t3ajax.getElementsByTagName("data")[0].getElementsByTagName("clickmenu")[0];
-                                               var tableData = clickmenu.getElementsByTagName("htmltable")[0].firstChild.data;
-                                               var cmlevel = clickmenu.getElementsByTagName("cmlevel")[0].firstChild.data;
-                                               setLayerObj(tableData,cmlevel);
-                                       }
-                               }
+              $this->JScodeArray['clickmenu'] = '
+                              Clickmenu.clickURL = "'.$this->backPath.'alt_clickmenu.php";
+                              Clickmenu.ajax     = '.($this->isCMLayers() ? 'true' : 'false' ).';';
 
-                               var GLV_gap=10;
-                               var GLV_curLayerX=new Array(0,0);
-                               var GLV_curLayerY=new Array(0,0);
-                               var GLV_curLayerWidth=new Array(0,0);
-                               var GLV_curLayerHeight=new Array(0,0);
-                               var GLV_isVisible=new Array(0,0);
-                               var GLV_x=0;
-                               var GLV_y=0;
-                               var GLV_xRel=0;
-                               var GLV_yRel=0;
-                               var layerObj=new Array();
-                               var layerObjCss=new Array();
-
-                                       //browsercheck...
-                               function GL_checkBrowser(){     //
-                                       this.dom= (document.getElementById);
-                                       this.safari =  (navigator.userAgent.indexOf("Safari")>-1);
-                                       this.op=  (navigator.userAgent.indexOf("Opera")>-1);
-                                       this.op7=  this.op && (navigator.appVersion.indexOf("7")>-1);  // check for Opera version 7
-                                       this.konq=  (navigator.userAgent.indexOf("Konq")>-1);
-                                       this.ie4= (document.all && !this.dom && !this.op && !this.konq);
-                                       this.ie5= (document.all && this.dom && !this.op && !this.konq);
-                                       this.ns4= (document.layers && !this.dom && !this.konq);
-                                       this.ns5= (!document.all && this.dom && !this.op && !this.konq);
-                                       this.ns6= (this.ns5);
-                                       this.bw=  (this.ie4 || this.ie5 || this.ns4 || this.ns6 || this.op || this.konq);
-                                       return this;
-                               }
-                               bw= new GL_checkBrowser();
-
-                                       // GL_getObj(obj)
-                               function GL_getObj(obj){        //
-                                       nest="";
-                                       this.el= (bw.ie4||bw.op7)?document.all[obj]:bw.ns4?eval(nest+"document."+obj):document.getElementById(obj);
-                                       this.css= bw.ns4?this.el:this.el.style;
-                                       this.ref= bw.ns4?this.el.document:document;
-                                       this.x= (bw.ns4||bw.op)?this.css.left:this.el.offsetLeft;
-                                       this.y= (bw.ns4||bw.op)?this.css.top:this.el.offsetTop;
-                                       this.height= (bw.ie4||bw.dom)?this.el.offsetHeight:bw.ns4?this.ref.height:0;
-                                       this.width= (bw.ie4||bw.dom)?this.el.offsetWidth:bw.ns4?this.ref.width:0;
-                                       return this;
-                               }
-                                       // GL_getObjCss(obj)
-                               function GL_getObjCss(obj){     //
-                                       return bw.dom? document.getElementById(obj).style:bw.ie4?document.all[obj].style:bw.ns4?document.layers[obj]:0;
-                               }
-                                       // GL_getMouse(event)
-                               function GL_getMouse(event) {   //
-                                       if (layerObj)   {
-//                                             GLV_x= (bw.ns4||bw.ns5)?event.pageX:(bw.ie4||bw.op)?event.clientX:(event.clientX-2)+document.body.scrollLeft;
-//                                             GLV_y= (bw.ns4||bw.ns5)?event.pageY:(bw.ie4||bw.op)?event.clientY:(event.clientY-2)+document.body.scrollTop;
-                                                       // 17/12 2003: When documents run in XHTML standard compliance mode, the old scrollLeft/Top properties of document.body is gone - and for Opera/MSIE we have to use document.documentElement:
-
-                                               GLV_xRel = event.clientX-2;
-                                               GLV_yRel = event.clientY-2;
-                                               
-                                               GLV_x = GLV_xRel;
-                                               GLV_y = GLV_yRel;
-                                               
-                                               if (!bw.safari) {
-                                                       GLV_x = GLV_xRel + (document.documentElement.scrollLeft ? document.documentElement.scrollLeft : document.body.scrollLeft);
-                                                       GLV_y = GLV_yRel + (document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop);
-                                               }
-                                               
-                                       //      status = (GLV_x+GLV_gap-GLV_curLayerX[0]) + " | " + (GLV_y+GLV_gap-GLV_curLayerY[0]);
-                                               if (GLV_isVisible[1])   {
-                                                       if (outsideLayer(1))    hideSpecific(1);
-                                               } else if (GLV_isVisible[0])    {
-                                                       if (outsideLayer(0))    hideSpecific(0);
-                                               }
-                                       }
-                               }
-                                       // outsideLayer(level)
-                               function outsideLayer(level)    {       //
-                                       return GLV_x+GLV_gap-GLV_curLayerX[level] <0 ||
-                                                       GLV_y+GLV_gap-GLV_curLayerY[level] <0 ||
-                                                       GLV_curLayerX[level]+GLV_curLayerWidth[level]+GLV_gap-GLV_x <0 ||
-                                                       GLV_curLayerY[level]+GLV_curLayerHeight[level]+GLV_gap-GLV_y <0;
-                               }
-                                       // setLayerObj(html,level)
-                               function setLayerObj(html,level)        {       //
-                                       var winHeight = document.documentElement.clientHeight && !bw.op7 ? document.documentElement.clientHeight : document.body.clientHeight;
-                                       var winWidth = document.documentElement.clientWidth && !bw.op7 ? document.documentElement.clientWidth : document.body.clientWidth;
-                                       var tempLayerObj = GL_getObj("contentMenu"+level);
-                                       var tempLayerObjCss = GL_getObjCss("contentMenu"+level);
-
-                                       if (tempLayerObj && (level==0 || GLV_isVisible[level-1]))       {
-                                               tempLayerObj.el.innerHTML = html;
-                                               tempLayerObj.width= (bw.ie4||bw.dom)?this.el.offsetWidth:bw.ns4?this.ref.width:0;
-                                               tempLayerObj.height= (bw.ie4||bw.dom)?this.el.offsetHeight:bw.ns4?this.ref.height:0;
-
-                                                       // konqueror (3.2.2) workaround
-                                               winHeight = (bw.konq)?window.innerHeight:winHeight;
-                                               winWidth = (bw.konq)?window.innerWidth:winWidth;
-
-                                                       // Adjusting the Y-height of the layer to fit it into the window frame if it goes under the window frame in the bottom:
-                                               if (winHeight-tempLayerObj.height < GLV_yRel)   {
-                                                       if (GLV_yRel < tempLayerObj.height) {
-                                                               GLV_y+= (winHeight-tempLayerObj.height-GLV_yRel);               // Setting it so bottom is just above window height.
-                                                       } else {
-                                                               GLV_y-= tempLayerObj.height-8;          // Showing the menu upwards
-                                                       }
-                                               }
-                                                       // Adjusting the X position like Y above
-                                               if (winWidth-tempLayerObj.width < GLV_xRel)     {
-                                                       if (GLV_xRel < tempLayerObj.width) {
-                                                               GLV_x+= (winWidth-tempLayerObj.width-GLV_xRel);
-                                                       } else {
-                                                               GLV_x-= tempLayerObj.width-8;
-                                                       }
-                                               }
-                                               GLV_x = Math.max(GLV_x,1);
-                                               GLV_y = Math.max(GLV_y,1);
-
-                                               GLV_curLayerX[level] = GLV_x;
-                                               GLV_curLayerY[level] = GLV_y;
-                                               tempLayerObjCss.left = GLV_x+"px";
-                                               tempLayerObjCss.top = GLV_y+"px";
-                                               tempLayerObjCss.visibility = "visible";
-                                               if (bw.ie5)     showHideSelectorBoxes("hidden");
-
-                                               GLV_isVisible[level]=1;
-                                               GLV_curLayerWidth[level] = tempLayerObj.width;
-                                               GLV_curLayerHeight[level] = tempLayerObj.height;
-                                       }
-                               }
-                                       // hideEmpty()
-                               function hideEmpty()    {       //
-                                       hideSpecific(0);
-                                       hideSpecific(1);
-                                       return false;
-                               }
-                                       // hideSpecific(level)
-                               function hideSpecific(level)    {       //
-                                       GL_getObjCss("contentMenu"+level).visibility = "hidden";
-                                       GL_getObj("contentMenu"+level).el.innerHTML = "";
-                                       GLV_isVisible[level]=0;
-
-                                       if (bw.ie5 && level==0) showHideSelectorBoxes("visible");
-                               }
-                                       // debugObj(obj,name)
-                               function debugObj(obj,name)     {       //
-                                       var acc;
-                                       for (i in obj) {if (obj[i])     {acc+=i+":  "+obj[i]+"\n";}}
-                                       alert("Object: "+name+"\n\n"+acc);
-                               }
-                                       // initLayer()
-                               function initLayer(){   //
-                                       if (document.all)   {
-                                               window.onmousemove=GL_getMouse;
-                                       }
-                                       layerObj = GL_getObj("contentMenu1");
-                                       layerObjCss = GL_getObjCss("contentMenu1");
-                               }
-                               function showHideSelectorBoxes(action)  {       // This function by Michiel van Leening
-                                       for (i=0;i<document.forms.length;i++) {
-                                               for (j=0;j<document.forms[i].elements.length;j++) {
-                                                       if(document.forms[i].elements[j].type=="select-one") {
-                                                               document.forms[i].elements[j].style.visibility=action;
-                                                       }
-                                               }
-                                       }
-                               }';
-                       $content.='     /*]]>*/
-                               </script>';
-                       return array(
-                               $content,
-                               ' onmousemove="GL_getMouse(event);" onload="initLayer();"',
-                               '<div id="contentMenu0" style="z-index:1; position:absolute;visibility:hidden"></div><div id="contentMenu1" style="z-index:2; position:absolute;visibility:hidden"></div>'
-                       );
-               } else {
-                       $content.='     /*]]>*/
-                               </script>';
-                       return array($content,'','');
-               }
+                              // return array deprecated since 4.2
+              return array('','','');
        }
 
-       /**
-        * Returns an array with parts (JavaScript, init-functions, <div>-layers) for use on pages which have the drag and drop functionality (usually pages and folder display trees)
-        *
-        * @param       string          indicator of which table the drag and drop function should work on (pages or folders)
-        * @return      array           If values are present: [0] = A <script> section for the HTML page header, [1] = onmousemove/onload handler for HTML tag or alike, [2] = One empty <div> layer for the follow-mouse drag element
-        */
-       function getDragDropCode($table)        {
-               $content = '
-                       <script type="text/javascript">
-                       /*<![CDATA[*/
-                       ';
-
-               if ($this->isCMlayers())        {
-                       $content.= '
-                               var dragID = null;
-                               var dragIconCSS = null;
-
-                               function cancelDragEvent(event) {
-                                       dragID = null;
-                                       dragIconCSS.visibility = "hidden";
-                                       document.onmouseup = null;
-                                       document.onmousemove = null;
-                               }
-
-       /**
-        * [Describe function...]
-        *
-        * @param       [type]          $event: ...
-        * @return      [type]          ...
-        */
-                               function mouseMoveEvent (event) {
-                                       dragIconCSS.left = GLV_x+5+"px";
-                                       dragIconCSS.top = GLV_y-5+"px";
-                                       dragIconCSS.visibility = "visible";
-                                       return false;
-                               }
-
-       /**
-        * [Describe function...]
-        *
-        * @param       [type]          $id,elementID: ...
-        * @return      [type]          ...
-        */
-                               function dragElement(id,elementID) {
-                                       dragID = id;
-                                       if (elementID == null)  {
-                                               elementID = id;
-                                       }
-                                       document.getElementById("dragIcon").innerHTML=document.getElementById("dragIconID_"+elementID).innerHTML + document.getElementById("dragTitleID_"+elementID).getElementsByTagName("a")[0].innerHTML;
-                                       dragIconCSS = new GL_getObjCss("dragIcon");
-                                       dragIconCSS.whiteSpace = "nowrap";
-                                       document.onmouseup = cancelDragEvent;
-                                       document.onmousemove = mouseMoveEvent;
-                                       return false;
-                               }
-
-       /**
-        * [Describe function...]
-        *
-        * @param       [type]          $id: ...
-        * @return      [type]          ...
-        */
-                               function dropElement(id) {
-                                       if ((dragID != null) && (dragID != id)) {
-                                               var url = "'.$this->backPath.'alt_clickmenu.php?dragDrop='.$table.'"
-                                                                       + "&srcId=" + dragID
-                                                                       + "&dstId=" + id
-                                                                       + "&backPath='.t3lib_div::shortMD5(''.'|'.$GLOBALS['TYPO3_CONF_VARS']['SYS']['encryptionKey']).'";
-                                               showClickmenu_raw(url);
-                                       }
-                                       cancelDragEvent();
-                                       return false;
-                               }
-                               ';
-               }
-               else {
-                       $content.= '
-                               function dragElement(id) { return false; }
-                               function dropElement(id) { return false; }
-                               ';
-               }
-               $content.='
-                       /*]]>*/
-                       </script>';
-
-               if ($this->isCMlayers())        {
-                       return array(
-                               $content,
-                               '',
-                               '<div id="dragIcon" style="z-index:1;position:absolute;visibility:hidden;filter:alpha(opacity=50);-moz-opacity:0.5;opacity:0.5;"><img src="" width="18" height="16"></div>'
-                       );
-               } else {
-                       return array($content,'','');
-               }
-       }
 
        /**
         * Creates a tab menu from an array definition
index f51bf31..4daf7bf 100755 (executable)
@@ -30,7 +30,8 @@
        // please use the function in the "Tree" object for future implementations
 function refresh_nav() { window.setTimeout('Tree.refresh();',0); }
 
-       // Deprecated! Another JS function, for highlighting rows in the page tree, kept alive for backwards
+       // Deprecated since 4.1.
+       // Another JS function, for highlighting rows in the page tree, kept alive for backwards
        // compatibility. Please use the function in the "Tree" object for future implementations.
 function hilight_row(frameSetModule, highLightID) { Tree.highlightActiveItem(frameSetModule, highlightID); }
 
@@ -171,7 +172,6 @@ var Tree = {
 // tested in IE 6, Firefox 2, Opera 9
 var DragDrop = {
        dragID: null,
-       dragIconCSS: null,
 
        // options needed for doing the changes when dropping
        table: null,    // can be "pages" or "folders"
@@ -190,8 +190,6 @@ var DragDrop = {
                $('dragIcon').innerHTML = $('dragIconID_'+elementID).innerHTML
                                                                + $('dragTitleID_'+elementID).firstChild.innerHTML;
 
-               this.dragIconCSS = new GL_getObjCss('dragIcon');
-               this.dragIconCSS.whiteSpace = 'nowrap';
                document.onmouseup   = function(event) { DragDrop.cancelDragEvent(event); };
                document.onmousemove = function(event) { DragDrop.mouseMoveEvent(event); };
                return false;
@@ -214,15 +212,21 @@ var DragDrop = {
 
        cancelDragEvent: function(event) {
                this.dragID = null;
-               if (this.dragIconCSS && this.dragIconCSS.visibility) { this.dragIconCSS.visibility = 'hidden'; }
+               if ($('dragIcon') && $('dragIcon').style.visibility == 'visible') {
+                       $('dragIcon').style.visibility = 'hidden';
+               }
+
                document.onmouseup = null;
                document.onmousemove = null;
        },
 
        mouseMoveEvent: function(event) {
-               this.dragIconCSS.left = (GLV_x + 5) + 'px';
-               this.dragIconCSS.top  = (GLV_y - 5) + 'px';
-               this.dragIconCSS.visibility = 'visible';
+               if (!event) {
+                       event = window.event;
+               }
+               $('dragIcon').style.left = (Event.pointerX(event) + 5) + 'px';
+               $('dragIcon').style.top  = (Event.pointerY(event) - 5) + 'px';
+               $('dragIcon').style.visibility = 'visible';
                return false;
        },