* Feature #6769: Enable htmlArea RTE in Safari
authorStanislas Rolland <typo3@sjbr.ca>
Mon, 19 Nov 2007 23:40:11 +0000 (23:40 +0000)
committerStanislas Rolland <typo3@sjbr.ca>
Mon, 19 Nov 2007 23:40:11 +0000 (23:40 +0000)
git-svn-id: https://svn.typo3.org/TYPO3v4/Core/trunk@2735 709f56b5-9817-0410-a4d7-c38de5d9e867

ChangeLog
typo3/sysext/rtehtmlarea/ChangeLog
typo3/sysext/rtehtmlarea/class.tx_rtehtmlarea_base.php
typo3/sysext/rtehtmlarea/ext_localconf.php
typo3/sysext/rtehtmlarea/htmlarea/htmlarea-gecko.js
typo3/sysext/rtehtmlarea/htmlarea/htmlarea.js

index a6e52ca..f0bb7ed 100755 (executable)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2007-11-19  Stanislas Rolland  <stanislas.rolland@fructifor.ca>
+
+       * Feature #6769: Enable htmlArea RTE in Safari
+
 2007-11-19  Oliver Hader  <oh@inpublica.de>
 
        * (feature) Added feature #6734: Integrate post processing for links handled by typoLink
index d6968ee..49159f0 100644 (file)
@@ -1,3 +1,7 @@
+2007-11-19  Stanislas Rolland  <stanislas.rolland@fructifor.ca>
+
+       * Feature #6769: Enable htmlArea RTE in Safari
+
 2007-11-16  Stanislas Rolland  <stanislas.rolland@fructifor.ca>
 
        * Feature/bugfix: Change to the initialisation sequence of htmlArea RTE
index 451bda8..16c0da5 100644 (file)
@@ -55,7 +55,7 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
                        ),
                        'safari' => array (
                                1 => array (
-                                       'version' => 312
+                                       'version' => 523
                                )
                        ),
                        'opera' => array (
@@ -72,7 +72,7 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
        
                // Hide toolbar buttons not implemented in client browsers
        var $hideButtonsFromClient = array (
-               'safari'        =>      array('strikethrough', 'line', 'orderedlist', 'unorderedlist'),
+               'safari'        =>      array('paste'),
                'opera'         =>      array('copy', 'cut', 'paste'),
                );
        
@@ -195,13 +195,13 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
                );
        
        var $defaultFontSizes_safari = array(
-               '1'     =>      'xx-small',
-               '2'     =>      'x-small',
-               '3'     =>      'small',
-               '4'     =>      'medium',
-               '5'     =>      'large',
-               '6'     =>      'x-large',
-               '7'     =>      'xx-large',
+               '1'     =>      'x-small (10px)',
+               '2'     =>      'small (13px)',
+               '3'     =>      'medium (16px)',
+               '4'     =>      'large (18px)',
+               '5'     =>      'x-large (24px)',
+               '6'     =>      'xx-large (32px)',
+               '7'     =>      'xxx-large (48px)',
                );
        
        var $pluginList = 'TableOperations, ContextMenu, SpellChecker, SelectColor, TYPO3Browsers, InsertSmiley, FindReplace, RemoveFormat, CharacterMap, QuickTag, DynamicCSS, UserElements, Acronym, TYPO3HtmlParser';
@@ -528,7 +528,7 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
                                // Preloading the pageStyle
                        $filename = trim($this->thisConfig['contentCSS']) ? trim($this->thisConfig['contentCSS']) : 'EXT:' . $this->ID . '/htmlarea/plugins/DynamicCSS/dynamiccss.css';
                        $this->TCEform->additionalCode_pre['loadCSS'] = '
-               <link rel="alternate stylesheet" type="text/css" href="' . $this->getFullFileName($filename) . '" />';
+               <link rel="alternate stylesheet" type="text/css" href="' . $this->getFullFileName($filename) . '" title="HTMLArea RTE Content CSS" />';
 
                                // Loading the editor skin
                        $skinFilename = trim($this->thisConfig['skin']) ? trim($this->thisConfig['skin']) : 'EXT:' . $this->ID . '/htmlarea/skins/default/htmlarea.css';
