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 );