From a816baedd98c6d9d0576fb173538d65fd9c41e80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bartosz=20Dziewo=C5=84ski?= Date: Fri, 7 Feb 2020 01:15:49 +0100 Subject: [PATCH] Fix handling of pasted internal red links Bug: T239550 Change-Id: Iacfba4b46bea8294f12a0c010344fda317f75df6 --- .../ve.dm.MWInternalLinkAnnotation.js | 22 +++++++++---- .../dm/ve.dm.MWInternalLinkAnnotation.test.js | 32 +++++++++++++++++-- 2 files changed, 46 insertions(+), 8 deletions(-) diff --git a/modules/ve-mw/dm/annotations/ve.dm.MWInternalLinkAnnotation.js b/modules/ve-mw/dm/annotations/ve.dm.MWInternalLinkAnnotation.js index 3afb2d2cc3..ed77449793 100644 --- a/modules/ve-mw/dm/annotations/ve.dm.MWInternalLinkAnnotation.js +++ b/modules/ve-mw/dm/annotations/ve.dm.MWInternalLinkAnnotation.js @@ -128,28 +128,38 @@ ve.dm.MWInternalLinkAnnotation.static.newFromTitle = function ( title, rawTitle * True if the href pointed to the local wiki, false if href is external */ ve.dm.MWInternalLinkAnnotation.static.getTargetDataFromHref = function ( href, doc ) { - var relativeBase, relativeBaseRegex, relativeHref, isInternal, matches, data; + var relativeBase, relativeBaseRegex, relativeHref, isInternal, matches, data, uri; function regexEscape( str ) { return str.replace( /([.?*+^$[\]\\(){}|-])/g, '\\$1' ); } - // Protocol relative base - relativeBase = ve.resolveUrl( mw.config.get( 'wgArticlePath' ), doc ).replace( /^https?:/i, '' ); - relativeBaseRegex = new RegExp( regexEscape( relativeBase ).replace( regexEscape( '$1' ), '(.*)' ) ); // Protocol relative href relativeHref = href.replace( /^https?:/i, '' ); // Paths without a host portion are assumed to be internal isInternal = !/^\/\//.test( relativeHref ); - // Check if this matches the server's article path - matches = relativeHref.match( relativeBaseRegex ); + // Check if this matches the server's article path + // Protocol relative base + relativeBase = ve.resolveUrl( mw.config.get( 'wgArticlePath' ), doc ).replace( /^https?:/i, '' ); + relativeBaseRegex = new RegExp( regexEscape( relativeBase ).replace( regexEscape( '$1' ), '(.*)' ) ); + matches = relativeHref.match( relativeBaseRegex ); if ( matches && matches[ 1 ].split( '#' )[ 0 ].indexOf( '?' ) === -1 ) { // Take the relative path href = matches[ 1 ]; isInternal = true; } + // Check if this matches the server's script path (as used by red links) + relativeBase = ve.resolveUrl( mw.config.get( 'wgScript' ), doc ).replace( /^https?:/i, '' ); + if ( relativeHref.indexOf( relativeBase ) === 0 ) { + uri = new mw.Uri( relativeHref ); + if ( uri.query.title ) { + href = uri.query.title; + isInternal = true; + } + } + // This href doesn't necessarily come from Parsoid (and it might not have the "./" prefix), but // this method will work fine. data = ve.parseParsoidResourceName( href ); diff --git a/modules/ve-mw/tests/dm/ve.dm.MWInternalLinkAnnotation.test.js b/modules/ve-mw/tests/dm/ve.dm.MWInternalLinkAnnotation.test.js index 0bcc8409d1..abd009405e 100644 --- a/modules/ve-mw/tests/dm/ve.dm.MWInternalLinkAnnotation.test.js +++ b/modules/ve-mw/tests/dm/ve.dm.MWInternalLinkAnnotation.test.js @@ -9,12 +9,27 @@ QUnit.module( 've.dm.MWInternalLinkAnnotation' ); QUnit.test( 'toDataElement', function ( assert ) { var i, l, doc = ve.dm.example.createExampleDocument(), - internalLink = function ( pageTitle ) { + externalLink = function ( href ) { var link = document.createElement( 'a' ); - link.setAttribute( 'href', location.origin + mw.Title.newFromText( pageTitle ).getUrl() ); + link.setAttribute( 'href', href ); + return link; + }, + internalLink = function ( pageTitle, params ) { + var link = document.createElement( 'a' ); + link.setAttribute( 'href', location.origin + mw.Title.newFromText( pageTitle ).getUrl( params ) ); return link; }, cases = [ + { + msg: 'Not an internal link', + element: externalLink( 'http://example.com/' ), + expected: { + type: 'link/mwExternal', + attributes: { + href: 'http://example.com/' + } + } + }, { msg: 'Simple', element: internalLink( 'Foo' ), @@ -28,6 +43,19 @@ QUnit.test( 'toDataElement', function ( assert ) { } } }, + { + msg: 'Red link', + element: internalLink( 'Foo', { action: 'edit', redlink: '1' } ), + expected: { + type: 'link/mwInternal', + attributes: { + lookupTitle: 'Foo', + normalizedTitle: 'Foo', + origTitle: 'Foo', + title: 'Foo' + } + } + }, { // Because percent-encoded URLs aren't valid titles, but what they decode to might be msg: 'Percent encoded characters',