@@ -1211,7 +1211,7 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
                
                foreach ($this->defaultFontSizes as $FontSizeItem => $FontSizeLabel) {
                        if ($this->client['BROWSER'] == 'safari') {
-                               $HTMLAreaFontSizes[$this->defaultFontSizes_safari[$FontSizeItem]] = $FontSizeLabel;
+                               $HTMLAreaFontSizes[$FontSizeItem] = $this->defaultFontSizes_safari[$FontSizeItem];
                        } else {
                                $HTMLAreaFontSizes[$FontSizeItem] = $FontSizeLabel;
                        }
@@ -1220,13 +1220,7 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
                        $hideFontSizes =  t3lib_div::trimExplode(',', $this->cleanList($this->thisConfig['hideFontSizes']), 1);
                        foreach ($hideFontSizes as $item)  {
                                if ($HTMLAreaFontSizes[strtolower($item)]) {
-                                       if ($this->client['BROWSER'] == 'safari') {
-                                               unset($HTMLAreaFontSizes[$this->defaultFontSizes_safari[strtolower($item)]]);
-                                       } else {
-                                               unset($HTMLAreaFontSizes[strtolower($item)]);
-                                       }
-                               } else {
-                                       
+                                       unset($HTMLAreaFontSizes[strtolower($item)]);
                                }
                        }
                }
