Catrope has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/74107


Change subject: Add a node class for mw:Nowiki
......................................................................

Add a node class for mw:Nowiki

These represent <nowiki> tags. If the user doesn't edit the text inside
the nowiki, we round-trip the <span typeof="mw:Nowiki"> wrapper cleanly,
but if they do edit it, we unwrap it. This then triggers re-escaping
in Parsoid, and prevents cases where the user edits the text to no
longer need escaping but Parsoid still wraps it in <nowiki> because
of the <span typeof="mw:Nowiki"> wrapper.

In order to detect whether the contents have changed, the nowiki
annotation stores a copy of its contents. But it can't store

Bug: 47678
Change-Id: I2edc46b6d87d2f91e952efcb09c0edae5166958f
---
M VisualEditor.php
A modules/ve-mw/ce/annotations/ve.ce.MWNowikiAnnotation.js
A modules/ve-mw/dm/annotations/ve.dm.MWNowikiAnnotation.js
M modules/ve-mw/test/dm/ve.dm.mwExample.js
M modules/ve-mw/test/index.php
5 files changed, 171 insertions(+), 0 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/VisualEditor 
refs/changes/07/74107/1

diff --git a/VisualEditor.php b/VisualEditor.php
index 679f77e..9186770 100644
--- a/VisualEditor.php
+++ b/VisualEditor.php
@@ -356,6 +356,7 @@
                        
've-mw/dm/annotations/ve.dm.MWExternalLinkAnnotation.js',
                        
've-mw/dm/annotations/ve.dm.MWInternalLinkAnnotation.js',
                        've/dm/annotations/ve.dm.TextStyleAnnotation.js',
+                       've-mw/dm/annotations/ve.dm.MWNowikiAnnotation.js',
 
                        've/dm/metaitems/ve.dm.AlienMetaItem.js',
                        've-mw/dm/metaitems/ve.dm.MWAlienMetaItem.js',
@@ -427,6 +428,7 @@
                        
've-mw/ce/annotations/ve.ce.MWExternalLinkAnnotation.js',
                        
've-mw/ce/annotations/ve.ce.MWInternalLinkAnnotation.js',
                        've/ce/annotations/ve.ce.TextStyleAnnotation.js',
+                       've-mw/ce/annotations/ve.ce.MWNowikiAnnotation.js',
 
                        // ui
                        've/ui/ve.ui.js',
