[TASK] RTE: Migrate event handling to jQuery 43/35043/2
authorStanislas Rolland <typo3@sjbr.ca>
Thu, 4 Dec 2014 14:57:20 +0000 (09:57 -0500)
committerStanislas Rolland <typo3@sjbr.ca>
Thu, 4 Dec 2014 15:02:08 +0000 (16:02 +0100)
Migrate non-widget event handling to jQuery.
Migrate custom events to jQuery.
Migrate ExtJs tasks to plain JavaScript.
Migrate ExtJs key maps to jQuery.

Releases: master
Resolves: #63572
Change-Id: I3828c24ad3ce7a5193d42ba76819cf09e47456c9
Reviewed-on: http://review.typo3.org/35043
Reviewed-by: Stanislas Rolland <typo3@sjbr.ca>
Tested-by: Stanislas Rolland <typo3@sjbr.ca>
31 files changed:
typo3/sysext/rtehtmlarea/Classes/RteHtmlAreaBase.php
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/CSS/Parser.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/DOM/DOM.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/DOM/Selection.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/Editor/Editor.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/Editor/Framework.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/Editor/Iframe.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/Editor/StatusBar.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/Editor/Toolbar.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/Event/Event.js [new file with mode: 0644]
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/Event/KeyMap.js [new file with mode: 0644]
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/Extjs/ux/Ext.ux.HTMLAreaButton.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/Extjs/ux/Ext.ux.Toolbar.HTMLAreaToolbarText.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/Extjs/ux/Ext.ux.form.HTMLAreaCombo.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/Plugin/Plugin.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/Util/Util.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/Plugins/block-elements.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/Plugins/block-style.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/Plugins/character-map.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/Plugins/context-menu.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/Plugins/copy-paste.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/Plugins/default-clean.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/Plugins/definition-list.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/Plugins/insert-smiley.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/Plugins/plain-text.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/Plugins/table-operations.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/Plugins/text-indicator.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/Plugins/text-style.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/Plugins/typo3html-parser.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/Plugins/typo3image.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/Plugins/undo-redo.js

