Fixed issue #10847: htmlArea RTE: undo/redo is erratic in IE8
authorStanislas Rolland <typo3@sjbr.ca>
Thu, 9 Apr 2009 16:44:23 +0000 (16:44 +0000)
committerStanislas Rolland <typo3@sjbr.ca>
Thu, 9 Apr 2009 16:44:23 +0000 (16:44 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/branches/TYPO3_4-2@5305 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/mod2/class.tx_rtehtmlarea_acronym_mod.php

index 7c3c93d..923b07c 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 3ac8077..e78e4ce 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 50e537c..a61f7b2 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();
 };
 
 /*
@@ -126,13 +128,13 @@ HTMLArea.prototype.getSelectedHTMLContents = function() {
 HTMLArea.prototype.getParentElement = function(sel) {
        if(!sel) var sel = this._getSelection();
        var range = this._createRange(sel);
-       switch (sel.type) {
-               case "Text":
-               case "None":
+       switch (sel.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;
        }
 };
@@ -147,7 +149,6 @@ HTMLArea.prototype.getParentElement = function(sel) {
 HTMLArea.prototype._activeElement = function(sel) {
        if(sel == null) return null;
        if(this._selectionEmpty(sel)) return null;
-       this.focusEditor();
        if(sel.type.toLowerCase() == "control") {
                return sel.createRange().item(0);
        } else {
index 8820d90..acc1f55 100644 (file)
@@ -1586,7 +1586,11 @@ HTMLArea.prototype.buildUndoSnapshot = function () {
                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
                        try {
-                               bookmark = this.getBookmark(this._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.hasOpenedWindow() || selection.type.toLowerCase() != "none") {
+                                       bookmark = this.getBookmark(this._createRange(selection));
+                               }
                        } catch (e) {
                                bookmark = null;
                        }
@@ -1647,6 +1651,20 @@ HTMLArea.prototype.redo = 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) {
@@ -3697,7 +3715,9 @@ HTMLArea.Dialog = HTMLArea.Base.extend({
         * @return      void
         */
        focus : function () {
-               this.dialogWindow.focus();
+               if (this.hasOpenedWindow()) {
+                       this.dialogWindow.focus();
+               }
        },
 
        /**
@@ -3805,10 +3825,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 20b5278..9f98298 100644 (file)
@@ -1,7 +1,7 @@
 /***************************************************************
 *  Copyright notice
 *
-*  (c) 2005-2008 Stanislas Rolland <typo3(arobas)sjbr.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
@@ -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 && editor._statusBarTree.selected) {
+                       this.abbr = editor._statusBarTree.selected;
+               }
+               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 f4ef44c..695078d 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-2008 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 b5fe4d2..f33d0ac 100644 (file)
@@ -59,28 +59,13 @@ class tx_rtehtmlarea_acronym_mod {
                $JScode='
                        var dialog = window.opener.HTMLArea.Dialog.Acronym;
                        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 && editor._statusBarTree.selected) {
-                               abbr = editor._statusBarTree.selected;
-                       }
-                       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) {
                                        abbrType = "acronym";
@@ -170,8 +155,7 @@ class tx_rtehtmlarea_acronym_mod {
                                                        html = document.content.acronymSelector.options[document.content.acronymSelector.selectedIndex].value;
                                                }
                                                abbr.innerHTML = html;
-                                               if (HTMLArea.is_ie) range.pasteHTML(abbr.outerHTML);
-                                                       else editor.insertNodeAtSelection(abbr);
+                                               editor.insertNodeAtSelection(abbr);
                                        } else {
                                                abbr.title = title;
                                                if(document.content.acronymSelector.options.length != 1 && document.content.termSelector.selectedIndex > 0 && document.content.termSelector.options[document.content.termSelector.selectedIndex].value == title) abbr.innerHTML = document.content.acronymSelector.options[document.content.acronymSelector.selectedIndex].value;