diff --git a/modules/ve-mw/ce/annotations/ve.ce.MWNowikiAnnotation.js 
b/modules/ve-mw/ce/annotations/ve.ce.MWNowikiAnnotation.js
new file mode 100644
index 0000000..50c3c77
--- /dev/null
+++ b/modules/ve-mw/ce/annotations/ve.ce.MWNowikiAnnotation.js
@@ -0,0 +1,37 @@
+/*!
+ * VisualEditor ContentEditable MWNowikiAnnotation class.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * ContentEditable MediaWiki nowiki annotation.
+ *
+ * @class
+ * @extends ve.ce.Annotation
+ * @constructor
+ * @param {ve.dm.MWNowikiAnnotation} model Model to observe
+ * @param {Object} [config] Config options
+ */
+ve.ce.MWNowikiAnnotation = function VeCeMWInternalLinkAnnotation( model, 
config ) {
+       // Parent constructor
+       ve.ce.Annotation.call( this, model, config );
+
+       // DOM changes
+       this.$.addClass( 've-ce-mwNowikiAnnotation' );
+};
+
+/* Inheritance */
+
+ve.inheritClass( ve.ce.MWNowikiAnnotation, ve.ce.Annotation );
+
+/* Static Properties */
+
+ve.ce.MWNowikiAnnotation.static.name = 'mwNowiki';
+
+ve.ce.MWNowikiAnnotation.static.tagName = 'span';
+
+/* Registration */
+
+ve.ce.annotationFactory.register( ve.ce.MWNowikiAnnotation );
diff --git a/modules/ve-mw/dm/annotations/ve.dm.MWNowikiAnnotation.js 
b/modules/ve-mw/dm/annotations/ve.dm.MWNowikiAnnotation.js
new file mode 100644
index 0000000..dbbc5d3
--- /dev/null
+++ b/modules/ve-mw/dm/annotations/ve.dm.MWNowikiAnnotation.js
@@ -0,0 +1,84 @@
+/*!
+ * VisualEditor DataModel MWNowikiAnnotation class.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * DataModel MediaWiki nowiki annotation
+ *
+ * Represents <nowiki> tags (in HTML as <span typeof="mw:Nowiki">) and unwraps 
them when they change
+ * so as to retrigger Parsoid's escaping mechanism.
+ *
+ * @class
+ * @extends ve.dm.Annotation
+ * @constructor
+ * @param {Object} element [description]
+ */
+ve.dm.MWNowikiAnnotation = function VeDmMwNowikiAnnotation( element ) {
+       // Parent constructor
+       ve.dm.Annotation.call( this, element );
+};
+
+/* Inheritance */
+
+ve.inheritClass( ve.dm.MWNowikiAnnotation, ve.dm.Annotation );
+
+/* Static Properties */
+
+ve.dm.MWNowikiAnnotation.static.name = 'mwNowiki';
+
+ve.dm.MWNowikiAnnotation.static.matchRdfaTypes = [ 'mw:Nowiki' ];
+
+ve.dm.MWNowikiAnnotation.static.toDataElement = function ( domElements ) {
+       return {
+               'type': 'mwNowiki',
+               'attributes': {
+                       'originalDomElements': ve.copyArray( domElements )
+               }
+       };
+};
+
+ve.dm.MWNowikiAnnotation.static.toDomElements = function ( dataElement, doc, 
converter, childDomElements ) {
+       var i, len,
+               originalDomElements = 
dataElement.attributes.originalDomElements,
+               originalChildren = originalDomElements && 
originalDomElements[0] && originalDomElements[0].childNodes,
+               contentsChanged = false,
+               domElement = document.createElement( 'span' );
+
+       // Determine whether the contents changed
+       if ( !originalChildren || childDomElements.length !== 
originalChildren.length ) {
+               contentsChanged = true;
+       } else {
+               for ( i = 0, len = originalChildren.length; i < len; i++ ) {
+                       if ( !originalChildren[i].isEqualNode( 
childDomElements[i] ) ) {
+                               contentsChanged = true;
+                               break;
+                       }
+               }
+       }
+
+       // If the contents changed, unwrap, otherwise, restore
+       if ( contentsChanged ) {
+               return [];
+       }
+       domElement.setAttribute( 'typeof', 'mw:Nowiki' );
+       return [ domElement ];
+};
+
+ve.dm.MWNowikiAnnotation.static.getHashObject = function ( dataElement ) {
+       var parentResult = ve.dm.Annotation.static.getHashObject( dataElement );
+       if ( parentResult.attributes.originalDomElements ) {
+               // If present, replace originalDomElements with a DOM summary
+               parentResult.attributes = ve.copyObject( 
parentResult.attributes );
+               parentResult.attributes.originalDomElements = ve.copyArray(
+                       parentResult.attributes.originalDomElements, 
ve.convertDomElements
+               );
+       }
+       return parentResult;
+};
+
+/* Registration */
+
+ve.dm.modelRegistry.register( ve.dm.MWNowikiAnnotation );
diff --git a/modules/ve-mw/test/dm/ve.dm.mwExample.js 
b/modules/ve-mw/test/dm/ve.dm.mwExample.js
index 76bc66f..ec10cbb 100644
--- a/modules/ve-mw/test/dm/ve.dm.mwExample.js
+++ b/modules/ve-mw/test/dm/ve.dm.mwExample.js
@@ -121,6 +121,32 @@
        'value': $( ve.dm.mwExample.MWTransclusion.mixed ).toArray()
 };
 
