mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/MultimediaViewer
synced 2024-12-01 19:26:14 +00:00
0b614c78e3
Adds a Route class hierarchy for various URL schemes and a Router class to convert Route classes to and from URLs. Right now we only have two(-ish) schemes, but in the future we want to be able to show related images which are not present on the current page and need shareable URLs for those as well; also we might want to specify other things in the URL than the current image (the reuse box being open was one thing discussed); this will be a good framework to add features like that. The MainFileRoute class will be used by #416. Change-Id: I489126a0ada37f91a22a2f48a4e686140a28d162 Mingle: https://wikimedia.mingle.thoughtworks.com/projects/multimedia/cards/371
199 lines
8.1 KiB
JavaScript
199 lines
8.1 KiB
JavaScript
/*
|
|
* This file is part of the MediaWiki extension MediaViewer.
|
|
*
|
|
* MediaViewer is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* MediaViewer is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with MediaViewer. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
( function( mw ) {
|
|
QUnit.module( 'mmv.routing.Router', QUnit.newMwEnvironment() );
|
|
|
|
QUnit.test( 'Constructor sanity checks', 1, function ( assert ) {
|
|
var router;
|
|
|
|
router = new mw.mmv.routing.Router();
|
|
assert.ok( router, 'Router created successfully' );
|
|
} );
|
|
|
|
QUnit.test( 'isMediaViewerHash()', 6, function ( assert ) {
|
|
var router = new mw.mmv.routing.Router();
|
|
|
|
assert.ok( router.isMediaViewerHash( 'mediaviewer/foo' ), 'Normal hash' );
|
|
assert.ok( router.isMediaViewerHash( '#mediaviewer/foo' ), 'Normal hash with #' );
|
|
assert.ok( router.isMediaViewerHash( 'mediaviewer' ), 'Bare hash' );
|
|
assert.ok( router.isMediaViewerHash( '#mediaviewer' ), 'Bare hash with #' );
|
|
assert.ok( !router.isMediaViewerHash( 'foo/mediaviewer' ), 'Foreign hash' );
|
|
assert.ok( !router.isMediaViewerHash( '' ), 'Empty hash' );
|
|
} );
|
|
|
|
QUnit.test( 'createHash()/parseHash()', 14, function ( assert ) {
|
|
var route, parsedRoute, hash, title,
|
|
router = new mw.mmv.routing.Router();
|
|
|
|
route = new mw.mmv.routing.MainFileRoute();
|
|
hash = router.createHash( route );
|
|
parsedRoute = router.parseHash( hash );
|
|
assert.deepEqual( parsedRoute, route, 'Bare hash' );
|
|
|
|
title = new mw.Title( 'File:Foo.png' );
|
|
route = new mw.mmv.routing.ThumbnailRoute( title );
|
|
hash = router.createHash( route );
|
|
parsedRoute = router.parseHash( hash );
|
|
assert.strictEqual( parsedRoute.fileTitle.getPrefixedDb(),
|
|
title.getPrefixedDb(), 'Normal hash' );
|
|
assert.ok( hash.match( /File:Foo.png/ ), 'Simple filenames remain readable' );
|
|
|
|
title = new mw.Title( 'File:Foo.png' );
|
|
route = new mw.mmv.routing.ThumbnailRoute( title );
|
|
hash = router.createHash( route );
|
|
assert.notEqual( hash[0], '#', 'Leading # is not included in the returned hash' );
|
|
parsedRoute = router.parseHash( '#' + hash );
|
|
assert.strictEqual( parsedRoute.fileTitle.getPrefixedDb(),
|
|
title.getPrefixedDb(), 'Leading # is accepted when parsing a hash' );
|
|
|
|
title = new mw.Title( 'File:Foo.png' );
|
|
route = new mw.mmv.routing.ThumbnailRoute( title );
|
|
hash = router.createHash( route );
|
|
parsedRoute = router.parseHash( hash );
|
|
assert.strictEqual( parsedRoute.fileTitle.getPrefixedDb(),
|
|
title.getPrefixedDb(), 'Normal hash' );
|
|
assert.ok( hash.match( /File:Foo.png/ ), 'Simple filenames remain readable' );
|
|
|
|
title = new mw.Title( 'File:Foo/bar.png' );
|
|
route = new mw.mmv.routing.ThumbnailRoute( title );
|
|
hash = router.createHash( route );
|
|
parsedRoute = router.parseHash( hash );
|
|
assert.strictEqual( parsedRoute.fileTitle.getPrefixedDb(),
|
|
title.getPrefixedDb(), 'Filename with /' );
|
|
assert.ok( !hash.match( 'Foo/bar' ), '/ is encoded' );
|
|
|
|
title = new mw.Title( 'File:Foo bar.png' );
|
|
route = new mw.mmv.routing.ThumbnailRoute( title );
|
|
hash = router.createHash( route );
|
|
parsedRoute = router.parseHash( hash );
|
|
assert.strictEqual( parsedRoute.fileTitle.getPrefixedDb(),
|
|
title.getPrefixedDb(), 'Filename with space' );
|
|
assert.ok( !hash.match( 'Foo bar' ), 'space is replaced...' );
|
|
assert.ok( hash.match( 'Foo_bar' ), '...with underscore' );
|
|
|
|
title = new mw.Title('File:看門狗 (遊戲).jpg');
|
|
route = new mw.mmv.routing.ThumbnailRoute( title );
|
|
hash = router.createHash( route );
|
|
parsedRoute = router.parseHash( hash );
|
|
assert.strictEqual( parsedRoute.fileTitle.getPrefixedDb(),
|
|
title.getPrefixedDb(), 'Unicode filename' );
|
|
|
|
title = new mw.Title( 'File:%!"$&\'()*,-./:;=?@\\^_`~+.jpg' );
|
|
if ( title ) {
|
|
route = new mw.mmv.routing.ThumbnailRoute( title );
|
|
hash = router.createHash( route );
|
|
parsedRoute = router.parseHash( hash );
|
|
assert.strictEqual( parsedRoute.fileTitle.getPrefixedDb(),
|
|
title.getPrefixedDb(), 'Special characters' );
|
|
} else {
|
|
// mw.Title depends on $wgLegalTitleChars - do not fail test if it is non-standard
|
|
assert.ok( true, 'Skipped' );
|
|
}
|
|
} );
|
|
|
|
QUnit.test( 'createHash() error handling', 3, function ( assert ) {
|
|
var router = new mw.mmv.routing.Router();
|
|
|
|
assert.ok( mw.mmv.testHelpers.getException( function() { return new mw.mmv.routing.ThumbnailRoute(); } ),
|
|
'Exception thrown then ThumbnailRoute has no title' );
|
|
assert.ok( mw.mmv.testHelpers.getException( function() {
|
|
router.createHash( this.sandbox.createStubInstance( mw.mmv.routing.Route ) );
|
|
} ), 'Exception thrown for unknown Route subclass' );
|
|
assert.ok( mw.mmv.testHelpers.getException( function() {
|
|
router.createHash( {} );
|
|
} ), 'Exception thrown for non-Route class' );
|
|
} );
|
|
|
|
QUnit.test( 'parseHash() with invalid hashes', 4, function ( assert ) {
|
|
var router = new mw.mmv.routing.Router();
|
|
|
|
assert.ok( !router.parseHash( 'foo' ), 'Non-MMV hash is rejected.' );
|
|
assert.ok( !router.parseHash( '#foo' ), 'Non-MMV hash is rejected (with #).' );
|
|
assert.ok( !router.parseHash( 'mediaviewer/foo/bar' ), 'Invalid MMV hash is rejected.' );
|
|
assert.ok( !router.parseHash( '#mediaviewer/foo/bar' ), 'Invalid MMV hash is rejected (with #).' );
|
|
} );
|
|
|
|
QUnit.test( 'parseHash() backwards compatibility', 2, function ( assert ) {
|
|
var route,
|
|
router = new mw.mmv.routing.Router();
|
|
|
|
route = router.parseHash( '#mediaviewer/File:Foo bar.png' );
|
|
assert.strictEqual( route.fileTitle.getPrefixedDb(), 'File:Foo_bar.png',
|
|
'Old urls (with space) are handled' );
|
|
|
|
route = router.parseHash( '#mediaviewer/File:Mexican \'Alien\' Piñata.jpg' );
|
|
assert.strictEqual( route.fileTitle.getPrefixedDb(), 'File:Mexican_\'Alien\'_Piñata.jpg',
|
|
'Old urls (without percent-encoding) are handled' );
|
|
} );
|
|
|
|
QUnit.test( 'createHashedUrl()', 2, function ( assert ) {
|
|
var url,
|
|
route = new mw.mmv.routing.MainFileRoute(),
|
|
router = new mw.mmv.routing.Router();
|
|
|
|
url = router.createHashedUrl( route, 'http://example.com/' );
|
|
assert.strictEqual( url, 'http://example.com/#mediaviewer', 'Url generation works' );
|
|
|
|
url = router.createHashedUrl( route, 'http://example.com/#foo' );
|
|
assert.strictEqual( url, 'http://example.com/#mediaviewer', 'Urls with fragments are handled' );
|
|
} );
|
|
|
|
QUnit.test( 'parseLocation()', 2, function ( assert ) {
|
|
var location, route,
|
|
router = new mw.mmv.routing.Router();
|
|
|
|
location = { href: 'http://example.com/foo#mediaviewer/File:Foo.png' };
|
|
route = router.parseLocation( location );
|
|
assert.strictEqual( route.fileTitle.getPrefixedDb(), 'File:Foo.png', 'Reading location works' );
|
|
|
|
location = { href: 'http://example.com/foo' };
|
|
route = router.parseLocation( location );
|
|
assert.ok( !route, 'Reading location without fragment part works' );
|
|
} );
|
|
|
|
QUnit.test( 'parseLocation() with real location', 2, function ( assert ) {
|
|
var route, title, hash,
|
|
router = new mw.mmv.routing.Router();
|
|
|
|
// mw.Title does not accept % in page names
|
|
this.sandbox.stub( mw, 'Title', function( name ) { return {
|
|
name: name,
|
|
getPrefixedDb: function() { return name; }
|
|
}; } );
|
|
title = new mw.Title( 'File:%40.png' );
|
|
hash = router.createHash( new mw.mmv.routing.ThumbnailRoute( title ) );
|
|
|
|
window.location.hash = hash;
|
|
route = router.parseLocation( window.location );
|
|
assert.strictEqual( route.fileTitle.getPrefixedDb(), 'File:%40.png',
|
|
'Reading location set via location.hash works' );
|
|
|
|
if ( window.history ) {
|
|
window.history.pushState( null, null, '#' + hash );
|
|
route = router.parseLocation( window.location );
|
|
assert.strictEqual( route.fileTitle.getPrefixedDb(), 'File:%40.png',
|
|
'Reading location set via pushState() works' );
|
|
} else {
|
|
assert.ok( true, 'Skipped pushState() test, not supported on this browser' );
|
|
}
|
|
|
|
// reset location, might interfere with other tests
|
|
window.location.hash = '#';
|
|
} );
|
|
}( mediaWiki ) );
|