* Added feature #8791: Let htmlArea RTE context menu use the RTE API
authorStanislas Rolland <typo3@sjbr.ca>
Sun, 22 Jun 2008 02:50:09 +0000 (02:50 +0000)
committerStanislas Rolland <typo3@sjbr.ca>
Sun, 22 Jun 2008 02:50:09 +0000 (02:50 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@3832 709f56b5-9817-0410-a4d7-c38de5d9e867

ChangeLog
typo3/sysext/rtehtmlarea/ChangeLog
typo3/sysext/rtehtmlarea/class.tx_rtehtmlarea_base.php
typo3/sysext/rtehtmlarea/class.tx_rtehtmlareaapi.php
typo3/sysext/rtehtmlarea/ext_localconf.php
typo3/sysext/rtehtmlarea/extensions/ContextMenu/class.tx_rtehtmlarea_contextmenu.php [new file with mode: 0644]
typo3/sysext/rtehtmlarea/htmlarea/plugins/ContextMenu/context-menu.js

index 38b430a..9107968 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,7 @@
 2008-06-21  Stanislas Rolland  <typo3@sjbr.ca>
 
        * Added feature #8790: htmlArea RTE image selection should honour hooking browsers
+       * Added feature #8791: Let htmlArea RTE context menu use the RTE API
        * Fixed bug #8717 (cleanup): htmlArea RTE link browser does not honour correctly hooking browsers
 
 2008-06-17  Stanislas Rolland  <typo3@sjbr.ca>
index 83e5083..7f97d7a 100644 (file)
@@ -1,6 +1,7 @@
 2008-06-21  Stanislas Rolland  <typo3@sjbr.ca>
 
        * Added feature #8790: htmlArea RTE image selection should honour hooking browsers
+       * Added feature #8791: Let htmlArea RTE context menu use the RTE API
        * Fixed bug #8717 (cleanup): htmlArea RTE link browser does not honour correctly hooking browsers
 
 2008-06-17  Stanislas Rolland  <typo3@sjbr.ca>
index 4e00897..600e720 100644 (file)
@@ -106,7 +106,7 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
                'redo'                  => 'Redo',
                );
        
-       var $pluginList = 'ContextMenu';
+       var $pluginList;
        var $pluginButton = array();
        var $pluginLabel = array();
        
@@ -335,18 +335,16 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
                                // htmlArea plugins list
                        $this->pluginEnabledArray = t3lib_div::trimExplode(',', $this->pluginList, 1);
                        $this->enableRegisteredPlugins();
-                       $hidePlugins = array();
+
                        if ($this->client['BROWSER'] == 'msie') {
                                $this->thisConfig['keepButtonGroupTogether'] = 0;
                        }
                        if ($this->client['BROWSER'] == 'opera') {
-                               $hidePlugins[] = 'ContextMenu';
                                $this->thisConfig['keepButtonGroupTogether'] = 0;
                        }
                        if ($this->client['BROWSER'] == 'gecko' && $this->client['VERSION'] == '1.3')  {
                                $this->thisConfig['keepButtonGroupTogether'] = 0;
                        }
-                       $this->pluginEnabledArray = array_diff($this->pluginEnabledArray, $hidePlugins);
 
                                // Toolbar
                        $this->setToolbar();
@@ -517,7 +515,7 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
                        // Process overrides
                $hidePlugins = array();
                foreach ($this->registeredPlugins as $pluginId => $plugin) {
-                       if (!$this->pluginButton[$pluginId]) {
+                       if ($plugin->addsButtons() && !$this->pluginButton[$pluginId]) {
                                $hidePlugins[] = $pluginId;
                        }
                }
@@ -659,36 +657,34 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
         * Disable some plugins
         *
         */
-
        function setPlugins() {
-               global $TYPO3_CONF_VARS;
                
-               $hideButtons = array();
-               
-                       // Disabling the plugins if their buttons are not in the toolbar
+                       // Disabling a plugin that adds buttons if none of its buttons is in the toolbar
                $hidePlugins = array();
                foreach ($this->pluginButton as $pluginId => $buttonList) {
-                       $showPlugin = false;
-                       $buttonArray = t3lib_div::trimExplode(',', $buttonList, 1);
-                       foreach ($buttonArray as $button) {
-                               if (in_array($button, $this->toolbar)) {
-                                       $showPlugin = true;
+                       if ($this->registeredPlugins[$pluginId]->addsButtons()) {
+                               $showPlugin = false;
+                               $buttonArray = t3lib_div::trimExplode(',', $buttonList, 1);
+                               foreach ($buttonArray as $button) {
+                                       if (in_array($button, $this->toolbar)) {
+                                               $showPlugin = true;
+                                       }
+                               }
+                               if (!$showPlugin) {
+                                       $hidePlugins[] = $pluginId;
                                }
-                       }
-                       if (!$showPlugin) {
-                               $hidePlugins[] = $pluginId;
                        }
                }
-               if ($this->thisConfig['disableContextMenu'] || $this->thisConfig['disableRightClick']) $hidePlugins[] = 'ContextMenu';
                $this->pluginEnabledArray = array_diff($this->pluginEnabledArray, $hidePlugins);
                
                        // Hiding labels of disabled plugins
+               $hideLabels = array();
                foreach ($this->pluginLabel as $pluginId => $label) {
                        if (!$this->isPluginEnabled($pluginId)) {
-                               $hideButtons[] = $label;
+                               $hideLabels[] = $label;
                        }
                }
-               $this->toolbar = array_diff($this->toolbar, $hideButtons);
+               $this->toolbar = array_diff($this->toolbar, $hideLabels);
                
                        // Completing the toolbar converion array for htmlArea
                foreach ($this->registeredPlugins as $pluginId => $plugin) {
index 608c79d..6378fae 100644 (file)
@@ -46,6 +46,7 @@ abstract class tx_rtehtmlareaapi {
        protected $LOCAL_LANG;                                  // Frontend language array
        protected $pluginButtons = '';                          // The comma-separated list of button names that the registered plugin is adding to the htmlArea RTE toolbar
        protected $pluginLabels = '';                           // The comma-separated list of label names that the registered plugin is adding to the htmlArea RTE toolbar
+       protected $pluginAddsButtons = true;                    // Boolean indicating whether the plugin is adding buttons or not
        protected $convertToolbarForHtmlAreaArray = array();    // The name-converting array, converting the button names used in the RTE PageTSConfing to the button id's used by the JS scripts
        protected $requiresClassesConfiguration = false;        // True if the registered plugin requires the PageTSConfig Classes configuration
 
@@ -64,6 +65,9 @@ abstract class tx_rtehtmlareaapi {
                $this->thisConfig =& $this->htmlAreaRTE->thisConfig;
                $this->toolbar =& $this->htmlAreaRTE->toolbar;
                $this->LOCAL_LANG =& $this->htmlAreaRTE->LOCAL_LANG;
+               
+                       // Set the value of this boolean based on the initial value of $this->pluginButtons
+               $this->pluginAddsButtons = !empty($this->pluginButtons);
 
                        // Check if the plugin should be disabled in frontend
                if ($this->htmlAreaRTE->is_FE() && $TYPO3_CONF_VARS['EXTCONF'][$this->rteExtensionKey]['plugins'][$this->pluginName]['disableInFE']) {
@@ -149,6 +153,15 @@ abstract class tx_rtehtmlareaapi {
        public function getPathToPluginDirectory() {
                return ($this->relativePathToPluginDirectory ? $this->htmlAreaRTE->httpTypo3Path . t3lib_extMgm::siteRelPath($this->extensionKey) . $this->relativePathToPluginDirectory : '');
        }
+       
+       /**
+        * Returns a boolean indicating whether the plugin adds buttons or not to the toolbar
+        *
+        * @return      boolean
+        */
+       public function addsButtons() {
+               return $this->pluginAddsButtons;
+       }
 
        /**
         * Returns the list of buttons implemented by the plugin
index 08b1047..df8ec4c 100644 (file)
@@ -2,7 +2,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 2005-2008 Stanislas Rolland <stanislas.rolland(arobas)fructifor.ca>
+*  (c) 2005-2008 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
@@ -27,7 +27,7 @@
 /**
  * Configuration of the htmlArea RTE extension
  *
- * @author     Stanislas Rolland <stanislas.rolland(arobas)fructifor.ca>
+ * @author     Stanislas Rolland <typo3(arobas)sjbr.ca>
  *
  * $Id$  *
  */
@@ -145,6 +145,10 @@ $TYPO3_CONF_VARS['EXTCONF']['rtehtmlarea']['plugins']['AboutEditor'] = array();
 $TYPO3_CONF_VARS['EXTCONF']['rtehtmlarea']['plugins']['AboutEditor']['objectReference'] = 'EXT:'.$_EXTKEY.'/extensions/AboutEditor/class.tx_rtehtmlarea_abouteditor.php:&tx_rtehtmlarea_abouteditor';
 $TYPO3_CONF_VARS['EXTCONF']['rtehtmlarea']['plugins']['AboutEditor']['addIconsToSkin'] = 0;
 $TYPO3_CONF_VARS['EXTCONF']['rtehtmlarea']['plugins']['AboutEditor']['disableInFE'] = 0;
+$TYPO3_CONF_VARS['EXTCONF']['rtehtmlarea']['plugins']['ContextMenu'] = array();
+$TYPO3_CONF_VARS['EXTCONF']['rtehtmlarea']['plugins']['ContextMenu']['objectReference'] = 'EXT:'.$_EXTKEY.'/extensions/ContextMenu/class.tx_rtehtmlarea_contextmenu.php:&tx_rtehtmlarea_contextmenu';
+$TYPO3_CONF_VARS['EXTCONF']['rtehtmlarea']['plugins']['ContextMenu']['addIconsToSkin'] = 0;
+$TYPO3_CONF_VARS['EXTCONF']['rtehtmlarea']['plugins']['ContextMenu']['disableInFE'] = 0;
 
 $_EXTCONF = unserialize($_EXTCONF);    // unserializing the configuration so we can use it here:
 
diff --git a/typo3/sysext/rtehtmlarea/extensions/ContextMenu/class.tx_rtehtmlarea_contextmenu.php b/typo3/sysext/rtehtmlarea/extensions/ContextMenu/class.tx_rtehtmlarea_contextmenu.php
new file mode 100644 (file)
index 0000000..e8c0bc1
--- /dev/null
@@ -0,0 +1,75 @@
+<?php
+/***************************************************************
+*  Copyright notice
+*
+*  (c) 2008 Stanislas Rolland <typo3(arobas)sjbr.ca>
+*  All rights reserved
+*
+*  This script is part of the Typo3 project. The Typo3 project is
+*  free software; you can redistribute it and/or modify
+*  it under the terms of the GNU General Public License as published by
+*  the Free Software Foundation; either version 2 of the License, or
+*  (at your option) any later version.
+*
+*  The GNU General Public License can be found at
+*  http://www.gnu.org/copyleft/gpl.html.
+*
+*  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.  See the
+*  GNU General Public License for more details.
+*
+*  This copyright notice MUST APPEAR in all copies of the script!
+***************************************************************/
+/**
+ * About Editor plugin for htmlArea RTE
+ *
+ * @author Stanislas Rolland <typo3(arobas)sjbr.ca>
+ *
+ * TYPO3 SVN ID: $Id: class.tx_rtehtmlarea_abouteditor.php 2985 2008-01-31 11:37:57Z ingmars $
+ *
+ */
+
+require_once(t3lib_extMgm::extPath('rtehtmlarea').'class.tx_rtehtmlareaapi.php');
+
+class tx_rtehtmlarea_contextmenu extends tx_rtehtmlareaapi {
+
+       protected $extensionKey = 'rtehtmlarea';        // The key of the extension that is extending htmlArea RTE
+       protected $pluginName = 'ContextMenu';          // The name of the plugin registered by the extension
+       protected $relativePathToLocallangFile = '';    // Path to this main locallang file of the extension relative to the extension dir.
+       protected $relativePathToSkin = '';             // Path to the skin (css) file relative to the extension dir.
+       protected $htmlAreaRTE;                         // Reference to the invoking object
+       protected $thisConfig;                          // Reference to RTE PageTSConfig
+       protected $toolbar;                             // Reference to RTE toolbar array
+       protected $LOCAL_LANG;                          // Frontend language array
+       
+       protected $pluginButtons;
+       protected $convertToolbarForHtmlAreaArray = array ();
+       
+       public function main($parentObject) {
+               return parent::main($parentObject) && !($this->htmlAreaRTE->client['BROWSER'] == 'opera' || $this->thisConfig['disableContextMenu'] || $this->thisConfig['disableRightClick']);
+       }
+       
+       /**
+        * Return JS configuration of the htmlArea plugins registered by the extension
+        *
+        * @param       integer         Relative id of the RTE editing area in the form
+        *
+        * @return string               JS configuration for registered plugins
+        *
+        * The returned string will be a set of JS instructions defining the configuration that will be provided to the plugin(s)
+        * Each of the instructions should be of the form:
+        *      RTEarea['.$RTEcounter.']["buttons"]["button-id"]["property"] = "value";
+        */
+       public function buildJavascriptConfiguration($RTEcounter) {
+               $registerRTEinJavascriptString = '';
+               return $registerRTEinJavascriptString;
+       }
+
+} // end of class
+
+if (defined('TYPO3_MODE') && $TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/rtehtmlarea/extensions/ContextMenu/class.tx_rtehtmlarea_contextmenu.php']) {
+       include_once($TYPO3_CONF_VARS[TYPO3_MODE]['XCLASS']['ext/rtehtmlarea/extensions/ContextMenu/class.tx_rtehtmlarea_contextmenu.php']);
+}
+
+?>
\ No newline at end of file
index 3d9e6a4..cd51e1e 100644 (file)
@@ -2,7 +2,7 @@
 *  Copyright notice
 *
 *  Copyright (c) 2003 dynarch.com. Authored by Mihai Bazon. Sponsored by www.americanbible.org.
-*  Copyright (c) 2004-2008 Stanislas Rolland <stanislas.rolland(arobas)fructifor.ca>
+*  Copyright (c) 2004-2008 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
  * TYPO3 SVN ID: $Id$
  */
 
-ContextMenu = function(editor) {
-       this.editor = editor;
-       this.currentMenu = null;
-       this.keys = [];
-       this.eventHandlers = {};
-};
-
-ContextMenu.I18N = ContextMenu_langArray;
-
-ContextMenu._pluginInfo = {
-       name          : "ContextMenu",
-       version       : "1.9",
-       developer     : "Mihai Bazon & Stanislas Rolland",
-       developer_url : "http://www.fructifor.ca/",
-       c_owner       : "dynarch.com & Stanislas Rolland",
-       sponsor       : "American Bible Society & Fructifor Inc.",
-       sponsor_url   : "http://www.fructifor.ca/",
-       license       : "GPL"
-};
-
-ContextMenu.prototype.onGenerate = function() {
-       if (!HTMLArea.is_opera) {
-               this.editor.eventHandlers["contextMenu"] = ContextMenu.contextMenuHandler(this);
-               HTMLArea._addEvent((HTMLArea.is_ie ? this.editor._doc.body : this.editor._doc), "contextmenu", this.editor.eventHandlers["contextMenu"]);
-       } else {
-               this.editor.eventHandlers["mousedown"] = ContextMenu.contextMenuHandler(this);
-               HTMLArea._addEvent(this.editor._doc, "mousedown", this.editor.eventHandlers["mousedown"]);
+ContextMenu = HTMLArea.Plugin.extend({
+       
+       constructor : function(editor, pluginName) {
+               this.base(editor, pluginName);
+       },
+       
+       /*
+        * This function gets called by the class constructor
+        */
+       configurePlugin : function(editor) {
+               this.currentMenu = null;
+               this.keys = [];
+               this.eventHandlers = {};
+               
+               /*
+                * Registering plugin "About" information
+                */
+               var pluginInformation = {
+                       version         : "2.0",
+                       developer       : "Mihai Bazon & Stanislas Rolland",
+                       developerUrl    : "http://www.sjbr.ca/",
+                       copyrightOwner  : "dynarch.com & Stanislas Rolland",
+                       sponsor         : "American Bible Society & SJBR",
+                       sponsorUrl      : "http://www.sjbr.ca/",
+                       license         : "GPL"
+               };
+               this.registerPluginInformation(pluginInformation);
+               
+               return true;
+       },
+       
+       /*
+        * This function gets called when the editor gets generated
+        */
+       onGenerate : function() {
+               this.editor.eventHandlers["contextMenu"] = this.makeFunctionReference("popupMenu");
+               HTMLArea._addEvent((HTMLArea.is_ie ? this.editor._doc.body : this.editor._doc), (HTMLArea.is_opera ? "mousedown" : "contextmenu"), this.editor.eventHandlers["contextMenu"]);
+       },
+       
+       popupMenu : function(ev, target) {
+               if (HTMLArea.is_opera && ev.button < 2) {
+                       return false;
+               }
+               var editor = this.editor;
+               if (!ev) var ev = window.event;
+               if (!target) var target = (ev.target) ? ev.target : ev.srcElement;
+               if (this.currentMenu) this.currentMenu.parentNode.removeChild(this.currentMenu);
+               this.keys = [];
+               var ifpos = ContextMenu.getPos(this.editor._iframe);
+               var x = ev.clientX + ifpos.x;
+               var y = ev.clientY + ifpos.y;
+       
+               var doc, list, separator = false;
+       
+               if (!HTMLArea.is_ie) {
+                       doc = document;
+               } else {
+                       var popup = this.iePopup = window.createPopup();
+                       doc = popup.document;
+                       var head = doc.getElementsByTagName("head")[0];
+                       var link = doc.createElement("link");
+                       link.rel = "stylesheet";
+                       link.type = "text/css";
+                       if ( _editor_CSS.indexOf("http") == -1 ) link.href = _typo3_host_url + _editor_CSS;
+                               else link.href = _editor_CSS;
+                       head.appendChild(link);
+               }
+       
+               list = doc.createElement("ul");
+               list.className = "htmlarea-context-menu";
+               doc.body.appendChild(list);
+       
+               var options = this.getContextMenu(target);
+               var n = options.length;
+               for (var i=0; i < n; ++i) {
+                       var option = options[i];
+                       if (!option){
+                               separator = true;
+                       } else {
+                               var item = doc.createElement("li");
+                               list.appendChild(item);
+                               var label = option[0];
+                               if (separator) {
+                                       item.className += " separator";
+                                       separator = false;
+                               }
+                               item.__msh = {
+                                       item:           item,
+                                       label:          label,
+                                       action:         option[1],
+                                       tooltip:        option[2] || null,
+                                       icon:           option[3] || null,
+                                       activate:       ContextMenu.activateHandler(item, this),
+                                       cmd:            option[4] || null
+                               };
+                               label = label.replace(/_([a-zA-Z0-9])/, "<u>$1</u>");
+                               if (label != option[0]) this.keys.push([ RegExp.$1, item ]);
+                               label = label.replace(/__/, "_");
+                               var button = doc.createElement("button");
+                               button.className = "button";
+                               if(item.__msh.cmd) {
+                                       button.className += " " + item.__msh.cmd;
+                                       if(typeof(editor.plugins["TYPO3Browsers"]) != "undefined" && (item.__msh.cmd == "CreateLink" || item.__msh.cmd == "UnLink" || item.__msh.cmd == "InsertImage")) button.className += "-TYPO3Browsers";
+                                       button.innerHTML = label;
+                               } else if(item.__msh.icon) {
+                                       button.innerHTML = "<img src='" + item.__msh.icon + "' />" + label;
+                               } else {
+                                       button.innerHTML = label;
+                               }
+                               item.appendChild(button);
+       
+                               item.__msh.mouseover = ContextMenu.mouseOverHandler(editor, item);
+                               HTMLArea._addEvent(item, "mouseover", item.__msh.mouseover);
+                               item.__msh.mouseout = ContextMenu.mouseOutHandler(item);
+                               HTMLArea._addEvent(item, "mouseout", item.__msh.mouseout);
+                               item.__msh.contextmenu = ContextMenu.itemContextMenuHandler(item);
+                               HTMLArea._addEvent(item, "contextmenu", item.__msh.contextmenu);
+                               if(!HTMLArea.is_ie) {
+                                       item.__msh.mousedown = ContextMenu.mouseDownHandler(item);
+                                       HTMLArea._addEvent(item, "mousedown", item.__msh.mousedown);
+                               }
+                               item.__msh.mouseup = ContextMenu.mouseUpHandler(item, this);
+                               HTMLArea._addEvent(item, "mouseup", item.__msh.mouseup);
+                       }
+               }
+               if (n) {
+                       if(!HTMLArea.is_ie) {
+                               var dx = x + list.offsetWidth - window.innerWidth - window.pageXOffset + 4;
+                               var dy = y + list.offsetHeight - window.innerHeight - window.pageYOffset + 4;
+                               if(dx > 0) x -= dx;
+                               if(dy > 0) y -= dy;
+                               list.style.left = x + "px";
+                               list.style.top = y + "px";
+                       } else {
+                                       // determine the size
+                               list.style.left = "0px";
+                               list.style.top = "0px";
+                               var foobar = document.createElement("ul");
+                               foobar.className = "htmlarea-context-menu";
+                               foobar.innerHTML = list.innerHTML;
+                               editor._iframe.contentWindow.parent.document.body.appendChild(foobar);
+                               this.iePopup.show(ev.screenX, ev.screenY, foobar.clientWidth+2, foobar.clientHeight+2);
+                               editor._iframe.contentWindow.parent.document.body.removeChild(foobar);
+                       }
+                       this.currentMenu = list;
+                       this.timeStamp = (new Date()).getTime();
+                       this.eventHandlers["documentClick"] = ContextMenu.documentClickHandler(this);
+                       HTMLArea._addEvent((HTMLArea.is_ie ? document.body : document), "mousedown", this.eventHandlers["documentClick"]);
+                       HTMLArea._addEvent((HTMLArea.is_ie ? editor._doc.body : editor._doc), "mousedown", this.eventHandlers["documentClick"]);
+                       if (this.keys.length > 0) {
+                               this.eventHandlers["keyPress"] = ContextMenu.keyPressHandler(this);
+                               HTMLArea._addEvents((HTMLArea.is_ie ? editor._doc.body : editor._doc), ["keypress", "keydown"], this.eventHandlers["keyPress"]);
+                       }
+               }
+               HTMLArea._stopEvent(ev);
+               return false;
+       },
+       
+       pushOperations : function (opcodes, elmenus, pluginId) {
+               var editor = this.editor;
+               var pluginInstance = this.editor.plugins[pluginId];
+               if (pluginInstance) {
+                       pluginInstance = pluginInstance.instance;
+               }
+               var toolbarObjects = editor._toolbarObjects;
+               var btnList = editor.config.btnList;
+               var enabled = false, opcode, opEnabled = [], i = opcodes.length;
+               for (i; i > 0;) {
+                       opcode = opcodes[--i];
+                       opEnabled[opcode] = toolbarObjects[opcode]  && toolbarObjects[opcode].enabled;
+                       enabled = enabled || opEnabled[opcode];
+               }
+               if (enabled && elmenus.length) {
+                       elmenus.push(null);
+               }
+               for (i = opcodes.length; i > 0;) {
+                       opcode = opcodes[--i];
+                       if (opEnabled[opcode]) {
+                               switch (pluginId) {
+                                       case "TableOperations" :
+                                               elmenus.push([this.localize(opcode + "-title"),
+                                                       ContextMenu.tableOperationsHandler(editor, pluginInstance, opcode),
+                                                       this.localize(opcode + "-tooltip"),
+                                                       btnList[opcode][1], opcode]);
+                                               break;
+                                       case "BlockElements" :
+                                               elmenus.push([this.localize(opcode + "-title"),
+                                                       ContextMenu.blockElementsHandler(editor, null, opcode),
+                                                       this.localize(opcode + "-tooltip"),
+                                                       btnList[opcode][1], opcode]);
+                                               break;
+                                       default :
+                                               elmenus.push([this.localize(opcode + "-title"),
+                                                       ContextMenu.execCommandHandler(editor, opcode),
+                                                       this.localize(opcode + "-tooltip"),
+                                                       btnList[opcode][1], opcode]);
+                                               break;
+                               }
+                       }
+               }
+       },
+       
+       getContextMenu : function(target) {
+               var editor = this.editor;
+               var toolbarObjects = editor._toolbarObjects;
+               var config = editor.config;
+               var btnList = config.btnList;
+               var menu = [], opcode;
+               var tbo = this.editor.plugins["TableOperations"];
+               if (tbo) tbo = "TableOperations";
+               
+               var selection = editor.hasSelectedText();
+               if(selection) {
+                       if (toolbarObjects['Cut'] && toolbarObjects['Cut'].enabled)  {
+                               opcode = "Cut";
+                               menu.push([this.localize(opcode), ContextMenu.execCommandHandler(editor, opcode), null, btnList[opcode][1], opcode]);
+                       }
+                       if (toolbarObjects['Copy'] && toolbarObjects['Copy'].enabled) {
+                               opcode = "Copy";
+                               menu.push([this.localize(opcode), ContextMenu.execCommandHandler(editor, opcode), null, btnList[opcode][1], opcode]);
+                       }
+               }
+               if (toolbarObjects['Paste'] && toolbarObjects['Paste'].enabled) {
+                       opcode = "Paste";
+                       menu.push([this.localize(opcode), ContextMenu.execCommandHandler(editor, opcode), null, btnList[opcode][1], opcode]);
+               }
+               
+               var currentTarget = target,
+                       tmp, tag, link = false,
+                       table = null, tr = null, td = null, img = null, list = null, div = null;
+               
+               for(; target; target = target.parentNode) {
+                       tag = target.nodeName;
+                       if(!tag) continue;
+                       tag = tag.toLowerCase();
+                       switch (tag) {
+                           case "img":
+                               img = target;
+                               if (toolbarObjects["InsertImage"] && toolbarObjects["InsertImage"].enabled)  {
+                                       if (menu.length) menu.push(null);
+                                       menu.push(
+                                               [this.localize("Image Properties"),
+                                                       ContextMenu.imageHandler(editor, img),
+                                                       this.localize("Show the image properties dialog"),
+                                                       btnList["InsertImage"][1], "InsertImage"]
+                                       );
+                               }
+                               break;
+                           case "a":
+                               link = target;
+                               if (toolbarObjects["CreateLink"])  {
+                                       if (menu.length) menu.push(null);
+                                       menu.push(
+                                               [this.localize("Modify Link"),
+                                                       ContextMenu.linkHandler(editor, link, "ModifyLink"),
+                                                       this.localize("Current URL is") + ': ' + link.href,
+                                                       btnList["CreateLink"][1], "CreateLink"],
+                                               [this.localize("Check Link"),
+                                                       ContextMenu.linkHandler(editor, link, "CheckLink"),
+                                                       this.localize("Opens this link in a new window"),
+                                                       null, null],
+                                               [this.localize("Remove Link"),
+                                                       ContextMenu.linkHandler(editor, link, "RemoveLink"),
+                                                       this.localize("Unlink the current element"),
+                                                       editor.imgURL("ed_unlink.gif"), "UnLink"]
+                                       );
+                               }
+                               break;
+                           case "td":
+                           case "th":
+                               td = target;
+                               if(!tbo) break;
+                               this.pushOperations(["TO-cell-split", "TO-cell-delete", "TO-cell-insert-after", "TO-cell-insert-before", "TO-cell-prop"], menu, tbo);
+                               break;
+                           case "tr":
+                               tr = target;
+                               if(!tbo) break;
+                               opcode = "TO-cell-merge";
+                               if (toolbarObjects[opcode]  && toolbarObjects[opcode].enabled) {
+                                       menu.push([this.localize(opcode + "-title"),
+                                       ContextMenu.tableOperationsHandler(editor, this.editor.plugins.TableOperations.instance, opcode),
+                                       this.localize(opcode + "-tooltip"),
+                                       btnList[opcode][1], opcode]);
+                               }
+                               this.pushOperations(["TO-row-split", "TO-row-delete", "TO-row-insert-under", "TO-row-insert-above", "TO-row-prop"], menu, tbo);
+                               break;
+                           case "table":
+                               table = target;
+                               if(!tbo) break;
+                               this.pushOperations(["TO-col-split", "TO-col-delete", "TO-col-insert-after", "TO-col-insert-before", "TO-col-prop"], menu, tbo);
+                               this.pushOperations(["TO-toggle-borders", "TO-table-restyle", "TO-table-prop"], menu, tbo);
+                               break;
+                           case "ol":
+                           case "ul":
+                           case "dl":
+                               list = target;
+                               break;
+                           case "div":
+                               div = target;
+                               break;
+                           case "body":
+                               this.pushOperations(["JustifyFull", "JustifyRight", "JustifyCenter", "JustifyLeft"], menu, "BlockElements");
+                               break;
+                       }
+               }
+               
+               if (selection && !link) {
+                       if (menu.length) menu.push(null);
+                       menu.push([this.localize("Make link"),
+                               ContextMenu.linkHandler(editor, link, "MakeLink"),
+                               this.localize("Create a link"),
+                               btnList["CreateLink"][1],"CreateLink"]);
+               }
+               
+               if (!/^(html|body)$/i.test(currentTarget.nodeName)) {
+                       if (/^(table|thead|tbody|tr|td|th|tfoot)$/i.test(currentTarget.nodeName)) {
+                               tmp = table;
+                               table = null;
+                       } else if(list) {
+                               tmp = list;
+                               list = null;
+                       } else {
+                               tmp = currentTarget;
+                       }
+                       if (menu.length) menu.push(null);
+                       menu.push(
+                         [this.localize("Remove the") + " &lt;" + tmp.tagName.toLowerCase() + "&gt; " + this.localize("Element"),
+                               ContextMenu.deleteElementHandler(editor, tmp, table), this.localize("Remove this node from the document")],
+                         [this.localize("Insert paragraph before"),
+                               ContextMenu.blockElementsHandler(editor, tmp, "InsertParagraphBefore"), this.localize("Insert a paragraph before the current node"), null, "InsertParagraphBefore"],
+                         [this.localize("Insert paragraph after"),
+                               ContextMenu.blockElementsHandler(editor, tmp, "InsertParagraphAfter"), this.localize("Insert a paragraph after the current node"), null, "InsertParagraphAfter"]
+                       );
+               }
+               return menu;
+       },
+       
+       closeMenu : function() {
+               HTMLArea._removeEvent((HTMLArea.is_ie ? document.body : document), "mousedown", this.eventHandlers["documentClick"]);
+               HTMLArea._removeEvent((HTMLArea.is_ie ? this.editor._doc.body : this.editor._doc), "mousedown", this.eventHandlers["documentClick"]);
+               if (this.keys.length > 0) HTMLArea._removeEvent((HTMLArea.is_ie ? this.editor._doc.body : this.editor._doc), "keypress", this.eventHandlers["keyPress"]);
+               for (var handler in this.eventHandlers) this.eventHandlers[handler] = null;
+               var e, items = document.getElementsByTagName("li");
+               if (HTMLArea.is_ie) items = this.iePopup.document.getElementsByTagName("li");;
+               for (var i = items.length; --i >= 0 ;) {
+                       e = items[i];
+                       if ( e.__msh ) {
+                               HTMLArea._removeEvent(e, "mouseover", e.__msh.mouseover);
+                               e.__msh.mouseover = null;
+                               HTMLArea._removeEvent(e, "mouseout", e.__msh.mouseout);
+                               e.__msh.mouseout = null;
+                               HTMLArea._removeEvent(e, "contextmenu", e.__msh.contextmenu);
+                               e.__msh.contextmenu = null;
+                               if (!HTMLArea.is_ie) HTMLArea._removeEvent(e, "mousedown", e.__msh.mousedown);
+                               e.__msh.mousedown = null;
+                               HTMLArea._removeEvent(e, "mouseup", e.__msh.mouseup);
+                               e.__msh.mouseup = null;
+                               e.__msh.action = null;
+                               e.__msh.activate = null;
+                               e.__msh = null;
+                       }
+               }
+               this.currentMenu.parentNode.removeChild(this.currentMenu);
+               this.currentMenu = null;
+               this.keys = [];
+               if (HTMLArea.is_ie) this.iePopup.hide();
        }
-};
-
-ContextMenu.contextMenuHandler = function(instance) {
-       return (function(ev) {
-               if (!HTMLArea.is_opera || (HTMLArea.is_opera && ev.button >= 2)) instance.popupMenu(ev);
-                       else return false;
-       });
-};
+});
 
 ContextMenu.tableOperationsHandler = function(editor,tbo,opcode) {
        return (function() {
@@ -160,184 +492,6 @@ ContextMenu.deleteElementHandler = function(editor,tmp,table) {
        });
 };
 
-ContextMenu.prototype.pushOperations = function(opcodes, elmenus, pluginId) {
-       var editor = this.editor;
-       var pluginInstance = this.editor.plugins[pluginId];
-       if (pluginInstance) {
-               pluginInstance = pluginInstance.instance;
-       }
-       var toolbarObjects = editor._toolbarObjects;
-       var i18n = ContextMenu.I18N;
-       var btnList = editor.config.btnList;
-       var enabled = false, opcode, opEnabled = [], i = opcodes.length;
-       for (i; i > 0;) {
-               opcode = opcodes[--i];
-               opEnabled[opcode] = toolbarObjects[opcode]  && toolbarObjects[opcode].enabled;
-               enabled = enabled || opEnabled[opcode];
-       }
-       if (enabled && elmenus.length) elmenus.push(null);
-       for (i = opcodes.length; i > 0;) {
-               opcode = opcodes[--i];
-               if(opEnabled[opcode]) {
-                       switch (pluginId) {
-                               case "TableOperations" :
-                                       elmenus.push([i18n[opcode + "-title"],
-                                               ContextMenu.tableOperationsHandler(editor, pluginInstance, opcode),
-                                               i18n[opcode + "-tooltip"],
-                                               btnList[opcode][1], opcode]);
-                                       break;
-                               case "BlockElements" :
-                                       elmenus.push([i18n[opcode + "-title"],
-                                               ContextMenu.blockElementsHandler(editor, null, opcode),
-                                               i18n[opcode + "-tooltip"],
-                                               btnList[opcode][1], opcode]);
-                                       break;
-                               default :
-                                       elmenus.push([i18n[opcode + "-title"],
-                                               ContextMenu.execCommandHandler(editor, opcode),
-                                               i18n[opcode + "-tooltip"],
-                                               btnList[opcode][1], opcode]);
-                                       break;
-                       }
-               }
-       }
-};
-
-ContextMenu.prototype.getContextMenu = function(target) {
-       var editor = this.editor;
-       var toolbarObjects = editor._toolbarObjects;
-       var i18n = ContextMenu.I18N;
-       var config = editor.config;
-       var btnList = config.btnList;
-       var menu = [], opcode;
-       var tbo = this.editor.plugins["TableOperations"];
-       if (tbo) tbo = "TableOperations";
-
-       var selection = editor.hasSelectedText();
-       if(selection) {
-               if (toolbarObjects['Cut'] && toolbarObjects['Cut'].enabled)  {
-                       opcode = "Cut";
-                       menu.push([i18n[opcode], ContextMenu.execCommandHandler(editor, opcode), null, btnList[opcode][1], opcode]);
-               }
-               if (toolbarObjects['Copy'] && toolbarObjects['Copy'].enabled) {
-                       opcode = "Copy";
-                       menu.push([i18n[opcode], ContextMenu.execCommandHandler(editor, opcode), null, btnList[opcode][1], opcode]);
-               }
-       }
-       if (toolbarObjects['Paste'] && toolbarObjects['Paste'].enabled) {
-               opcode = "Paste";
-               menu.push([i18n[opcode], ContextMenu.execCommandHandler(editor, opcode), null, btnList[opcode][1], opcode]);
-       }
-
-       var currentTarget = target,
-               tmp, tag, link = false,
-               table = null, tr = null, td = null, img = null, list = null, div = null;
-
-       for(; target; target = target.parentNode) {
-               tag = target.nodeName;
-               if(!tag) continue;
-               tag = tag.toLowerCase();
-               switch (tag) {
-                   case "img":
-                       img = target;
-                       if (toolbarObjects["InsertImage"] && toolbarObjects["InsertImage"].enabled)  {
-                               if (menu.length) menu.push(null);
-                               menu.push(
-                                       [i18n["Image Properties"],
-                                               ContextMenu.imageHandler(editor, img),
-                                               i18n["Show the image properties dialog"],
-                                               btnList["InsertImage"][1], "InsertImage"]
-                               );
-                       }
-                       break;
-                   case "a":
-                       link = target;
-                       if (toolbarObjects["CreateLink"])  {
-                               if (menu.length) menu.push(null);
-                               menu.push(
-                                       [i18n["Modify Link"],
-                                               ContextMenu.linkHandler(editor, link, "ModifyLink"),
-                                               i18n["Current URL is"] + ': ' + link.href,
-                                               btnList["CreateLink"][1], "CreateLink"],
-                                       [i18n["Check Link"],
-                                               ContextMenu.linkHandler(editor, link, "CheckLink"),
-                                               i18n["Opens this link in a new window"],
-                                               null, null],
-                                       [i18n["Remove Link"],
-                                               ContextMenu.linkHandler(editor, link, "RemoveLink"),
-                                               i18n["Unlink the current element"],
-                                               editor.imgURL("ed_unlink.gif"), "UnLink"]
-                               );
-                       }
-                       break;
-                   case "td":
-                   case "th":
-                       td = target;
-                       if(!tbo) break;
-                       this.pushOperations(["TO-cell-split", "TO-cell-delete", "TO-cell-insert-after", "TO-cell-insert-before", "TO-cell-prop"], menu, tbo);
-                       break;
-                   case "tr":
-                       tr = target;
-                       if(!tbo) break;
-                       opcode = "TO-cell-merge";
-                       if(toolbarObjects[opcode]  && toolbarObjects[opcode].enabled)
-                               menu.push([i18n[opcode + "-title"],
-                               ContextMenu.tableOperationsHandler(editor, this.editor.plugins.TableOperations.instance, opcode),
-                               i18n[opcode + "-tooltip"],
-                               btnList[opcode][1], opcode]);
-                       this.pushOperations(["TO-row-split", "TO-row-delete", "TO-row-insert-under", "TO-row-insert-above", "TO-row-prop"], menu, tbo);
-                       break;
-                   case "table":
-                       table = target;
-                       if(!tbo) break;
-                       this.pushOperations(["TO-col-split", "TO-col-delete", "TO-col-insert-after", "TO-col-insert-before", "TO-col-prop"], menu, tbo);
-                       this.pushOperations(["TO-toggle-borders", "TO-table-restyle", "TO-table-prop"], menu, tbo);
-                       break;
-                   case "ol":
-                   case "ul":
-                   case "dl":
-                       list = target;
-                       break;
-                   case "div":
-                       div = target;
-                       break;
-                   case "body":
-                       this.pushOperations(["JustifyFull", "JustifyRight", "JustifyCenter", "JustifyLeft"], menu, "BlockElements");
-                       break;
-               }
-       }
-
-       if (selection && !link) {
-               if (menu.length) menu.push(null);
-               menu.push([i18n["Make link"],
-                       ContextMenu.linkHandler(editor, link, "MakeLink"),
-                       i18n["Create a link"],
-                       btnList["CreateLink"][1],"CreateLink"]);
-       }
-
-       if (!/^(html|body)$/i.test(currentTarget.nodeName)) {
-               if (/^(table|thead|tbody|tr|td|th|tfoot)$/i.test(currentTarget.nodeName)) {
-                       tmp = table;
-                       table = null;
-               } else if(list) {
-                       tmp = list;
-                       list = null;
-               } else {
-                       tmp = currentTarget;
-               }
-               if (menu.length) menu.push(null);
-               menu.push(
-                 [i18n["Remove the"] + " &lt;" + tmp.tagName.toLowerCase() + "&gt; " + i18n["Element"],
-                       ContextMenu.deleteElementHandler(editor, tmp, table), i18n["Remove this node from the document"]],
-                 [i18n["Insert paragraph before"],
-                       ContextMenu.blockElementsHandler(editor, tmp, "InsertParagraphBefore"), i18n["Insert a paragraph before the current node"], null, "InsertParagraphBefore"],
-                 [i18n["Insert paragraph after"],
-                       ContextMenu.blockElementsHandler(editor, tmp, "InsertParagraphAfter"), i18n["Insert a paragraph after the current node"], null, "InsertParagraphAfter"]
-               );
-       }
-       return menu;
-};
-
 ContextMenu.mouseOverHandler = function(editor,item) {
        return (function() {
                item.className += " hover";
@@ -419,37 +573,6 @@ ContextMenu.keyPressHandler = function(instance) {
        });
 };
 
-ContextMenu.prototype.closeMenu = function() {
-       HTMLArea._removeEvent((HTMLArea.is_ie ? document.body : document), "mousedown", this.eventHandlers["documentClick"]);
-       HTMLArea._removeEvent((HTMLArea.is_ie ? this.editor._doc.body : this.editor._doc), "mousedown", this.eventHandlers["documentClick"]);
-       if (this.keys.length > 0) HTMLArea._removeEvent((HTMLArea.is_ie ? this.editor._doc.body : this.editor._doc), "keypress", this.eventHandlers["keyPress"]);
-       for (var handler in this.eventHandlers) this.eventHandlers[handler] = null;
-       var e, items = document.getElementsByTagName("li");
-       if (HTMLArea.is_ie) items = this.iePopup.document.getElementsByTagName("li");;
-       for (var i = items.length; --i >= 0 ;) {
-               e = items[i];
-               if ( e.__msh ) {
-                       HTMLArea._removeEvent(e, "mouseover", e.__msh.mouseover);
-                       e.__msh.mouseover = null;
-                       HTMLArea._removeEvent(e, "mouseout", e.__msh.mouseout);
-                       e.__msh.mouseout = null;
-                       HTMLArea._removeEvent(e, "contextmenu", e.__msh.contextmenu);
-                       e.__msh.contextmenu = null;
-                       if (!HTMLArea.is_ie) HTMLArea._removeEvent(e, "mousedown", e.__msh.mousedown);
-                       e.__msh.mousedown = null;
-                       HTMLArea._removeEvent(e, "mouseup", e.__msh.mouseup);
-                       e.__msh.mouseup = null;
-                       e.__msh.action = null;
-                       e.__msh.activate = null;
-                       e.__msh = null;
-               }
-       }
-       this.currentMenu.parentNode.removeChild(this.currentMenu);
-       this.currentMenu = null;
-       this.keys = [];
-       if (HTMLArea.is_ie) this.iePopup.hide();
-};
-
 ContextMenu.getPos = function(el) {
        var r = { x: el.offsetLeft, y: el.offsetTop };
        if (el.offsetParent) {
@@ -460,119 +583,3 @@ ContextMenu.getPos = function(el) {
        return r;
 };
 
-ContextMenu.prototype.popupMenu = function(ev,target) {
-       var editor = this.editor;
-       if (!ev) var ev = window.event;
-       if (!target) var target = (ev.target) ? ev.target : ev.srcElement;
-       if (this.currentMenu) this.currentMenu.parentNode.removeChild(this.currentMenu);
-       this.keys = [];
-       var ifpos = ContextMenu.getPos(this.editor._iframe);
-       var x = ev.clientX + ifpos.x;
-       var y = ev.clientY + ifpos.y;
-
-       var doc, list, separator = false;
-
-       if (!HTMLArea.is_ie) {
-               doc = document;
-       } else {
-               var popup = this.iePopup = window.createPopup();
-               doc = popup.document;
-               var head = doc.getElementsByTagName("head")[0];
-               var link = doc.createElement("link");
-               link.rel = "stylesheet";
-               link.type = "text/css";
-               if ( _editor_CSS.indexOf("http") == -1 ) link.href = _typo3_host_url + _editor_CSS;
-                       else link.href = _editor_CSS;
-               head.appendChild(link);
-       }
-
-       list = doc.createElement("ul");
-       list.className = "htmlarea-context-menu";
-       doc.body.appendChild(list);
-
-       var options = this.getContextMenu(target);
-       var n = options.length;
-       for (var i=0; i < n; ++i) {
-               var option = options[i];
-               if (!option){
-                       separator = true;
-               } else {
-                       var item = doc.createElement("li");
-                       list.appendChild(item);
-                       var label = option[0];
-                       if(separator) {
-                               item.className += " separator";
-                               separator = false;
-                       }
-                       item.__msh = {
-                               item:           item,
-                               label:          label,
-                               action:         option[1],
-                               tooltip:        option[2] || null,
-                               icon:           option[3] || null,
-                               activate:       ContextMenu.activateHandler(item, this),
-                               cmd:            option[4] || null
-                       };
-                       label = label.replace(/_([a-zA-Z0-9])/, "<u>$1</u>");
-                       if (label != option[0]) this.keys.push([ RegExp.$1, item ]);
-                       label = label.replace(/__/, "_");
-                       var button = doc.createElement("button");
-                       button.className = "button";
-                       if(item.__msh.cmd) {
-                               button.className += " " + item.__msh.cmd;
-                               if(typeof(editor.plugins["TYPO3Browsers"]) != "undefined" && (item.__msh.cmd == "CreateLink" || item.__msh.cmd == "UnLink" || item.__msh.cmd == "InsertImage")) button.className += "-TYPO3Browsers";
-                               button.innerHTML = label;
-                       } else if(item.__msh.icon) {
-                               button.innerHTML = "<img src='" + item.__msh.icon + "' />" + label;
-                       } else {
-                               button.innerHTML = label;
-                       }
-                       item.appendChild(button);
-
-                       item.__msh.mouseover = ContextMenu.mouseOverHandler(editor, item);
-                       HTMLArea._addEvent(item, "mouseover", item.__msh.mouseover);
-                       item.__msh.mouseout = ContextMenu.mouseOutHandler(item);
-                       HTMLArea._addEvent(item, "mouseout", item.__msh.mouseout);
-                       item.__msh.contextmenu = ContextMenu.itemContextMenuHandler(item);
-                       HTMLArea._addEvent(item, "contextmenu", item.__msh.contextmenu);
-                       if(!HTMLArea.is_ie) {
-                               item.__msh.mousedown = ContextMenu.mouseDownHandler(item);
-                               HTMLArea._addEvent(item, "mousedown", item.__msh.mousedown);
-                       }
-                       item.__msh.mouseup = ContextMenu.mouseUpHandler(item, this);
-                       HTMLArea._addEvent(item, "mouseup", item.__msh.mouseup);
-               }
-       }
-       if (n) {
-               if(!HTMLArea.is_ie) {
-                       var dx = x + list.offsetWidth - window.innerWidth - window.pageXOffset + 4;
-                       var dy = y + list.offsetHeight - window.innerHeight - window.pageYOffset + 4;
-                       if(dx > 0) x -= dx;
-                       if(dy > 0) y -= dy;
-                       list.style.left = x + "px";
-                       list.style.top = y + "px";
-               } else {
-                               // determine the size
-                       list.style.left = "0px";
-                       list.style.top = "0px";
-                       var foobar = document.createElement("ul");
-                       foobar.className = "htmlarea-context-menu";
-                       foobar.innerHTML = list.innerHTML;
-                       editor._iframe.contentWindow.parent.document.body.appendChild(foobar);
-                       this.iePopup.show(ev.screenX, ev.screenY, foobar.clientWidth+2, foobar.clientHeight+2);
-                       editor._iframe.contentWindow.parent.document.body.removeChild(foobar);
-               }
-               this.currentMenu = list;
-               this.timeStamp = (new Date()).getTime();
-               this.eventHandlers["documentClick"] = ContextMenu.documentClickHandler(this);
-               HTMLArea._addEvent((HTMLArea.is_ie ? document.body : document), "mousedown", this.eventHandlers["documentClick"]);
-               HTMLArea._addEvent((HTMLArea.is_ie ? editor._doc.body : editor._doc), "mousedown", this.eventHandlers["documentClick"]);
-               if (this.keys.length > 0) {
-                       this.eventHandlers["keyPress"] = ContextMenu.keyPressHandler(this);
-                       HTMLArea._addEvents((HTMLArea.is_ie ? editor._doc.body : editor._doc), ["keypress", "keydown"], this.eventHandlers["keyPress"]);
-               }
-       }
-       HTMLArea._stopEvent(ev);
-       return false;
-};
-