Fixed issue #10847: htmlArea RTE: undo/redo is erratic in IE8
authorStanislas Rolland <typo3@sjbr.ca>
Thu, 9 Apr 2009 16:57:19 +0000 (16:57 +0000)
committerStanislas Rolland <typo3@sjbr.ca>
Thu, 9 Apr 2009 16:57:19 +0000 (16:57 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@5306 709f56b5-9817-0410-a4d7-c38de5d9e867

ChangeLog
typo3/sysext/rtehtmlarea/ChangeLog
typo3/sysext/rtehtmlarea/htmlarea/htmlarea-ie.js
typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/Acronym/acronym.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/CharacterMap/character-map.js
typo3/sysext/rtehtmlarea/htmlarea/plugins/UndoRedo/undo-redo.js
typo3/sysext/rtehtmlarea/mod2/class.tx_rtehtmlarea_acronym_mod.php

index dcfb18d..560de0f 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2009-04-09  Stanislas Rolland  <typo3@sjbr.ca>
+
+       * Fixed issue #10847: htmlArea RTE: undo/redo is erratic in IE8
+
 2009-04-09  Oliver Hader  <oliver@typo3.org>
 
        * Fixed bug #8882: drag & drop of section elements and IRRE records does not work if frame has to be scrolled (thanks to Sebastian Fuchs & Helmut Hummel)
index 754f272..cbb67eb 100644 (file)
@@ -1,3 +1,7 @@
+2009-04-09  Stanislas Rolland  <typo3@sjbr.ca>
+
+       * Fixed issue #10847: htmlArea RTE: undo/redo is erratic in IE8
+
 2009-04-06  Stanislas Rolland  <typo3@sjbr.ca>
 
        * Follow-up to issue #10834: htmlArea RTE: IE8 now uses standard name for DOM class attribute
index 6f53f65..b328f44 100644 (file)
@@ -53,11 +53,13 @@ HTMLArea.prototype._getSelection = function() {
  * Create a range for the current selection
  */
 HTMLArea.prototype._createRange = function(sel) {
-       this.focusEditor();
-       if (typeof(sel) != "undefined") {
-               return sel.createRange();
+       if (typeof(sel) == "undefined") {
+               var sel = this._getSelection();
+       }
+       if (sel.type.toLowerCase() == "none") {
+               this.focusEditor();
        }
-       return this._doc.selection.createRange();
+       return sel.createRange();
 };
 
 /*
@@ -130,13 +132,13 @@ HTMLArea.prototype.getParentElement = function(selection, range) {
        if (typeof(range) === "undefined") {
                var range = this._createRange(selection);
        }
-       switch (selection.type) {
-               case "Text":
-               case "None":
+       switch (selection.type.toLowerCase()) {
+               case "text":
+               case "none":
                        var el = range.parentElement();
                        if(el.nodeName.toLowerCase() == "li" && range.htmlText.replace(/\s/g,"") == el.parentNode.outerHTML.replace(/\s/g,"")) return el.parentNode;
                        return el;
-               case "Control": return range.item(0);
+               case "control": return range.item(0);
                default: return this._doc.body;
        }
 };
@@ -149,10 +151,13 @@ HTMLArea.prototype.getParentElement = function(selection, range) {
  * Borrowed from Xinha (is not htmlArea) - http://xinha.gogo.co.nz/
  */
 HTMLArea.prototype._activeElement = function(sel) {
-       if(sel == null) return null;
-       if(this._selectionEmpty(sel)) return null;
-       this.focusEditor();
-       if(sel.type.toLowerCase() == "control") {
+       if (sel == null) {
+               return null;
+       }
+       if (this._selectionEmpty(sel)) {
+               return null;
+       }
+       if (sel.type.toLowerCase() == "control") {
                return sel.createRange().item(0);
        } else {
                        // If it's not a control, then we need to see if the selection is the _entire_ text of a parent node
index b84f9ac..88a038d 100644 (file)
@@ -1450,6 +1450,20 @@ HTMLArea.prototype.focusEditor = function() {
 };
 
 /*
+ * Check if any plugin has an opened window
+ */
+HTMLArea.prototype.hasOpenedWindow = function () {
+       for (var plugin in this.plugins) {
+               if (this.plugins.hasOwnProperty(plugin)) {
+                       if (HTMLArea.Dialog[plugin.name] && HTMLArea.Dialog[plugin.name].hasOpenedWindow && HTMLArea.Dialog[plugin.name].hasOpenedWindow()) {
+                               return true;
+                       }
+               }
+       }
+       return false
+};
+
+/*
  * Update the enabled/disabled/active state of the toolbar elements
  */
 HTMLArea.updateToolbar = function(editorNumber) {
@@ -3527,7 +3541,9 @@ HTMLArea.Dialog = HTMLArea.Base.extend({
         * @return      void
         */
        focus : function () {
-               this.dialogWindow.focus();
+               if (this.hasOpenedWindow()) {
+                       this.dialogWindow.focus();
+               }
        },
 
        /**
@@ -3636,10 +3652,8 @@ HTMLArea.Dialog = HTMLArea.Base.extend({
                this.escapeFunctionReference = this.makeFunctionReference("closeOnEscape");
                HTMLArea._addEvent(this.dialogWindow.document, "keypress", this.escapeFunctionReference);
                        // Capture focus events on the opener window and its frames
-               if (HTMLArea.is_gecko) {
-                       this.recoverFocusFunctionReference = this.makeFunctionReference("recoverFocus");
-                       this.captureFocus(this.dialogWindow.opener);
-               }
+               this.recoverFocusFunctionReference = this.makeFunctionReference("recoverFocus");
+               this.captureFocus(this.dialogWindow.opener);
         },
 
        /**
index e976391..b8288d1 100644 (file)
@@ -83,6 +83,23 @@ Acronym = HTMLArea.Plugin.extend({
         * @return      boolean         false if action is completed
         */
        onButtonPress : function(editor, id) {
+               var selection = editor._getSelection();
+               var html = editor.getSelectedHTML();
+               this.abbr = editor._activeElement(selection);
+               this.abbrType = null;
+                       // Working around Safari issue
+               if (!this.abbr && this.getPluginInstance("StatusBar") && this.getPluginInstance("StatusBar").getSelection()) {
+                       this.abbr = this.getPluginInstance("StatusBar").getSelection();
+               }
+               if (!(this.abbr != null && /^(acronym|abbr)$/i.test(this.abbr.nodeName))) {
+                       this.abbr = editor._getFirstAncestor(selection, ["acronym", "abbr"]);
+               }
+               if (this.abbr != null && /^(acronym|abbr)$/i.test(this.abbr.nodeName)) {
+                       this.param = { title : this.abbr.title, text : this.abbr.innerHTML};
+                       this.abbrType = this.abbr.nodeName.toLowerCase();
+               } else {
+                       this.param = { title : "", text : html};
+               }
                this.dialog = this.openDialog("Acronym", this.makeUrlFromModulePath(this.acronymModulePath), null, null, {width:580, height:280});
                return false;
        },
@@ -112,6 +129,9 @@ Acronym = HTMLArea.Plugin.extend({
                                        this.editor._toolbarObjects[buttonId].state("enabled", !((el.nodeName.toLowerCase() == "acronym" && this.pageTSConfiguration.noAcronym) || (el.nodeName.toLowerCase() == "abbr" && this.pageTSConfiguration.noAbbr)));
                                        this.editor._toolbarObjects[buttonId].state("active", ((el.nodeName.toLowerCase() == "acronym" && !this.pageTSConfiguration.noAcronym) || (el.nodeName.toLowerCase() == "abbr" && !this.pageTSConfiguration.noAbbr)));
                                }
+                               if (this.dialog) {
+                                       this.dialog.focus();
+                               }
                        }
                }
        }
index 2ac1943..50a9b82 100644 (file)
@@ -3,7 +3,7 @@
 *
 *  (c) 2004 Bernhard Pfeifer novocaine@gmx.net
 *  (c) 2004 systemconcept.de. Authored by Holger Hees based on HTMLArea XTD 1.5 (http://mosforge.net/projects/htmlarea3xtd/).
-*  (c) 2005-2009 Stanislas Rolland <stanislas.rolland(arobas)fructifor.ca>
+*  (c) 2005-2009 Stanislas Rolland <typo3(arobas)sjbr.ca>
 *  All rights reserved
 *
 *  This script is part of the TYPO3 project. The TYPO3 project is
@@ -95,11 +95,22 @@ CharacterMap = HTMLArea.Plugin.extend({
         */
        insertCharacter : function(entity) {
                if (typeof(entity) != "undefined") {
-                       this.editor.focusEditor();
                        this.editor.insertHTML(entity);
                        this.dialog.focus();
                }
                return false;
+       },
+
+       /*
+        * This function gets called when the toolbar is updated
+        *
+        * @return      void
+        */
+       onUpdateToolbar : function () {
+                       // Reclaim focus
+               if (this.dialog) {
+                       this.dialog.focus();
+               }
        }
 });
 
index 0b04c35..312f194 100644 (file)
@@ -154,7 +154,7 @@ UndoRedo = HTMLArea.Plugin.extend({
                        }
                }
        },
-       
+
        /*
         * Build the snapshot entry
         *
@@ -169,9 +169,13 @@ UndoRedo = HTMLArea.Plugin.extend({
                if (this.editor.getMode() == "wysiwyg" && this.editor.isEditable()) {
                        var selection = this.editor._getSelection();
                        if ((HTMLArea.is_gecko && !HTMLArea.is_opera) || (HTMLArea.is_ie && selection.type.toLowerCase() != "control")) {
-                                       // catch error in FF when the selection contains no usable range
+                                       // Catch error in FF when the selection contains no usable range
                                try {
-                                       bookmark = this.editor.getBookmark(this.editor._createRange(selection));
+                                               // Work around IE8 bug: can't create a range correctly if the selection is empty and the focus is not on the editor window
+                                               // But we cannot grab focus from an opened window just for the sake of taking this bookmark
+                                       if (!HTMLArea.is_ie || !this.editor.hasOpenedWindow() || selection.type.toLowerCase() != "none") {
+                                               bookmark = this.editor.getBookmark(this.editor._createRange(selection));
+                                       }
                                } catch (e) {
                                        bookmark = null;
                                }
index e867216..d82e1f4 100644 (file)
@@ -59,27 +59,12 @@ class tx_rtehtmlarea_acronym_mod {
                        var dialog = window.opener.HTMLArea.Dialog.Acronym;
                        var plugin = dialog.plugin;
                        var editor = dialog.plugin.editor;
-                       var param = null;
-                       var html = editor.getSelectedHTML();
-                       var sel = editor._getSelection();
-                       var range = editor._createRange(sel);
-                       var abbr = editor._activeElement(sel);
-                               // Working around Safari issue
-                       if (!abbr && plugin.getPluginInstance("StatusBar") && plugin.getPluginInstance("StatusBar").getSelection()) {
-                               abbr = plugin.getPluginInstance("StatusBar").getSelection();
-                       }
-                       var abbrType = null;
-                       var acronyms = new Object();
-                       var abbreviations = new Object();
-                       if (!(abbr != null && /^(acronym|abbr)$/i.test(abbr.nodeName))) {
-                               abbr = editor._getFirstAncestor(sel, ["acronym", "abbr"]);
-                       }
-                       if (abbr != null && /^(acronym|abbr)$/i.test(abbr.nodeName)) {
-                               param = { title : abbr.title, text : abbr.innerHTML};
-                               abbrType = abbr.nodeName.toLowerCase();
-                       } else {
-                               param = { title : "", text : html};
-                       }
+                       var param = dialog.plugin.param,
+                               abbr = dialog.plugin.abbr,
+                               abbrType = dialog.plugin.abbrType,
+                               html = "",
+                               acronyms = new Object(),
+                               abbreviations = new Object();
 
                        function setType() {
                                if (document.content.acronym.checked) {
@@ -186,8 +171,7 @@ class tx_rtehtmlarea_acronym_mod {
                                                if (languageObject && plugin.isButtonInToolbar("Language")) {
                                                        languageObject.setLanguageAttributes(abbr, language);
                                                }
-                                               if (HTMLArea.is_ie) range.pasteHTML(abbr.outerHTML);
-                                                       else editor.insertNodeAtSelection(abbr);
+                                               editor.insertNodeAtSelection(abbr);
                                        } else {
                                                abbr.title = title;
                                                if (languageObject && plugin.isButtonInToolbar("Language")) {