[TASK] RTE: Use CSS3 resize when possible 25/36225/3
authorStanislas Rolland <typo3@sjbr.ca>
Sat, 24 Jan 2015 03:59:52 +0000 (22:59 -0500)
committerStanislas Rolland <typo3@sjbr.ca>
Sat, 24 Jan 2015 04:07:02 +0000 (05:07 +0100)
This works fine in Firefox. In all other browsers, we need to fallback
to jQuery UI Resizable, because IE 11 does not support this property,
and in WebKit and Opera there are bugs in this special case in
Mutation Observer (required to resize the iframe which does not
follow automatically).

Releases: master
Resolves: #64470
Change-Id: Iac1f4d721908967f2bc10429c6a3b716eb33adbe
Reviewed-on: http://review.typo3.org/36225
Reviewed-by: Stanislas Rolland <typo3@sjbr.ca>
Tested-by: Stanislas Rolland <typo3@sjbr.ca>
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/Editor/Framework.js
typo3/sysext/rtehtmlarea/Resources/Public/JavaScript/HTMLArea/Util/Util.js

index 29029d2..b1f9e0a 100644 (file)
  * Framework is the visual component of the Editor and contains the tool bar, the iframe, the textarea and the status bar
  */
 define('TYPO3/CMS/Rtehtmlarea/HTMLArea/Editor/Framework',
-       ['TYPO3/CMS/Rtehtmlarea/HTMLArea/Util/Util',
+       ['TYPO3/CMS/Rtehtmlarea/HTMLArea/UserAgent/UserAgent',
+       'TYPO3/CMS/Rtehtmlarea/HTMLArea/Util/Util',
        'TYPO3/CMS/Rtehtmlarea/HTMLArea/Util/Resizable',
        'TYPO3/CMS/Rtehtmlarea/HTMLArea/DOM/DOM',
        'TYPO3/CMS/Rtehtmlarea/HTMLArea/Util/TYPO3',
        'TYPO3/CMS/Rtehtmlarea/HTMLArea/Event/Event'],
-       function (Util, Resizable, Dom, Typo3, Event) {
+       function (UserAgent, Util, Resizable, Dom, Typo3, Event) {
 
        /**
         * Framework constructor
@@ -209,34 +210,63 @@ define('TYPO3/CMS/Rtehtmlarea/HTMLArea/Editor/Framework',
                makeResizable: function () {
                        if (this.resizable) {
                                var self = this;
-                               this.resizer = Resizable.makeResizable(this.getEl(), {
-                                       delay: 150,
-                                       minHeight: 200,
-                                       minWidth: 300,
-                                       alsoResize: '#' + this.editorId + '-iframe',
-                                       maxHeight: this.maxHeight,
-                                       start: function (event, ui) {
-                                               Event.stopEvent(event);
-                                               self.isResizing = true;
-                                               return false;
-                                       },
-                                       resize: function (event, ui) {
-                                               Event.stopEvent(event);
-                                               self.doHtmlAreaResize(ui.size);
-                                               return false;
-                                       },
-                                       stop: function (event, ui) {
-                                               Event.stopEvent(event);
-                                               self.isResizing = false;
-                                               self.doHtmlAreaResize(ui.size);
-                                               return false;
+                               // Mutation observer will not work in WebKit on manual resize: https://code.google.com/p/chromium/issues/detail?id=293948
+                               // The same is true in Opera 26
+                               if (Util.testCssPropertySupport(this.getEl(), 'resize', 'both') && typeof MutationObserver === 'function' && !UserAgent.isWebKit && !UserAgent.isOpera) {
+                                       this.getEl().style['resize'] = 'both';
+                                       this.getEl().style['maxHeight'] = this.maxHeight;
+                                       // WebKit adds scollbars
+                                       this.getEl().style['overflow'] = UserAgent.isWebKit ? 'hidden' : 'auto';
+                                       // For WebKit, we need to reset the resize property set by default on textareas and iframes
+                                       if (UserAgent.isWebKit) {
+                                               this.textArea.style['resize'] = 'none';
+                                               this.iframe.getEl().style['resize'] = 'none';
                                        }
-                               });
+                                       this.mutationObserver = new MutationObserver(function (mutations) { self.onSizeMutation(mutations); });
+                                       var options = {
+                                               attributes: true,
+                                               attributeFilter: ['style']
+                                       };
+                                       this.mutationObserver.observe(this.getEl(), options);
+                               } else {
+                                       this.resizer = Resizable.makeResizable(this.getEl(), {
+                                               delay: 150,
+                                               minHeight: 200,
+                                               minWidth: 300,
+                                               alsoResize: '#' + this.editorId + '-iframe',
+                                               maxHeight: this.maxHeight,
+                                               start: function (event, ui) {
+                                                       Event.stopEvent(event);
+                                                       self.isResizing = true;
+                                                       return false;
+                                               },
+                                               resize: function (event, ui) {
+                                                       Event.stopEvent(event);
+                                                       self.doHtmlAreaResize(ui.size);
+                                                       return false;
+                                               },
+                                               stop: function (event, ui) {
+                                                       Event.stopEvent(event);
+                                                       self.isResizing = false;
+                                                       self.doHtmlAreaResize(ui.size);
+                                                       return false;
+                                               }
+                                       });
+                               }
+                       }
+               },
+
+               /**
+                * Mutations handler invoked when the framework is resized by css
+                */
+               onSizeMutation: function (mutations) {
+                       for (var i = mutations.length; --i >= 0;) {
+                               this.onFrameworkResize();
                        }
                },
 
                /**
-                * Resize the framework when the resizer handles are used
+                * Resize the framework when the handle is used
                 */
                doHtmlAreaResize: function (size) {
                        Dom.setSize(this.getEl(), size);
@@ -381,6 +411,9 @@ define('TYPO3/CMS/Rtehtmlarea/HTMLArea/Editor/Framework',
                                Event.off(form);
                                form.htmlAreaPreviousOnReset = null;
                        }
+                       if (this.mutationObserver) {
+                               this.mutationObserver.disconnect();
+                       }
                        if (this.resizer) {
                                Resizable.destroy(this.resizer);
                        }
index ff3864e..d1637a7 100644 (file)
@@ -133,6 +133,27 @@ define('TYPO3/CMS/Rtehtmlarea/HTMLArea/Util/Util',
                                Util.scrollBarWidth = w1 - w2 + 2;
                    }
                    return Util.scrollBarWidth;
+               },
+
+               /**
+                * Test whether a css property is supported by the browser
+                *
+                * @param object element: the DOM element on which to test
+                * @param string property: the CSSS property to test
+                * @param value value: the value to test
+                * @return boolean true if the property is supported
+                */
+               testCssPropertySupport: function (element, property, value) {
+                       var style = element.style;
+                       var before = style[property];
+                       try {
+                               style[property] = value;
+                       } catch (e) {}
+                       var after = style[property];
+                       if (typeof before !== 'undefined') {
+                               style[property] = before;
+                       }
+                       return before !== after;
                }
        };