+ve.dm.mwExample.mwNowikiAnnotation = {
+       'type': 'mwNowiki',
+       'attributes': {
+               'originalDomElements': $( '<span 
typeof="mw:Nowiki">[[Bar]]</span>' ).toArray()
+       },
+       'htmlAttributes': [ { 'values': { 'typeof': 'mw:Nowiki' } } ]
+};
+
+ve.dm.mwExample.mwNowiki = [
+       { 'type': 'paragraph' },
+       'F', 'o', 'o',
+       [ '[', [ ve.dm.mwExample.mwNowikiAnnotation ] ],
+       [ '[', [ ve.dm.mwExample.mwNowikiAnnotation ] ],
+       [ 'B', [ ve.dm.mwExample.mwNowikiAnnotation ] ],
+       [ 'a', [ ve.dm.mwExample.mwNowikiAnnotation ] ],
+       [ 'r', [ ve.dm.mwExample.mwNowikiAnnotation ] ],
+       [ ']', [ ve.dm.mwExample.mwNowikiAnnotation ] ],
+       [ ']', [ ve.dm.mwExample.mwNowikiAnnotation ] ],
+       'B', 'a', 'z',
+       { 'type': '/paragraph' },
+       { 'type': 'internalList' },
+       { 'type': '/internalList' }
+];
+
+ve.dm.mwExample.mwNowikiHtml = '<body><p>Foo<span 
typeof="mw:Nowiki">[[Bar]]</span>Baz</p></body>';
+
 ve.dm.mwExample.withMeta = [
        {
                'type': 'alienMeta',
@@ -1598,5 +1624,25 @@
                        { 'type': 'internalList' },
                        { 'type': '/internalList' }
                ]
+       },
+       'mw:Nowiki': {
+               'html': ve.dm.mwExample.mwNowikiHtml,
+               'data': ve.dm.mwExample.mwNowiki
+       },
+       'mw:Nowiki unwraps when text modified': {
+               'html': null,
+               'data': ve.dm.mwExample.mwNowiki,
+               'modify': function ( data ) {
+                       data[7][0] = 'z';
+               },
+               'normalizedHtml': '<body><p>Foo[[Bzr]]Baz</p></body>'
+       },
+       'mw:Nowiki unwraps when annotations modified': {
+               'html': null,
+               'data': ve.dm.mwExample.mwNowiki,
+               'modify': function ( data ) {
+                       data[7][1].push( ve.dm.example.bold );
+               },
+               'normalizedHtml': '<body><p>Foo[[B<b>a</b>r]]Baz</p></body>'
        }
 };
diff --git a/modules/ve-mw/test/index.php b/modules/ve-mw/test/index.php
index c30f562..0eb21b8 100644
--- a/modules/ve-mw/test/index.php
+++ b/modules/ve-mw/test/index.php
@@ -129,6 +129,7 @@
                <script 
src="../../ve-mw/dm/annotations/ve.dm.MWExternalLinkAnnotation.js"></script>
                <script 
src="../../ve-mw/dm/annotations/ve.dm.MWInternalLinkAnnotation.js"></script>
                <script 
src="../../ve/dm/annotations/ve.dm.TextStyleAnnotation.js"></script>
+               <script 
src="../../ve-mw/dm/annotations/ve.dm.MWNowikiAnnotation.js"></script>
                <script 
src="../../ve/dm/metaitems/ve.dm.AlienMetaItem.js"></script>
                <script 
src="../../ve-mw/dm/metaitems/ve.dm.MWAlienMetaItem.js"></script>
                <script 
src="../../ve-mw/dm/metaitems/ve.dm.MWCategoryMetaItem.js"></script>
@@ -191,6 +192,7 @@
                <script 
src="../../ve-mw/ce/annotations/ve.ce.MWExternalLinkAnnotation.js"></script>
                <script 
src="../../ve-mw/ce/annotations/ve.ce.MWInternalLinkAnnotation.js"></script>
                <script 
src="../../ve/ce/annotations/ve.ce.TextStyleAnnotation.js"></script>
+               <script 
src="../../ve-mw/ce/annotations/ve.ce.MWNowikiAnnotation.js"></script>
                <script src="../../ve/ui/ve.ui.js"></script>
                <script src="../../ve/ui/ve.ui.Surface.js"></script>
                <script src="../../ve/ui/ve.ui.Context.js"></script>

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

Gerrit-MessageType: newchange
Gerrit-Change-Id: I2edc46b6d87d2f91e952efcb09c0edae5166958f
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Catrope <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to