From 5e6cbc187cfb9164e3167e543a538b1aff34c58e Mon Sep 17 00:00:00 2001 From: Ed Sanders Date: Thu, 17 Mar 2016 15:30:59 +0000 Subject: [PATCH] Link pasting: Match RDFa-less links as external Now that some targets support link pasting (Flow) we need to make sure that pasted links match to an allowed type ('link/mwExternal') instead of plain 'link' annotations which should never exist in an MW document. In a later commit we should auto-detect internal links. Change-Id: I7faae834aa6e730c3cf93a691331a05fd0fe3d5c --- .../ve.dm.MWExternalLinkAnnotation.js | 22 +++++--- .../nodes/ve.dm.MWNumberedExternalLinkNode.js | 4 +- modules/ve-mw/tests/dm/ve.dm.mwExample.js | 52 +++++++++++++++++++ modules/ve-mw/tests/ve.test.utils.js | 4 +- 4 files changed, 72 insertions(+), 10 deletions(-) diff --git a/modules/ve-mw/dm/annotations/ve.dm.MWExternalLinkAnnotation.js b/modules/ve-mw/dm/annotations/ve.dm.MWExternalLinkAnnotation.js index 055594cef7..5ab1301dcc 100644 --- a/modules/ve-mw/dm/annotations/ve.dm.MWExternalLinkAnnotation.js +++ b/modules/ve-mw/dm/annotations/ve.dm.MWExternalLinkAnnotation.js @@ -33,18 +33,26 @@ OO.inheritClass( ve.dm.MWExternalLinkAnnotation, ve.dm.LinkAnnotation ); ve.dm.MWExternalLinkAnnotation.static.name = 'link/mwExternal'; -ve.dm.MWExternalLinkAnnotation.static.matchRdfaTypes = [ 'mw:ExtLink' ]; +ve.dm.MWExternalLinkAnnotation.static.matchFunction = function ( domElement ) { + var rel = domElement.getAttribute( 'rel' ); + // Match explicity mw:ExtLink, or plain RDFa-less links (e.g. from external paste) + return !rel || rel === 'mw:ExtLink'; +}; ve.dm.MWExternalLinkAnnotation.static.toDataElement = function ( domElements ) { - var parentResult = ve.dm.LinkAnnotation.static.toDataElement.apply( this, arguments ); - parentResult.attributes.rel = domElements[ 0 ].getAttribute( 'rel' ); - return parentResult; + // Parent method + var dataElement = ve.dm.MWExternalLinkAnnotation.super.static.toDataElement.apply( this, arguments ); + + dataElement.attributes.rel = domElements[ 0 ].getAttribute( 'rel' ); + return dataElement; }; ve.dm.MWExternalLinkAnnotation.static.toDomElements = function ( dataElement ) { - var parentResult = ve.dm.LinkAnnotation.static.toDomElements.apply( this, arguments ); - parentResult[ 0 ].setAttribute( 'rel', dataElement.attributes.rel || 'mw:ExtLink' ); - return parentResult; + // Parent method + var domElements = ve.dm.MWExternalLinkAnnotation.super.static.toDomElements.apply( this, arguments ); + + domElements[ 0 ].setAttribute( 'rel', dataElement.attributes.rel || 'mw:ExtLink' ); + return domElements; }; /* Methods */ diff --git a/modules/ve-mw/dm/nodes/ve.dm.MWNumberedExternalLinkNode.js b/modules/ve-mw/dm/nodes/ve.dm.MWNumberedExternalLinkNode.js index 7f37dc1520..9011b9af29 100644 --- a/modules/ve-mw/dm/nodes/ve.dm.MWNumberedExternalLinkNode.js +++ b/modules/ve-mw/dm/nodes/ve.dm.MWNumberedExternalLinkNode.js @@ -41,9 +41,9 @@ ve.dm.MWNumberedExternalLinkNode.static.matchRdfaTypes = [ 'mw:ExtLink' ]; ve.dm.MWNumberedExternalLinkNode.static.blacklistedAnnotationTypes = [ 'link' ]; -ve.dm.MWNumberedExternalLinkNode.static.matchFunction = function ( element ) { +ve.dm.MWNumberedExternalLinkNode.static.matchFunction = function ( domElement ) { // Must be empty - return element.childNodes.length === 0; + return domElement.childNodes.length === 0; }; ve.dm.MWNumberedExternalLinkNode.static.toDataElement = function ( domElements ) { diff --git a/modules/ve-mw/tests/dm/ve.dm.mwExample.js b/modules/ve-mw/tests/dm/ve.dm.mwExample.js index 7857f635df..66f67aed83 100644 --- a/modules/ve-mw/tests/dm/ve.dm.mwExample.js +++ b/modules/ve-mw/tests/dm/ve.dm.mwExample.js @@ -1515,5 +1515,57 @@ ve.dm.mwExample.domToDataCases = { doc.metadata.data[ 1 ].splice( 0, 1 ); }, normalizedBody: '

' + }, + 'Plain links (e.g. on paste) are converted to link/mwExternal': { + body: 'Foobar', + data: [ + { + type: 'paragraph', + internal: { + generated: 'wrapper' + } + }, + 'F', 'o', 'o', + [ + 'b', + [ { + type: 'link/mwExternal', + attributes: { + href: 'Bar', + rel: null + } + } ] + ], + [ + 'a', + [ { + type: 'link/mwExternal', + attributes: { + href: 'Bar', + rel: null + } + } ] + ], + [ + 'r', + [ { + type: 'link/mwExternal', + attributes: { + href: 'Bar', + rel: null + } + } ] + ], + { + type: '/paragraph' + }, + { + type: 'internalList' + }, + { + type: '/internalList' + } + ], + normalizedBody: 'Foobar' } }; diff --git a/modules/ve-mw/tests/ve.test.utils.js b/modules/ve-mw/tests/ve.test.utils.js index ec19af35e5..ce6859bbaa 100644 --- a/modules/ve-mw/tests/ve.test.utils.js +++ b/modules/ve-mw/tests/ve.test.utils.js @@ -30,6 +30,7 @@ ve.test.utils.createSurfaceFromDocument = function ( doc ) { ve.dm.modelRegistry.unregister( ve.dm.MWHeadingNode ); ve.dm.modelRegistry.unregister( ve.dm.MWPreformattedNode ); ve.dm.modelRegistry.unregister( ve.dm.MWTableNode ); +ve.dm.modelRegistry.unregister( ve.dm.MWExternalLinkAnnotation ); // Re-register unregistered nodes. ve.dm.modelRegistry.register( ve.dm.InlineImageNode ); ve.dm.modelRegistry.register( ve.dm.BlockImageNode ); @@ -38,7 +39,8 @@ ve.test.utils.mwEnvironment = ( function () { var overrides = [ ve.dm.MWHeadingNode, ve.dm.MWPreformattedNode, - ve.dm.MWTableNode + ve.dm.MWTableNode, + ve.dm.MWExternalLinkAnnotation ], overridden = [ ve.dm.InlineImageNode,