index 9189b8e..ee41ab9 100644 (file)
@@ -810,8 +810,10 @@ class RteHtmlAreaBase extends \TYPO3\CMS\Backend\Rte\AbstractRte {
                        'Util/Tips',
                        'Util/TYPO3',
                        'Ajax/Ajax',
-                       'CSS/Parser',
                        'DOM/DOM',
+                       'Event/Event',
+                       'Event/KeyMap',
+                       'CSS/Parser',
                        'DOM/BookMark',
                        'DOM/Node',
                        'DOM/Selection',
index 4eea0b5..cf1aa8f 100644 (file)
@@ -1,7 +1,7 @@
 /***************************************************
  *  HTMLArea.CSS.Parser: CSS Parser
  ***************************************************/
-HTMLArea.CSS.Parser = function (UserAgent, Util) {
+HTMLArea.CSS.Parser = function (UserAgent, Util, Event) {
 
        var Parser = Ext.extend(Ext.util.Observable, {
 
@@ -22,13 +22,6 @@ HTMLArea.CSS.Parser = function (UserAgent, Util) {
                        if (this.editor.config.styleSheetsMaximumAttempts) {
                                this.parseAttemptsMaximumNumber = this.editor.config.styleSheetsMaximumAttempts;
                        }
-                       this.addEvents(
-                               /*
-                                * @event HTMLAreaEventCssParsingComplete
-                                * Fires when parsing of the stylesheets of the iframe is complete
-                                */
-                               'HTMLAreaEventCssParsingComplete'
-                       );
                        this.parsedClasses = {};
                        this.ready = false;
                },
@@ -92,7 +85,11 @@ HTMLArea.CSS.Parser = function (UserAgent, Util) {
                                if (!this.cssLoaded) {
                                        if (/Security/i.test(this.error)) {
                                                this.editor.appendToLog('HTMLArea.CSS.Parser', 'parse', 'A security error occurred. Make sure all stylesheets are accessed from the same domain/subdomain and using the same protocol as the current script.', 'error');
-                                               this.fireEvent('HTMLAreaEventCssParsingComplete');
+                                               /**
+                                                * @event HTMLAreaEventCssParsingComplete
+                                                * Fires when parsing of the stylesheets of the iframe is complete
+                                                */
+                                               Event.trigger(this, 'HTMLAreaEventCssParsingComplete');
                                        } else if (this.parseAttemptsCounter < this.parseAttemptsMaximumNumber) {
                                                this.parseAttemptsCounter++;
                                                var self = this;
@@ -101,14 +98,22 @@ HTMLArea.CSS.Parser = function (UserAgent, Util) {
                                                }, 200);
                                        } else {
                                                this.editor.appendToLog('HTMLArea.CSS.Parser', 'parse', 'The stylesheets could not be parsed. Reported error: ' + this.error, 'error');
-                                               this.fireEvent('HTMLAreaEventCssParsingComplete');
+                                               /**
+                                                * @event HTMLAreaEventCssParsingComplete
+                                                * Fires when parsing of the stylesheets of the iframe is complete
+                                                */
+                                               Event.trigger(this, 'HTMLAreaEventCssParsingComplete');
                                        }
                                } else {
                                        this.attemptTimeout = null;
                                        this.ready = true;
                                        this.filterAllowedClasses();
                                        this.sort();
-                                       this.fireEvent('HTMLAreaEventCssParsingComplete');
+                                       /**
+                                        * @event HTMLAreaEventCssParsingComplete
+                                        * Fires when parsing of the stylesheets of the iframe is complete
+                                        */
+                                       Event.trigger(this, 'HTMLAreaEventCssParsingComplete');
                                }
                        }
                },
@@ -364,4 +369,4 @@ HTMLArea.CSS.Parser = function (UserAgent, Util) {
 
        return Parser;
 
-}(HTMLArea.UserAgent, HTMLArea.util);
+}(HTMLArea.UserAgent, HTMLArea.util, HTMLArea.Event);
index 6259890..fcf0a4b 100644 (file)
@@ -414,7 +414,7 @@ HTMLArea.DOM = function (UserAgent) {
                 * @return      void
                 */
                makeUrlsAbsolute: function (node, baseUrl, walker) {
-                       walker.walk(node, true, 'HTMLArea.DOM.makeImageSourceAbsolute(node, args[0]) || HTMLArea.DOM.makeLinkHrefAbsolute(node, args[0])', 'function(){}', [baseUrl]);
+                       walker.walk(node, true, 'HTMLArea.DOM.makeImageSourceAbsolute(node, args[0]) || HTMLArea.DOM.makeLinkHrefAbsolute(node, args[0])', 'HTMLArea.util.emptyFunction', [baseUrl]);
                },
 
                /**
index 1d93c22..41991ac 100644 (file)
@@ -13,7 +13,7 @@
 /***************************************************
  *  HTMLArea.DOM.Selection: Selection object
  ***************************************************/
-HTMLArea.DOM.Selection = function(UserAgent, Util, Dom) {
+HTMLArea.DOM.Selection = function(UserAgent, Util, Dom, Event) {
 
        /**
         * Constructor method
@@ -775,12 +775,12 @@ HTMLArea.DOM.Selection = function(UserAgent, Util, Dom) {
         * Detect emails and urls as they are typed in non-IE browsers
         * Borrowed from Xinha (is not htmlArea) - http://xinha.gogo.co.nz/
         *
-        * @param       object          event: the ExtJS key event
+        * @param object event: the browser key event
         *
-        * @return      void
+        * @return void
         */
        Selection.prototype.detectURL = function (event) {
-               var ev = event.browserEvent;
+               var key = Event.getKey(event);
                var editor = this.editor;
                var selection = this.get().selection;
                if (!/^(a)$/i.test(this.getParentElement().nodeName)) {
@@ -808,17 +808,17 @@ HTMLArea.DOM.Selection = function(UserAgent, Util, Dom) {
                                editor.unlinkOnUndo = true;
                                return a;
                        };
-                       switch (ev.which) {
-                                       // Space or Enter or >, see if the text just typed looks like a URL, or email address and link it accordingly
-                               case 13:
-                               case 32:
+                       switch (key) {
+                               // Space or Enter, see if the text just typed looks like a URL, or email address and link it accordingly
+                               case Event.ENTER:
+                               case Event.SPACE:
                                        if (selection && selection.isCollapsed && selection.anchorNode.nodeType === Dom.TEXT_NODE && selection.anchorNode.data.length > 3 && selection.anchorNode.data.indexOf('.') >= 0) {
                                                var midStart = selection.anchorNode.data.substring(0,selection.anchorOffset).search(/[a-zA-Z0-9]+\S{3,}$/);
                                                if (midStart == -1) {
                                                        break;
                                                }
                                                if (this.getFirstAncestorOfType('a')) {
-                                                               // already in an anchor
+                                                       // already in an anchor
                                                        break;
                                                }
                                                var matchData = selection.anchorNode.data.substring(0,selection.anchorOffset).replace(/^.*?(\S*)$/, '$1');
@@ -851,16 +851,16 @@ HTMLArea.DOM.Selection = function(UserAgent, Util, Dom) {
                                        }
                                        break;
                                default:
-                                       if (ev.keyCode == 27 || (editor.unlinkOnUndo && ev.ctrlKey && ev.which == 122)) {
+                                       if (key === Event.ESC || (editor.unlinkOnUndo && (event.ctrlKey || event.metaKey) && key === Event.F11)) {
                                                if (editor.unLink) {
                                                        editor.unLink();
-                                                       event.stopEvent();
+                                                       Event.stopEvent(event);
                                                }
                                                break;
-                                       } else if (ev.which || ev.keyCode == 8 || ev.keyCode == 46) {
+                                       } else if (key) {
                                                editor.unlinkOnUndo = false;
                                                if (selection.anchorNode && selection.anchorNode.nodeType === Dom.TEXT_NODE) {
-                                                               // See if we might be changing a link
+                                                       // See if we might be changing a link
                                                        var a = this.getFirstAncestorOfType('a');
                                                        if (!a) {
                                                                break;
@@ -1081,4 +1081,4 @@ HTMLArea.DOM.Selection = function(UserAgent, Util, Dom) {
 
        return Selection;
 
-}(HTMLArea.UserAgent, HTMLArea.util, HTMLArea.DOM);
+}(HTMLArea.UserAgent, HTMLArea.util, HTMLArea.DOM, HTMLArea.Event);
index af26c4b..3d38828 100644 (file)
@@ -13,7 +13,7 @@
 /**
  * Editor extends Ext.util.Observable
  */
-HTMLArea.Editor = function(UserAgent, Util, Ajax, Dom, Selection, BookMark, Node, Typo3, Framework) {
+HTMLArea.Editor = function(UserAgent, Util, Ajax, Dom, Event, Selection, BookMark, Node, Typo3, Framework) {
 
        var Editor = Ext.extend(Ext.util.Observable, {
 
@@ -69,20 +69,8 @@ HTMLArea.Editor = function(UserAgent, Util, Ajax, Dom, Selection, BookMark, Node
                        this.ajax = new Ajax({
                                editor: this
                        });
-                               // Initialize keyboard input inhibit flag
+                       // Initialize keyboard input inhibit flag
                        this.inhibitKeyboardInput = false;
-                       this.addEvents(
-                               /*
-                                * @event HTMLAreaEventEditorReady
-                                * Fires when initialization of the editor is complete
-                                */
-                               'HTMLAreaEventEditorReady',
-                               /*
-                                * @event HTMLAreaEventModeChange
-                                * Fires when the editor changes mode
-                                */
-                               'HTMLAreaEventModeChange'
-                       );
                },
                /*
                 * Flag set to true when the editor initialization has completed
@@ -219,8 +207,8 @@ HTMLArea.Editor = function(UserAgent, Util, Ajax, Dom, Selection, BookMark, Node
                        this.iframe = this.htmlArea.getComponent('iframe');
                        this.textAreaContainer = this.htmlArea.getComponent('textAreaContainer');
                        // Get triggered when the framework becomes ready
-                       this.relayEvents(this.htmlArea, ['HTMLAreaEventFrameworkReady']);
-                       this.on('HTMLAreaEventFrameworkReady', this.onFrameworkReady, this, {single: true});
+                       var self = this;
+                       Event.one(this.htmlArea, 'HTMLAreaEventFrameworkReady', function (event) { Event.stopEvent(event); self.onFrameworkReady(); return false; });
                },
                /**
                 * Initialize the editor
@@ -290,7 +278,11 @@ HTMLArea.Editor = function(UserAgent, Util, Ajax, Dom, Selection, BookMark, Node
                                }
                        }
                        this.ready = true;
-                       this.fireEvent('HTMLAreaEventEditorReady');
+                       /**
+                        * @event EditorReady
+                        * Fires when initialization of the editor is complete
+                        */
+                       Event.trigger(this, 'HtmlAreaEventEditorReady');
                        this.appendToLog('HTMLArea.Editor', 'onFrameworkReady', 'Editor ready.', 'info');
                },
        
@@ -326,13 +318,18 @@ HTMLArea.Editor = function(UserAgent, Util, Ajax, Dom, Selection, BookMark, Node
                                        this.mode = mode;
                                        break;
                        }
-                       this.fireEvent('HTMLAreaEventModeChange', this.mode);
+                       /**
+                        * @event HTMLAreaEventModeChange
+                        * Fires when the editor changes mode
+                        */
+                       Event.trigger(this, 'HTMLAreaEventModeChange', [this.mode]);
                        this.focus();
                        for (var pluginId in this.plugins) {
                                this.getPlugin(pluginId).onMode(this.mode);
                        }
                },
-               /*
+
+               /**
                 * Get current editor mode
                 */
                getMode: function () {
@@ -482,18 +479,21 @@ HTMLArea.Editor = function(UserAgent, Util, Ajax, Dom, Selection, BookMark, Node
                                }
                        }
                },
-               /*
+
+               /**
                 * Add listeners
                 */
                initEventsListening: function () {
                        if (UserAgent.isOpera) {
                                this.iframe.startListening();
                        }
-                               // Add unload handler
+                       // Add unload handler
                        var iframe = this.iframe.getEl().dom;
-                       Ext.EventManager.on(iframe.contentWindow ? iframe.contentWindow : iframe.contentDocument, 'unload', this.onUnload, this, {single: true});
+                       var self = this;
+                       Event.one(iframe.contentWindow ? iframe.contentWindow : iframe.contentDocument, 'unload', function (event) { return self.onUnload(event); });
                },
-               /*
+
+               /**
                 * Make the editor framework visible
                 */
                show: function () {
@@ -523,17 +523,18 @@ HTMLArea.Editor = function(UserAgent, Util, Ajax, Dom, Selection, BookMark, Node
                                this.textArea.value = this.getHTML();
                        }
                        // Cleanup
-                       Ext.TaskMgr.stopAll();
                        for (var pluginId in this.plugins) {
                                this.unRegisterPlugin(pluginId);
                        }
+                       Event.off(this.textarea);
                        this.purgeListeners();
                        RTEarea[this.editorId].editor = null;
                        // ExtJS is not releasing any resources when the iframe is unloaded
                        this.htmlArea.destroy();
+                       return true;
                }
        });
 
        return Editor;
 
-}(HTMLArea.UserAgent, HTMLArea.util, HTMLArea.Ajax, HTMLArea.DOM, HTMLArea.DOM.Selection, HTMLArea.DOM.BookMark, HTMLArea.DOM.Node, HTMLArea.util.TYPO3, HTMLArea.Framework);
+}(HTMLArea.UserAgent, HTMLArea.util, HTMLArea.Ajax, HTMLArea.DOM, HTMLArea.Event, HTMLArea.DOM.Selection, HTMLArea.DOM.BookMark, HTMLArea.DOM.Node, HTMLArea.util.TYPO3, HTMLArea.Framework);
index ee8de32..b56d68f 100644 (file)
@@ -13,7 +13,7 @@
 /**
  * Framework extends Ext.Panel and is the visual component of the Editor and contains the tool bar, the iframe, the textarea and the status bar
  */
-HTMLArea.Framework = function(Typo3) {
+HTMLArea.Framework = function(Typo3, Event) {
 
        var Framework = Ext.extend(Ext.Panel, {
 
@@ -27,13 +27,6 @@ HTMLArea.Framework = function(Typo3) {
                        this.statusBar = this.getBottomToolbar();
                        this.iframe = this.getComponent('iframe');
                        this.textAreaContainer = this.getComponent('textAreaContainer');
-                       this.addEvents(
-                               /*
-                                * @event HTMLAreaEventFrameworkReady
-                                * Fires when the iframe is ready and all components are rendered
-                                */
-                               'HTMLAreaEventFrameworkReady'
-                       );
                        this.addListener({
                                beforedestroy: {
                                        fn: this.onBeforeDestroy,
@@ -41,7 +34,8 @@ HTMLArea.Framework = function(Typo3) {
                                }
                        });
                        // Monitor iframe becoming ready
-                       this.mon(this.iframe, 'HTMLAreaEventIframeReady', this.onIframeReady, this, {single: true});
+                       var self = this;
+                       Event.one(this.iframe, 'HTMLAreaEventIframeReady', function (event) { Event.stopEvent(event); self.onIframeReady(); return false; });
                        // Let the framefork render itself, but it will fail to do so if inside a hidden tab or inline element
                        if (!this.isNested || Typo3.allElementsAreDisplayed(this.nestedParentElements.sorted)) {
                                this.render(this.textArea.parentNode, this.textArea.id);
@@ -57,6 +51,7 @@ HTMLArea.Framework = function(Typo3) {
                 * Initiate events monitoring
                 */
                initEventListeners: function () {
+                       var self = this;
                        // Make the framework resizable, if configured by the user
                        this.makeResizable();
                        // Monitor textArea container becoming shown or hidden as it may change the height of the status bar
@@ -74,7 +69,7 @@ HTMLArea.Framework = function(Typo3) {
                                        }
                                        form.htmlAreaPreviousOnReset.push(form.onreset);
                                }
-                               this.mon(Ext.get(form), 'reset', this.onReset, this);
+                               Event.on(form, 'reset', function (event) { return self.onReset(event); });
                        }
                        this.addListener({
                                resize: {
@@ -283,11 +278,18 @@ HTMLArea.Framework = function(Typo3) {
                                if (!this.getEditor().config.showStatusBar) {
                                        this.statusBar.hide();
                                }
-                                       // Set the initial size of the framework
+                               // Set the initial size of the framework
                                this.onWindowResize();
-                               this.fireEvent('HTMLAreaEventFrameworkReady');
+                               /**
+                                * @event HTMLAreaEventFrameworkReady
+                                * Fires when the iframe is ready and all components are rendered
+                                */
+                               Event.trigger(this, 'HTMLAreaEventFrameworkReady');
                        } else {
-                               this.onIframeReady.defer(50, this);
+                               var self = this;
+                               window.setTimeout(function () {
+                                       self.onIframeReady();   
+                               }, 50);
                        }
                },
 
@@ -299,12 +301,13 @@ HTMLArea.Framework = function(Typo3) {
                        this.getEditor().setHTML(this.textArea.value);
                        this.toolbar.update();
                        // Invoke previous reset handlers, if any
-                       var htmlAreaPreviousOnReset = event.getTarget().dom.htmlAreaPreviousOnReset;
+                       var htmlAreaPreviousOnReset = event.target.htmlAreaPreviousOnReset;
                        if (typeof htmlAreaPreviousOnReset !== 'undefined') {
                                for (var i = 0, n = htmlAreaPreviousOnReset.length; i < n; i++) {
                                        htmlAreaPreviousOnReset[i]();
                                }
                        }
+                       return true;
                },
 
                /**
@@ -332,5 +335,5 @@ HTMLArea.Framework = function(Typo3) {
 
        return Framework;
 
-}(HTMLArea.util.TYPO3);
+}(HTMLArea.util.TYPO3, HTMLArea.Event);
 Ext.reg('htmlareaframework', HTMLArea.Framework);
index 1a004f0..48691cf 100644 (file)
@@ -13,7 +13,7 @@
 /**
  * HTMLArea.Iframe extends Ext.BoxComponent
  */
-HTMLArea.Iframe = function (UserAgent, Walker, Typo3, Dom) {
+HTMLArea.Iframe = function (UserAgent, Walker, Typo3, Dom, Event, KeyMap) {
 
        var Iframe = Ext.extend(Ext.BoxComponent, {
 
@@ -22,18 +22,6 @@ HTMLArea.Iframe = function (UserAgent, Walker, Typo3, Dom) {
                 */
                initComponent: function () {
                        Iframe.superclass.initComponent.call(this);
-                       this.addEvents(
-                               /*
-                                * @event HTMLAreaEventIframeReady
-                                * Fires when the iframe style sheets become accessible
-                                */
-                               'HTMLAreaEventIframeReady',
-                               /*
-                                * @event HTMLAreaEventWordCountChange
-                                * Fires when the word count may have changed
-                                */
-                               'HTMLAreaEventWordCountChange'
-                       );
                        this.addListener({
                                afterrender: {
                                        fn: this.initEventListeners,
@@ -55,58 +43,62 @@ HTMLArea.Iframe = function (UserAgent, Walker, Typo3, Dom) {
                                this.addClass('noStatusBar');
                        }
                },
-               /*
+
+               /**
                 * Initialize event listeners and the document after the iframe has rendered
                 */
                initEventListeners: function () {
                        this.initStyleChangeEventListener();
                        if (UserAgent.isOpera) {
-                               this.mon(this.getEl(), 'load', this.initializeIframe , this, {single: true});
+                               var self = this;
+                               Event.one(this.getEl().dom, 'load', function (event) { Event.stopEvent(event); self.initializeIframe(event); return false; })
                        } else {
                                this.initializeIframe();
                        }
                },
-               /*
+
+               /**
                 * The editor iframe may become hidden with style.display = "none" on some parent div
                 * This breaks the editor in Firefox: the designMode attribute needs to be reset after the style.display of the container div is reset to "block"
                 * In all browsers, it breaks the evaluation of the framework dimensions
                 */
                initStyleChangeEventListener: function () {
                        if (this.isNested && UserAgent.isGecko) {
+                               var self = this;
                                var options = {
-                                       stopEvent: true,
                                        delay: 50
                                };
                                for (var i = this.nestedParentElements.sorted.length; --i >= 0;) {
-                                       var nestedElement = Ext.get(this.nestedParentElements.sorted[i]);
-                                       this.mon(
+                                       var nestedElement = document.getElementById(this.nestedParentElements.sorted[i]);
+                                       Event.on(
                                                nestedElement,
-                                               UserAgent.isIE ? 'propertychange' : 'DOMAttrModified',
-                                               this.onNestedShow,
-                                               this,
+                                               'DOMAttrModified',
+                                               function (event) { return self.onNestedShow(event); },
                                                options
                                        );
-                                       this.mon(
-                                               nestedElement.parent(),
-                                               UserAgent.isIE ? 'propertychange' : 'DOMAttrModified',
-                                               this.onNestedShow,
-                                               this,
+                                       Event.on(
+                                               nestedElement.parentNode,
+                                               'DOMAttrModified',
+                                               function (event) { return self.onNestedShow(event); },
                                                options
                                        );
                                }
                        }
                },
-               /*
+
+               /**
                 * editorId should be set in config
                 */
                editorId: null,
-               /*
+
+               /**
                 * Get a reference to the editor
                 */
-               getEditor: function() {
+               getEditor: function () {
                        return RTEarea[this.editorId].editor;
                },
-               /*
+
+               /**
                 * Get a reference to the toolbar
                 */
                getToolbar: function () {
@@ -183,10 +175,15 @@ HTMLArea.Iframe = function (UserAgent, Walker, Typo3, Dom) {
                                this.hide();
                                // Set iframe ready
                                this.ready = true;
-                               this.fireEvent('HTMLAreaEventIframeReady');
+                               /**
+                                * @event HTMLAreaEventIframeReady
+                                * Fires when the iframe style sheets become accessible
+                                */
+                               Event.trigger(this, 'HTMLAreaEventIframeReady');
                        }
                },
-               /*
+
+               /**
                 * Create one of each of the configured custom tags so they are properly parsed by the walker when using IE
                 * See: http://en.wikipedia.org/wiki/HTML5_Shiv
                 *
@@ -321,209 +318,265 @@ HTMLArea.Iframe = function (UserAgent, Walker, Typo3, Dom) {
                                } catch(e) {}
                        }
                },
-               /*
+
+               /**
                 * Handler invoked when an hidden TYPO3 hidden nested tab or inline element is shown
                 */
-               onNestedShow: function (event, target) {
-                       var styleEvent = true;
+               onNestedShow: function (event) {
+                       Event.stopEvent(event);
+                       var target = event.target;
+                       var delay = event.data.delay;
+                       var self = this;
+                       window.setTimeout(function () {
+                               var styleEvent = true;
                                // In older versions of Gecko attrName is not set and refering to it causes a non-catchable crash
-                       if ((UserAgent.isGecko && navigator.productSub > 2007112700) || UserAgent.isOpera) {
-                               styleEvent = (event.browserEvent.attrName == 'style') || (event.browserEvent.attrName == 'className');
-                       } else if (UserAgent.isIE) {
-                               styleEvent = (event.browserEvent.propertyName == 'style.display');
-                       }
-                       if (styleEvent && (this.nestedParentElements.sorted.indexOf(target.id) != -1 || this.nestedParentElements.sorted.indexOf(target.id.replace('_div', '_fields')) != -1)) {
+                               if ((UserAgent.isGecko && navigator.productSub > 2007112700) || UserAgent.isOpera) {
+                                       //styleEvent = (event.browserEvent.attrName == 'style') || (event.browserEvent.attrName == 'className');
+                                       styleEvent = (event.attrName == 'style') || (event.attrName == 'className');
+                               } else if (UserAgent.isIE) {
+                                       //styleEvent = (event.browserEvent.propertyName == 'style.display');
+                                       styleEvent = (event.propertyName == 'style.display');
+                               }
+                               if (styleEvent && (self.nestedParentElements.sorted.indexOf(target.id) != -1 || self.nestedParentElements.sorted.indexOf(target.id.replace('_div', '_fields')) != -1)) {
                                        // Check if all container nested elements are displayed
-                               if (Typo3.allElementsAreDisplayed(this.nestedParentElements.sorted)) {
-                                       if (this.getEditor().getMode() === 'wysiwyg') {
-                                               if (UserAgent.isGecko) {
-                                                       this.setDesignMode(true);
+                                       if (Typo3.allElementsAreDisplayed(self.nestedParentElements.sorted)) {
+                                               if (self.getEditor().getMode() === 'wysiwyg') {
+                                                       if (UserAgent.isGecko) {
+                                                               self.setDesignMode(true);
+                                                       }
+                                                       self.fireEvent('show');
+                                               } else {
+                                                       self.ownerCt.textAreaContainer.fireEvent('show');
                                                }
-                                               this.fireEvent('show');
-                                       } else {
-                                               this.ownerCt.textAreaContainer.fireEvent('show');
+                                               self.getToolbar().update();
                                        }
-                                       this.getToolbar().update();
-                                       return false;
                                }
-                       }
+                       }, delay);
+                       return false;
                },
-               /*
+
+               /**
                 * Instance of DOM walker
                 */
                htmlRenderer: {},
-               /*
+
+               /**
                 * Get the HTML content of the iframe
                 */
                getHTML: function () {
                        return this.htmlRenderer.render(this.document.body, false);
                },
-               /*
+
+               /**
                 * Start listening to things happening in the iframe
                 */
                startListening: function () {
-                               // Create keyMap so that plugins may bind key handlers
-                       this.keyMap = new Ext.KeyMap(Ext.get(this.document.documentElement), [], (UserAgent.isIE || UserAgent.isWebKit) ? 'keydown' : 'keypress');
-                               // Special keys map
-                       this.keyMap.addBinding([
+                       var self = this;
+                       // Create keyMap so that plugins may bind key handlers
+                       this.keyMap = new KeyMap(this.document.documentElement, (UserAgent.isIE || UserAgent.isWebKit) ? 'keydown' : 'keypress');
+                       // Special keys map
+                       this.keyMap.addBinding(
                                {
-                                       key: [Ext.EventObject.DOWN, Ext.EventObject.UP, Ext.EventObject.LEFT, Ext.EventObject.RIGHT],
+                                       key: [Event.DOWN, Event.UP, Event.LEFT, Event.RIGHT],
                                        alt: false,
-                                       handler: this.onArrow,
-                                       scope: this
-                               },
+                                       handler: function (event) { return self.onArrow(event); }
+                               }
+                       );
+                       this.keyMap.addBinding(
                                {
-                                       key: Ext.EventObject.TAB,
+                                       key: Event.TAB,
                                        ctrl: false,
                                        alt: false,
-                                       handler: this.onTab,
-                                       scope: this
-                               },
+                                       handler: function (event) { return self.onTab(event); }
+                               }
+                       );
+                       this.keyMap.addBinding(
                                {
-                                       key: Ext.EventObject.SPACE,
+                                       key: Event.SPACE,
                                        ctrl: true,
                                        shift: false,
                                        alt: false,
-                                       handler: this.onCtrlSpace,
-                                       scope: this
+                                       handler: function (event) { return self.onCtrlSpace(event); }
                                }
-                       ]);
+                       );
                        if (UserAgent.isGecko || UserAgent.isIE || UserAgent.isWebKit) {
                                this.keyMap.addBinding(
                                {
-                                       key: [Ext.EventObject.BACKSPACE, Ext.EventObject.DELETE],
+                                       key: [Event.BACKSPACE, Event.DELETE],
                                        alt: false,
-                                       handler: this.onBackSpace,
-                                       scope: this
+                                       handler: function (event) { return self.onBackSpace(event); }
                                });
                        }
                        if (!UserAgent.isIE && !this.config.disableEnterParagraphs) {
                                this.keyMap.addBinding(
                                {
-                                       key: Ext.EventObject.ENTER,
+                                       key: Event.ENTER,
                                        shift: false,
-                                       handler: this.onEnter,
-                                       scope: this
+                                       handler: function (event) { return self.onEnter(event); }
                                });
                        }
                        if (UserAgent.isWebKit) {
                                this.keyMap.addBinding(
                                {
-                                       key: Ext.EventObject.ENTER,
+                                       key: Event.ENTER,
                                        alt: false,
-                                       handler: this.onWebKitEnter,
-                                       scope: this
+                                       handler: function (event) { return self.onWebKitEnter(event); }
                                });
                        }
                        // Hot key map (on keydown for all browsers)
-                       var hotKeys = '';
+                       var hotKeys = [];
                        for (var key in this.config.hotKeyList) {
-                               if (key.length == 1) {
-                                       hotKeys += key.toUpperCase();
+                               if (key.length === 1) {
+                                       hotKeys.push(key);
                                }
                        }
-                               // Make hot key map available, even if empty, so that plugins may add bindings
-                       this.hotKeyMap = new Ext.KeyMap(Ext.get(this.document.documentElement));
+                       // Make hot key map available, even if empty, so that plugins may add bindings
+                       this.hotKeyMap = new KeyMap(this.document.documentElement, 'keydown');
                        if (hotKeys.length > 0) {
                                this.hotKeyMap.addBinding({
                                        key: hotKeys,
                                        ctrl: true,
                                        shift: false,
                                        alt: false,
-                                       handler: this.onHotKey,
-                                       scope: this
+                                       handler: function (event) { return self.onHotKey(event); }
                                });
                        }
-                       this.mon(Ext.get(this.document.documentElement), (UserAgent.isIE || UserAgent.isWebKit) ? 'keydown' : 'keypress', this.onAnyKey, this);
-                       this.mon(Ext.get(this.document.documentElement), 'mouseup', this.onMouse, this);
-                       this.mon(Ext.get(this.document.documentElement), 'click', this.onMouse, this);
+                       Event.on(
+                               this.document.documentElement,
+                               (UserAgent.isIE || UserAgent.isWebKit) ? 'keydown' : 'keypress',
+                               function (event) { return self.onAnyKey(event); }
+                       );
+                       Event.on(
+                               this.document.documentElement,
+                               'mouseup',
+                               function (event) { return self.onMouse(event); }
+                       );
+                       Event.on(
+                               this.document.documentElement,
+                               'click',
+                               function (event) { return self.onMouse(event); }
+                       );
                        if (UserAgent.isGecko) {
-                               this.mon(Ext.get(this.document.documentElement), 'paste', this.onPaste, this);
-                       }
-                       this.mon(Ext.get(this.document.documentElement), 'drop', this.onDrop, this);
+                               Event.on(
+                                       this.document.documentElement,
+                                       'paste',
+                                       function (event) { return self.onPaste(event); }
+                               );
+                       }
+                       Event.on(
+                               this.document.documentElement,
+                               'drop',
+                               function (event) { return self.onDrop(event); }
+                       );
                        if (UserAgent.isWebKit) {
-                               this.mon(Ext.get(this.document.body), 'dragend', this.onDrop, this);
+                               Event.on(
+                                       this.document.body,
+                                       'dragend',
+                                       function (event) { return self.onDrop(event); }
+                               );
                        }
                },
-               /*
+
+               /**
                 * Handler for other key events
                 */
-               onAnyKey: function(event) {
+               onAnyKey: function (event) {
                        if (this.inhibitKeyboardInput(event)) {
                                return false;
                        }
-                       this.fireEvent('HTMLAreaEventWordCountChange', 100);
-                       if (!event.altKey && !event.ctrlKey) {
-                                       // Detect URL in non-IE browsers
-                               if (!UserAgent.isIE && (event.getKey() != Ext.EventObject.ENTER || (event.shiftKey && !UserAgent.isWebKit))) {
+                       /**
+                        * @event HTMLAreaEventWordCountChange
+                        * Fires when the word count may have changed
+                        */
+                       Event.trigger(this, 'HTMLAreaEventWordCountChange', [100]);
+                       if (!event.altKey && !(event.ctrlKey || event.metaKey)) {
+                               var key = Event.getKey(event);
+                               // Detect URL in non-IE browsers
+                               if (!UserAgent.isIE && (key !== Event.ENTER || (event.shiftKey && !UserAgent.isWebKit))) {
                                        this.getEditor().getSelection().detectURL(event);
                                }
-                                       // Handle option+SPACE for Mac users
-                               if (UserAgent.isMac && event.browserEvent.charCode == 160) {
-                                       return this.onOptionSpace(event.browserEvent.charCode, event);
+                               // Handle option+SPACE for Mac users
+                               if (UserAgent.isMac && key === Event.NON_BREAKING_SPACE) {
+                                       return this.onOptionSpace(key, event);
                                }
                        }
                        return true;
                },
-               /*
+
+               /**
                 * On any key input event, check if input is currently inhibited
                 */
                inhibitKeyboardInput: function (event) {
-                               // Inhibit key events while server-based cleaning is being processed
+                       // Inhibit key events while server-based cleaning is being processed
                        if (this.getEditor().inhibitKeyboardInput) {
-                               event.stopEvent();
+                               Event.stopEvent(event);
                                return true;
                        } else {
                                return false;
                        }
                },
-               /*
+
+               /**
                 * Handler for mouse events
                 */
-               onMouse: function (event, target) {
-                               // In WebKit, select the image when it is clicked
-                       if (UserAgent.isWebKit && /^(img)$/i.test(target.nodeName) && event.browserEvent.type == 'click') {
-                               this.getEditor().getSelection().selectNode(target);
+               onMouse: function (event) {
+                       // In WebKit, select the image when it is clicked
+                       if (UserAgent.isWebKit && /^(img)$/i.test(event.target.nodeName) && event.type === 'click') {
+                               this.getEditor().getSelection().selectNode(event.target);
                        }
-                       this.getToolbar().updateLater.delay(100);
+                       this.getToolbar().updateLater(100);
                        return true;
                },
-               /*
+
+               /**
                 * Handler for paste operations in Gecko
                 */
                onPaste: function (event) {
-                               // Make src and href urls absolute
+                       // Make src and href urls absolute
                        if (UserAgent.isGecko) {
-                               Dom.makeUrlsAbsolute.defer(50, this, [this.getEditor().document.body, this.config.baseURL, this.htmlRenderer]);
+                               var self = this;
+                               window.setTimeout(function () {
+                                       Dom.makeUrlsAbsolute(self.getEditor().document.body, self.config.baseURL, self.htmlRenderer);   
+                               }, 50);
                        }
+                       return true;
                },
-               /*
+
+               /**
                 * Handler for drag and drop operations
                 */
-               onDrop: function (event, target) {
-                               // Clean up span elements added by WebKit
+               onDrop: function (event) {
+                       var self = this;
+                       // Clean up span elements added by WebKit
                        if (UserAgent.isWebKit) {
-                               this.getEditor().getDomNode().cleanAppleStyleSpans.defer(50, this.getEditor(), [this.getEditor().document.body]);
+                               window.setTimeout(function () {
+                                       self.getEditor().getDomNode().cleanAppleStyleSpans(self.getEditor().document.body);
+                               }, 50);
                        }
-                               // Make src url absolute in Firefox
+                       // Make src url absolute in Firefox
                        if (UserAgent.isGecko) {
-                               Dom.makeUrlsAbsolute.defer(50, this, [target, this.config.baseURL, this.htmlRenderer]);
+                               window.setTimeout(function () {
+                                       Dom.makeUrlsAbsolute(event.target, self.config.baseURL, self.htmlRenderer);
+                               }, 50);
                        }
-                       this.getToolbar().updateLater.delay(100);
+                       this.getToolbar().updateLater(100);
+                       return true;
                },
-               /*
-                * Handler for UP, DOWN, LEFT and RIGHT keys
+
+               /**
+                * Handler for UP, DOWN, LEFT and RIGHT arrow keys
                 */
-               onArrow: function () {
-                       this.getToolbar().updateLater.delay(100);
+               onArrow: function (event) {
+                       this.getToolbar().updateLater(100);
                        return true;
                },
-               /*
+
+               /**
                 * Handler for TAB and SHIFT-TAB keys
                 *
                 * If available, BlockElements plugin will handle the TAB key
                 */
-               onTab: function (key, event) {
+               onTab: function (event) {
                        if (this.inhibitKeyboardInput(event)) {
                                return false;
                        }
@@ -531,49 +584,59 @@ HTMLArea.Iframe = function (UserAgent, Walker, Typo3, Dom) {
                        if (this.config.hotKeyList[keyName] && this.config.hotKeyList[keyName].cmd) {
                                var button = this.getButton(this.config.hotKeyList[keyName].cmd);
                                if (button) {
-                                       event.stopEvent();
-                                       button.fireEvent('HTMLAreaEventHotkey', keyName, event);
+                                       Event.stopEvent(event);
+                                       /**
+                                        * @event HTMLAreaEventHotkey
+                                        * Fires when the button hotkey is pressed
+                                        */
+                                       Event.trigger(button, 'HTMLAreaEventHotkey', [keyName, event]);
                                        return false;
                                }
                        }
-                       event.stopEvent();
-                       return false;
+                       return true;
                },
-               /*
+
+               /**
                 * Handler for BACKSPACE and DELETE keys
                 */
-               onBackSpace: function (key, event) {
+               onBackSpace: function (event) {
                        if (this.inhibitKeyboardInput(event)) {
                                return false;
                        }
                        if ((!UserAgent.isIE && !event.shiftKey) || UserAgent.isIE) {
                                if (this.getEditor().getSelection().handleBackSpace()) {
-                                       event.stopEvent();
+                                       Event.stopEvent(event);
+                                       return false;
                                }
                        }
-                               // Update the toolbar state after some time
-                       this.getToolbar().updateLater.delay(200);
-                       return false;
+                       // Update the toolbar state after some time
+                       this.getToolbar().updateLater(200);
+                       return true;
                },
-               /*
+
+               /**
                 * Handler for ENTER key in non-IE browsers
                 */
-               onEnter: function (key, event) {
+               onEnter: function (event) {
                        if (this.inhibitKeyboardInput(event)) {
                                return false;
                        }
                        this.getEditor().getSelection().detectURL(event);
                        if (this.getEditor().getSelection().checkInsertParagraph()) {
-                               event.stopEvent();
-                       }
+                               Event.stopEvent(event);
                                // Update the toolbar state after some time
-                       this.getToolbar().updateLater.delay(200);
-                       return false;
+                               this.getToolbar().updateLater(200);
+                               return false;
+                       }
+                       // Update the toolbar state after some time
+                       this.getToolbar().updateLater(200);
+                       return true;
                },
-               /*
+
+               /**
                 * Handler for ENTER key in WebKit browsers
                 */
-               onWebKitEnter: function (key, event) {
+               onWebKitEnter: function (event) {
                        if (this.inhibitKeyboardInput(event)) {
                                return false;
                        }
@@ -584,7 +647,7 @@ HTMLArea.Iframe = function (UserAgent, Walker, Typo3, Dom) {
                                        var brNode = editor.document.createElement('br');
                                        editor.getSelection().insertNode(brNode);
                                        brNode.parentNode.normalize();
-                                               // Selection issue when an URL was detected
+                                       // Selection issue when an URL was detected
                                        if (editor._unlinkOnUndo) {
                                                brNode = brNode.parentNode.parentNode.insertBefore(brNode, brNode.parentNode.nextSibling);
                                        }
@@ -593,25 +656,30 @@ HTMLArea.Iframe = function (UserAgent, Walker, Typo3, Dom) {
                                                secondBrNode = brNode.parentNode.appendChild(secondBrNode);
                                        }
                                        editor.getSelection().selectNode(brNode, false);
-                                       event.stopEvent();
+                                       Event.stopEvent(event);
+                                       // Update the toolbar state after some time
+                                       this.getToolbar().updateLater(200);
+                                       return false;
                                }
                        }
-                               // Update the toolbar state after some time
-                       this.getToolbar().updateLater.delay(200);
-                       return false;
+                       // Update the toolbar state after some time
+                       this.getToolbar().updateLater(200);
+                       return true;
                },
-               /*
+
+               /**
                 * Handler for CTRL-SPACE keys
                 */
-               onCtrlSpace: function (key, event) {
+               onCtrlSpace: function (event) {
                        if (this.inhibitKeyboardInput(event)) {
                                return false;
                        }
                        this.getEditor().getSelection().insertHtml('&nbsp;');
-                       event.stopEvent();
+                       Event.stopEvent(event);
                        return false;
                },
-               /*
+
+               /**
                 * Handler for OPTION-SPACE keys on Mac
                 */
                onOptionSpace: function (key, event) {
@@ -619,18 +687,24 @@ HTMLArea.Iframe = function (UserAgent, Walker, Typo3, Dom) {
                                return false;
                        }
                        this.getEditor().getSelection().insertHtml('&nbsp;');
-                       event.stopEvent();
+                       Event.stopEvent(event);
                        return false;
                },
-               /*
+
+               /**
                 * Handler for configured hotkeys
                 */
-               onHotKey: function (key, event) {
+               onHotKey: function (event) {
+                       var key = Event.getKey(event);
                        if (this.inhibitKeyboardInput(event)) {
                                return false;
                        }
                        var hotKey = String.fromCharCode(key).toLowerCase();
-                       this.getButton(this.config.hotKeyList[hotKey].cmd).fireEvent('HTMLAreaEventHotkey', hotKey, event);
+                       /**
+                        * @event HTMLAreaEventHotkey
+                        * Fires when the button hotkey is pressed
+                        */
+                       Event.trigger(this.getButton(this.config.hotKeyList[hotKey].cmd), 'HTMLAreaEventHotkey', [hotKey, event]);
                        return false;
                },
 
@@ -638,30 +712,27 @@ HTMLArea.Iframe = function (UserAgent, Walker, Typo3, Dom) {
                 * Cleanup
                 */
                onBeforeDestroy: function () {
-                       // ExtJS KeyMap object makes IE leak memory
-                       // Nullify EXTJS private handlers
-                       for (var index = this.keyMap.bindings.length; --index >= 0;) {
-                               this.keyMap.bindings[index] = null;
-                       }
-                       this.keyMap.handleKeyDown = null;
-                       for (var index = this.hotKeyMap.bindings.length; --index >= 0;) {
-                               this.hotKeyMap.bindings[index] = null;
-                       }
-                       this.hotKeyMap.handleKeyDown = null;
-                       this.keyMap.disable();
-                       this.hotKeyMap.disable();
+                       // Remove listeners on nested elements
+                       if (this.isNested && UserAgent.isGecko) {
+                               for (var i = this.nestedParentElements.sorted.length; --i >= 0;) {
+                                       var nestedElement = document.getElementById(this.nestedParentElements.sorted[i]);
+                                       Event.off(
+                                               nestedElement,
+                                               'DOMAttrModified'
+                                       );
+                                       Event.off(
+                                               nestedElement.parentNode,
+                                               'DOMAttrModified'
+                                       );
+                               }
+                       }
+                       Event.off(this);
+                       Event.off(this.getEl().dom);
+                       Event.off(this.document.body);
+                       Event.off(this.document.documentElement);
                        // Cleaning references to DOM in order to avoid IE memory leaks
-                       Ext.get(this.document.body).purgeAllListeners();
-                       Ext.get(this.document.body).dom = null;
-                       Ext.get(this.document.documentElement).purgeAllListeners();
-                       Ext.get(this.document.documentElement).dom = null;
                        this.document = null;
                        this.getEditor().document = null;
-                       for (var index = this.nestedParentElements.sorted.length; --index >= 0;) {
-                               var nested = this.nestedParentElements.sorted[index];
-                               Ext.get(nested).purgeAllListeners();
-                               Ext.get(nested).dom = null;
-                       }
                        Ext.destroy(this.autoEl, this.el, this.resizeEl, this.positionEl);
                        return true;
                }
@@ -669,5 +740,5 @@ HTMLArea.Iframe = function (UserAgent, Walker, Typo3, Dom) {
 
        return Iframe;
 
-}(HTMLArea.UserAgent, HTMLArea.DOM.Walker, HTMLArea.util.TYPO3, HTMLArea.DOM);
+}(HTMLArea.UserAgent, HTMLArea.DOM.Walker, HTMLArea.util.TYPO3, HTMLArea.DOM, HTMLArea.Event, HTMLArea.Event.KeyMap);
 Ext.reg('htmlareaiframe', HTMLArea.Iframe);
index e08ab5b..9491212 100644 (file)
@@ -13,7 +13,7 @@
 /**
  * HTMLArea.StatusBar extends Ext.Container
  */
-HTMLArea.StatusBar = function (UserAgent, Dom) {
+HTMLArea.StatusBar = function (UserAgent, Dom, Event) {
 
        var StatusBar = Ext.extend(Ext.Container, {
 
@@ -22,8 +22,6 @@ HTMLArea.StatusBar = function (UserAgent, Dom) {
                 */
                initComponent: function () {
                        StatusBar.superclass.initComponent.call(this);
-                       // Build the deferred word count update task
-                       this.updateWordCountLater = new Ext.util.DelayedTask(this.updateWordCount, this);
                        this.addListener({
                                render: {
                                        fn: this.addComponents,
@@ -46,13 +44,14 @@ HTMLArea.StatusBar = function (UserAgent, Dom) {
                                        single: true
                                }
                        });
+                       var self = this;
                        // Monitor toolbar updates in order to refresh the contents of the statusbar
                        // The toolbar must have been rendered
-                       this.mon(this.ownerCt.toolbar, 'HTMLAreaEventToolbarUpdate', this.onUpdateToolbar, this);
+                       Event.on(this.ownerCt.toolbar, 'HTMLAreaEventToolbarUpdate', function (event, mode, selectionEmpty, ancestors, endPointsInSameBlock) { Event.stopEvent(event); self.onUpdateToolbar(mode, selectionEmpty, ancestors, endPointsInSameBlock); return false; });
                        // Monitor editor changing mode
-                       this.mon(this.getEditor(), 'HTMLAreaEventModeChange', this.onModeChange, this);
+                       Event.on(this.getEditor(), 'HTMLAreaEventModeChange', function (event, mode) { Event.stopEvent(event); self.onModeChange(mode); return false; });
                        // Monitor word count change
-                       this.mon(this.ownerCt.iframe, 'HTMLAreaEventWordCountChange', this.onWordCountChange, this);
+                       Event.on(this.ownerCt.iframe, 'HTMLAreaEventWordCountChange', function (event, delay) { Event.stopEvent(event); self.onWordCountChange(delay); return false; });
                },
 
                /**
@@ -101,8 +100,8 @@ HTMLArea.StatusBar = function (UserAgent, Dom) {
                        var node = this.statusBarTree.firstChild;
                        while (node) {
                                if (/^(a)$/i.test(node.nodeName)) {
+                                       Event.off(node);
                                        var extNode = Ext.get(node);
-                                       extNode.removeAllListeners();
                                        Ext.QuickTips.unregister(extNode);
                                        extNode.dom = null;
                                }
@@ -119,7 +118,9 @@ HTMLArea.StatusBar = function (UserAgent, Dom) {
                noUpdate: false,
 
                /**
-                * Update the status bar
+                * Update the status bar when the toolbar was updated
+                *
+                * @return void
                 */
                onUpdateToolbar: function (mode, selectionEmpty, ancestors, endPointsInSameBlock) {
                        if (mode === 'wysiwyg' && !this.noUpdate) {
@@ -166,10 +167,11 @@ HTMLArea.StatusBar = function (UserAgent, Dom) {
                                        element.innerHTML = text;
                                        element = path.parentNode.insertBefore(element, path.nextSibling);
                                        element.ancestor = ancestor;
-                                       Ext.get(element).on('click', this.onClick, this);
-                                       Ext.get(element).on('mousedown', this.onClick, this);
+                                       var self = this;
+                                       Event.on(element, 'click', function (event) { return self.onClick(event); });
+                                       Event.on(element, 'mousedown', function (event) { return self.onClick(event); });
                                        if (!UserAgent.isOpera) {
-                                               Ext.get(element).on('contextmenu', this.onContextMenu, this);
+                                               Event.on(element, 'contextmenu', function (event) { return self.onContextMenu(event); });
                                        }
                                        if (index) {
                                                var separator = document.createElement('span');
@@ -184,9 +186,22 @@ HTMLArea.StatusBar = function (UserAgent, Dom) {
 
                /**
                 * Handler when the word count may have changed
+                *
+                * @param integer delay: the delay before updating the word count
+                * @return void
                 */
-               onWordCountChange: function(delay) {
-                       this.updateWordCountLater.delay(delay ? delay : 0);
+               onWordCountChange: function (delay) {
+                       if (this.updateWordCountLater) {
+                               window.clearTimeout(this.updateWordCountLater);
+                       }
+                       if (delay) {
+                               var self = this;
+                               this.updateWordCountLater = window.setTimeout(function () {
+                                       self.updateWordCount();
+                               }, delay);
+                       } else {
+                               this.updateWordCount();
+                       }
                },
 
                /**
@@ -215,7 +230,8 @@ HTMLArea.StatusBar = function (UserAgent, Dom) {
                /**
                 * Adapt status bar to current editor mode
                 *
-                * @param       string  mode: the mode to which the editor got switched to
+                * @param string mode: the mode to which the editor got switched to
+                * @return void
                 */
                onModeChange: function (mode) {
                        switch (mode) {
@@ -281,18 +297,18 @@ HTMLArea.StatusBar = function (UserAgent, Dom) {
                /**
                 * Click handler
                 */
-               onClick: function (event, element) {
-                       this.selectElement(element);
-                       event.stopEvent();
+               onClick: function (event) {
+                       this.selectElement(event.target);
+                       Event.stopEvent(event);
                        return false;
                },
 
                /**
                 * ContextMenu handler
                 */
-               onContextMenu: function (event, target) {
-                       this.selectElement(target);
-                       return this.getEditor().getPlugin('ContextMenu') ? this.getEditor().getPlugin('ContextMenu').show(event, target.ancestor) : false;
+               onContextMenu: function (event) {
+                       this.selectElement(event.target);
+                       return this.getEditor().getPlugin('ContextMenu') ? this.getEditor().getPlugin('ContextMenu').show(event, event.target.ancestor) : false;
                },
 
                /**
@@ -309,5 +325,5 @@ HTMLArea.StatusBar = function (UserAgent, Dom) {
 
        return StatusBar;
 
-}(HTMLArea.UserAgent, HTMLArea.DOM);
+}(HTMLArea.UserAgent, HTMLArea.DOM, HTMLArea.Event);
 Ext.reg('htmlareastatusbar', HTMLArea.StatusBar);
index b65ab98..e561468 100644 (file)
@@ -13,7 +13,7 @@
 /**
  * HTMLArea.Toolbar extends Ext.Container
  */
-HTMLArea.Toolbar = function () {
+HTMLArea.Toolbar = function (Event) {
 
        Toolbar = Ext.extend(Ext.Container, {
 
@@ -22,16 +22,7 @@ HTMLArea.Toolbar = function () {
                 */
                initComponent: function () {
                        Toolbar.superclass.initComponent.call(this);
-                       this.addEvents(
-                               /*
-                                * @event HTMLAreaEventToolbarUpdate
-                                * Fires when the toolbar is updated
-                                */
-                               'HTMLAreaEventToolbarUpdate'
-                       );
-                               // Build the deferred toolbar update task
-                       this.updateLater = new Ext.util.DelayedTask(this.update, this);
-                               // Add the toolbar items
+                       // Add the toolbar items
                        this.addItems();
                        this.addListener({
                                afterrender: {
@@ -40,7 +31,8 @@ HTMLArea.Toolbar = function () {
                                }
                        });
                },
-               /*
+
+               /**
                 * Initialize listeners
                 */
                initEventListeners: function () {
@@ -50,19 +42,23 @@ HTMLArea.Toolbar = function () {
                                        single: true
                                }
                        });
-                               // Monitor editor becoming ready
-                       this.mon(this.getEditor(), 'HTMLAreaEventEditorReady', this.update, this, {single: true});
+                       // Monitor editor becoming ready
+                       var self = this;
+                       Event.one(this.getEditor(), 'HtmlAreaEventEditorReady', function (event) { Event.stopEvent(event); self.update(); return false; });
                },
-               /*
+
+               /**
                 * editorId should be set in config
                 */
                editorId: null,
-               /*
+
+               /**
                 * Get a reference to the editor
                 */
                getEditor: function() {
                        return RTEarea[this.editorId].editor;
                },
+
                /**
                 * Create the toolbar items based on editor toolbar configuration
                 */
@@ -120,13 +116,32 @@ HTMLArea.Toolbar = function () {
                                cls: 'x-form-clear-left'
                        });
                },
-               /*
+
+               /**
                 * Retrieve a toolbar item by itemId
                 */
                getButton: function (buttonId) {
                        return this.find('itemId', buttonId)[0];
                },
-               /*
+
+               /**
+                * Update the toolbar after some delay
+                */
+               updateLater: function (delay) {
+                       if (this.updateToolbarLater) {
+                               window.clearTimeout(this.updateToolbarLater);
+                       }
+                       if (delay) {
+                               var self = this;
+                               this.updateToolbarLater = window.setTimeout(function () {
+                                       self.update();
+                               }, delay);
+                       } else {
+                               this.update();
+                       }
+               },
+
+               /**
                 * Update the state of the toolbar
                 */
                update: function() {
@@ -141,12 +156,18 @@ HTMLArea.Toolbar = function () {
                                ancestors = selection.getAllAncestors();
                                endPointsInSameBlock = selection.endPointsInSameBlock();
                        }
-                       this.fireEvent('HTMLAreaEventToolbarUpdate', mode, selectionEmpty, ancestors, endPointsInSameBlock);
+                       /**
+                        * @event HTMLAreaEventToolbarUpdate
+                        * Fires when the toolbar is updated
+                        */
+                       Event.trigger(this, 'HTMLAreaEventToolbarUpdate', [mode, selectionEmpty, ancestors, endPointsInSameBlock]);
                },
-               /*
+
+               /**
                 * Cleanup
                 */
                onBeforeDestroy: function () {
+                       Event.off(this);
                        this.removeAll(true);
                        return true;
                }
@@ -154,5 +175,5 @@ HTMLArea.Toolbar = function () {
 
        return Toolbar;
 
-}();
+}(HTMLArea.Event);
 Ext.reg('htmlareatoolbar', HTMLArea.Toolbar);
diff --git a/typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/Event/Event.js b/typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/Event/Event.js
new file mode 100644 (file)
index 0000000..611a3c6
--- /dev/null
@@ -0,0 +1,199 @@
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+/*****************************************************************
+ * HTMLArea.Event: Utility functions for dealing with events     *
+ *****************************************************************/
+HTMLArea.Event = function ($, UserAgent, Util) {
+
+       var Event = {
+
+               NAMESPACE: '.htmlarea',
+
+               // Key codes for key events
+               BACKSPACE: 8,
+               TAB: 9,
+               ENTER: 13,
+               ESC: 27,
+               SPACE: 32,
+               LEFT: 37,
+               UP: 38,
+               RIGHT: 39,
+               DOWN: 40,
+               DELETE: 46,
+               F11: 122,
+               NON_BREAKING_SPACE: 160,
+
+               // DOM Level 3 defines values for event.key
+               domLevel3Keys: {
+                       'Backspace': 8,
+                       'Tab': 9,
+                       'Enter': 13,
+                       'Esc': 27,
+                       'Escape': 27,
+                       'Spacebar': 32,
+                       ' ': 32,
+                       'Left': 37,
+                       'ArrowLeft': 37,
+                       'Up': 38,
+                       'ArrowUp': 38,
+                       'Right': 39,
+                       'ArrowRight': 39,
+                       'Down': 40,
+                       'ArrowDown': 40,
+                       'Del': 46,
+                       'Delete': 46,
+                       '0': 48,
+                       '1': 49,
+                       '2': 50,
+                       '3': 51,
+                       '4': 52,
+                       '5': 53,
+                       '6': 54,
+                       '7': 55,
+                       '8': 56,
+                       '9': 57,
+                       'F11': 122
+               },
+
+               // Safari keypress events for special keys return bad keycodes
+               safariKeys: {
+                   3 : 13, // enter
+                   63234 : 37, // left
+                   63235 : 39, // right
+                   63232 : 38, // up
+                   63233 : 40, // down
+                   63276 : 33, // page up
+                   63277 : 34, // page down
+                   63272 : 46, // delete
+                   63273 : 36, // home
+                   63275 : 35  // end
+               },
+
+               /**
+                * Attach an event handler on an element
+                *
+                * @param object|string element: the element to which the event handler is attached or a jquery selector
+                * @param string eventName: the name of the event
+                * @param function handler: the event handler
+                * @param object options: options for handling the event
+                * @return void
+                */
+               on: function (element, eventName, handler, options) {
+                       var data = {};
+                       if (typeof options === 'object') {
+                               Util.apply(data, options);
+                       }
+                       if (data.delegate) {
+                               $(element).on(eventName + Event.NAMESPACE, data.delegate, data, handler);
+                       } else {
+                               $(element).on(eventName + Event.NAMESPACE, data, handler);
+                       }
+               },
+
+               /**
+                * Attach an event handler on an element. The handler is executed at most once.
+                *
+                * @param object|string element: the element to which the event handler is attached or a jquery selector
+                * @param string eventName: the name of the event
+                * @param function handler: the event handler
+                * @param object options: options for handling the event
+                * @return void
+                */
+               one: function (element, eventName, handler, options) {
+                       var data = {};
+                       if (typeof options === 'object') {
+                               Util.apply(data, options);
+                       }
+                       $(element).one(eventName + Event.NAMESPACE, data, handler);
+               },
+
+               /**
+                * Attach an event handler on an element
+                *
+                * @param object|string element: the element to which the event handler is attached or a jquery selector
+                * @param string eventName: the name of the event
+                * @param function handler: the event handler
+                * @return void
+                */
+               off: function (element, eventName, handler) {
+                       if (typeof eventName === 'undefined' && typeof handler === 'undefined') {
+                               $(element).off(Event.NAMESPACE);
+                       } else if (typeof handler === 'undefined') {
+                               $(element).off(eventName + Event.NAMESPACE);
+                       } else {
+                               $(element).off(eventName + Event.NAMESPACE, handler);
+                       }
+               },
+
+               /**
+                * Attach an event handler on an element
+                *
+                * @param object event: the jQuery event object
+                * @return void
+                */
+               stopEvent: function (event) {
+                       event.preventDefault();
+                       event.stopPropagation();
+               },
+
+               /**
+                * Trigger an event
+                *
+                * @param object|string element: the element to which the event handler is attached or a jquery selector
+                * @param string eventName: the name of the event
+                * @param array extraParameters: extra parameters to be passed to the event handler
+                * @return void
+                */
+               trigger: function(element, eventName, extraParameters) {
+                       if (typeof extraParameters === 'undefined') {
+                               $(element).trigger(eventName);
+                       } else {
+                               $(element).trigger(eventName, extraParameters);
+                       }
+               },
+
+               /**
+                * Returns a normalized key for the event.
+                *
+                * @param object event: the jQuery event object
+                * @return integer the normalized key
+                */
+               getKey: function (event) {
+                       return Event.normalizeKey(event.originalEvent.key ? event.originalEvent.key : (event.originalEvent.charCode ? event.originalEvent.charCode : (event.originalEvent.keyCode ? event.originalEvent.keyCode : event.originalEvent.which)));
+                       return Event.normalizeKey((event.originalEvent.charCode ? event.originalEvent.charCode : (event.originalEvent.keyCode ? event.originalEvent.keyCode : event.originalEvent.which)));
+               },
+
+               /**
+                * Returns a normalized key
+                *
+                * @param integer key: the key
+                * @return integer the normalized key
+                */
+               normalizeKey: function(key){
+                   return UserAgent.isSafari ? (Event.safariKeys[key] || key) : (Event.domLevel3Keys[key] || key);
+               },
+
+               /**
+                * Get the original browser event
+                *
+                * @param object event: the jQuery  event object
+                * @return object the browser event
+                */
+               getBrowserEvent: function (event) {
+                       return event.originalEvent;
+               }
+       };
+
+       return Event;
+
+}(HTMLArea.jQuery, HTMLArea.UserAgent, HTMLArea.util);
diff --git a/typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/Event/KeyMap.js b/typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/Event/KeyMap.js
new file mode 100644 (file)
index 0000000..1bb8a63
--- /dev/null
@@ -0,0 +1,93 @@
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+/********************************************************************
+ * HTMLArea.KeyMap: Utility functions for dealing with key events   *
+ ********************************************************************/
+HTMLArea.Event.KeyMap = function ($, Event) {
+
+       /**
+        * Constructor method
+        *
+        * @param object element: the element to which the key map is attached
+        * @param string eventName: the event name
+        * @return void
+        */
+       var KeyMap = function (element, eventName) {
+
+               // Key bindings
+               this.keyBindings = {};
+
+               // Attach the key map event handler to the element
+               var self = this;
+               Event.on(element, eventName, function (event) { return self.handler(event); });
+       };      
+
+       /**
+        * Add an event handler to the keymap for a given combination of keys
+        *
+        * @param object options: options for the binding; possible keys:
+        *      key: a key or an array of keys
+        *      ctrl: boolean,
+        *      shift: boolean,
+        *      alt: boolean,
+        *      handler: an event handler
+        * @return void
+        */
+       KeyMap.prototype.addBinding = function (options) {
+               var key = options.key,
+                       normalizedKey;
+               if (typeof key === 'string' || typeof key === 'number') {
+                       key = [key];
+               }
+               for (var i = 0, n = key.length; i < n; i++) {
+                       // Normalizing hot keys
+                       normalizedKey = key[i];
+                       if (typeof normalizedKey === 'string' && normalizedKey.length === 1) {
+                               normalizedKey = normalizedKey.toUpperCase().charCodeAt(0);
+                       }
+                       if (typeof this.keyBindings[normalizedKey] === 'undefined') {
+                               this.keyBindings[normalizedKey] = [];
+                       }
+                       this.keyBindings[normalizedKey].push({
+                               ctrl: options.ctrl,
+                               shift: options.shift,
+                               alt: options.alt,
+                               handler: options.handler
+                       });
+               }
+       };
+
+       /**
+        * Key map handler
+        * @return boolean false if the event was handled
+        */
+       KeyMap.prototype.handler = function (event) {
+               var key = Event.getKey(event);
+               var keyBindings = this.keyBindings[key];
+               if (typeof keyBindings !== 'undefined') {
+                       for (var i = 0, n = keyBindings.length; i < n; i++) {
+                               var keyBinding = keyBindings[i];
+                               if ((typeof keyBinding.alt === 'undefined' || event.altKey == keyBinding.alt)
+                                       && (typeof keyBinding.shift === 'undefined' || event.shiftKey == keyBinding.shift)
+                                       && (typeof keyBinding.ctrl === 'undefined' || event.ctrlKey == keyBinding.ctrl || event.metaKey == keyBinding.ctrl)
+                               ) {
+                                       return keyBinding.handler(event);
+                               }
+                       }
+               }
+               return true;
+       };
+
+       return KeyMap;
+
+}(HTMLArea.jQuery, HTMLArea.Event);
index 711a6e8..a941d9a 100644 (file)
-/*
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+/**
  * Ext.ux.HTMLAreaButton extends Ext.Button
  */
-Ext.ux.HTMLAreaButton = Ext.extend(Ext.Button, {
-       /*
-        * Component initialization
-        */
-       initComponent: function () {
-               Ext.ux.HTMLAreaButton.superclass.initComponent.call(this);
-               this.addEvents(
-                       /*
-                        * @event HTMLAreaEventHotkey
-                        * Fires when the button hotkey is pressed
-                        */
-                       'HTMLAreaEventHotkey',
-                       /*
-                        * @event HTMLAreaEventContextMenu
-                        * Fires when the button is triggered from the context menu
-                        */
-                       'HTMLAreaEventContextMenu'
-               );
-               this.addListener({
-                       afterrender: {
-                               fn: this.initEventListeners,
-                               single: true
-                       }
-               });
-       },
-       /*
-        * Initialize listeners
-        */
-       initEventListeners: function () {
-               this.addListener({
-                       HTMLAreaEventHotkey: {
-                               fn: this.onHotKey
-                       },
-                       HTMLAreaEventContextMenu: {
-                               fn: this.onButtonClick
-                       }
-               });
-               this.setHandler(this.onButtonClick, this);
+Ext.ux.HTMLAreaButton = function (UserAgent, Event) {
+
+       var Button = Ext.extend(Ext.Button, {
+
+               /**
+                * Component initialization
+                */
+               initComponent: function () {
+                       Button.superclass.initComponent.call(this);
+                       this.addListener({
+                               afterrender: {
+                                       fn: this.initEventListeners,
+                                       single: true
+                               }
+                       });
+               },
+
+               /**
+                * Initialize listeners
+                */
+               initEventListeners: function () {
+                       var self = this;
+                       Event.on(this, 'HTMLAreaEventHotkey', function (event, key, keyEvent) { return self.onHotKey(key, keyEvent); });
+                       Event.on(this, 'HTMLAreaEventContextMenu', function (event, button) { return self.onButtonClick(button, event); });
+                       this.setHandler(this.onButtonClick, this);
                        // Monitor toolbar updates in order to refresh the state of the button
-               this.mon(this.getToolbar(), 'HTMLAreaEventToolbarUpdate', this.onUpdateToolbar, this);
-       },
-       /*
-        * Get a reference to the editor
-        */
-       getEditor: function() {
-               return RTEarea[this.ownerCt.editorId].editor;
-       },
-       /*
-        * Get a reference to the toolbar
-        */
-       getToolbar: function() {
-               return this.ownerCt;
-       },
-       /*
-        * Add properties and function to set button active or not depending on current selection
-        */
-       inactive: true,
-       activeClass: 'buttonActive',
-       setInactive: function (inactive) {
-               this.inactive = inactive;
-               return inactive ? this.removeClass(this.activeClass) : this.addClass(this.activeClass);
-       },
-       /*
-        * Determine if the button should be enabled based on the current selection and context configuration property
-        */
-       isInContext: function (mode, selectionEmpty, ancestors) {
-               var editor = this.getEditor();
-               var inContext = true;
-               if (mode === 'wysiwyg' && this.context) {
-                       var attributes = [],
-                               contexts = [];
-                       if (/(.*)\[(.*?)\]/.test(this.context)) {
-                               contexts = RegExp.$1.split(',');
-                               attributes = RegExp.$2.split(',');
-                       } else {
-                               contexts = this.context.split(',');
-                       }
-                       contexts = new RegExp( '^(' + contexts.join('|') + ')$', 'i');
-                       var matchAny = contexts.test('*');
-                       var i, j, n;
-                       for (i = 0, n = ancestors.length; i < n; i++) {
-                               var ancestor = ancestors[i];
-                               inContext = matchAny || contexts.test(ancestor.nodeName);
-                               if (inContext) {
-                                       for (j = attributes.length; --j >= 0;) {
-                                               inContext = eval("ancestor." + attributes[j]);
-                                               if (!inContext) {
-                                                       break;
+                       Event.on(this.getToolbar(), 'HTMLAreaEventToolbarUpdate', function (event, mode, selectionEmpty, ancestors, endPointsInSameBlock) { Event.stopEvent(event); self.onUpdateToolbar(mode, selectionEmpty, ancestors, endPointsInSameBlock); return false; });
+               },
+
+               /**
+                * Get a reference to the editor
+                */
+               getEditor: function() {
+                       return RTEarea[this.ownerCt.editorId].editor;
+               },
+
+               /**
+                * Get a reference to the toolbar
+                */
+               getToolbar: function() {
+                       return this.ownerCt;
+               },
+
+               /**
+                * Add properties and function to set button active or not depending on current selection
+                */
+               inactive: true,
+               activeClass: 'buttonActive',
+               setInactive: function (inactive) {
+                       this.inactive = inactive;
+                       return inactive ? this.removeClass(this.activeClass) : this.addClass(this.activeClass);
+               },
+
+               /**
+                * Determine if the button should be enabled based on the current selection and context configuration property
+                */
+               isInContext: function (mode, selectionEmpty, ancestors) {
+                       var editor = this.getEditor();
+                       var inContext = true;
+                       if (mode === 'wysiwyg' && this.context) {
+                               var attributes = [],
+                                       contexts = [];
+                               if (/(.*)\[(.*?)\]/.test(this.context)) {
+                                       contexts = RegExp.$1.split(',');
+                                       attributes = RegExp.$2.split(',');
+                               } else {
+                                       contexts = this.context.split(',');
+                               }
+                               contexts = new RegExp( '^(' + contexts.join('|') + ')$', 'i');
+                               var matchAny = contexts.test('*');
+                               var i, j, n;
+                               for (i = 0, n = ancestors.length; i < n; i++) {
+                                       var ancestor = ancestors[i];
+                                       inContext = matchAny || contexts.test(ancestor.nodeName);
+                                       if (inContext) {
+                                               for (j = attributes.length; --j >= 0;) {
+                                                       inContext = eval("ancestor." + attributes[j]);
+                                                       if (!inContext) {
+                                                               break;
+                                                       }
                                                }
                                        }
-                               }
-                               if (inContext) {
-                                       break;
+                                       if (inContext) {
+                                               break;
+                                       }
                                }
                        }
-               }
-               return inContext && (!this.selection || !selectionEmpty);
-       },
-       /*
-        * Handler invoked when the button is clicked
-        */
-       onButtonClick: function (button, event, key) {
-               if (!this.disabled) {
-                       if (!this.plugins[this.action](this.getEditor(), key || this.itemId) && event) {
-                               event.stopEvent();
-                       }
-                       if (HTMLArea.UserAgent.isOpera) {
-                               this.getEditor().focus();
-                       }
-                       if (this.dialog) {
-                               this.setDisabled(true);
-                       } else {
-                               this.getToolbar().update();
+                       return inContext && (!this.selection || !selectionEmpty);
+               },
+
+               /**
+                * Handler invoked when the button is clicked
+                */
+               onButtonClick: function (button, event, key) {
+                       if (!this.disabled) {
+                               if (!this.plugins[this.action](this.getEditor(), key || this.itemId) && event) {
+                                       Event.stopEvent(event);
+                               }
+                               if (UserAgent.isOpera) {
+                                       this.getEditor().focus();
+                               }
+                               if (this.dialog) {
+                                       this.setDisabled(true);
+                               } else {
+                                       this.getToolbar().update();
+                               }
                        }
-               }
-               return false;
-       },
-       /*
-        * Handler invoked when the hotkey configured for this button is pressed
-        */
-       onHotKey: function (key, event) {
-               return this.onButtonClick(this, event, key);
-       },
-       /*
-        * Handler invoked when the toolbar is updated
-        */
-       onUpdateToolbar: function (mode, selectionEmpty, ancestors, endPointsInSameBlock) {
-               this.setDisabled(mode === 'textmode' && !this.textMode);
-               if (!this.disabled) {
-                       if (!this.noAutoUpdate) {
-                               this.setDisabled(!this.isInContext(mode, selectionEmpty, ancestors));
+                       return false;
+               },
+
+               /**
+                * Handler invoked when the hotkey configured for this button is pressed
+                */
+               onHotKey: function (key, event) {
+                       return this.onButtonClick(this, event, key);
+               },
+
+               /**
+                * Handler invoked when the toolbar is updated
+                */
+               onUpdateToolbar: function (mode, selectionEmpty, ancestors, endPointsInSameBlock) {
+                       this.setDisabled(mode === 'textmode' && !this.textMode);
+                       if (!this.disabled) {
+                               if (!this.noAutoUpdate) {
+                                       this.setDisabled(!this.isInContext(mode, selectionEmpty, ancestors));
+                               }
+                               this.plugins['onUpdateToolbar'](this, mode, selectionEmpty, ancestors, endPointsInSameBlock);
                        }
-                       this.plugins['onUpdateToolbar'](this, mode, selectionEmpty, ancestors, endPointsInSameBlock);
                }
-       }
-});
+       });
+
+       return Button;
+
+}(HTMLArea.UserAgent, HTMLArea.Event);
 Ext.reg('htmlareabutton', Ext.ux.HTMLAreaButton);
index 54d60d4..72c92aa 100644 (file)
@@ -1,46 +1,70 @@
-/*
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+/**
  * Ext.ux.Toolbar.HTMLAreaToolbarText extends Ext.Toolbar.TextItem
  */
-Ext.ux.Toolbar.HTMLAreaToolbarText = Ext.extend(Ext.Toolbar.TextItem, {
-       /*
-        * Constructor
-        */
-       initComponent: function () {
-               Ext.ux.Toolbar.HTMLAreaToolbarText.superclass.initComponent.call(this);
-               this.addListener({
-                       afterrender: {
-                               fn: this.initEventListeners,
-                               single: true
-                       }
-               });
-       },
-       /*
-        * Initialize listeners
-        */
-       initEventListeners: function () {
+Ext.ux.Toolbar.HTMLAreaToolbarText = function (Event) {
+
+       var ToolbarText = Ext.extend(Ext.Toolbar.TextItem, {
+
+               /**
+                * Constructor
+                */
+               initComponent: function () {
+                       Ext.ux.Toolbar.HTMLAreaToolbarText.superclass.initComponent.call(this);
+                       this.addListener({
+                               afterrender: {
+                                       fn: this.initEventListeners,
+                                       single: true
+                               }
+                       });
+               },
+
+               /**
+                * Initialize listeners
+                */
+               initEventListeners: function () {
                        // Monitor toolbar updates in order to refresh the state of the button
-               this.mon(this.getToolbar(), 'HTMLAreaEventToolbarUpdate', this.onUpdateToolbar, this);
-       },
-       /*
-        * Get a reference to the editor
-        */
-       getEditor: function() {
-               return RTEarea[this.ownerCt.editorId].editor;
-       },
-       /*
-        * Get a reference to the toolbar
-        */
-       getToolbar: function() {
-               return this.ownerCt;
-       },
-       /*
-        * Handler invoked when the toolbar is updated
-        */
-       onUpdateToolbar: function (mode, selectionEmpty, ancestors, endPointsInSameBlock) {
-               this.setDisabled(mode === 'textmode' && !this.textMode);
-               if (!this.disabled) {
-                       this.plugins['onUpdateToolbar'](this, mode, selectionEmpty, ancestors, endPointsInSameBlock);
+                       var self = this;
+                       Event.on(this.getToolbar(), 'HTMLAreaEventToolbarUpdate', function (event, mode, selectionEmpty, ancestors, endPointsInSameBlock) { Event.stopEvent(event); self.onUpdateToolbar(mode, selectionEmpty, ancestors, endPointsInSameBlock); return false; });
+               },
+
+               /**
+                * Get a reference to the editor
+                */
+               getEditor: function() {
+                       return RTEarea[this.ownerCt.editorId].editor;
+               },
+
+               /**
+                * Get a reference to the toolbar
+                */
+               getToolbar: function() {
+                       return this.ownerCt;
+               },
+
+               /**
+                * Handler invoked when the toolbar is updated
+                */
+               onUpdateToolbar: function (mode, selectionEmpty, ancestors, endPointsInSameBlock) {
+                       this.setDisabled(mode === 'textmode' && !this.textMode);
+                       if (!this.disabled) {
+                               this.plugins['onUpdateToolbar'](this, mode, selectionEmpty, ancestors, endPointsInSameBlock);
+                       }
                }
-       }
-});
+       });
+
+       return ToolbarText;
+
+}(HTMLArea.Event);
 Ext.reg('htmlareatoolbartext', Ext.ux.Toolbar.HTMLAreaToolbarText);
index 620ba88..e4e8be5 100644 (file)
-/*
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+/**
  * Ext.ux.form.HTMLAreaCombo extends Ext.form.ComboBox
  */
-Ext.ux.form.HTMLAreaCombo = Ext.extend(Ext.form.ComboBox, {
-       /*
-        * Constructor
-        */
-       initComponent: function () {
-               Ext.ux.form.HTMLAreaCombo.superclass.initComponent.call(this);
-               this.addEvents(
-                       /*
-                        * @event HTMLAreaEventHotkey
-                        * Fires when a hotkey configured for the combo is pressed
-                        */
-                       'HTMLAreaEventHotkey'
-               );
-               this.addListener({
-                       afterrender: {
-                               fn: this.initEventListeners,
-                               single: true
-                       }
-               });
-       },
-       /*
-        * Initialize listeners
-        */
-       initEventListeners: function () {
-               this.addListener({
-                       select: {
-                               fn: this.onComboSelect
-                       },
-                       specialkey: {
-                               fn: this.onSpecialKey
-                       },
-                       HTMLAreaEventHotkey: {
-                               fn: this.onHotKey
-                       },
-                       beforedestroy: {
-                               fn: this.onBeforeDestroy,
-                               single: true
-                       }
-               });
+Ext.ux.form.HTMLAreaCombo = function (UserAgent, Event) {
+
+       var Combo = Ext.extend(Ext.form.ComboBox, {
+
+               /**
+                * Constructor
+                */
+               initComponent: function () {
+                       Ext.ux.form.HTMLAreaCombo.superclass.initComponent.call(this);
+                       this.addListener({
+                               afterrender: {
+                                       fn: this.initEventListeners,
+                                       single: true
+                               }
+                       });
+               },
+
+               /**
+                * Initialize listeners
+                */
+               initEventListeners: function () {
+                       var self = this;
+                       Event.on(this, 'HTMLAreaEventHotkey', function (event, key, event) { return self.onHotKey(key); });
+                       this.addListener({
+                               select: {
+                                       fn: this.onComboSelect
+                               },
+                               specialkey: {
+                                       fn: this.onSpecialKey
+                               },
+                               beforedestroy: {
+                                       fn: this.onBeforeDestroy,
+                                       single: true
+                               }
+                       });
                        // Monitor toolbar updates in order to refresh the state of the combo
-               this.mon(this.getToolbar(), 'HTMLAreaEventToolbarUpdate', this.onUpdateToolbar, this);
+                       Event.on(this.getToolbar(), 'HTMLAreaEventToolbarUpdate', function (event, mode, selectionEmpty, ancestors, endPointsInSameBlock) { Event.stopEvent(event); self.onUpdateToolbar(mode, selectionEmpty, ancestors, endPointsInSameBlock); return false; });
                        // Monitor framework becoming ready
-               this.mon(this.getToolbar().ownerCt, 'HTMLAreaEventFrameworkReady', this.onFrameworkReady, this);
-       },
-       /*
-        * Get a reference to the editor
-        */
-       getEditor: function() {
-               return RTEarea[this.ownerCt.editorId].editor;
-       },
-       /*
-        * Get a reference to the toolbar
-        */
-       getToolbar: function() {
-               return this.ownerCt;
-       },
-       /*
-        * Handler invoked when an item is selected in the dropdown list
-        */
-       onComboSelect: function (combo, record, index) {
-               if (!combo.disabled) {
-                       var editor = this.getEditor();
-                               // In IE, reclaim lost focus on the editor iframe and restore the bookmarked selection
-                       if (HTMLArea.UserAgent.isIE) {
-                               if (typeof this.savedRange === 'object' && this.savedRange !== null) {
-                                       editor.getSelection().selectRange(this.savedRange);
-                                       this.savedRange = null;
+                       Event.one(this.getToolbar().ownerCt, 'HTMLAreaEventFrameworkReady', function (event) { Event.stopEvent(event); self.onFrameworkReady(); return false; });
+               },
+
+               /**
+                * Get a reference to the editor
+                */
+               getEditor: function() {
+                       return RTEarea[this.ownerCt.editorId].editor;
+               },
+
+               /**
+                * Get a reference to the toolbar
+                */
+               getToolbar: function() {
+                       return this.ownerCt;
+               },
+
+               /**
+                * Handler invoked when an item is selected in the dropdown list
+                */
+               onComboSelect: function (combo, record, index) {
+                       if (!combo.disabled) {
+                               var editor = this.getEditor();
+                                       // In IE, reclaim lost focus on the editor iframe and restore the bookmarked selection
+                               if (UserAgent.isIE) {
+                                       if (typeof this.savedRange === 'object' && this.savedRange !== null) {
+                                               editor.getSelection().selectRange(this.savedRange);
+                                               this.savedRange = null;
+                                       }
+                               }
+                                       // Invoke the plugin onChange handler
+                               this.plugins[this.action](editor, combo, record, index);
+                                       // In IE, bookmark the updated selection as the editor will be loosing focus
+                               if (UserAgent.isIE) {
+                                       this.savedRange = editor.getSelection().createRange();
+                                       this.triggered = true;
                                }
+                               if (UserAgent.isOpera) {
+                                       editor.focus();
+                               }
+                               this.getToolbar().update();
                        }
-                               // Invoke the plugin onChange handler
-                       this.plugins[this.action](editor, combo, record, index);
-                               // In IE, bookmark the updated selection as the editor will be loosing focus
-                       if (HTMLArea.UserAgent.isIE) {
-                               this.savedRange = editor.getSelection().createRange();
+                       return false;
+               },
+
+               /**
+                * Handler invoked when the trigger element is clicked
+                * In IE, need to reclaim lost focus for the editor in order to restore the selection
+                */
+               onTriggerClick: function () {
+                       Ext.ux.form.HTMLAreaCombo.superclass.onTriggerClick.call(this);
+                       // In IE, avoid focus being stolen and selection being lost
+                       if (UserAgent.isIE) {
                                this.triggered = true;
+                               this.getEditor().focus();
                        }
-                       if (HTMLArea.UserAgent.isOpera) {
-                               editor.focus();
-                       }
-                       this.getToolbar().update();
-               }
-               return false;
-       },
-       /*
-        * Handler invoked when the trigger element is clicked
-        * In IE, need to reclaim lost focus for the editor in order to restore the selection
-        */
-       onTriggerClick: function () {
-               Ext.ux.form.HTMLAreaCombo.superclass.onTriggerClick.call(this);
-                       // In IE, avoid focus being stolen and selection being lost
-               if (HTMLArea.UserAgent.isIE) {
-                       this.triggered = true;
-                       this.getEditor().focus();
-               }
-       },
-       /*
-        * Handler invoked when the list of options is clicked in
-        */
-       onViewClick: function (doFocus) {
+               },
+
+               /**
+                * Handler invoked when the list of options is clicked in
+                */
+               onViewClick: function (doFocus) {
                        // Avoid stealing focus from the editor
-               Ext.ux.form.HTMLAreaCombo.superclass.onViewClick.call(this, false);
-       },
-       /*
-        * Handler invoked in IE when the mouse moves out of the editor iframe
-        */
-       saveSelection: function (event) {
-               var editor = this.getEditor();
-               if (editor.document.hasFocus()) {
-                       this.savedRange = editor.getSelection().createRange();
-               }
-       },
-       /*
-        * Handler invoked in IE when the editor gets the focus back
-        */
-       restoreSelection: function (event) {
-               if (typeof this.savedRange === 'object' && this.savedRange !== null && this.triggered) {
-                       this.getEditor().getSelection().selectRange(this.savedRange);
-                       this.triggered = false;
-               }
-       },
-       /*
-        * Handler invoked when the enter key is pressed while the combo has focus
-        */
-       onSpecialKey: function (combo, event) {
-               if (event.getKey() == event.ENTER) {
-                       event.stopEvent();
-                }
-               return false;
-       },
-       /*
-        * Handler invoked when a hot key configured for this dropdown list is pressed
-        */
-       onHotKey: function (key) {
-               if (!this.disabled) {
-                       this.plugins.onHotKey(this.getEditor(), key);
-                       if (HTMLArea.UserAgent.isOpera) {
-                               this.getEditor().focus();
+                       Ext.ux.form.HTMLAreaCombo.superclass.onViewClick.call(this, false);
+               },
+
+               /**
+                * Handler invoked in IE when the mouse moves out of the editor iframe
+                */
+               saveSelection: function (event) {
+                       var editor = this.getEditor();
+                       if (editor.document.hasFocus()) {
+                               this.savedRange = editor.getSelection().createRange();
                        }
-                       this.getToolbar().update();
-               }
-               return false;
-       },
-       /*
-        * Handler invoked when the toolbar is updated
-        */
-       onUpdateToolbar: function (mode, selectionEmpty, ancestors, endPointsInSameBlock) {
-               this.setDisabled(mode === 'textmode' && !this.textMode);
-               if (!this.disabled) {
-                       this.plugins['onUpdateToolbar'](this, mode, selectionEmpty, ancestors, endPointsInSameBlock);
-               }
-       },
-       /*
-        * The iframe must have been rendered
-        */
-       onFrameworkReady: function () {
-               var iframe = this.getEditor().iframe;
+               },
+
+               /**
+                * Handler invoked in IE when the editor gets the focus back
+                */
+               restoreSelection: function (event) {
+                       if (typeof this.savedRange === 'object' && this.savedRange !== null && this.triggered) {
+                               this.getEditor().getSelection().selectRange(this.savedRange);
+                               this.triggered = false;
+                       }
+               },
+
+               /**
+                * Handler invoked when the enter key is pressed while the combo has focus
+                */
+               onSpecialKey: function (combo, event) {
+                       if (event.getKey() == event.ENTER) {
+                               event.stopEvent();
+                       }
+                       return false;
+               },
+
+               /**
+                * Handler invoked when a hot key configured for this dropdown list is pressed
+                */
+               onHotKey: function (key) {
+                       if (!this.disabled) {
+                               this.plugins.onHotKey(this.getEditor(), key);
+                               if (UserAgent.isOpera) {
+                                       this.getEditor().focus();
+                               }
+                               this.getToolbar().update();
+                       }
+                       return false;
+               },
+
+               /**
+                * Handler invoked when the toolbar is updated
+                */
+               onUpdateToolbar: function (mode, selectionEmpty, ancestors, endPointsInSameBlock) {
+                       this.setDisabled(mode === 'textmode' && !this.textMode);
+                       if (!this.disabled) {
+                               this.plugins['onUpdateToolbar'](this, mode, selectionEmpty, ancestors, endPointsInSameBlock);
+                       }
+               },
+
+               /**
+                * The iframe must have been rendered
+                */
+               onFrameworkReady: function () {
+                       var iframe = this.getEditor().iframe;
                        // Close the combo on a click in the iframe
                        // Note: ExtJS is monitoring events only on the parent window
-               this.mon(Ext.get(iframe.document.documentElement), 'click', this.collapse, this);
+                       var self = this;
+                       Event.on(iframe.document.documentElement, 'click', function (event) { self.collapse(); return true; });
                        // Special handling for combo stealing focus in IE
-               if (HTMLArea.UserAgent.isIE) {
+                       if (UserAgent.isIE) {
                                // Take a bookmark in case the editor looses focus by activation of this combo
-                       this.mon(iframe.getEl(), 'mouseleave', this.saveSelection, this);
+                               Event.on(iframe.getEl().dom, 'mouseleave', function (event) { self.saveSelection(event); return true; });
                                // Restore the selection if combo was triggered
-                       this.mon(iframe.getEl(), 'focus', this.restoreSelection, this);
+                               Event.on(iframe.getEl().dom, 'focus', function (event) { self.restoreSelection(event); return true; });
+                       }
+               },
+
+               /**
+                * Cleanup
+                */
+               onBeforeDestroy: function () {
+                       this.savedRange = null;
+                       this.getStore().removeAll();
+                       this.getStore().destroy();
                }
-       },
-       /*
-        * Cleanup
-        */
-       onBeforeDestroy: function () {
-               this.savedRange = null;
-               this.getStore().removeAll();
-               this.getStore().destroy();
-       }
-});
+       });
+
+       return Combo;
+
+}(HTMLArea.UserAgent, HTMLArea.Event);
 Ext.reg('htmlareacombo', Ext.ux.form.HTMLAreaCombo);
index de1c59b..ab886e0 100644 (file)
@@ -319,7 +319,7 @@ HTMLArea.Plugin = function(UserAgent, Util) {
         *
         * @return      void
         */
-       Plugin.prototype.init = function () {};
+       Plugin.prototype.init = Util.emptyFunction;
 
        /**
         * The toolbar refresh handler of the plugin
@@ -328,7 +328,7 @@ HTMLArea.Plugin = function(UserAgent, Util) {
         *
         * @return      boolean
         */
-       Plugin.prototype.onUpdateToolbar = function () {};
+       Plugin.prototype.onUpdateToolbar = Util.emptyFunction;
 
        /**
         * The onMode event handler
@@ -352,7 +352,7 @@ HTMLArea.Plugin = function(UserAgent, Util) {
         *
         * @return      boolean
         */
-       Plugin.prototype.onGenerate = function () {};
+       Plugin.prototype.onGenerate = Util.emptyFunction;
 
        /**
         * Localize a string
@@ -570,9 +570,18 @@ HTMLArea.Plugin = function(UserAgent, Util) {
        };
 
        /**
+        * Remove listeners
+        * This function may be defined by the plugin subclass.
+        * The function is invoked when a plugin dialog is closed
+        * @return void
+        */
+       Plugin.prototype.removeListeners = Util.emptyFunction;
+
+       /**
         * Close the dialogue window (after saving the selection, if IE)
         */
        Plugin.prototype.close = function () {
+               this.removeListeners();
                this.saveSelection();
                this.dialog.close();
        };
@@ -581,6 +590,7 @@ HTMLArea.Plugin = function(UserAgent, Util) {
         * Dialogue window onClose handler
         */
        Plugin.prototype.onClose = function () {
+               this.removeListeners();
                this.editor.focus();
                this.restoreSelection();
                this.editor.updateToolbar();
@@ -590,6 +600,7 @@ HTMLArea.Plugin = function(UserAgent, Util) {
         * Handler for window cancel
         */
        Plugin.prototype.onCancel = function () {
+               this.removeListeners();
                this.dialog.close();
                this.editor.focus();
        };
index 4fe3102..0c05b67 100644 (file)
@@ -45,6 +45,11 @@ HTMLArea.util = function() {
                },
 
                /**
+                * Empty function
+                */
+               emptyFunction: function () {},
+
+               /**
                 * Copies all the properties of config to obj.
                 * @param Object obj The receiver of the properties
                 * @param Object config The source of the properties
index 27c3254..4422764 100644 (file)
@@ -13,7 +13,7 @@
 /**
  * BlockElements Plugin for TYPO3 htmlArea RTE
  */
-HTMLArea.BlockElements = function (Plugin, UserAgent, Dom) {
+HTMLArea.BlockElements = function (Plugin, UserAgent, Dom, Event) {
 
        var BlockElements = Ext.extend(Plugin, {
 
@@ -938,30 +938,30 @@ HTMLArea.BlockElements = function (Plugin, UserAgent, Dom) {
                                }
                        }
                },
-               /*
+
+               /**
                 * This function gets called when the plugin is generated
                 */
                onGenerate: function () {
-                               // Register the enter key handler for IE when the cursor is at the end of a dt or a dd element
+                       // Register the enter key handler for IE when the cursor is at the end of a dt or a dd element
                        if (UserAgent.isIE) {
+                               var self = this;
                                this.editor.iframe.keyMap.addBinding({
-                                       key: Ext.EventObject.ENTER,
+                                       key: Event.ENTER,
                                        shift: false,
-                                       handler: this.onKey,
-                                       scope: this
+                                       handler: function (event) { return self.onKey(event); }
                                });
                        }
                },
-               /*
+
+               /**
                 * This function gets called when the enter key was pressed in IE
                 * It will process the enter key for IE when the cursor is at the end of a dt or a dd element
                 *
-                * @param       string          key: the key code
-                * @param       object          event: the Ext event object (keydown)
-                *
-                * @return      boolean         false, if the event was taken care of
+                * @param object event: the Ext event object (keydown)
+                * @return boolean false, if the event was taken care of
                 */
-               onKey: function (key, event) {
+               onKey: function (event) {
                        if (this.editor.getSelection().isEmpty()) {
                                var range = this.editor.getSelection().createRange();
                                var parentElement = this.editor.getSelection().getParentElement();
@@ -976,7 +976,7 @@ HTMLArea.BlockElements = function (Plugin, UserAgent, Dom) {
                                                var item = parentElement.parentNode.insertBefore(this.editor.document.createElement((parentElement.nodeName.toLowerCase() === "dt") ? "dd" : "dt"), parentElement.nextSibling);
                                                item.innerHTML = "\x20";
                                                this.editor.getSelection().selectNodeContents(item, true);
-                                               event.stopEvent();
+                                               Event.stopEvent(event);
                                                return false;
                                        }
                                } else if (/^(li)$/i.test(parentElement.nodeName)
@@ -986,13 +986,14 @@ HTMLArea.BlockElements = function (Plugin, UserAgent, Dom) {
                                        var item = parentElement.parentNode.parentNode.insertBefore(this.editor.document.createTextNode("\x20"), parentElement.parentNode.nextSibling);
                                        this.editor.getSelection().selectNodeContents(parentElement.parentNode.parentNode, false);
                                        parentElement.parentNode.removeChild(parentElement);
-                                       event.stopEvent();
+                                       Event.stopEvent(event);
                                        return false;
                                }
                        }
                        return true;
                },
-               /*
+
+               /**
                 * This function removes any disallowed class or mutually exclusive classes from the class attribute of the node
                 */
                cleanClasses: function (node) {
@@ -1202,4 +1203,4 @@ HTMLArea.BlockElements = function (Plugin, UserAgent, Dom) {
 
        return BlockElements;
 
-}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.DOM);
+}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.DOM, HTMLArea.Event);
index 126aa64..8676e9e 100644 (file)
@@ -13,7 +13,7 @@
 /**
  * Block Style Plugin for TYPO3 htmlArea RTE
  */
-HTMLArea.BlockStyle = function (Plugin, Dom, Parser) {
+HTMLArea.BlockStyle = function (Plugin, Dom, Event, Parser) {
 
        var BlockStyle = Ext.extend(Plugin, {
 
@@ -42,7 +42,7 @@ HTMLArea.BlockStyle = function (Plugin, Dom, Parser) {
                        this.showTagFreeClasses = this.pageTSconfiguration ? this.pageTSconfiguration.showTagFreeClasses : false;
                        this.prefixLabelWithClassName = this.pageTSconfiguration ? this.pageTSconfiguration.prefixLabelWithClassName : false;
                        this.postfixLabelWithClassName = this.pageTSconfiguration ? this.pageTSconfiguration.postfixLabelWithClassName : false;
-                       /*
+                       /**
                         * Registering plugin "About" information
                         */
                        var pluginInformation = {
@@ -55,7 +55,7 @@ HTMLArea.BlockStyle = function (Plugin, Dom, Parser) {
                                license         : 'GPL'
                        };
                        this.registerPluginInformation(pluginInformation);
-                       /*
+                       /**
                         * Registering the drop-down list
                         */
                        var dropDownId = 'BlockStyle';
@@ -86,7 +86,8 @@ HTMLArea.BlockStyle = function (Plugin, Dom, Parser) {
                        this.registerDropDown(dropDownConfiguration);
                        return true;
                },
-               /*
+
+               /**
                 * This handler gets called when some block style was selected in the drop-down list
                 */
                onChange: function (editor, combo, record, index) {
@@ -106,7 +107,8 @@ HTMLArea.BlockStyle = function (Plugin, Dom, Parser) {
                                }
                        }
                },
-               /*
+
+               /**
                 * This function applies the class change to the node
                 */
                applyClassChange: function (node, className) {
@@ -140,12 +142,14 @@ HTMLArea.BlockStyle = function (Plugin, Dom, Parser) {
                                }
                        }
                },
+
                /**
                 * This handler gets called when the editor is generated
                 */
                onGenerate: function () {
+                       var self = this;
                        // Monitor editor changing mode
-                       this.editor.iframe.mon(this.editor, 'HTMLAreaEventModeChange', this.onModeChange, this);
+                       Event.on(this.editor, 'HTMLAreaEventModeChange', function (event, mode) { Event.stopEvent(event); self.onModeChange(mode); return false; });
                        // Create CSS Parser object
                        this.blockStyles = new Parser({
                                prefixLabelWithClassName: this.prefixLabelWithClassName,
@@ -160,10 +164,11 @@ HTMLArea.BlockStyle = function (Plugin, Dom, Parser) {
                                dropDown.setDisabled(true);
                        }
                        // Monitor css parsing being completed
-                       this.editor.iframe.mon(this.blockStyles, 'HTMLAreaEventCssParsingComplete', this.onCssParsingComplete, this);
+                       Event.one(this.blockStyles, 'HTMLAreaEventCssParsingComplete', function (event) { Event.stopEvent(event); self.onCssParsingComplete(); return false; }); 
                        this.blockStyles.parse();
                },
-               /*
+
+               /**
                 * This handler gets called when parsing of css classes is completed
                 */
                onCssParsingComplete: function () {
@@ -174,7 +179,8 @@ HTMLArea.BlockStyle = function (Plugin, Dom, Parser) {
                                }
                        }
                },
-               /*
+
+               /**
                 * This handler gets called when the toolbar is being updated
                 */
                onUpdateToolbar: function (button, mode, selectionEmpty, ancestors) {
@@ -182,7 +188,8 @@ HTMLArea.BlockStyle = function (Plugin, Dom, Parser) {
                                this.updateValue(button.itemId);
                        }
                },
-               /*
+
+               /**
                 * This handler gets called when the editor has changed its mode to "wysiwyg"
                 */
                onModeChange: function(mode) {
@@ -190,7 +197,8 @@ HTMLArea.BlockStyle = function (Plugin, Dom, Parser) {
                                this.updateValue('BlockStyle');
                        }
                },
-               /*
+
+               /**
                 * This function updates the current value of the dropdown list
                 */
                updateValue: function(dropDownId) {
@@ -216,7 +224,8 @@ HTMLArea.BlockStyle = function (Plugin, Dom, Parser) {
                                }
                        }
                },
-               /*
+
+               /**
                 * This function reinitializes the options of the dropdown
                 */
                initializeDropDown: function (dropDown) {
@@ -228,7 +237,8 @@ HTMLArea.BlockStyle = function (Plugin, Dom, Parser) {
                        }));
                        dropDown.setValue('none');
                },
-               /*
+
+               /**
                 * This function builds the options to be displayed in the dropDown box
                 */
                buildDropDownOptions: function (dropDown, nodeName) {
@@ -260,7 +270,8 @@ HTMLArea.BlockStyle = function (Plugin, Dom, Parser) {
                                }
                        }
                },
-               /*
+
+               /**
                 * This function sets the selected option of the dropDown box
                 */
                setSelectedOption: function (dropDown, classNames, noUnknown, defaultClass) {
@@ -307,4 +318,4 @@ HTMLArea.BlockStyle = function (Plugin, Dom, Parser) {
 
        return BlockStyle;
 
-}(HTMLArea.Plugin, HTMLArea.DOM, HTMLArea.CSS.Parser);
+}(HTMLArea.Plugin, HTMLArea.DOM, HTMLArea.Event, HTMLArea.CSS.Parser);
index 2aeeca2..568bb1a 100644 (file)
@@ -13,7 +13,7 @@
 /**
  * Character Map Plugin for TYPO3 htmlArea RTE
  */
-HTMLArea.CharacterMap = function (Plugin, UserAgent) {
+HTMLArea.CharacterMap = function (Plugin, UserAgent, Event) {
 
        var CharacterMap = Ext.extend(Plugin, {
 
@@ -34,7 +34,8 @@ HTMLArea.CharacterMap = function (Plugin, UserAgent) {
                                license         : 'GPL'
                        };
                        this.registerPluginInformation(pluginInformation);
-                       /*
+
+                       /**
                         * Registering the buttons
                         */
                        for (var i = 0, n = this.buttons.length; i < n; ++i) {
@@ -50,7 +51,8 @@ HTMLArea.CharacterMap = function (Plugin, UserAgent) {
                                };
                                this.registerButton(buttonConfiguration);
                        }
-                       /*
+
+                       /**
                         * Localizing the maps
                         */
                        for (var key in this.maps) {
@@ -60,15 +62,17 @@ HTMLArea.CharacterMap = function (Plugin, UserAgent) {
                                }
                        }
                        return true;
-                },
-               /*
+               },
+
+               /**
                 * The list of buttons added by this plugin
                 */
                buttons: [
                        ['InsertCharacter', null, 'character-insert-from-map'],
                        ['InsertSoftHyphen', null, 'soft-hyphen-insert']
                ],
-               /*
+
+               /**
                 * Character maps
                 */
                maps: {
@@ -427,29 +431,29 @@ HTMLArea.CharacterMap = function (Plugin, UserAgent) {
                        }
                        return tabItems;
                },
-               /*
+
+               /**
                 * Render an array of characters
                 *
-                * @param       object          component: the box containing the characters
-                *
-                * @return      void
+                * @param object component: the box containing the characters
+                * @return void
                 */
                renderMap: function (component) {
                        component.tpl.overwrite(component.el, this.maps[component.itemId]);
-                       component.mon(component.el, 'click', this.insertCharacter, this, {delegate: 'a'});
+                       var self = this;
+                       Event.on(component.el.dom, 'click', function (event) { return self.insertCharacter(event); }, {delegate: 'a'});
                },
 
                /**
                 * Handle the click on an item of the map
                 *
-                * @param object event: the Ext event
-                * @param HTMLelement target: the html element target
+                * @param object event: the jQuery event
                 * @return boolean
                 */
-               insertCharacter: function (event, target) {
-                       event.stopEvent();
+               insertCharacter: function (event) {
+                       Event.stopEvent(event);
                        this.restoreSelection();
-                       var entity = target.innerHTML;
+                       var entity = event.target.innerHTML;
                        this.insertEntity(entity);
                        this.saveSelection();
                        return false;
@@ -472,14 +476,28 @@ HTMLArea.CharacterMap = function (Plugin, UserAgent) {
                                this.editor.getSelection().selectNode(node, false);
                        }
                },
-               /*
+
+               /**
                 * Reset focus on the the current selection, if at all possible
                 *
                 */
                resetFocus: function () {
                        this.restoreSelection();
+               },
+
+               /**
+                * Remove listeners before closing the window
+                */             
+               removeListeners: function () {
+                       var components = this.dialog.findByType('box');
+                       for (var i = components.length; --i > 0;) {
+                               if (components[i].el) {
+                                       Event.off(components[i].el.dom);
+                               }
+                       }                       
                }
        });
 
        return CharacterMap;
-}(HTMLArea.Plugin, HTMLArea.UserAgent);
+
+}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.Event);
index 27d228c..c395426 100644 (file)
 /**
  * Context Menu Plugin for TYPO3 htmlArea RTE
  */
-HTMLArea.ContextMenu = function (Plugin, UserAgent, Util, Dom) {
+HTMLArea.ContextMenu = function (Plugin, UserAgent, Util, Dom, Event) {
 
        var ContextMenu = Ext.extend(Plugin, {
 
                /**
                 * This function gets called by the class constructor
                 */
-               configurePlugin : function(editor) {
+               configurePlugin: function(editor) {
                        this.pageTSConfiguration = this.editorConfiguration.contextMenu;
                        if (!this.pageTSConfiguration) {
                                this.pageTSConfiguration = {};
@@ -51,6 +51,7 @@ HTMLArea.ContextMenu = function (Plugin, UserAgent, Util, Dom) {
                 * This function gets called when the editor gets generated
                 */
                onGenerate: function() {
+                       var self = this;
                        // Build the context menu
                        this.menu = new Ext.menu.Menu(Util.applyIf({
                                cls: 'htmlarea-context-menu',
@@ -71,9 +72,9 @@ HTMLArea.ContextMenu = function (Plugin, UserAgent, Util, Dom) {
                                },
                                items: this.buildItemsConfig()
                        }, this.pageTSConfiguration));
-                               // Monitor contextmenu clicks on the iframe
-                       this.menu.mon(Ext.get(this.editor.document.documentElement), 'contextmenu', this.show, this);
-                               // Monitor editor being destroyed
+                       // Monitor contextmenu clicks on the iframe
+                       Event.on(this.editor.document.documentElement, 'contextmenu', function (event) { return self.show(event, event.target); });
+                       // Monitor editor being destroyed
                        this.menu.mon(this.editor, 'beforedestroy', this.onBeforeDestroy, this, {single: true});
                },
                /**
@@ -140,27 +141,37 @@ HTMLArea.ContextMenu = function (Plugin, UserAgent, Util, Dom) {
                        });
                        return itemsConfig;
                },
-               /*
+
+               /**
                 * Handler when the menu gets shown
                 */
                onShow: function () {
-                       this.menu.mon(Ext.get(this.editor.document.documentElement), 'mousedown', this.menu.hide, this.menu, {single: true});
+                       var self = this;
+                       Event.one(this.editor.document.documentElement, 'mousedown.contextmeu', function (event) { Event.stopEvent(event); self.menu.hide(); return false; });
                },
-               /*
+
+               /**
                 * Handler when the menu gets hidden
                 */
                onHide: function () {
-                       this.menu.mun(Ext.get(this.editor.document.documentElement), 'mousedown', this.menu.hide, this.menu);
+                       var self = this;
+                       Event.off(this.editor.document.documentElement, 'mousedown.contextmeu');
                },
-               /*
+
+               /**
                 * Handler to show the context menu
                 */
                show: function (event, target) {
-                       event.stopEvent();
-                               // Need to wait a while for the toolbar state to be updated
-                       this.showMenu.defer(150, this, [target]);
+                       Event.stopEvent(event);
+                       // Need to wait a while for the toolbar state to be updated
+                       var self = this;
+                       window.setTimeout(function () {
+                               self.showMenu(target);
+                       }, 150);
+                       return false;
                },
-               /*
+
+               /**
                 * Show the context menu
                 */
                showMenu: function (target) {
@@ -220,7 +231,8 @@ HTMLArea.ContextMenu = function (Plugin, UserAgent, Util, Dom) {
                                lastVisible.setVisible(false);
                        }
                },
-               /*
+
+               /**
                 * Handler invoked when a menu item is clicked on
                 */
                onItemClick: function (item, event) {
@@ -229,7 +241,11 @@ HTMLArea.ContextMenu = function (Plugin, UserAgent, Util, Dom) {
                        }
                        var button = this.getButton(item.getItemId());
                        if (button) {
-                               button.fireEvent('HTMLAreaEventContextMenu', button, event);
+                               /**
+                                * @event HTMLAreaEventContextMenu
+                                * Fires when the button is triggered from the context menu
+                                */
+                               Event.trigger(button, 'HTMLAreaEventContextMenu', [button]);
                        } else if (item.getItemId() === 'DeleteTarget') {
                                        // Do not leave a non-ie table cell empty
                                var parent = this.deleteTarget.parentNode;
@@ -250,7 +266,8 @@ HTMLArea.ContextMenu = function (Plugin, UserAgent, Util, Dom) {
                                this.editor.updateToolbar();
                        }
                },
-               /*
+
+               /**
                 * Handler invoked when the editor is about to be destroyed
                 */
                onBeforeDestroy: function () {
@@ -264,4 +281,4 @@ HTMLArea.ContextMenu = function (Plugin, UserAgent, Util, Dom) {
 
        return ContextMenu;
 
-}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.util, HTMLArea.DOM);
+}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.util, HTMLArea.DOM, HTMLArea.Event);
index 646010d..fdf3ef5 100644 (file)
@@ -13,7 +13,7 @@
 /**
  * Copy Paste for TYPO3 htmlArea RTE
  */
-HTMLArea.CopyPaste = function (Plugin, UserAgent, Dom) {
+HTMLArea.CopyPaste = function (Plugin, UserAgent, Dom, Event) {
 
        var CopyPaste = Ext.extend(Plugin, {
 
@@ -40,7 +40,8 @@ HTMLArea.CopyPaste = function (Plugin, UserAgent, Dom) {
                                license         : 'GPL'
                        };
                        this.registerPluginInformation(pluginInformation);
-                       /*
+
+                       /**
                         * Registering the buttons
                         */
                        for (var buttonId in this.buttonList) {
@@ -58,7 +59,8 @@ HTMLArea.CopyPaste = function (Plugin, UserAgent, Dom) {
                        }
                        return true;
                },
-               /*
+
+               /**
                 * The list of buttons added by this plugin
                 */
                buttonList: {
@@ -66,30 +68,32 @@ HTMLArea.CopyPaste = function (Plugin, UserAgent, Dom) {
                        Cut     : [null, 'x', 'cut', true],
                        Paste   : [null, 'v', 'paste', false]
                },
-               /*
+
+               /**
                 * This function gets called when the editor is generated
                 */
                onGenerate: function () {
-                       this.editor.iframe.mon(Ext.get(UserAgent.isIE ? this.editor.document.body : this.editor.document.documentElement), 'cut', this.cutHandler, this);
+                       var self = this;
+                       Event.on(UserAgent.isIE ? this.editor.document.body : this.editor.document.documentElement, 'cut', function (event) { return self.cutHandler(event); });
                        for (var buttonId in this.buttonList) {
                                var button = this.buttonList[buttonId];
-                                       // Remove button from toolbar, if command is not supported
-                                       // Starting with Safari 5 and Chrome 6, cut and copy commands are not supported anymore by WebKit
-                                       // Starting with Firefox 29, cut, copy and paste commands are not supported anymore by Firefox
+                               // Remove button from toolbar, if command is not supported
+                               // Starting with Safari 5 and Chrome 6, cut and copy commands are not supported anymore by WebKit
+                               // Starting with Firefox 29, cut, copy and paste commands are not supported anymore by Firefox
                                if (UserAgent.isGecko || !this.editor.document.queryCommandSupported(buttonId)) {
                                        this.editor.toolbar.remove(buttonId);
                                }
-                                       // Add hot key handling if the button is not enabled in the toolbar
+                               // Add hot key handling if the button is not enabled in the toolbar
                                if (!this.getButton(buttonId)) {
+                                       var self = this;
                                        this.editor.iframe.hotKeyMap.addBinding({
-                                               key: button[1].toUpperCase(),
+                                               key: button[1],
                                                ctrl: true,
                                                shift: false,
                                                alt: false,
-                                               handler: this.onHotKey,
-                                               scope: this
+                                               handler: function (event) { return self.onHotKey(event); }
                                        });
-                                               // Ensure the hot key can be translated
+                                       // Ensure the hot key can be translated
                                        this.editorConfiguration.hotKeyList[button[1]] = {
                                                id      : button[1],
                                                cmd     : buttonId
@@ -97,7 +101,8 @@ HTMLArea.CopyPaste = function (Plugin, UserAgent, Dom) {
                                }
                        }
                },
-               /*
+
+               /**
                 * This function gets called when a button or a hotkey was pressed.
                 *
                 * @param       object          editor: the editor instance
@@ -131,14 +136,16 @@ HTMLArea.CopyPaste = function (Plugin, UserAgent, Dom) {
                                                break;
                                        case 'Paste':
                                                if (buttonId == id) {
-                                                               // If we are handling a button, not a hotkey
+                                                       // If we are handling a button, not a hotkey
                                                        this.applyBrowserCommand(buttonId);
                                                }
-                                                       // In FF3, the paste operation will indeed trigger the onPaste event not in FF2; nor in Opera
+                                               // In FF3, the paste operation will indeed trigger the onPaste event not in FF2; nor in Opera
                                                if (UserAgent.isOpera || UserAgent.isGecko2) {
                                                        var cleaner = this.getButton('CleanWord');
                                                        if (cleaner) {
-                                                               cleaner.fireEvent.defer(250, cleaner, ['click', cleaner]);
+                                                               window.setTimeout(function () {
+                                                                       cleaner.fireEvent('click', cleaner);    
+                                                               }, 250);
                                                        }
                                                }
                                                break;
@@ -156,7 +163,10 @@ HTMLArea.CopyPaste = function (Plugin, UserAgent, Dom) {
                                        this.editor.inhibitKeyboardInput = true;
                                        var bookmark = this.editor.getBookMark().get(this.editor.getSelection().createRange());
                                        var html = this.editor.getInnerHTML();
-                                       this.revertPaste.defer(200, this, [html, bookmark]);
+                                       var self = this;
+                                       window.setTimeout(function () {
+                                               self.revertPaste(html, bookmark);       
+                                       }, 200);
                                }
                                return false;
                        }
@@ -176,23 +186,33 @@ HTMLArea.CopyPaste = function (Plugin, UserAgent, Dom) {
                applyBrowserCommand: function (buttonId) {
                        this.editor.getSelection().execCommand(buttonId, false, null);
                },
-               /*
+
+               /**
                 * Handler for hotkeys configured through the hotKeyMap while button not enabled in toolbar (see onGenerate above)
                 */
-               onHotKey: function (key, event) {
+               onHotKey: function (event) {
+                       var key = Event.getKey(event);
                        var hotKey = String.fromCharCode(key).toLowerCase();
-                               // Stop the event if it was handled here
+                       // Stop the event if it was handled here
                        if (!this.onButtonPress(this, hotKey)) {
-                               event.stopEvent();
+                               Event.stopEvent(event);
+                               return false;
                        }
+                       return true;
                },
-               /*
+
+               /**
                 * This function removes any link left over by the cut operation
                 */
                cutHandler: function (event) {
-                       this.removeEmptyLink.defer(50, this);
+                       var self = this;
+                       window.setTimeout(function () {
+                               self.removeEmptyLink(); 
+                       }, 50);
+                       return true;
                },
-               /*
+
+               /**
                 * This function unlinks any empty link left over by the cut operation
                 */
                removeEmptyLink: function() {
@@ -431,4 +451,4 @@ HTMLArea.CopyPaste = function (Plugin, UserAgent, Dom) {
 
        return CopyPaste;
 
-}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.DOM);
+}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.DOM, HTMLArea.Event);
index 31a209c..34354d0 100644 (file)
@@ -13,7 +13,7 @@
 /**
  * Default Clean Plugin for TYPO3 htmlArea RTE
  */
-HTMLArea.DefaultClean = function (Plugin, UserAgent, Util, Dom) {
+HTMLArea.DefaultClean = function (Plugin, UserAgent, Util, Dom, Event) {
 
        var DefaultClean = Ext.extend(Plugin, {
 
@@ -50,28 +50,31 @@ HTMLArea.DefaultClean = function (Plugin, UserAgent, Util, Dom) {
                        };
                        this.registerButton(buttonConfiguration);
                },
-               /*
+
+               /**
                 * This function gets called when the button was pressed.
                 *
-                * @param       object          editor: the editor instance
-                * @param       string          id: the button id or the key
-                *
-                * @return      boolean         false if action is completed
+                * @param object editor: the editor instance
+                * @param string id: the button id or the key
+                * @return boolean false if action is completed
                 */
                onButtonPress: function (editor, id, target) {
-                               // Could be a button or its hotkey
+                       // Could be a button or its hotkey
                        var buttonId = this.translateHotKey(id);
                        buttonId = buttonId ? buttonId : id;
                        this.clean();
                        return false;
                },
-               /*
+
+               /**
                 * This function gets called when the editor is generated
                 */
                onGenerate: function () {
-                       this.editor.iframe.mon(Ext.get(UserAgent.isIE ? this.editor.document.body : this.editor.document.documentElement), 'paste', this.wordCleanHandler, this);
+                       var self = this;
+                       Event.on(UserAgent.isIE ? this.editor.document.body : this.editor.document.documentElement, 'paste', function (event) { return self.wordCleanHandler(event); });
                },
-               /*
+
+               /**
                 * This function cleans all nodes in the node tree below the input node
                 *
                 * @param       object  node: the root of the node tree to clean
@@ -164,10 +167,14 @@ HTMLArea.DefaultClean = function (Plugin, UserAgent, Util, Dom) {
                 * Handler for paste, dragdrop and drop events
                 */
                wordCleanHandler: function (event) {
-                       this.clean.defer(250, this);
+                       var self = this;
+                       window.setTimeout(function () {
+                               self.clean();
+                       }, 250);
+                       return true;
                }
        });
 
        return DefaultClean;
 
-}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.util, HTMLArea.DOM);
+}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.util, HTMLArea.DOM, HTMLArea.Event);
index ed22be2..9b7e26e 100644 (file)
@@ -13,7 +13,7 @@
 /**
  * DefinitionList Plugin for TYPO3 htmlArea RTE
  */
-HTMLArea.DefinitionList = function (BlockElements, UserAgent, Dom) {
+HTMLArea.DefinitionList = function (BlockElements, UserAgent, Util, Dom) {
 
        var DefinitionList = Ext.extend(BlockElements, {
 
@@ -72,7 +72,8 @@ HTMLArea.DefinitionList = function (BlockElements, UserAgent, Dom) {
                        }
                        return true;
                },
-               /*
+
+               /**
                 * The list of buttons added by this plugin
                 */
                buttonList: [
@@ -80,13 +81,15 @@ HTMLArea.DefinitionList = function (BlockElements, UserAgent, Dom) {
                        ['Outdent', null, 'SHIFT-TAB', 'outdent', false, 'outdent'],
                        ['DefinitionList', null, null, 'definitionlist', true, 'definition-list'],
                        ['DefinitionItem', 'dd,dt', null, 'definitionitem', false, 'definition-list-item']
-                ],
-               /*
+               ],
+
+               /**
                 * This function gets called when the plugin is generated
                 * Avoid re-execution of the base function
                 */
-               onGenerate: Ext.emptyFn,
-               /*
+               onGenerate: Util.emptyFunction,
+
+               /**
                 * This function gets called when a button was pressed.
                 *
                 * @param       object          editor: the editor instance
@@ -328,4 +331,4 @@ HTMLArea.DefinitionList = function (BlockElements, UserAgent, Dom) {
 
        return DefinitionList;
 
-}(HTMLArea.BlockElements, HTMLArea.UserAgent, HTMLArea.DOM);
+}(HTMLArea.BlockElements, HTMLArea.UserAgent, HTMLArea.util, HTMLArea.DOM);
index 89a2a87..d51383e 100644 (file)
@@ -13,7 +13,7 @@
 /**
  * Insert Smiley Plugin for TYPO3 htmlArea RTE
  */
-HTMLArea.InsertSmiley = function (Plugin, UserAgent) {
+HTMLArea.InsertSmiley = function (Plugin, UserAgent, Event) {
 
        var InsertSmiley = Ext.extend(Plugin, {
 
@@ -113,42 +113,54 @@ HTMLArea.InsertSmiley = function (Plugin, UserAgent) {
                        });
                        this.show();
                },
-               /*
+
+               /**
                 * Render the array of emoticon
                 *
-                * @param       object          component: the box containing the emoticons
-                *
-                * @return      void
+                * @param object component: the box containing the emoticons
+                * @return void
                 */
                render: function (component) {
                        component.tpl.overwrite(component.el, this.icons);
-                       component.mon(component.el, 'click', this.insertImageTag, this, {delegate: 'a'});
+                       var self = this;
+                       Event.on(component.el.dom, 'click', function (event) { return self.insertImageTag(event); }, {delegate: 'a'});
                },
 
                /**
                 * Insert the selected emoticon
                 *
-                * @param object event: the Ext event
-                * @param HTMLelement target: the html element target
+                * @param object event: the jQuery click event
                 * @return void
                 */
-               insertImageTag: function (event, target) {
-                       event.stopEvent();
+               insertImageTag: function (event) {
+                       Event.stopEvent(event);
+                       var icon = event.target;
                        this.restoreSelection();
-                       var icon = target.firstChild;
                        var imgTag = this.editor.document.createElement('img');
                        imgTag.setAttribute('src', icon.getAttribute('src'));
-                       imgTag.setAttribute('alt', target.getAttribute('ext:qtitle'));
-                       imgTag.setAttribute('title', target.getAttribute('ext:qtip'));
+                       imgTag.setAttribute('alt', icon.parentNode.getAttribute('ext:qtitle'));
+                       imgTag.setAttribute('title', icon.parentNode.getAttribute('ext:qtip'));
                        this.editor.getSelection().insertNode(imgTag);
                        if (!UserAgent.isIEBeforeIE9) {
                                this.editor.getSelection().selectNode(imgTag, false);
                        }
                        this.close();
                        return false;
+               },
+
+               /**
+                * Remove listeners before closing the window
+                */             
+               removeListeners: function () {
+                       var components = this.dialog.findByType('box');
+                       for (var i = components.length; --i > 0;) {
+                               if (components[i].el) {
+                                       Event.off(components[i].el.dom);
+                               }
+                       }                       
                }
        });
 
        return InsertSmiley;
 
-}(HTMLArea.Plugin, HTMLArea.UserAgent);
+}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.Event);
index 4f8665f..e060e8c 100644 (file)
@@ -13,7 +13,7 @@
 /**
  * Paste as Plain Text Plugin for TYPO3 htmlArea RTE
  */
-HTMLArea.PlainText = function (Plugin, UserAgent, Dom, Walker) {
+HTMLArea.PlainText = function (Plugin, UserAgent, Dom, Event, Walker) {
 
        var PlainText = Ext.extend(Plugin, {
 
@@ -109,10 +109,12 @@ HTMLArea.PlainText = function (Plugin, UserAgent, Dom, Walker) {
                        if (this.buttonsConfiguration && this.buttonsConfiguration['pastetoggle'] && this.buttonsConfiguration['pastetoggle'].setActiveOnRteOpen) {
                                this.toggleButton('PasteToggle');
                        }
-                               // Start monitoring paste events
-                       this.editor.iframe.mon(Ext.get(UserAgent.isIE ? this.editor.document.body : this.editor.document.documentElement), 'paste', this.onPaste, this);
+                       // Start monitoring paste events
+                       var self = this;
+                       Event.on(UserAgent.isIE ? this.editor.document.body : this.editor.document.documentElement, 'paste', function (event) { return self.onPaste(event); });
                },
-               /*
+
+               /**
                 * This function toggles the state of a button
                 *
                 * @param       string          buttonId: id of button to be toggled
@@ -235,7 +237,7 @@ HTMLArea.PlainText = function (Plugin, UserAgent, Dom, Walker) {
                /**
                 * Handler for paste event
                 *
-                * @param object event: the paste event
+                * @param object event: the jQuery paste event
                 * @return boolean false, if the event was handled, true otherwise
                 */
                onPaste: function (event) {
@@ -266,9 +268,9 @@ HTMLArea.PlainText = function (Plugin, UserAgent, Dom, Walker) {
                                                                )
                                                        );
                                                        if (UserAgent.isIEBeforeIE9) {
-                                                               event.browserEvent.returnValue = false;
+                                                               Event.getBrowserEvent(event).returnValue = false;
                                                        } else {
-                                                               event.stopEvent();
+                                                               Event.stopEvent(event);
                                                        }
                                                        return false;
                                                } else {
@@ -278,7 +280,7 @@ HTMLArea.PlainText = function (Plugin, UserAgent, Dom, Walker) {
                                                        // WebKit seems to be pondering a very long time over what is happenning here...
                                                        var self = this;
                                                        window.setTimeout(function () {
-                                                               return self.processPastedContent();
+                                                               self.processPastedContent();
                                                        }, UserAgent.isWebKit ? 500 : 50);
                                                }
                                                break;
@@ -289,25 +291,25 @@ HTMLArea.PlainText = function (Plugin, UserAgent, Dom, Walker) {
                        return true;
                },
 
-               /*
+               /**
                 * Grab the text content directly from the clipboard
                 * If successful, stop the paste event
                 *
-                * @param       object          event: the paste event
-                *
-                * @return      string          clipboard content, in plain text, if access was granted
+                * @param object event: the jQuery paste event
+                * @return string clipboard content, in plain text, if access was granted
                 */
                grabClipboardText: function (event) {
                        var clipboardText = '';
-                               // Grab the text content
-                       if (window.clipboardData || event.browserEvent.clipboardData || event.browserEvent.dataTransfer) {
-                               clipboardText = (window.clipboardData || event.browserEvent.clipboardData || event.browserEvent.dataTransfer).getData('text');
+                       var browserEvent = Event.getBrowserEvent(event);
+                       // Grab the text content
+                       if (window.clipboardData || browserEvent.clipboardData || browserEvent.dataTransfer) {
+                               clipboardText = (window.clipboardData || browserEvent.clipboardData || browserEvent.dataTransfer).getData('text');
                        }
                        if (clipboardText) {
-                                       // Stop the event
-                               event.stopEvent();
+                               // Stop the event
+                               Event.stopEvent(event);
                        } else {
-                                       // If the user denied access to the clipboard, let the browser paste without intervention
+                               // If the user denied access to the clipboard, let the browser paste without intervention
                                TYPO3.Dialog.InformationDialog({
                                        title: this.localize('Paste-as-Plain-Text'),
                                        msg: this.localize('Access-to-clipboard-denied')
@@ -315,7 +317,8 @@ HTMLArea.PlainText = function (Plugin, UserAgent, Dom, Walker) {
                        }
                        return clipboardText;
                },
-               /*
+
+               /**
                 * Redirect the paste operation towards a hidden section
                 *
                 * @return      void
@@ -399,7 +402,7 @@ HTMLArea.PlainText = function (Plugin, UserAgent, Dom, Walker) {
                                                }
                                        },
                                        close: {
-                                               fn: this.onClose,
+                                               fn: this.onPastingPadClose,
                                                scope: this
                                        }
                                },
@@ -440,12 +443,13 @@ HTMLArea.PlainText = function (Plugin, UserAgent, Dom, Walker) {
                        this.pastingPadDocument = iframe.contentWindow ? iframe.contentWindow.document : iframe.contentDocument;
                        this.pastingPadBody = this.pastingPadDocument.body;
                        this.pastingPadBody.contentEditable = true;
+                       var self = this;
                        // Start monitoring paste events
-                       this.dialog.mon(Ext.get(this.pastingPadBody), 'paste', this.onPastingPadPaste, this);
+                       Event.on(this.pastingPadBody, 'paste', function (event) { return self.onPastingPadPaste(); });
                        // Try to keep focus on the pasting pad
-                       this.dialog.mon(Ext.get(this.editor.document.documentElement), 'mouseover', function (event) { this.focusOnPastingPad(); }, this);
-                       this.dialog.mon(Ext.get(this.editor.document.body), 'focus', function (event) { this.focusOnPastingPad(); }, this);
-                       this.dialog.mon(Ext.get(this.pastingPadDocument.documentElement), 'mouseover', function (event) { this.focusOnPastingPad(); }, this);
+                       Event.on(UserAgent.isIE ? this.editor.document.body : this.editor.document.documentElement, 'mouseover', function (event) { return self.focusOnPastingPad(); });
+                       Event.on(this.editor.document.body, 'focus', function (event) { return self.focusOnPastingPad(); });
+                       Event.on(UserAgent.isIE ? this.pastingPadBody: this.pastingPadDocument.documentElement, 'mouseover', function (event) { return self.focusOnPastingPad(); });
                        this.focusOnPastingPad();
                },
 
@@ -454,8 +458,11 @@ HTMLArea.PlainText = function (Plugin, UserAgent, Dom, Walker) {
                 */
                focusOnPastingPad: function () {
                        this.pastingPadBody.focus();
-                       this.pastingPadDocument.getSelection().selectAllChildren(this.pastingPadBody);
+                       if (!UserAgent.isIE) {
+                               this.pastingPadDocument.getSelection().selectAllChildren(this.pastingPadBody);
+                       }
                        this.pastingPadDocument.getSelection().collapseToEnd();
+                       return false;
                },
 
                /**
@@ -467,6 +474,7 @@ HTMLArea.PlainText = function (Plugin, UserAgent, Dom, Walker) {
                        window.setTimeout(function () {
                                self.cleanPastingPadContents();
                        }, 50);
+                       return true;
                },
 
                /**
@@ -502,6 +510,16 @@ HTMLArea.PlainText = function (Plugin, UserAgent, Dom, Walker) {
                },
 
                /**
+                * Remove the listeners on the pasing pad
+                */
+               removeListeners: function () {
+                       if(this.pastingPadBody) {
+                               Event.off(this.pastingPadBody);
+                               Event.off(this.pastingPadDocument.documentElement);
+                       }
+               },
+
+               /**
                 * This function gets called when the toolbar is updated
                 */
                onUpdateToolbar: function (button, mode, selectionEmpty, ancestors) {
@@ -519,4 +537,4 @@ HTMLArea.PlainText = function (Plugin, UserAgent, Dom, Walker) {
 
        return PlainText;
 
-}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.DOM, HTMLArea.DOM.Walker);
+}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.DOM, HTMLArea.Event, HTMLArea.DOM.Walker);
index 1666c6f..c2120f3 100644 (file)
@@ -13,7 +13,7 @@
 /**
  * Table Operations Plugin for TYPO3 htmlArea RTE
  */
-HTMLArea.TableOperations = function (Plugin, UserAgent, Util, Dom, Color) {
+HTMLArea.TableOperations = function (Plugin, UserAgent, Util, Dom, Event, Color) {
 
        var TableOperations = Ext.extend(Plugin, {
 
@@ -618,25 +618,27 @@ HTMLArea.TableOperations = function (Plugin, UserAgent, Util, Dom, Color) {
                        this.reStyleTable(table);
                        this.close();
                },
-               /*
+
+               /**
                 * This function gets called when the plugin is generated
                 */
                onGenerate: function () {
-                               // Set table borders if requested by configuration
+                       // Set table borders if requested by configuration
                        if (this.buttonsConfiguration.toggleborders && this.buttonsConfiguration.toggleborders.setOnRTEOpen) {
                                this.toggleBorders(true);
                        }
-                               // Register handler for the enter key for IE and Opera when buttons.table.disableEnterParagraphs is set in the editor configuration
+                       // Register handler for the enter key for IE and Opera when buttons.table.disableEnterParagraphs is set in the editor configuration
                        if ((UserAgent.isIE || UserAgent.isOpera) && this.disableEnterParagraphs) {
+                               var self = this;
                                this.editor.iframe.keyMap.addBinding({
-                                       key: Ext.EventObject.ENTER,
+                                       key: Event.ENTER,
                                        shift: false,
-                                       handler: this.onKey,
-                                       scope: this
+                                       handler: function (event) { return self.onKey(event); }
                                });
                        }
                },
-               /*
+
+               /**
                 * This function gets called when the toolbar is being updated
                 */
                onUpdateToolbar: function (button, mode, selectionEmpty, ancestors) {
@@ -2581,12 +2583,10 @@ HTMLArea.TableOperations = function (Plugin, UserAgent, Util, Dom, Color) {
                 * This function gets called by the editor key map when a key was pressed.
                 * It will process the enter key for IE and Opera when buttons.table.disableEnterParagraphs is set in the editor configuration
                 *
-                * @param       string          key: the key code
-                * @param       object          event: the Ext event object (keydown)
-                *
-                * @return      boolean         false, if the event was taken care of
+                * @param object event: the jQuery event object (keydown)
+                * @return boolean false, if the event was taken care of
                 */
-               onKey: function (key, event) {
+               onKey: function (event) {
                        var range = this.editor.getSelection().createRange();
                        var parentElement = this.editor.getSelection().getParentElement();
                        while (parentElement && !Dom.isBlockElement(parentElement)) {
@@ -2605,7 +2605,7 @@ HTMLArea.TableOperations = function (Plugin, UserAgent, Util, Dom, Color) {
                                                this.editor.getSelection().selectNodeContents(brNode, false);
                                        }
                                }
-                               event.stopEvent();
+                               Event.stopEvent(event);
                                return false;
                        }
                        return true;
@@ -2614,4 +2614,4 @@ HTMLArea.TableOperations = function (Plugin, UserAgent, Util, Dom, Color) {
 
        return TableOperations;
 
-}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.util, HTMLArea.DOM, HTMLArea.util.Color);
+}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.util, HTMLArea.DOM, HTMLArea.Event, HTMLArea.util.Color);
index feeea68..dfe47bc 100644 (file)
@@ -13,7 +13,7 @@
 /**
  * TextIndicator Plugin for TYPO3 htmlArea RTE
  */
-HTMLArea.TextIndicator = function (Plugin, UserAgent, Color) {
+HTMLArea.TextIndicator = function (Plugin, UserAgent, Event, Color) {
 
        var TextIndicator = Ext.extend(Plugin, {
 
@@ -54,19 +54,21 @@ HTMLArea.TextIndicator = function (Plugin, UserAgent, Color) {
                 * This handler gets called when the editor is generated
                 */
                onGenerate: function () {
-                               // Ensure text indicator is updated AFTER style sheets are loaded
+                       var self = this;
+                       // Ensure text indicator is updated AFTER style sheets are loaded
                        var blockStylePlugin = this.getPluginInstance('BlockStyle');
                        if (blockStylePlugin && blockStylePlugin.blockStyles) {
-                                       // Monitor css parsing being completed
-                               this.editor.iframe.mon(blockStylePlugin.blockStyles, 'HTMLAreaEventCssParsingComplete', this.onCssParsingComplete, this);
+                               // Monitor css parsing being completed
+                               Event.one(blockStylePlugin.blockStyles, 'HTMLAreaEventCssParsingComplete', function (event) { Event.stopEvent(event); self.onCssParsingComplete(); return false; }); 
                        }
                        var textStylePlugin = this.getPluginInstance('TextStyle');
                        if (textStylePlugin && textStylePlugin.textStyles) {
-                                       // Monitor css parsing being completed
-                               this.editor.iframe.mon(textStylePlugin.textStyles, 'HTMLAreaEventCssParsingComplete', this.onCssParsingComplete, this);
+                               // Monitor css parsing being completed
+                               Event.one(textStylePlugin.textStyles, 'HTMLAreaEventCssParsingComplete', function (event) { Event.stopEvent(event); self.onCssParsingComplete(); return false; });
                        }
                },
-               /*
+
+               /**
                 * This handler gets called when parsing of css classes is completed
                 */
                onCssParsingComplete: function () {
@@ -123,4 +125,4 @@ HTMLArea.TextIndicator = function (Plugin, UserAgent, Color) {
 
        return TextIndicator;
 
-}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.util.Color);
+}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.Event, HTMLArea.util.Color);
index 3ac1eb5..5b65883 100644 (file)
@@ -13,7 +13,7 @@
 /**
  * Text Style Plugin for TYPO3 htmlArea RTE
  */
-HTMLArea.TextStyle = function (Plugin, UserAgent, Dom, Parser) {
+HTMLArea.TextStyle = function (Plugin, UserAgent, Dom, Event, Parser) {
 
        var TextStyle = Ext.extend(Plugin, {
 
@@ -180,13 +180,15 @@ HTMLArea.TextStyle = function (Plugin, UserAgent, Dom, Parser) {
                                }
                        }
                },
+
                /**
                 * This function gets called when the plugin is generated
                 * Get the classes configuration and initiate the parsing of the style sheets
                 */
                onGenerate: function () {
+                       var self = this;
                        // Monitor editor changing mode
-                       this.editor.iframe.mon(this.editor, 'HTMLAreaEventModeChange', this.onModeChange, this);
+                       Event.on(this.editor, 'HTMLAreaEventModeChange', function (event, mode) { Event.stopEvent(event); self.onModeChange(mode); return false; });
                        // Create CSS Parser object
                        this.textStyles = new Parser({
                                prefixLabelWithClassName: this.prefixLabelWithClassName,
@@ -201,10 +203,11 @@ HTMLArea.TextStyle = function (Plugin, UserAgent, Dom, Parser) {
                                dropDown.setDisabled(true);
                        }
                        // Monitor css parsing being completed
-                       this.editor.iframe.mon(this.textStyles, 'HTMLAreaEventCssParsingComplete', this.onCssParsingComplete, this);
+                       Event.one(this.textStyles, 'HTMLAreaEventCssParsingComplete', function (event) { Event.stopEvent(event); self.onCssParsingComplete(); return false; }); 
                        this.textStyles.parse();
                },
-               /*
+
+               /**
                 * This handler gets called when parsing of css classes is completed
                 */
                onCssParsingComplete: function () {
@@ -215,7 +218,8 @@ HTMLArea.TextStyle = function (Plugin, UserAgent, Dom, Parser) {
                                }
                        }
                },
-               /*
+
+               /**
                 * This handler gets called when the toolbar is being updated
                 */
                onUpdateToolbar: function (button, mode, selectionEmpty, ancestors) {
@@ -223,7 +227,8 @@ HTMLArea.TextStyle = function (Plugin, UserAgent, Dom, Parser) {
                                this.updateToolbar(button.itemId);
                        }
                },
-               /*
+
+               /**
                 * This handler gets called when the editor has changed its mode to "wysiwyg"
                 */
                onModeChange: function (mode) {
@@ -231,7 +236,8 @@ HTMLArea.TextStyle = function (Plugin, UserAgent, Dom, Parser) {
                                this.updateToolbar('TextStyle');
                        }
                },
-               /*
+
+               /**
                * This function gets called when the drop-down list needs to be refreshed
                */
                updateToolbar: function (dropDownId) {
@@ -386,4 +392,4 @@ HTMLArea.TextStyle = function (Plugin, UserAgent, Dom, Parser) {
 
        return TextStyle;
 
-}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.DOM, HTMLArea.CSS.Parser);
+}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.DOM, HTMLArea.Event, HTMLArea.CSS.Parser);
index 99f81e2..cb5e76e 100644 (file)
@@ -13,7 +13,7 @@
 /**
  * TYPO3HtmlParser Plugin for TYPO3 htmlArea RTE
  */
-HTMLArea.TYPO3HtmlParser = function (Plugin, UserAgent) {
+HTMLArea.TYPO3HtmlParser = function (Plugin, UserAgent, Event) {
 
        var TYPO3HtmlParser = Ext.extend(Plugin, {
 
@@ -37,7 +37,8 @@ HTMLArea.TYPO3HtmlParser = function (Plugin, UserAgent) {
                                license         : 'GPL'
                        };
                        this.registerPluginInformation(pluginInformation);
-                       /*
+
+                       /**
                         * Registering the (hidden) button
                         */
                        var buttonId = 'CleanWord';
@@ -50,7 +51,8 @@ HTMLArea.TYPO3HtmlParser = function (Plugin, UserAgent) {
                        };
                        this.registerButton(buttonConfiguration);
                },
-               /*
+
+               /**
                 * This function gets called when the button was pressed.
                 *
                 * @param       object          editor: the editor instance
@@ -59,18 +61,24 @@ HTMLArea.TYPO3HtmlParser = function (Plugin, UserAgent) {
                 * @return      boolean         false if action is completed
                 */
                onButtonPress: function (editor, id) {
-                               // Could be a button or its hotkey
+                       // Could be a button or its hotkey
                        var buttonId = this.translateHotKey(id);
                        buttonId = buttonId ? buttonId : id;
                        this.clean();
                        return false;
                },
-               /*
+
+               /**
                 * This function gets called when the editor is generated
                 */
                onGenerate: function () {
-                       this.editor.iframe.mon(Ext.get(UserAgent.isIE ? this.editor.document.body : this.editor.document.documentElement), 'paste', this.wordCleanHandler, this);
+                       var self = this;
+                       Event.on(UserAgent.isIE ? this.editor.document.body : this.editor.document.documentElement, 'paste', function (event) { return self.wordCleanHandler(event); });
                },
+
+               /**
+                * This function posts a cleaning request to the server
+                */
                clean: function() {
                        this.editor.inhibitKeyboardInput = true;
                        var editor = this.editor;
@@ -83,7 +91,7 @@ HTMLArea.TYPO3HtmlParser = function (Plugin, UserAgent) {
                                editorNo : this.editorId,
                                content  : editor.getInnerHTML()
                        };
-                               // Server-based cleaning of pasted content
+                       // Server-based cleaning of pasted content
                        this.postData(  url,
                                        content,
                                        function (options, success, response) {
@@ -106,9 +114,10 @@ HTMLArea.TYPO3HtmlParser = function (Plugin, UserAgent) {
                        window.setTimeout(function () {
                                self.clean();
                        }, 50);
+                       return true;
                }
        });
 
        return TYPO3HtmlParser;
 
-}(HTMLArea.Plugin, HTMLArea.UserAgent);
+}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.Event);
index 467e9f2..5d2f3ff 100644 (file)
@@ -13,7 +13,7 @@
 /**
  * TYPO3Image plugin for htmlArea RTE
  */
-HTMLArea.TYPO3Image = function (Plugin, UserAgent) {
+HTMLArea.TYPO3Image = function (Plugin, UserAgent, Event) {
 
        var TYPO3Image = Ext.extend(Plugin, {
 
@@ -37,7 +37,8 @@ HTMLArea.TYPO3Image = function (Plugin, UserAgent) {
                                license         : 'GPL'
                        };
                        this.registerPluginInformation(pluginInformation);
-                       /*
+
+                       /**
                         * Registering the button
                         */
                        var buttonId = 'InsertImage';
@@ -51,8 +52,9 @@ HTMLArea.TYPO3Image = function (Plugin, UserAgent) {
                        };
                        this.registerButton(buttonConfiguration);
                        return true;
-                },
-               /*
+               },
+
+               /**
                 * This function gets called when the button was pressed
                 *
                 * @param       object          editor: the editor instance
@@ -61,7 +63,7 @@ HTMLArea.TYPO3Image = function (Plugin, UserAgent) {
                 * @return      boolean         false if action is completed
                 */
                onButtonPress: function (editor, id) {
-                               // Could be a button or its hotkey
+                       // Could be a button or its hotkey
                        var buttonId = this.translateHotKey(id);
                        buttonId = buttonId ? buttonId : id;
                        var additionalParameter;
@@ -84,10 +86,12 @@ HTMLArea.TYPO3Image = function (Plugin, UserAgent) {
                                ),
                                this.makeUrlFromModulePath(this.imageModulePath, additionalParameter)
                        );
-                       this.dialog.mon(Ext.get(UserAgent.isIE ? this.editor.document.body : this.editor.document.documentElement), 'drop', this.onDrop, this, {single: true});
+                       var self = this;
+                       Event.one(UserAgent.isIE ? this.editor.document.body : this.editor.document.documentElement, 'drop.TYPO3Image', function (event) { return self.onDrop(event); });
                        return false;
                },
-               /*
+
+               /**
                 * Insert the image
                 * This function is called from the TYPO3 image script
                 */
@@ -96,7 +100,8 @@ HTMLArea.TYPO3Image = function (Plugin, UserAgent) {
                        this.editor.getSelection().insertHtml(image);
                        this.close();
                },
-               /*
+
+               /**
                 * Handlers for drag and drop operations
                 */
                onDrop: function (event) {
@@ -104,6 +109,14 @@ HTMLArea.TYPO3Image = function (Plugin, UserAgent) {
                                this.editor.iframe.onDrop();
                        }
                        this.close();
+                       return true;
+               },
+
+               /**
+                * Remove the event listeners
+                */
+               removeListeners: function () {
+                       Event.off(UserAgent.isIE ? this.editor.document.body : this.editor.document.documentElement, '.TYPO3Image');
                },
 
                /**
@@ -126,4 +139,4 @@ HTMLArea.TYPO3Image = function (Plugin, UserAgent) {
 
        return TYPO3Image;
 
-}(HTMLArea.Plugin, HTMLArea.UserAgent);
+}(HTMLArea.Plugin, HTMLArea.UserAgent, HTMLArea.Event);
index ff1730f..c212a77 100644 (file)
@@ -43,7 +43,7 @@ HTMLArea.UndoRedo = function (Plugin, UserAgent) {
                                license         : 'GPL'
                        };
                        this.registerPluginInformation(pluginInformation);
-                       /*
+                       /**
                         * Registering the buttons
                         */
                        var buttonList = this.buttonList, buttonId;
@@ -62,44 +62,46 @@ HTMLArea.UndoRedo = function (Plugin, UserAgent) {
                        }
                        return true;
                },
-               /*
+
+               /**
                 * The list of buttons added by this plugin
                 */
                buttonList: [
                        ['Undo', null, 'z', 'undo'],
                        ['Redo', null, 'y', 'redo']
                ],
-               /*
+
+               /**
                 * This function gets called when the editor is generated
                 */
                onGenerate: function () {
-                               // Start undo snapshots
-                       if (this.customUndo) {
-                               this.task = {
-                                       run: this.takeSnapshot,
-                                       scope: this,
-                                       interval: this.undoTimeout
-                               };
-                               this.start();
-                       }
+                       // Start undo snapshots
+                       this.start();
                },
-               /*
+
+               /**
                 * Start the undo/redo snapshot task
                 */
                start: function () {
                        if (this.customUndo) {
-                               Ext.TaskMgr.start(this.task);
+                               this.stop();
+                               var self = this;
+                               this.task = window.setInterval(function () {
+                                       self.takeSnapshot();
+                               }, this.undoTimeout);
                        }
                },
-               /*
-                * Start the undo/redo snapshot task
+
+               /**
+                * Stop the undo/redo snapshot task
                 */
                stop: function () {
-                       if (this.customUndo) {
-                               Ext.TaskMgr.stop(this.task);
+                       if (this.customUndo && this.task) {
+                               window.clearInterval(this.task);
                        }
                },
-               /*
+
+               /**
                 * Take a snapshot of the current contents for undo
                 */
                takeSnapshot: function () {