Builder for ve.dm.MWInternalLinkAnnotation

Add ve.dm.MWInternalLinkAnnotation.static.newFromTitle to build an
appropriate internal link annotation from a mw.Title.  Tweaked some
method signatures to avoid repeated reparsing of the title text.

Also refactor ve.dm.MWInternalLinkAnnotation.static.getTargetDataFromHref
to explicitly return a boolean indicating whether the result was determined
to be an internal link.

Bug: T64816
Change-Id: I74385d7b3ede1794398dabb749185f4080509b99
This commit is contained in:
C. Scott Ananian 2015-08-12 15:20:45 -04:00
parent bf520fee03
commit 2852f6368f
2 changed files with 50 additions and 31 deletions

View file

@ -50,15 +50,47 @@ ve.dm.MWInternalLinkAnnotation.static.toDataElement = function ( domElements, co
};
};
/**
* Build a ve.dm.MWInternalLinkAnnotation from a given mw.Title.
*
* @param {mw.Title} title The title to link to.
* @return {ve.dm.MWInternalLinkAnnotation} The annotation.
*/
ve.dm.MWInternalLinkAnnotation.static.newFromTitle = function ( title ) {
var target = title.toText();
if ( title.getNamespaceId() === 6 || title.getNamespaceId() === 14 ) {
// File: or Category: link
// We have to prepend a colon so this is interpreted as a link
// rather than an image inclusion or categorization
target = ':' + target;
}
return new ve.dm.MWInternalLinkAnnotation( {
type: 'link/mwInternal',
attributes: {
title: target,
normalizedTitle: ve.dm.MWInternalLinkAnnotation.static.normalizeTitle( title ),
lookupTitle: ve.dm.MWInternalLinkAnnotation.static.getLookupTitle( title )
}
} );
};
/**
* Parse URL to get title it points to.
*
* @param {string} href
* @param {HTMLDocument|string} doc Document whose base URL to use, or base URL as a string.
* @return {Object} Plain object with 'title' and 'hrefPrefix' keys.
* @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.hrefPrefix
* Any ./ or ../ prefixes on a relative link
* @return {boolean} return.isInternal
* 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, matches;
var relativeBase, relativeBaseRegex, relativeHref, isInternal, matches;
function regexEscape( str ) {
return str.replace( /([.?*+^$[\]\\(){}|-])/g, '\\$1' );
@ -69,19 +101,22 @@ ve.dm.MWInternalLinkAnnotation.static.getTargetDataFromHref = function ( href, d
relativeBaseRegex = new RegExp( regexEscape( relativeBase ).replace( regexEscape( '$1' ), '(.*)' ) );
// Protocol relative href
relativeHref = href.replace( /^https?:/, '' );
// 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 );
if ( matches ) {
// Take the relative path
href = matches[ 1 ];
isInternal = true;
}
// The href is simply the title, unless we're dealing with a page that has slashes in its name
// in which case it's preceded by one or more instances of "./" or "../", so strip those
matches = href.match( /^((?:\.\.?\/)*)(.*)$/ );
return { title: matches[ 2 ], hrefPrefix: matches[ 1 ] };
return { title: matches[ 2 ], hrefPrefix: matches[ 1 ], isInternal: isInternal };
};
ve.dm.MWInternalLinkAnnotation.static.toDomElements = function () {
@ -111,11 +146,11 @@ ve.dm.MWInternalLinkAnnotation.static.getHref = function ( dataElement ) {
* Normalize title for comparison purposes.
* E.g. capitalisation and underscores.
*
* @param {string} original Original title
* @return {string} Normalized title, or the original if it is invalid
* @param {string|mw.Title} original Original title
* @return {string} Normalized title, or the original string if it is invalid
*/
ve.dm.MWInternalLinkAnnotation.static.normalizeTitle = function ( original ) {
var title = mw.Title.newFromText( original );
var title = original instanceof mw.Title ? original : mw.Title.newFromText( original );
if ( !title ) {
return original;
}
@ -125,11 +160,11 @@ ve.dm.MWInternalLinkAnnotation.static.normalizeTitle = function ( original ) {
/**
* Normalize title for lookup (search suggestion, existence) purposes.
*
* @param {string} original Original title
* @return {string} Normalized title, or the original if it is invalid
* @param {string|mw.Title} original Original title
* @return {string} Normalized title, or the original string if it is invalid
*/
ve.dm.MWInternalLinkAnnotation.static.getLookupTitle = function ( original ) {
var title = mw.Title.newFromText( original );
var title = original instanceof mw.Title ? original : mw.Title.newFromText( original );
if ( !title ) {
return original;
}

View file

@ -92,7 +92,7 @@ ve.ui.MWLinkAnnotationInspector.prototype.isExternal = function () {
* @param {ve.dm.MWInternalLinkAnnotation} annotation Annotation
*/
ve.ui.MWLinkAnnotationInspector.prototype.onInternalLinkChange = function ( annotation ) {
var title,
var targetData,
href = annotation ? annotation.getAttribute( 'title' ) : '',
// Have to check that this.getFragment() is defined because parent class's teardown
// invokes setAnnotation( null ) which calls this code after fragment is unset
@ -101,12 +101,12 @@ ve.ui.MWLinkAnnotationInspector.prototype.onInternalLinkChange = function ( anno
if ( htmlDoc && ve.init.platform.getExternalLinkUrlProtocolsRegExp().test( href ) ) {
// Check if the 'external' link is in fact a page on the same wiki
// e.g. http://en.wikipedia.org/wiki/Target -> Target
title = ve.dm.MWInternalLinkAnnotation.static.getTargetDataFromHref(
targetData = ve.dm.MWInternalLinkAnnotation.static.getTargetDataFromHref(
href,
htmlDoc
).title;
if ( title !== href ) {
this.internalAnnotationInput.text.setValue( title );
);
if ( targetData.isInternal ) {
this.internalAnnotationInput.text.setValue( targetData.title );
return;
}
}
@ -226,23 +226,7 @@ ve.ui.MWLinkAnnotationInspector.prototype.getAnnotationFromFragment = function (
} );
} else if ( title ) {
// Internal link
if ( title.getNamespaceId() === 6 || title.getNamespaceId() === 14 ) {
// File: or Category: link
// We have to prepend a colon so this is interpreted as a link
// rather than an image inclusion or categorization
target = ':' + target;
}
return new ve.dm.MWInternalLinkAnnotation( {
type: 'link/mwInternal',
attributes: {
title: target,
// bug 62816: we really need a builder for this stuff
normalizedTitle: ve.dm.MWInternalLinkAnnotation.static.normalizeTitle( target ),
lookupTitle: ve.dm.MWInternalLinkAnnotation.static.getLookupTitle( target )
}
} );
return ve.dm.MWInternalLinkAnnotation.static.newFromTitle( title );
} else {
// Doesn't look like an external link and mw.Title considered it an illegal value,
// for an internal link.