dm.MWInternalLinkAnnotation: Fix href normalization for special characters

<a href="Foo%3F"> would dirty-diff to <a href="Foo?"> and also render
as such, pointing to the wrong page.

We also called decodeURIComponent() on the href twice, which can't
have been good.

Move URI decoding and underscore normalization into
getTargetDataFromHref(), and add rawTitle for callers that need it.
Put rawTitle in the origTitle attribute, so that equivalence
comparisons (decode(origTitle) === title) work as intended.

Bug: T145978
Change-Id: I29331a4ab0f8f7ef059c109f6813fa670a2c7390
This commit is contained in:
Roan Kattouw 2016-09-18 15:22:09 -07:00 committed by James D. Forrester
parent 5bc54fd036
commit bb45d984ca
4 changed files with 31 additions and 5 deletions

View file

@ -201,7 +201,7 @@ ve.ce.MWTransclusionNode.prototype.getRenderedDomElements = function ( domElemen
var targetData = ve.dm.MWInternalLinkAnnotation.static.getTargetDataFromHref(
this.href, transclusionNode.getModelHtmlDocument()
),
normalisedHref = ve.decodeURIComponentIntoArticleTitle( targetData.title, false );
normalisedHref = ve.decodeURIComponentIntoArticleTitle( targetData.rawTitle, false );
if ( mw.Title.newFromText( normalisedHref ) ) {
normalisedHref = mw.Title.newFromText( normalisedHref ).getPrefixedText();
}

View file

@ -42,10 +42,10 @@ ve.dm.MWInternalLinkAnnotation.static.toDataElement = function ( domElements, co
type: this.name,
attributes: {
hrefPrefix: targetData.hrefPrefix,
title: ve.decodeURIComponentIntoArticleTitle( targetData.title ),
title: targetData.title,
normalizedTitle: this.normalizeTitle( targetData.title ),
lookupTitle: this.getLookupTitle( targetData.title ),
origTitle: targetData.title
origTitle: targetData.rawTitle
}
};
};
@ -88,6 +88,8 @@ ve.dm.MWInternalLinkAnnotation.static.newFromTitle = function ( title ) {
* @return {Object} Information about the given href
* @return {string} return.title
* The title of the internal link, else the original href if href is external
* @return {string} return.rawTitle
* The title without URL decoding and underscore normalization applied
* @return {string} return.hrefPrefix
* Any ./ or ../ prefixes on a relative link
* @return {boolean} return.isInternal
@ -125,7 +127,8 @@ ve.dm.MWInternalLinkAnnotation.static.getTargetDataFromHref = function ( href, d
// point. So decode them, otherwise this is going to cause failures
// elsewhere.
return {
title: ve.safeDecodeURIComponent( matches[ 2 ] ),
title: ve.decodeURIComponentIntoArticleTitle( matches[ 2 ] ),
rawTitle: matches[ 2 ],
hrefPrefix: matches[ 1 ],
isInternal: isInternal
};

View file

@ -39,7 +39,7 @@ QUnit.test( 'toDataElement', function ( assert ) {
hrefPrefix: '',
lookupTitle: 'Foo?',
normalizedTitle: 'Foo?',
origTitle: 'Foo?',
origTitle: 'Foo%3F',
title: 'Foo?'
}
}

View file

@ -1076,6 +1076,29 @@ ve.dm.mwExample.domToDataCases = {
{ type: '/internalList' }
]
},
'internal link with special characters': {
body: '<p><a rel="mw:WikiLink" href="./Foo%3F+%25&Bar">x</a></p>',
head: '<base href="http://example.com" />',
data: [
{ type: 'paragraph' },
[
'x',
[ {
type: 'link/mwInternal',
attributes: {
title: 'Foo?+%&Bar',
origTitle: 'Foo%3F+%25&Bar',
normalizedTitle: 'Foo?+%&Bar',
lookupTitle: 'Foo?+%&Bar',
hrefPrefix: './'
}
} ]
],
{ type: '/paragraph' },
{ type: 'internalList' },
{ type: '/internalList' }
]
},
'numbered external link (empty mw:Extlink)': {
body: '<p>Foo<a rel="mw:ExtLink" href="http://www.example.com"></a>Bar</p>',
data: [