jenkins-bot has submitted this change and it was merged.
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. To avoid infinite recursion,
we have to exclude this attribute for hash generation.
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(-)
Approvals:
Esanders: Looks good to me, approved
jenkins-bot: Verified
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..ceb1bc0
--- /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: merged
Gerrit-Change-Id: I2edc46b6d87d2f91e952efcb09c0edae5166958f
Gerrit-PatchSet: 3
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Catrope <[email protected]>
Gerrit-Reviewer: Esanders <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits