jenkins-bot has submitted this change and it was merged.

Change subject: Factor the <pre> newline hack out of the converter into 
ve.properInnerHTML()
......................................................................


Factor the <pre> newline hack out of the converter into ve.properInnerHTML()

Also add detection for whether the browser is actually broken (most are,
but some, like Opera, aren't), treat <textarea> and <listing> in addition
to <pre>, and fix a bug where the function would crash if the <pre> was
empty (because .firstChild was undefined/null).

Change-Id: I541b57e9fd5c9c42d19d0a59f6e29fb43d35c9b6
---
M modules/ve/dm/ve.dm.Converter.js
M modules/ve/init/mw/ve.init.mw.Target.js
M modules/ve/test/dm/ve.dm.example.js
M modules/ve/ve.js
4 files changed, 48 insertions(+), 25 deletions(-)

Approvals:
  Esanders: Looks good to me, approved
  jenkins-bot: Verified



diff --git a/modules/ve/dm/ve.dm.Converter.js b/modules/ve/dm/ve.dm.Converter.js
index 66191be..93ab24a 100644
--- a/modules/ve/dm/ve.dm.Converter.js
+++ b/modules/ve/dm/ve.dm.Converter.js
@@ -1145,22 +1145,6 @@
                }
                delete container.lastOuterPost;
        }
-
-       // Workaround for bug 42469: if a <pre> starts with a newline, that 
means .innerHTML will
-       // screw up and stringify it with one fewer newline. Work around this 
by adding a newline.
-       // If we don't see a leading newline, we still don't know if the 
original HTML was
-       // <pre>Foo</pre> or <pre>\nFoo</pre> , but that's a syntactic 
difference, not a semantic
-       // one, and handling that is Parsoid's job.
-       $( container ).find( 'pre' ).each( function() {
-               var matches;
-               if ( this.firstChild.nodeType === Node.TEXT_NODE ) {
-                       matches = this.firstChild.data.match( /^(\r\n|\r|\n)/ );
-                       if ( matches && matches[1] ) {
-                               // Prepend a newline exactly like the one we saw
-                               this.firstChild.insertData( 0, matches[1] );
-                       }
-               }
-       } );
 };
 
 /* Initialization */
diff --git a/modules/ve/init/mw/ve.init.mw.Target.js 
b/modules/ve/init/mw/ve.init.mw.Target.js
index 30fd921..a51582f 100644
--- a/modules/ve/init/mw/ve.init.mw.Target.js
+++ b/modules/ve/init/mw/ve.init.mw.Target.js
@@ -437,7 +437,7 @@
                        'oldid': this.oldid,
                        'basetimestamp': this.baseTimeStamp,
                        'starttimestamp': this.startTimeStamp,
-                       'html': doc.body.innerHTML, // TODO make this send the 
whole document in the future
+                       'html': ve.properInnerHTML( doc.body ), // TODO make 
this send the whole document in the future
                        'token': this.editToken,
                        'summary': options.summary,
                        'minor': Number( options.minor ),
@@ -468,7 +468,7 @@
                        'paction': 'diff',
                        'page': this.pageName,
                        'oldid': this.oldid,
-                       'html': doc.body.innerHTML, // TODO make this send the 
whole document in the future
+                       'html': ve.properInnerHTML( doc.body ), // TODO make 
this send the whole document in the future
                        // TODO: API required editToken, though not relevant 
for diff
                        'token': this.editToken
                },
@@ -556,7 +556,7 @@
                'data': {
                        'action': 'visualeditor',
                        'paction': 'serialize',
-                       'html': doc.body.innerHTML, // TODO make this send the 
whole document in the future
+                       'html': ve.properInnerHTML( doc.body ), // TODO make 
this send the whole document in the future
                        'page': this.pageName,
                        'oldid': this.oldid,
                        'token': this.editToken,
@@ -598,7 +598,7 @@
                                        ve.createDocumentFromHTML( '<body>' + 
this.originalHtml  + '</body>' )
                        ),
                        'editedData': editedData,
