From 642bdf013e1ac56e578dcafefa8d0b1dd3230202 Mon Sep 17 00:00:00 2001 From: wctaiwan Date: Wed, 25 Mar 2015 16:53:27 -0400 Subject: [PATCH] Use href attribute to calculate titles This is needed for wikis that use LanguageConverter, since the title attribute is converted to the user's variant, and the canonical title is needed for the API unless converttitles is specified. For filtering, instead of comparing linkHref and expectedHref, filter out links that have other query parameters or aren't in content namespaces. Bug: T93605 Change-Id: I5534753307ed5e1d4b27c52c616fd143b2a397e1 --- Popups.hooks.php | 7 ++- resources/ext.popups.core.js | 54 ++++++++++++++++--- resources/ext.popups.renderer.article.js | 5 +- tests/qunit/ext.popups.core.test.js | 33 ++++++++++++ .../qunit/ext.popups.renderer.article.test.js | 3 +- 5 files changed, 91 insertions(+), 11 deletions(-) create mode 100644 tests/qunit/ext.popups.core.test.js diff --git a/Popups.hooks.php b/Popups.hooks.php index 4944c8c98..e7d98a2f1 100644 --- a/Popups.hooks.php +++ b/Popups.hooks.php @@ -52,11 +52,13 @@ class PopupsHooks { public static function onResourceLoaderRegisterModules( ResourceLoader $rl ) { $moduleDependencies = array( 'mediawiki.api', + 'mediawiki.Title', 'mediawiki.jqueryMsg', 'mediawiki.Uri', 'moment', 'jquery.jStorage', 'jquery.client', + 'jquery.mwExtension', ); // If EventLogging is present, add the schema as a dependency. @@ -121,7 +123,10 @@ class PopupsHooks { */ public static function onResourceLoaderTestModules( array &$testModules, ResourceLoader &$resourceLoader ) { $testModules['qunit']['ext.popups.tests'] = array( - 'scripts' => array( 'tests/qunit/ext.popups.renderer.article.test.js' ), + 'scripts' => array( + 'tests/qunit/ext.popups.renderer.article.test.js', + 'tests/qunit/ext.popups.core.test.js', + ), 'dependencies' => array( 'ext.popups' ), 'localBasePath' => __DIR__, 'remoteExtPath' => 'Popups', diff --git a/resources/ext.popups.core.js b/resources/ext.popups.core.js index dbb454f2d..7ae47d53a 100644 --- a/resources/ext.popups.core.js +++ b/resources/ext.popups.core.js @@ -145,21 +145,63 @@ } ); }; + /** + * Given an href string for the local wiki, return the title, or undefined if + * the link is external, has extra query parameters, or contains no title. + * + * Note that the returned title is not sanitized (may contain underscores). + * + * @param {string} href + * @return {string|undefined} + */ + mw.popups.getTitle = function ( href ) { + var title, titleRegex, matches, + linkHref = new mw.Uri( href ); + + // External links + if ( linkHref.host !== location.hostname ) { + return undefined; + } + + if ( linkHref.query.hasOwnProperty( 'title' ) ) { + // linkHref is not a pretty URL, e.g. /w/index.php?title=Foo + + title = linkHref.query.title; + // Return undefined if there are query parameters other than title + delete linkHref.query.title; + return $.isEmptyObject( linkHref.query ) ? title : undefined; + } else { + // linkHref is a pretty URL, e.g. /wiki/Foo + + // Return undefined if there are any query parameters + if ( !$.isEmptyObject( linkHref.query ) ) { + return undefined; + } + titleRegex = new RegExp( $.escapeRE( mw.config.get( 'wgArticlePath' ) ) + .replace( '\\$1', '(.+)' ) ); + matches = titleRegex.exec( linkHref.path ); + return matches ? decodeURIComponent( matches[1] ) : undefined; + } + }; + /** * Returns links that can have Popups * * @method selectPopupElements */ mw.popups.selectPopupElements = function () { + var contentNamespaces = mw.config.get( 'wgContentNamespaces' ); return mw.popups.$content .find( 'a[href][title]:not(' + mw.popups.IGNORE_CLASSES.join(', ') + ')' ) .filter( function () { - var linkHref = new mw.Uri( this.href ), - expectedHref = new mw.Uri( mw.util.getUrl( this.title ) ); - - // don't compare fragment to display popups on anchored page links - linkHref.fragment = undefined; - return linkHref.toString() === expectedHref.toString(); + var title, + titleText = mw.popups.getTitle( this.href ); + if ( !titleText ) { + return false; + } + // Is titleText in a content namespace? + title = mw.Title.newFromText( titleText ); + return title && ( $.inArray( title.namespace, contentNamespaces ) >= 0 ); } ); }; diff --git a/resources/ext.popups.renderer.article.js b/resources/ext.popups.renderer.article.js index 5e2a7903f..507f75689 100644 --- a/resources/ext.popups.renderer.article.js +++ b/resources/ext.popups.renderer.article.js @@ -32,9 +32,8 @@ * @return {jQuery.Promise} */ article.init = function ( link ) { - var - href = link.attr( 'href' ), - title = link.data( 'title' ), + var href = link.attr( 'href' ), + title = mw.popups.getTitle( href ), deferred = $.Deferred(); if ( !title ) { diff --git a/tests/qunit/ext.popups.core.test.js b/tests/qunit/ext.popups.core.test.js new file mode 100644 index 000000000..301cab836 --- /dev/null +++ b/tests/qunit/ext.popups.core.test.js @@ -0,0 +1,33 @@ +( function ( $, mw ) { + + QUnit.module( 'ext.popups.core', QUnit.newMwEnvironment( { + config: { + wgArticlePath: '/wiki/$1' + } + } ) ); + + QUnit.test( 'getTitle', function ( assert ) { + var cases, i, expected, actual; + + QUnit.expect( 10 ); + cases = [ + [ '/wiki/Foo', 'Foo' ], + [ '/wiki/Foo#Bar', 'Foo' ], + [ '/wiki/Foo?oldid=1', undefined ], + [ '/wiki/%E6%B8%AC%E8%A9%A6', '測試' ], + [ '/w/index.php?title=Foo', 'Foo' ], + [ '/w/index.php?title=Foo#Bar', 'Foo' ], + [ '/w/Foo?title=Foo&action=edit', undefined ], + [ '/w/index.php?title=%E6%B8%AC%E8%A9%A6', '測試' ], + [ '/w/index.php?oldid=1', undefined ], + [ '/Foo', undefined ] + ]; + + for ( i = 0; i < cases.length; i++ ) { + expected = cases[i][1]; + actual = mw.popups.getTitle( cases[i][0] ); + assert.equal( actual, expected ); + } + } ); + +} ) ( jQuery, mediaWiki ); diff --git a/tests/qunit/ext.popups.renderer.article.test.js b/tests/qunit/ext.popups.renderer.article.test.js index 0e33c9439..6c735f077 100644 --- a/tests/qunit/ext.popups.renderer.article.test.js +++ b/tests/qunit/ext.popups.renderer.article.test.js @@ -1,6 +1,7 @@ ( function ( $, mw ) { - QUnit.module( 'ext.popups' ); + QUnit.module( 'ext.popups.renderer.article', QUnit.newMwEnvironment() ); + QUnit.test( 'render.article.getProcessedElements', function ( assert ) { QUnit.expect( 13 );