mirror of
https://gerrit.wikimedia.org/r/mediawiki/extensions/MultimediaViewer
synced 2024-09-24 02:39:37 +00:00
Adopt mediawiki.router
Bug: T77258 Change-Id: Id4df92b0ebed3fb4f4b9269862c952f3968bf957
This commit is contained in:
parent
870735c0e9
commit
b1ade19388
|
@ -46,11 +46,6 @@
|
|||
"mmv/logging/mmv.logging.DimensionLogger.js",
|
||||
"mmv/logging/mmv.logging.ViewLogger.js",
|
||||
"mmv/logging/mmv.logging.PerformanceLogger.js",
|
||||
"mmv/routing/mmv.routing.js",
|
||||
"mmv/routing/mmv.routing.Route.js",
|
||||
"mmv/routing/mmv.routing.ThumbnailRoute.js",
|
||||
"mmv/routing/mmv.routing.MainFileRoute.js",
|
||||
"mmv/routing/mmv.routing.Router.js",
|
||||
"mmv/model/mmv.model.js",
|
||||
"mmv/model/mmv.model.IwTitle.js",
|
||||
"mmv/model/mmv.model.License.js",
|
||||
|
@ -109,6 +104,7 @@
|
|||
"mediawiki.user",
|
||||
"mediawiki.util",
|
||||
"oojs",
|
||||
"oojs-router",
|
||||
"jquery.fullscreen",
|
||||
"jquery.throttle-debounce",
|
||||
"jquery.color",
|
||||
|
@ -350,7 +346,8 @@
|
|||
"mediawiki.notify",
|
||||
"mediawiki.storage",
|
||||
"mmv.head",
|
||||
"oojs"
|
||||
"oojs",
|
||||
"oojs-router"
|
||||
],
|
||||
"messages": [
|
||||
"multimediaviewer-view-expanded",
|
||||
|
@ -414,9 +411,6 @@
|
|||
"tests/qunit/mmv/provider/mmv.provider.ThumbnailInfo.test.js",
|
||||
"tests/qunit/mmv/provider/mmv.provider.GuessedThumbnailInfo.test.js",
|
||||
"tests/qunit/mmv/provider/mmv.provider.Image.test.js",
|
||||
"tests/qunit/mmv/routing/mmv.routing.MainFileRoute.test.js",
|
||||
"tests/qunit/mmv/routing/mmv.routing.ThumbnailRoute.test.js",
|
||||
"tests/qunit/mmv/routing/mmv.routing.Router.test.js",
|
||||
"tests/qunit/mmv/ui/mmv.ui.test.js",
|
||||
"tests/qunit/mmv/ui/mmv.ui.canvas.test.js",
|
||||
"tests/qunit/mmv/ui/mmv.ui.canvasButtons.test.js",
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
{
|
||||
"name": "Base",
|
||||
"classes": [
|
||||
"mw.mmv",
|
||||
"mw.mmv.Config",
|
||||
"mw.mmv.EmbedFileFormatter",
|
||||
"mw.mmv.HtmlUtils",
|
||||
|
@ -33,12 +34,6 @@
|
|||
"mw.mmv.provider.*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Routers",
|
||||
"classes": [
|
||||
"mw.mmv.routing.*"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Interface",
|
||||
"classes": [
|
||||
|
@ -74,6 +69,12 @@
|
|||
"String"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "OOjs Router",
|
||||
"classes": [
|
||||
"OO.Router"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "OOUI",
|
||||
"classes": [
|
||||
|
|
|
@ -46,6 +46,11 @@
|
|||
* An HTML <img> element.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class OO.Router
|
||||
* <https://doc.wikimedia.org/oojs-router/master/#!/api/OO.Router>
|
||||
*/
|
||||
|
||||
/**
|
||||
* @class OO.ui.MenuOptionWidget
|
||||
* <https://doc.wikimedia.org/mediawiki-core/master/js/#!/api/OO.ui.MenuOptionWidget>
|
||||
|
|
|
@ -59,7 +59,6 @@
|
|||
// e.g. via a VE edit or pagination in a multipage file
|
||||
mw.hook( 'wikipage.content' ).add( $.proxy( this, 'processThumbs' ) );
|
||||
|
||||
this.browserHistory = window.history;
|
||||
}
|
||||
|
||||
MMVB = MultimediaViewerBootstrap.prototype;
|
||||
|
@ -417,7 +416,7 @@
|
|||
this.ensureEventHandlersAreSetUp();
|
||||
|
||||
return this.loadViewer( true ).then( function ( viewer ) {
|
||||
viewer.loadImageByTitle( title, true );
|
||||
viewer.loadImageByTitle( title, false );
|
||||
} );
|
||||
};
|
||||
|
||||
|
@ -461,8 +460,8 @@
|
|||
* @private
|
||||
*/
|
||||
MMVB.isViewerHash = function () {
|
||||
return window.location.hash.indexOf( '#mediaviewer/' ) === 0 ||
|
||||
window.location.hash.indexOf( '#/media/' ) === 0;
|
||||
var path = OO.Router.prototype.getPath();
|
||||
return path.match( mw.mmv.ROUTE_REGEXP ) || path.match( mw.mmv.LEGACY_ROUTE_REGEXP );
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -479,13 +478,8 @@
|
|||
return;
|
||||
}
|
||||
|
||||
if ( this.skipNextHashHandling ) {
|
||||
this.skipNextHashHandling = false;
|
||||
return;
|
||||
}
|
||||
|
||||
this.loadViewer( this.isViewerHash() ).then( function ( viewer ) {
|
||||
viewer.hash();
|
||||
viewer.router.checkRoute();
|
||||
// this is an ugly temporary fix to avoid a black screen of death when
|
||||
// the page is loaded with an invalid MMV url
|
||||
if ( !viewer.isOpen ) {
|
||||
|
@ -498,35 +492,6 @@
|
|||
} );
|
||||
};
|
||||
|
||||
/**
|
||||
* Handles hash change requests coming from mmv
|
||||
*
|
||||
* @param {jQuery.Event} e Custom mmv-hash event
|
||||
*/
|
||||
MMVB.internalHashChange = function ( e ) {
|
||||
var hash = e.hash,
|
||||
title = e.title;
|
||||
|
||||
// The advantage of using pushState when it's available is that it has to ability to truly
|
||||
// clear the hash, not leaving "#" in the history
|
||||
// An entry with "#" in the history has the side-effect of resetting the scroll position when navigating the history
|
||||
if ( this.browserHistory && this.browserHistory.pushState ) {
|
||||
// In order to truly clear the hash, we need to reconstruct the hash-free URL
|
||||
if ( hash === '#' ) {
|
||||
hash = window.location.href.replace( /#.*$/, '' );
|
||||
}
|
||||
|
||||
window.history.pushState( null, title, hash );
|
||||
} else {
|
||||
// Since we voluntarily changed the hash, we don't want MMVB.hash (which will trigger on hashchange event) to treat it
|
||||
this.skipNextHashHandling = true;
|
||||
|
||||
window.location.hash = hash;
|
||||
}
|
||||
|
||||
document.title = title;
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiates a new viewer if necessary
|
||||
*
|
||||
|
@ -551,15 +516,11 @@
|
|||
/** @property {boolean} eventHandlersHaveBeenSetUp tracks domready event handler state */
|
||||
this.eventHandlersHaveBeenSetUp = true;
|
||||
|
||||
$( window ).on( this.browserHistory && this.browserHistory.pushState ? 'popstate.mmvb' : 'hashchange', function () {
|
||||
self.hash();
|
||||
} );
|
||||
|
||||
// Interpret any hash that might already be in the url
|
||||
self.hash( true );
|
||||
|
||||
$( document ).on( 'mmv-hash', function ( e ) {
|
||||
self.internalHashChange( e );
|
||||
$( document ).on( 'mmv-setup-overlay', function () {
|
||||
self.setupOverlay();
|
||||
} ).on( 'mmv-cleanup-overlay', function () {
|
||||
self.cleanupOverlay();
|
||||
} );
|
||||
|
@ -569,8 +530,7 @@
|
|||
* Cleans up event handlers, used for tests
|
||||
*/
|
||||
MMVB.cleanupEventHandlers = function () {
|
||||
$( window ).off( 'hashchange popstate.mmvb' );
|
||||
$( document ).off( 'mmv-hash' );
|
||||
$( document ).off( 'mmv-setup-overlay mmv-cleanup-overlay' );
|
||||
this.eventHandlersHaveBeenSetUp = false;
|
||||
};
|
||||
|
||||
|
|
|
@ -17,5 +17,31 @@
|
|||
|
||||
// Included on every page which has images so keep it lightweight.
|
||||
( function () {
|
||||
mw.mmv = {};
|
||||
mw.mmv = {
|
||||
/**
|
||||
* The media route prefix
|
||||
* @member mw.mmv
|
||||
*/
|
||||
ROUTE: 'media',
|
||||
/**
|
||||
* RegExp representing the media route
|
||||
* @member mw.mmv
|
||||
*/
|
||||
ROUTE_REGEXP: /^\/media\/(.+)$/,
|
||||
/**
|
||||
* @property
|
||||
* RegExp representing the legacy media route
|
||||
* @member mw.mmv
|
||||
*/
|
||||
LEGACY_ROUTE_REGEXP: /^mediaviewer\/(.+)$/,
|
||||
/**
|
||||
* Returns the location hash (route string) for the given file title.
|
||||
* @param {string} imageFileTitle the file title
|
||||
* @return {string} the location hash
|
||||
* @member mw.mmv
|
||||
*/
|
||||
getMediaHash: function ( imageFileTitle ) {
|
||||
return '#/' + mw.mmv.ROUTE + '/' + imageFileTitle;
|
||||
}
|
||||
};
|
||||
}() );
|
||||
|
|
|
@ -27,11 +27,6 @@
|
|||
function EmbedFileFormatter() {
|
||||
/** @property {mw.mmv.HtmlUtils} htmlUtils - */
|
||||
this.htmlUtils = new mw.mmv.HtmlUtils();
|
||||
|
||||
/**
|
||||
* @property {mw.mmv.routing.Router} router -
|
||||
*/
|
||||
this.router = new mw.mmv.routing.Router();
|
||||
}
|
||||
EFFP = EmbedFileFormatter.prototype;
|
||||
|
||||
|
@ -251,8 +246,7 @@
|
|||
* @return {string} URL
|
||||
*/
|
||||
EFFP.getLinkUrl = function ( info ) {
|
||||
var route = new mw.mmv.routing.ThumbnailRoute( info.imageInfo.title );
|
||||
return this.router.createHashedUrl( route, info.imageInfo.descriptionUrl );
|
||||
return info.imageInfo.descriptionUrl + mw.mmv.getMediaHash( info.imageInfo.title );
|
||||
};
|
||||
|
||||
mw.mmv.EmbedFileFormatter = EmbedFileFormatter;
|
||||
|
|
|
@ -28,12 +28,6 @@
|
|||
*/
|
||||
function Share( $container ) {
|
||||
mw.mmv.ui.reuse.Tab.call( this, $container );
|
||||
|
||||
/**
|
||||
* @property {mw.mmv.routing.Router} router -
|
||||
*/
|
||||
this.router = new mw.mmv.routing.Router();
|
||||
|
||||
this.init();
|
||||
}
|
||||
OO.inheritClass( Share, mw.mmv.ui.reuse.Tab );
|
||||
|
@ -115,8 +109,7 @@
|
|||
* @param {mw.mmv.model.Image} image
|
||||
*/
|
||||
SP.set = function ( image ) {
|
||||
var route = new mw.mmv.routing.ThumbnailRoute( image.title ),
|
||||
url = this.router.createHashedUrl( route, image.descriptionUrl );
|
||||
var url = image.descriptionUrl + mw.mmv.getMediaHash( image.title );
|
||||
|
||||
this.pageInput.setValue( url );
|
||||
|
||||
|
|
|
@ -79,9 +79,11 @@
|
|||
this.currentIndex = 0;
|
||||
|
||||
/**
|
||||
* @property {mw.mmv.routing.Router} router -
|
||||
* @property {OO.Router} router
|
||||
*/
|
||||
this.router = new mw.mmv.routing.Router();
|
||||
this.router = new OO.Router();
|
||||
this.setupRouter();
|
||||
comingFromHashChange = false;
|
||||
|
||||
/**
|
||||
* UI object used to display the pictures in the page.
|
||||
|
@ -245,8 +247,9 @@
|
|||
*
|
||||
* @param {mw.mmv.LightboxImage} image
|
||||
* @param {HTMLImageElement} initialImage A thumbnail to use as placeholder while the image loads
|
||||
* @param {boolean} useReplaceState Whether to update history entry to avoid long history queues
|
||||
*/
|
||||
MMVP.loadImage = function ( image, initialImage ) {
|
||||
MMVP.loadImage = function ( image, initialImage, useReplaceState ) {
|
||||
var imageWidths,
|
||||
canvasDimensions,
|
||||
imagePromise,
|
||||
|
@ -264,12 +267,14 @@
|
|||
this.currentImageFileTitle = image.filePageTitle;
|
||||
|
||||
if ( !this.isOpen ) {
|
||||
$( document ).trigger( $.Event( 'mmv-setup-overlay' ) );
|
||||
this.ui.open();
|
||||
this.isOpen = true;
|
||||
} else {
|
||||
this.ui.empty();
|
||||
}
|
||||
this.setHash();
|
||||
|
||||
this.setMediaHash( useReplaceState );
|
||||
|
||||
// At this point we can't show the thumbnail because we don't
|
||||
// know what size it should be. We still assign it to allow for
|
||||
|
@ -384,29 +389,25 @@
|
|||
viewer.ui.panel.scroller.animateMetadataOnce();
|
||||
viewer.preloadDependencies();
|
||||
} );
|
||||
|
||||
this.comingFromHashChange = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Loads an image by its title
|
||||
*
|
||||
* @param {mw.Title} title
|
||||
* @param {boolean} updateHash Viewer should update the location hash when true
|
||||
* @param {boolean} useReplaceState Whether to update history entry to avoid long history queues
|
||||
*/
|
||||
MMVP.loadImageByTitle = function ( title, updateHash ) {
|
||||
MMVP.loadImageByTitle = function ( title, useReplaceState ) {
|
||||
var i, thumb;
|
||||
|
||||
if ( !this.thumbs || !this.thumbs.length ) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.comingFromHashChange = !updateHash;
|
||||
|
||||
for ( i = 0; i < this.thumbs.length; i++ ) {
|
||||
thumb = this.thumbs[ i ];
|
||||
if ( thumb.title.getPrefixedText() === title.getPrefixedText() ) {
|
||||
this.loadImage( thumb.image, thumb.$thumb.clone()[ 0 ], true );
|
||||
this.loadImage( thumb.image, thumb.$thumb.clone()[ 0 ], useReplaceState );
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -877,17 +878,15 @@
|
|||
* Handles close event coming from the lightbox
|
||||
*/
|
||||
MMVP.close = function () {
|
||||
var windowTitle;
|
||||
|
||||
this.viewLogger.recordViewDuration();
|
||||
this.viewLogger.unattach();
|
||||
|
||||
windowTitle = this.createDocumentTitle( null );
|
||||
document.title = this.createDocumentTitle( null );
|
||||
|
||||
if ( comingFromHashChange === false ) {
|
||||
$( document ).trigger( $.Event( 'mmv-hash', { hash: '#', title: windowTitle } ) );
|
||||
} else {
|
||||
if ( comingFromHashChange ) {
|
||||
comingFromHashChange = false;
|
||||
} else {
|
||||
this.router.back();
|
||||
}
|
||||
|
||||
// This has to happen after the hash reset, because setting the hash to # will reset the page scroll
|
||||
|
@ -897,36 +896,56 @@
|
|||
};
|
||||
|
||||
/**
|
||||
* Handles a hash change coming from the browser
|
||||
* Sets up the route handlers
|
||||
*/
|
||||
MMVP.hash = function () {
|
||||
var route = this.router.parseLocation( window.location );
|
||||
|
||||
if ( route instanceof mw.mmv.routing.ThumbnailRoute ) {
|
||||
document.title = this.createDocumentTitle( route.fileTitle );
|
||||
this.loadImageByTitle( route.fileTitle );
|
||||
} else if ( this.isOpen ) {
|
||||
// This allows us to avoid the mmv-hash event that normally happens on close
|
||||
MMVP.setupRouter = function () {
|
||||
function route( fileName ) {
|
||||
var fileTitle;
|
||||
comingFromHashChange = true;
|
||||
|
||||
document.title = this.createDocumentTitle( null );
|
||||
if ( this.ui ) {
|
||||
// FIXME triggers mmv-close event, which calls viewer.close()
|
||||
this.ui.unattach();
|
||||
} else {
|
||||
this.close();
|
||||
fileName = decodeURIComponent( fileName );
|
||||
try {
|
||||
fileTitle = new mw.Title( fileName );
|
||||
this.loadImageByTitle( fileTitle );
|
||||
} catch ( err ) {
|
||||
// ignore routes to invalid titles
|
||||
mw.log.warn( err );
|
||||
}
|
||||
}
|
||||
this.router.addRoute( mw.mmv.ROUTE_REGEXP, route.bind( this ) );
|
||||
this.router.addRoute( mw.mmv.LEGACY_ROUTE_REGEXP, route.bind( this ) );
|
||||
|
||||
// handle empty hashes, and anchor links (page sections)
|
||||
this.router.addRoute( /^[^/]*$/, function () {
|
||||
comingFromHashChange = true;
|
||||
if ( this.isOpen ) {
|
||||
document.title = this.createDocumentTitle( null );
|
||||
if ( this.ui ) {
|
||||
// FIXME triggers mmv-close event, which calls viewer.close()
|
||||
this.ui.unattach();
|
||||
} else {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
}.bind( this ) );
|
||||
};
|
||||
|
||||
MMVP.setHash = function () {
|
||||
var route, windowTitle, hashFragment;
|
||||
if ( !this.comingFromHashChange ) {
|
||||
route = new mw.mmv.routing.ThumbnailRoute( this.currentImageFileTitle );
|
||||
hashFragment = '#' + this.router.createHash( route );
|
||||
windowTitle = this.createDocumentTitle( this.currentImageFileTitle );
|
||||
$( document ).trigger( $.Event( 'mmv-hash', { hash: hashFragment, title: windowTitle } ) );
|
||||
/**
|
||||
* Updates the hash to reflect an open image file
|
||||
* @param {boolean} useReplaceState Whether to update history entry to avoid long history queues
|
||||
*/
|
||||
MMVP.setMediaHash = function ( useReplaceState ) {
|
||||
if ( useReplaceState === undefined ) {
|
||||
useReplaceState = true;
|
||||
}
|
||||
if ( comingFromHashChange ) {
|
||||
comingFromHashChange = false;
|
||||
return;
|
||||
}
|
||||
document.title = this.createDocumentTitle( this.currentImageFileTitle );
|
||||
this.router.navigateTo( document.title, {
|
||||
path: mw.mmv.getMediaHash( this.currentImageFileTitle ),
|
||||
useReplaceState: useReplaceState
|
||||
} );
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,30 +0,0 @@
|
|||
/*
|
||||
* 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 () {
|
||||
/**
|
||||
* Route for showing the main image on the page, (whatever that means might depend on the page).
|
||||
* This is typically used on file pages.
|
||||
*
|
||||
* @class mw.mmv.routing.MainFileRoute
|
||||
* @extends mw.mmv.routing.Route
|
||||
* @constructor
|
||||
*/
|
||||
function MainFileRoute() {}
|
||||
OO.inheritClass( MainFileRoute, mw.mmv.routing.Route );
|
||||
mw.mmv.routing.MainFileRoute = MainFileRoute;
|
||||
}() );
|
|
@ -1,28 +0,0 @@
|
|||
/*
|
||||
* 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 () {
|
||||
/**
|
||||
* The base class for routes. Route classes don't really do anything, they are just simple
|
||||
* containers which specify a certain way of referencing images.
|
||||
*
|
||||
* @class mw.mmv.routing.Route
|
||||
* @constructor
|
||||
*/
|
||||
function Route() {}
|
||||
mw.mmv.routing.Route = Route;
|
||||
}() );
|
|
@ -1,197 +0,0 @@
|
|||
/*
|
||||
* 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 () {
|
||||
var RP;
|
||||
|
||||
/**
|
||||
* Converts between routes and their URL hash representations such as `mediaviewer/File:Foo`.
|
||||
*
|
||||
* @class mw.mmv.routing.Router
|
||||
* @constructor
|
||||
*/
|
||||
function Router() {}
|
||||
RP = Router.prototype;
|
||||
|
||||
/**
|
||||
* The prefix originally used to namespace MediaViewer routing hashes. Since there are many links
|
||||
* out there pointing to those URLs, we should keep them working.
|
||||
*
|
||||
* @protected
|
||||
* @property {string}
|
||||
*/
|
||||
RP.legacyPrefix = 'mediaviewer';
|
||||
|
||||
/**
|
||||
* The prefix used to namespace MediaViewer routing hashes
|
||||
*
|
||||
* @protected
|
||||
* @property {string}
|
||||
*/
|
||||
RP.applicationPrefix = '/media';
|
||||
|
||||
/**
|
||||
* Takes an URL hash and returns a route (or null if it could not be parsed).
|
||||
* Returns null for URL hashes which were not created by MediaViewer; you should use
|
||||
* #isMediaViewerHash() if you want to differentiate such hashes.
|
||||
* The hash can contain the starting `#` but does not have to; it should be in raw (percent-
|
||||
* encoded) form. Note that the percent-encoding behavior of location.hash is not consistent
|
||||
* between browsers; location.href can be used instead.
|
||||
*
|
||||
* @param {string} hash
|
||||
* @return {mw.mmv.routing.Route|null}
|
||||
*/
|
||||
RP.parseHash = function ( hash ) {
|
||||
var hashParts, fileName;
|
||||
|
||||
hashParts = this.tokenizeHash( hash );
|
||||
|
||||
if ( hashParts.length === 0 ) {
|
||||
return null;
|
||||
} else if ( hashParts.length === 1 ) {
|
||||
return new mw.mmv.routing.MainFileRoute();
|
||||
} else if ( hashParts.length === 2 ) {
|
||||
fileName = this.decodeRouteComponent( hashParts[ 1 ] );
|
||||
return new mw.mmv.routing.ThumbnailRoute( new mw.Title( fileName ) );
|
||||
}
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
/**
|
||||
* Takes a route and returns a string representation which can be used in the URL fragment.
|
||||
* The string does not contain the starting `#`, and it is encoded and guaranteed to be a
|
||||
* valid URL.
|
||||
*
|
||||
* @param {mw.mmv.routing.Route} route
|
||||
* @return {string}
|
||||
*/
|
||||
RP.createHash = function ( route ) {
|
||||
if ( route instanceof mw.mmv.routing.ThumbnailRoute ) {
|
||||
return this.applicationPrefix + '/' +
|
||||
this.encodeRouteComponent( 'File:' + route.fileTitle.getMain() );
|
||||
} else if ( route instanceof mw.mmv.routing.MainFileRoute ) {
|
||||
return this.applicationPrefix;
|
||||
} else if ( route instanceof mw.mmv.routing.Route ) {
|
||||
throw new Error( 'mw.mmv.routing.Router.createHash: not implemented for ' + route.constructor.name );
|
||||
} else {
|
||||
throw new Error( 'mw.mmv.routing.Router.createHash: invalid argument' );
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Like #parseHash(), but takes a window.location object. This is a helper function to make
|
||||
* sure that hashes are decoded correctly in spite of browser inconsistencies.
|
||||
*
|
||||
* @param {{href: string}} location window.location object
|
||||
* @return {mw.mmv.routing.Route|null}
|
||||
*/
|
||||
RP.parseLocation = function ( location ) {
|
||||
// Firefox percent-decodes location.hash: https://bugzilla.mozilla.org/show_bug.cgi?id=483304
|
||||
// which would cause inconsistent cross-browser behavior for files which have % or /
|
||||
// characters in their names. Using location.href is safe.
|
||||
return this.parseHash( location.href.split( '#' )[ 1 ] || '' );
|
||||
};
|
||||
|
||||
/**
|
||||
* Like #createHash(), but appends the hash to a specified URL
|
||||
*
|
||||
* @param {mw.mmv.routing.Route} route
|
||||
* @param {string} baseUrl the URL of the page the image is on (can contain a hash part,
|
||||
* which will be stripped)
|
||||
* @return {string} an URL to the same page as baseUrl, with the hash for the given route
|
||||
*/
|
||||
RP.createHashedUrl = function ( route, baseUrl ) {
|
||||
return baseUrl.replace( /#.*/, '' ) + '#' + this.createHash( route );
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns true if this hash looks like it was created by MediaViewer.
|
||||
* The hash can contain the starting `#` but does not have to.
|
||||
*
|
||||
* @param {string} hash
|
||||
* @return {boolean}
|
||||
*/
|
||||
RP.isMediaViewerHash = function ( hash ) {
|
||||
return this.tokenizeHash( hash ).length !== 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns "segments" of a hash. The first segment is always the #applicationPrefix.
|
||||
* If the hash is not a MediaViewer routing hash, an empty array is returned.
|
||||
* The input hash can contain the starting `#` but does not have to.
|
||||
*
|
||||
* @protected
|
||||
* @param {string} hash
|
||||
* @return {string[]}
|
||||
*/
|
||||
RP.tokenizeHash = function ( hash ) {
|
||||
var prefix,
|
||||
hashParts;
|
||||
|
||||
if ( hash[ 0 ] === '#' ) {
|
||||
hash = hash.slice( 1 );
|
||||
}
|
||||
|
||||
if ( hash.indexOf( this.legacyPrefix ) === 0 ) {
|
||||
prefix = this.legacyPrefix;
|
||||
}
|
||||
|
||||
if ( hash.indexOf( this.applicationPrefix ) === 0 ) {
|
||||
prefix = this.applicationPrefix;
|
||||
}
|
||||
|
||||
if ( prefix === undefined ) {
|
||||
return [];
|
||||
}
|
||||
|
||||
hash = hash.slice( prefix.length );
|
||||
|
||||
hashParts = hash.split( '/' );
|
||||
hashParts[ 0 ] = prefix;
|
||||
|
||||
return hashParts;
|
||||
};
|
||||
|
||||
/**
|
||||
* URL-encodes a route component.
|
||||
* Almost identical to mw.util.wikiUrlencode but makes sure there are no unencoded `/`
|
||||
* characters left since we use those to delimit components.
|
||||
*
|
||||
* @protected
|
||||
* @param {string} component
|
||||
* @return {string}
|
||||
*/
|
||||
RP.encodeRouteComponent = function ( component ) {
|
||||
return mw.util.wikiUrlencode( component ).replace( /\//g, '%2F' );
|
||||
};
|
||||
|
||||
/**
|
||||
* URL-decodes a route component.
|
||||
* This is basically just a standard percent-decode, but for backwards compatibility with
|
||||
* older schemes, we also replace spaces which underlines (the current scheme never has spaces).
|
||||
*
|
||||
* @protected
|
||||
* @param {string} component
|
||||
* @return {string}
|
||||
*/
|
||||
RP.decodeRouteComponent = function ( component ) {
|
||||
return decodeURIComponent( component ).replace( / /g, '_' );
|
||||
};
|
||||
|
||||
mw.mmv.routing.Router = Router;
|
||||
}() );
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
* 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 () {
|
||||
/**
|
||||
* Route for a specific thumbnail on the current page. The thumbnail must be that of a wiki
|
||||
* file (can't be e.g. an external image); can be a file from a remote repo though.
|
||||
*
|
||||
* @class mw.mmv.routing.ThumbnailRoute
|
||||
* @extends mw.mmv.routing.Route
|
||||
* @constructor
|
||||
* @param {mw.Title} fileTitle the name of the image
|
||||
*/
|
||||
function ThumbnailRoute( fileTitle ) {
|
||||
if ( !fileTitle ) {
|
||||
throw new Error( 'mw.mmv.routing.ThumbnailRoute: fileTitle parameter is required' );
|
||||
}
|
||||
this.fileTitle = fileTitle;
|
||||
}
|
||||
OO.inheritClass( ThumbnailRoute, mw.mmv.routing.Route );
|
||||
mw.mmv.routing.ThumbnailRoute = ThumbnailRoute;
|
||||
}() );
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* 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.mmv.routing = {};
|
||||
}() );
|
|
@ -78,8 +78,6 @@
|
|||
// wait for if we want to see these tests through
|
||||
mw.mmv.testHelpers.asyncMethod( bootstrap, 'loadViewer' );
|
||||
|
||||
bootstrap.setupEventHandlers();
|
||||
|
||||
// invalid hash, should not trigger MMV load
|
||||
window.location.hash = 'Foo';
|
||||
|
||||
|
@ -89,6 +87,7 @@
|
|||
// without us interfering with another immediate change
|
||||
setTimeout( function () {
|
||||
window.location.hash = hash;
|
||||
bootstrap.hash();
|
||||
} );
|
||||
|
||||
return mw.mmv.testHelpers.waitForAsync().then( function () {
|
||||
|
@ -430,58 +429,6 @@
|
|||
assert.strictEqual( bootstrap.setupOverlay.called, false, 'Overlay is not set up' );
|
||||
} );
|
||||
|
||||
QUnit.test( 'internalHashChange', function ( assert ) {
|
||||
var bootstrap = createBootstrap(),
|
||||
hash = '#/media/foo',
|
||||
callCount = 0,
|
||||
clock = this.sandbox.useFakeTimers();
|
||||
|
||||
window.location.hash = '';
|
||||
|
||||
bootstrap.loadViewer = function () {
|
||||
callCount++;
|
||||
return $.Deferred().reject();
|
||||
};
|
||||
|
||||
bootstrap.setupEventHandlers();
|
||||
|
||||
bootstrap.internalHashChange( { hash: hash } );
|
||||
clock.tick( 10 );
|
||||
|
||||
assert.strictEqual( callCount, 0, 'Viewer should not be loaded' );
|
||||
assert.strictEqual( window.location.hash, hash, 'Window\'s hash has been updated correctly' );
|
||||
|
||||
bootstrap.cleanupEventHandlers();
|
||||
window.location.hash = '';
|
||||
clock.restore();
|
||||
} );
|
||||
|
||||
QUnit.test( 'internalHashChange (legacy)', function ( assert ) {
|
||||
var bootstrap = createBootstrap(),
|
||||
hash = '#mediaviewer/foo',
|
||||
callCount = 0,
|
||||
clock = this.sandbox.useFakeTimers();
|
||||
|
||||
window.location.hash = '';
|
||||
|
||||
bootstrap.loadViewer = function () {
|
||||
callCount++;
|
||||
return $.Deferred().reject();
|
||||
};
|
||||
|
||||
bootstrap.setupEventHandlers();
|
||||
|
||||
bootstrap.internalHashChange( { hash: hash } );
|
||||
clock.tick( 10 );
|
||||
|
||||
assert.strictEqual( callCount, 0, 'Viewer should not be loaded' );
|
||||
assert.strictEqual( window.location.hash, hash, 'Window\'s hash has been updated correctly' );
|
||||
|
||||
bootstrap.cleanupEventHandlers();
|
||||
window.location.hash = '';
|
||||
clock.restore();
|
||||
} );
|
||||
|
||||
QUnit.test( 'Restoring article scroll position', function ( assert ) {
|
||||
var stubbedScrollTop,
|
||||
bootstrap = createBootstrap(),
|
||||
|
|
|
@ -54,11 +54,10 @@
|
|||
|
||||
assert.strictEqual( viewer.isOpen, false, 'Viewer is closed' );
|
||||
|
||||
viewer.isOpen = true;
|
||||
viewer.loadImageByTitle( image.filePageTitle );
|
||||
|
||||
// Verify that passing an invalid mmv hash when the mmv is open triggers unattach()
|
||||
window.location.hash = 'Foo';
|
||||
viewer.hash();
|
||||
|
||||
// Verify that mmv doesn't reset a foreign hash
|
||||
assert.strictEqual( window.location.hash, '#Foo', 'Foreign hash remains intact' );
|
||||
|
@ -71,7 +70,6 @@
|
|||
|
||||
// Verify that passing an invalid mmv hash when the mmv is closed doesn't trigger unattach()
|
||||
window.location.hash = 'Bar';
|
||||
viewer.hash();
|
||||
|
||||
// Verify that mmv doesn't reset a foreign hash
|
||||
assert.strictEqual( window.location.hash, '#Bar', 'Foreign hash remains intact' );
|
||||
|
@ -87,24 +85,19 @@
|
|||
// Open a valid mmv hash link and check that the right image is requested.
|
||||
// imageSrc contains a space without any encoding on purpose
|
||||
window.location.hash = '/media/File:' + imageSrc;
|
||||
viewer.hash();
|
||||
|
||||
// Reset the hash, because for some browsers switching from the non-URI-encoded to
|
||||
// the non-URI-encoded version of the same text with a space will not trigger a hash change
|
||||
window.location.hash = '';
|
||||
viewer.hash();
|
||||
|
||||
// Try again with an URI-encoded imageSrc containing a space
|
||||
window.location.hash = '/media/File:' + encodeURIComponent( imageSrc );
|
||||
viewer.hash();
|
||||
|
||||
// Reset the hash
|
||||
window.location.hash = '';
|
||||
viewer.hash();
|
||||
|
||||
// Try again with a legacy hash
|
||||
window.location.hash = 'mediaviewer/File:' + imageSrc;
|
||||
viewer.hash();
|
||||
|
||||
viewer.cleanupEventHandlers();
|
||||
|
||||
|
@ -703,7 +696,7 @@
|
|||
|
||||
viewer.currentImageFileTitle = title;
|
||||
bootstrap.setupEventHandlers();
|
||||
viewer.setHash();
|
||||
viewer.setMediaHash();
|
||||
|
||||
assert.ok( document.title.match( title.getNameText() ), 'File name is visible in title' );
|
||||
|
||||
|
|
|
@ -1,24 +0,0 @@
|
|||
/*
|
||||
* 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 () {
|
||||
QUnit.module( 'mmv.routing.MainFileRoute', QUnit.newMwEnvironment() );
|
||||
|
||||
QUnit.test( 'Constructor sanity checks', function ( assert ) {
|
||||
assert.ok( new mw.mmv.routing.MainFileRoute(), 'MainFileRoute created successfully' );
|
||||
} );
|
||||
}() );
|
|
@ -1,232 +0,0 @@
|
|||
/*
|
||||
* 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 () {
|
||||
QUnit.module( 'mmv.routing.Router', QUnit.newMwEnvironment() );
|
||||
|
||||
QUnit.test( 'Constructor sanity checks', function ( assert ) {
|
||||
var router;
|
||||
|
||||
router = new mw.mmv.routing.Router();
|
||||
assert.ok( router, 'Router created successfully' );
|
||||
} );
|
||||
|
||||
QUnit.test( 'isMediaViewerHash()', function ( assert ) {
|
||||
var router = new mw.mmv.routing.Router();
|
||||
|
||||
assert.strictEqual( router.isMediaViewerHash( 'mediaviewer/foo' ), true, 'Legacy hash' );
|
||||
assert.strictEqual( router.isMediaViewerHash( '#mediaviewer/foo' ), true, 'Legacy hash with #' );
|
||||
assert.strictEqual( router.isMediaViewerHash( 'mediaviewer' ), true, 'Bare legacy hash' );
|
||||
assert.strictEqual( router.isMediaViewerHash( '#mediaviewer' ), true, 'Bare legacy hash with #' );
|
||||
assert.strictEqual( router.isMediaViewerHash( '/media/foo' ), true, 'Normal hash' );
|
||||
assert.strictEqual( router.isMediaViewerHash( '#/media/foo' ), true, 'Normal hash with #' );
|
||||
assert.strictEqual( router.isMediaViewerHash( '/media' ), true, 'Bare hash' );
|
||||
assert.strictEqual( router.isMediaViewerHash( '#/media' ), true, 'Bare hash with #' );
|
||||
assert.strictEqual( router.isMediaViewerHash( 'foo/media' ), false, 'Foreign hash' );
|
||||
assert.strictEqual( router.isMediaViewerHash( '' ), false, 'Empty hash' );
|
||||
} );
|
||||
|
||||
QUnit.test( 'createHash()/parseHash()', 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.notOk( 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.notOk( 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', 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', function ( assert ) {
|
||||
var router = new mw.mmv.routing.Router();
|
||||
|
||||
assert.notOk( router.parseHash( 'foo' ), 'Non-MMV hash is rejected.' );
|
||||
assert.notOk( router.parseHash( '#foo' ), 'Non-MMV hash is rejected (with #).' );
|
||||
assert.notOk( router.parseHash( '/media/foo/bar' ), 'Invalid MMV hash is rejected.' );
|
||||
assert.notOk( router.parseHash( '#/media/foo/bar' ), 'Invalid MMV hash is rejected (with #).' );
|
||||
} );
|
||||
|
||||
QUnit.test( 'parseHash() backwards compatibility', 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()', 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/#/media', 'Url generation works' );
|
||||
|
||||
url = router.createHashedUrl( route, 'http://example.com/#foo' );
|
||||
assert.strictEqual( url, 'http://example.com/#/media', 'Urls with fragments are handled' );
|
||||
} );
|
||||
|
||||
QUnit.test( 'parseLocation()', 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#/media/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.notOk( route, 'Reading location without fragment part works' );
|
||||
} );
|
||||
|
||||
QUnit.test( 'parseLocation() with real location', 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,
|
||||
getMain: function () { return name.replace( /^File:/, '' ); }
|
||||
};
|
||||
} );
|
||||
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.getMain(), '%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.getMain(), '%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 = '#';
|
||||
} );
|
||||
|
||||
QUnit.test( 'tokenizeHash()', function ( assert ) {
|
||||
var router = new mw.mmv.routing.Router();
|
||||
|
||||
router.legacyPrefix = 'legacy';
|
||||
router.applicationPrefix = 'prefix';
|
||||
|
||||
assert.deepEqual( router.tokenizeHash( '#foo/bar' ), [], 'No known prefix' );
|
||||
|
||||
assert.deepEqual( router.tokenizeHash( '#prefix' ), [ 'prefix' ], 'Current prefix, with #' );
|
||||
assert.deepEqual( router.tokenizeHash( 'prefix' ), [ 'prefix' ], 'Current prefix, without #' );
|
||||
assert.deepEqual( router.tokenizeHash( '#prefix/bar' ), [ 'prefix', 'bar' ], 'Current prefix, with # and element' );
|
||||
assert.deepEqual( router.tokenizeHash( 'prefix/bar' ), [ 'prefix', 'bar' ], 'Current prefix, with element without #' );
|
||||
assert.deepEqual( router.tokenizeHash( '#prefix/bar/baz' ), [ 'prefix', 'bar', 'baz' ], 'Current prefix, with # and 2 elements' );
|
||||
assert.deepEqual( router.tokenizeHash( 'prefix/bar/baz' ), [ 'prefix', 'bar', 'baz' ], 'Current prefix, with 2 elements without #' );
|
||||
|
||||
assert.deepEqual( router.tokenizeHash( '#legacy' ), [ 'legacy' ], 'Legacy prefix, with #' );
|
||||
assert.deepEqual( router.tokenizeHash( 'legacy' ), [ 'legacy' ], 'Legacy prefix, without #' );
|
||||
assert.deepEqual( router.tokenizeHash( '#legacy/bar' ), [ 'legacy', 'bar' ], 'Legacy prefix, with # and element' );
|
||||
assert.deepEqual( router.tokenizeHash( 'legacy/bar' ), [ 'legacy', 'bar' ], 'Legacy prefix, with element without #' );
|
||||
assert.deepEqual( router.tokenizeHash( '#legacy/bar/baz' ), [ 'legacy', 'bar', 'baz' ], 'Legacy prefix, with # and 2 elements' );
|
||||
assert.deepEqual( router.tokenizeHash( 'legacy/bar/baz' ), [ 'legacy', 'bar', 'baz' ], 'Legacy prefix, with 2 elements without #' );
|
||||
|
||||
} );
|
||||
}() );
|
|
@ -1,32 +0,0 @@
|
|||
/*
|
||||
* 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 () {
|
||||
QUnit.module( 'mmv.routing.ThumbnailRoute', QUnit.newMwEnvironment() );
|
||||
|
||||
QUnit.test( 'Constructor sanity checks', function ( assert ) {
|
||||
var route,
|
||||
title = new mw.Title( 'File:Foo.png' );
|
||||
|
||||
route = new mw.mmv.routing.ThumbnailRoute( title );
|
||||
assert.ok( route, 'ThumbnailRoute created successfully' );
|
||||
|
||||
assert.ok( mw.mmv.testHelpers.getException( function () {
|
||||
return new mw.mmv.routing.ThumbnailRoute();
|
||||
} ), 'Exception is thrown when ThumbnailRoute is created without arguments' );
|
||||
} );
|
||||
}() );
|
Loading…
Reference in a new issue