-                       'editedHtml': ve.dm.converter.getDomFromData( store, 
editedData ).body.innerHTML,
+                       'editedHtml': ve.properInnerHTML( 
ve.dm.converter.getDomFromData( store, editedData ).body ),
                        'wiki': mw.config.get( 'wgDBname' )
                };
        $.post(
diff --git a/modules/ve/test/dm/ve.dm.example.js 
b/modules/ve/test/dm/ve.dm.example.js
index 21d4343..e0ac641 100644
--- a/modules/ve/test/dm/ve.dm.example.js
+++ b/modules/ve/test/dm/ve.dm.example.js
@@ -1645,11 +1645,7 @@
                        '\n',
                        '\n',
                        { 'type': '/preformatted' }
-               ],
-               // pre newline hack
-               // TODO we should test this using a better, more 
.innerHTML-based mechanism for
-               // comparing DOM trees
-               'normalizedHtml': 
'<body>\n<pre>\n\n\n\nFoo\n\n\nBar\n\n\n\n</pre>\n\n\n\n\n</body>'
+               ]
        },
        'whitespace preservation in table cell starting with text and ending 
with annotation': {
                'html': '<body><table><tbody><tr><td>Foo 
<b>Bar</b></td></tr></tbody></table></body>',
diff --git a/modules/ve/ve.js b/modules/ve/ve.js
index 720e224..00cd8f0 100644
--- a/modules/ve/ve.js
+++ b/modules/ve/ve.js
@@ -881,6 +881,49 @@
                return newDocument;
        };
 
+       /**
+        * Get the actual inner HTML of a DOM node.
+        *
+        * In most browsers, .innerHTML is broken and eats newlines in <pre>s, 
see
+        * https://bugzilla.mozilla.org/show_bug.cgi?id=838954 . This function 
detects this behavior
+        * and works around it, to the extent possible. <pre>\nFoo</pre> will 
become <pre>Foo</pre>
+        * if the browser is broken, but newlines are preserved in all other 
cases.
+        *
+        * @param {HTMLElement} element HTML element to get inner HTML of
+        * @returns {string} Inner HTML
+        */
+       ve.properInnerHTML = function ( element ) {
+               var div, $element;
+               if ( ve.isPreInnerHTMLBroken === undefined ) {
+                       // Test whether newlines in <pre> are serialized back 
correctly
+                       div = document.createElement( 'div' );
+                       div.innerHTML = '<pre>\n\n</pre>';
+                       ve.isPreInnerHTMLBroken = div.innerHTML === 
'<pre>\n</pre>';
+               }
+
+               if ( !ve.isPreInnerHTMLBroken ) {
+                       return element.innerHTML;
+               }
+
+               // Workaround for bug 42469: if a <pre> starts with a newline, 
that means .innerHTML will
+               // screw up and stringify it with one fewer newline. Work 
around this by adding a newline.
+               // If we don't see a leading newline, we still don't know if 
the original HTML was
+               // <pre>Foo</pre> or <pre>\nFoo</pre> , but that's a syntactic 
difference, not a semantic
+               // one, and handling that is Parsoid's job.
+               $element = $( element ).clone();
+               $element.find( 'pre, textarea, listing' ).each( function() {
+                       var matches;
+                       if ( this.firstChild && this.firstChild.nodeType === 
Node.TEXT_NODE ) {
+                               matches = this.firstChild.data.match( 
/^(\r\n|\r|\n)/ );
+                               if ( matches && matches[1] ) {
+                                       // Prepend a newline exactly like the 
one we saw
+                                       this.firstChild.insertData( 0, 
matches[1] );
+                               }
+                       }
+               } );
+               return $element.get( 0 ).innerHTML;
+       };
+
        // Based on the KeyEvent DOM Level 3 (add more as you need them)
        // 
http://www.w3.org/TR/2001/WD-DOM-Level-3-Events-20010410/DOM3-Events.html#events-Events-KeyEvent
        ve.Keys = window.KeyEvent || {

-- 
To view, visit https://gerrit.wikimedia.org/r/59781
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: I541b57e9fd5c9c42d19d0a59f6e29fb43d35c9b6
Gerrit-PatchSet: 4
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Catrope <roan.katt...@gmail.com>
Gerrit-Reviewer: Esanders <esand...@wikimedia.org>
Gerrit-Reviewer: jenkins-bot

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to