@@ -1966,7 +1960,7 @@ class tx_rtehtmlarea_base extends t3lib_rteapi {
                        $bInfo['BROWSER']= 'msie';
                } elseif (strstr($useragent,'Gecko/'))  {
                        $bInfo['BROWSER']='gecko';
-               } elseif (strstr($useragent,'Safari/') &&  $TYPO3_CONF_VARS['EXTCONF']['rtehtmlarea']['safari_test'] == 1) {
+               } elseif (strstr($useragent,'Safari/')) {
                        $bInfo['BROWSER']='safari';
                } elseif (strstr($useragent,'Mozilla/4')) {
                        $bInfo['BROWSER']='net';
index 8f39771..70d530e 100644 (file)
@@ -77,7 +77,6 @@ $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['noSpellCheckLanguages'] = $_EXTCONF["noSp
 if ($_EXTCONF['plainImageMaxWidth']) $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plainImageMaxWidth'] = intval($_EXTCONF['plainImageMaxWidth']);
 if ($_EXTCONF['plainImageMaxHeight']) $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['plainImageMaxHeight'] = intval($_EXTCONF['plainImageMaxHeight']);
 
-//$TYPO3_CONF_VARS['EXTCONF']['rtehtmlarea']['safari_test'] = 0;
 $TYPO3_CONF_VARS['EXTCONF'][$_EXTKEY]['enableInOpera9'] = $_EXTCONF['enableInOpera9'] ? $_EXTCONF['enableInOpera9'] : 0;
 
        // Add default RTE transformation configuration
index 9b56c2c..3095b6a 100644 (file)
@@ -92,7 +92,6 @@ HTMLArea.prototype._initEditMode = function () {
  * Get the current selection object
  */
 HTMLArea.prototype._getSelection = function() {
-       if (HTMLArea.is_safari) return window.getSelection();
        return this._iframe.contentWindow.getSelection();
 };
 
@@ -102,21 +101,21 @@ HTMLArea.prototype._getSelection = function() {
 HTMLArea.prototype._createRange = function(sel) {
        if (HTMLArea.is_safari) {
                var range = this._doc.createRange();
-               if (typeof(sel) == "undefined") return range;
-               switch (sel.type) {
-                       case "Range": 
-                               range.setStart(sel.baseNode,sel.baseOffset);
-                               range.setEnd(sel.extentNode,sel.extentOffset);
-                               break;
-                       case "Caret":
-                               range.setStart(sel.baseNode,sel.baseOffset);
-                               range.setEnd(sel.baseNode,sel.baseOffset);
-                               break;
-                       case "None":
-                               range.setStart(this._doc.body,0);
-                               range.setEnd(this._doc.body,0);
+               if (typeof(sel) == "undefined") {
+                       return range;
+               } else if (sel.baseNode == null) {
+                       range.setStart(this._doc.body,0);
+                       range.setEnd(this._doc.body,0);
+                       return range;
+               } else {
+                       range.setStart(sel.baseNode, sel.baseOffset);
+                       range.setEnd(sel.extentNode, sel.extentOffset);
+                       if (range.collapsed != sel.isCollapsed) {
+                               range.setStart(sel.extentNode, sel.extentOffset);
+                               range.setEnd(sel.baseNode, sel.baseOffset);
+                       }
+                       return range;
                }
-               return range;
        }
        if (typeof(sel) == "undefined") return this._doc.createRange();
        try {
@@ -169,9 +168,11 @@ HTMLArea.prototype.selectNodeContents = function(node,pos) {
 HTMLArea.prototype.getSelectedHTML = function() {
        var sel = this._getSelection();
        var range = this._createRange(sel);
-       var cloneContents = "";
-       try {cloneContents = range.cloneContents();} catch(e) { }
-       return (cloneContents ? HTMLArea.getHTML(cloneContents,false,this) : "");
+       var cloneContents = range.cloneContents();
+       if (!cloneContents) {
+               cloneContents = this._doc.createDocumentFragment();
+       }
+       return HTMLArea.getHTML(cloneContents, false, this);
 };
 
 /*
@@ -185,14 +186,21 @@ HTMLArea.prototype.getSelectedHTMLContents = function() {
  * Get the deepest node that contains both endpoints of the current selection.
  */
 HTMLArea.prototype.getParentElement = function(sel,range) {
-       if(!sel) var sel = this._getSelection();
-       if (typeof(range) == "undefined") var range = this._createRange(sel);
+       if (!sel) {
+               var sel = this._getSelection();
+       }
+       if (typeof(range) === "undefined") {
+               var range = this._createRange(sel);
+       }
        try {
                var p = range.commonAncestorContainer;
-               if(!range.collapsed && range.startContainer == range.endContainer &&
-                   range.startOffset - range.endOffset <= 1 && range.startContainer.hasChildNodes())
+               if (!range.collapsed && range.startContainer == range.endContainer &&
+                               range.startOffset - range.endOffset <= 1 && range.startContainer.hasChildNodes()) {
                        p = range.startContainer.childNodes[range.startOffset];
-               while (p.nodeType == 3) {p = p.parentNode;}
+               }
+               while (p.nodeType == 3) {
+                       p = p.parentNode;
+               }
                return p;
        } catch (e) {
                return this._doc.body;
index 7451dd8..66585f2 100644 (file)
@@ -1031,12 +1031,12 @@ HTMLArea.prototype.initIframe = function() {
        if (!this._iframe || (!this._iframe.contentWindow && !this._iframe.contentDocument)) {
                this._initIframeTimer = window.setTimeout("HTMLArea.initIframe(" + this._editorNumber + ");", 50);
                return false;
-       } else if (this._iframe.contentWindow) {
+       } else if (this._iframe.contentWindow && !HTMLArea.is_safari) {
                if (!this._iframe.contentWindow.document || !this._iframe.contentWindow.document.documentElement) {
                        this._initIframeTimer = window.setTimeout("HTMLArea.initIframe(" + this._editorNumber + ");", 50);
                        return false;
                }
-       } else if (!this._iframe.contentDocument.documentElement) {
+       } else if (!this._iframe.contentDocument.documentElement || !this._iframe.contentDocument.body) {
                this._initIframeTimer = window.setTimeout("HTMLArea.initIframe(" + this._editorNumber + ");", 50);
                return false;
        }
@@ -1141,9 +1141,17 @@ HTMLArea.prototype.stylesLoaded = function() {
 
                // Set contents editable
        if (docWellFormed) {
-               if (HTMLArea.is_gecko && !HTMLArea.is_safari && !HTMLArea.is_opera && !this._initEditMode()) return false;
-               if (HTMLArea.is_opera) doc.designMode = "on";
-               if (HTMLArea.is_ie || HTMLArea.is_safari) doc.body.contentEditable = true;
+               if (HTMLArea.is_gecko && !HTMLArea.is_safari && !HTMLArea.is_opera && !this._initEditMode()) {
+                       return false;
+               }
+               if (HTMLArea.is_ie || HTMLArea.is_safari) {
+                       doc.body.contentEditable = true;
+               }
+               if (HTMLArea.is_opera || HTMLArea.is_safari) {
+                       doc.designMode = "on";
+                       if (this._doc.queryCommandEnabled("insertbronreturn")) this._doc.execCommand("insertbronreturn", false, this.config.disableEnterParagraphs);
+                       if (this._doc.queryCommandEnabled("styleWithCSS")) this._doc.execCommand("styleWithCSS", false, this.config.useCSS);
+               }
                if (HTMLArea.is_ie) doc.selection.empty();
                this._editMode = "wysiwyg";
                if (doc.body.contentEditable || doc.designMode == "on") HTMLArea._appendToLog("[HTMLArea::initIframe]: Design mode successfully set.");
@@ -1274,7 +1282,7 @@ HTMLArea.prototype.setMode = function(mode) {
                        }
                        this._textArea.style.display = "none";
                        this._iframe.style.display = "block";
-                       if(HTMLArea.is_gecko && !HTMLArea.is_safari && !HTMLArea.is_opera) this._doc.designMode = "on";
+                       if (HTMLArea.is_gecko && !HTMLArea.is_safari && !HTMLArea.is_opera) this._doc.designMode = "on";
                        if(this.config.statusBar) {
                                this._statusBar.innerHTML = "";
                                this._statusBar.appendChild(this._statusBarTree);
@@ -1290,7 +1298,7 @@ HTMLArea.prototype.setMode = function(mode) {
                default:
                        return false;
        }
-       if (!(mode == "docnotwellformedmode")) this.focusEditor();
+       if (mode !== "docnotwellformedmode") this.focusEditor();
        for (var pluginId in this.plugins) {
                if (this.plugins.hasOwnProperty(pluginId)) {
                        var pluginInstance = this.plugins[pluginId].instance;
@@ -1513,7 +1521,7 @@ HTMLArea.cleanWordOnPaste = function(ev) {
                owner = owner.parentElement;
        }
                // if we dropped an image dragged from the TYPO3 Browser, let's close the browser window
-       if (typeof(browserWin) != "undefined") browserWin.close();
+       if (typeof(browserWin) != "undefined" && browserWin.close) browserWin.close();
        window.setTimeout("HTMLArea.wordCleanLater(" + owner._editorNo + ", true);", 250);
 };
 
@@ -1528,9 +1536,14 @@ HTMLArea.prototype.forceRedraw = function() {
 HTMLArea.prototype.focusEditor = function() {
        switch (this._editMode) {
                case "wysiwyg" :
-                       try { 
-                               if (HTMLArea.is_safari || HTMLArea.is_opera) this._doc.focus();
-                                       else this._iframe.contentWindow.focus();
+                       try {
+                               if (HTMLArea.is_safari) {
+                                       this._iframe.focus();
+                               } else if (HTMLArea.is_opera) {
+                                       this._doc.focus();
+                               } else {
+                                       this._iframe.contentWindow.focus();
+                               }
                        } catch(e) { };
                        break;
                case "textmode":
@@ -1623,10 +1636,11 @@ HTMLArea.updateToolbar = function(editorNumber) {
 HTMLArea.prototype.updateToolbar = function(noStatus) {
        var doc = this._doc,
                text = (this._editMode == "textmode"),
-               selection = this.hasSelectedText(),
+               selection = false,
                ancestors = null, cls = new Array(),
                txt, txtClass, i, inContext, match, matchAny, k, j, n, commandState;
        if(!text) {
+               selection = this.hasSelectedText();
                ancestors = this.getAllAncestors();
                if(this.config.statusBar && !noStatus) {
                                // Unhook previous events handlers
@@ -1721,7 +1735,7 @@ HTMLArea.prototype.updateToolbar = function(noStatus) {
                                case "FontName":
                                case "FontSize":
                                        if(!text) try {
-                                               var value = ("" + doc.queryCommandValue(cmd)).toLowerCase();
+                                               var value = ("" + doc.queryCommandValue(cmd)).trim().toLowerCase().replace(/\'/g, "");
                                                if(!value) {
                                                        document.getElementById(btn.elementId).selectedIndex = 0;
                                                        break;
@@ -1731,7 +1745,9 @@ HTMLArea.prototype.updateToolbar = function(noStatus) {
                                                k = 0;
                                                for (var j in options) {
                                                        if (options.hasOwnProperty(j)) {
-                                                               if((j.toLowerCase() == value) || (options[j].substr(0, value.length).toLowerCase() == value)) {
+                                                               if ((j.toLowerCase().indexOf(value) !== -1)
+                                                                               || (options[j].trim().substr(0, value.length).toLowerCase() == value)
+                                                                               || ((cmd === "FontName") && (options[j].toLowerCase().indexOf(value) !== -1))) {
                                                                        document.getElementById(btn.elementId).selectedIndex = k;
                                                                        throw "ok";
                                                                }
@@ -1742,19 +1758,21 @@ HTMLArea.prototype.updateToolbar = function(noStatus) {
                                        } catch(e) {}
                                        break;
                                case "FormatBlock":
-                                       var blocks = [ ];
-                                       for (var j in this.config['FormatBlock']) {
-                                               if (this.config['FormatBlock'].hasOwnProperty(j)) {
-                                                       blocks[blocks.length] = this.config['FormatBlock'][j];
+                                       if (!text) {
+                                               var blocks = [ ];
+                                               for (var j in this.config['FormatBlock']) {
+                                                       if (this.config['FormatBlock'].hasOwnProperty(j)) {
+                                                               blocks[blocks.length] = this.config['FormatBlock'][j];
+                                                       }
                                                }
-                                       }
-                                       var deepestAncestor = this._getFirstAncestor(this._getSelection(), blocks);
-                                       if(deepestAncestor) {
-                                               for(var x= 0; x < blocks.length; x++) {
-                                                       if(blocks[x].toLowerCase() == deepestAncestor.tagName.toLowerCase()) document.getElementById(btn.elementId).selectedIndex = x;
+                                               var deepestAncestor = this._getFirstAncestor(this._getSelection(), blocks);
+                                               if(deepestAncestor) {
+                                                       for(var x= 0; x < blocks.length; x++) {
+                                                               if(blocks[x].toLowerCase() == deepestAncestor.tagName.toLowerCase()) document.getElementById(btn.elementId).selectedIndex = x;
+                                                       }
+                                               } else {
+                                                       document.getElementById(btn.elementId).selectedIndex = 0;
                                                }
-                                       } else {
-                                               document.getElementById(btn.elementId).selectedIndex = 0;
                                        }
                                        break;
                                case "TextIndicator":
@@ -1778,9 +1796,16 @@ HTMLArea.prototype.updateToolbar = function(noStatus) {
                                case "HtmlMode": btn.state("active", text); break;
                                case "LeftToRight":
                                case "RightToLeft":
-                                       var el = this.getParentElement();
-                                       while (el && !HTMLArea.isBlockElement(el)) { el = el.parentNode; }
-                                       if (el) btn.state("active",(el.style.direction == ((cmd == "RightToLeft") ? "rtl" : "ltr")));
+                                       if (!text) {
+                                               var el = this.getParentElement();
+                                               while (el && !HTMLArea.isBlockElement(el)) { el = el.parentNode; }
+                                               if (el) btn.state("active",(el.style.direction == ((cmd == "RightToLeft") ? "rtl" : "ltr")));
+                                               break;
+                                       }
+                               case "Paste":
+                                       if(!text) {
+                                               btn.state("enabled", doc.queryCommandEnabled('Paste'));
+                                       }
                                        break;
                                case "JustifyLeft":
                                case "JustifyCenter":
@@ -1887,7 +1912,7 @@ HTMLArea.prototype.hasSelectedText = function() {
 HTMLArea.prototype.getAllAncestors = function() {
        var p = this.getParentElement();
        var a = [];
-       while (p && (p.nodeType == 1) && (p.tagName.toLowerCase() != 'body')) {
+       while (p && (p.nodeType === 1) && (p.nodeName.toLowerCase() !== "body")) {
                a.push(p);
                p = p.parentNode;
        }
@@ -2228,7 +2253,7 @@ HTMLArea.prototype.execCommand = function(cmdID, UI, param) {
            case "Copy"         :
            case "Paste"        :
                try {
-                       this._doc.execCommand(cmdID,false,null);
+                       this._doc.execCommand(cmdID, false, null);
                        if (cmdID == "Paste" && this.config.cleanWordOnPaste) HTMLArea._wordClean(this, this._doc.body);
                } catch (e) {
                        if (HTMLArea.is_gecko && !HTMLArea.is_safari && !HTMLArea.is_opera) this._mozillaPasteException(cmdID, UI, param);
@@ -2460,9 +2485,13 @@ HTMLArea.prototype.scrollToCaret = function() {
 HTMLArea.prototype.getHTML = function() {
        switch (this._editMode) {
                case "wysiwyg":
-                       if(!this.config.fullPage) { return HTMLArea.getHTML(this._doc.body,false,this); }
-                               else { return this.doctype + "\n" + HTMLArea.getHTML(this._doc.documentElement,true,this); }
-               case "textmode": return this._textArea.value;
+                       if (!this.config.fullPage) {
+                               return HTMLArea.getHTML(this._doc.body, false, this);
+                       } else {
+                               return this.doctype + "\n" + HTMLArea.getHTML(this._doc.documentElement,true,this);
+                       }
+               case "textmode":
+                       return this._textArea.value;
        }
        return false;
 };
@@ -2679,7 +2708,7 @@ HTMLArea.htmlEncode = function(str) {
  * Wrapper catches a Mozilla-Exception with non well-formed html source code.
  */
 HTMLArea.getHTML = function(root, outputRoot, editor){
-       try { 
+       try {
                return HTMLArea.getHTMLWrapper(root,outputRoot,editor); 
        } catch(e) {
                HTMLArea._appendToLog("The HTML document is not well-formed.");