--- /dev/null
+Copyright 2011-2016 OOjs Team and other contributors.
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+++ /dev/null
-Copyright 2011-2016 OOjs Team and other contributors.
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
/*!
* OOjs Router v0.1.0
- * https://www.mediawiki.org/wiki/OOjs
+ * https://www.mediawiki.org/wiki/OOjs_Router
*
- * Copyright 2011-2016 OOjs Team and other contributors.
+ * Copyright 2011-2019 OOjs Team and other contributors.
* Released under the MIT license
- * http://oojs-router.mit-license.org
+ * http://oojs.mit-license.org
*
- * Date: 2016-05-05T19:27:58Z
+ * Date: 2019-01-11T03:40:55Z
*/
( function ( $ ) {
'use strict';
-/**
- * Does hash match entry.path? If it does apply the
- * callback for the Entry object.
- *
- * @method
- * @private
- * @ignore
- * @param {string} hash string to match
- * @param {Object} entry Entry object
- * @return {boolean} Whether hash matches entry.path
- */
-function matchRoute( hash, entry ) {
- var match = hash.match( entry.path );
- if ( match ) {
- entry.callback.apply( this, match.slice( 1 ) );
- return true;
- }
- return false;
-}
-
/**
* Provides navigation routing and location information
*
- * @class Router
- * @mixins OO.EventEmitter
+ * @class OO.Router
+ * @extends OO.Registry
*/
-function Router() {
- var self = this;
- OO.EventEmitter.call( this );
- // use an object instead of an array for routes so that we don't
- // duplicate entries that already exist
- this.routes = {};
+OO.Router = function OoRouter() {
+ var router = this;
+
+ // Parent constructor
+ OO.Router.parent.call( this );
+
this.enabled = true;
this.oldHash = this.getPath();
$( window ).on( 'popstate', function () {
- self.emit( 'popstate' );
+ router.emit( 'popstate' );
} );
$( window ).on( 'hashchange', function () {
- self.emit( 'hashchange' );
+ router.emit( 'hashchange' );
} );
this.on( 'hashchange', function () {
- // ev.originalEvent.newURL is undefined on Android 2.x
- var routeEv;
+ // event.originalEvent.newURL is undefined on Android 2.x
+ var routeEvent;
- if ( self.enabled ) {
- routeEv = $.Event( 'route', {
- path: self.getPath()
+ if ( router.enabled ) {
+ routeEvent = $.Event( 'route', {
+ path: router.getPath()
} );
- self.emit( 'route', routeEv );
+ router.emit( 'route', routeEvent );
- if ( !routeEv.isDefaultPrevented() ) {
- self.checkRoute();
+ if ( !routeEvent.isDefaultPrevented() ) {
+ router.checkRoute();
} else {
// if route was prevented, ignore the next hash change and revert the
// hash to its old value
- self.enabled = false;
- self.navigate( self.oldHash );
+ router.enabled = false;
+ router.navigate( router.oldHash );
}
} else {
- self.enabled = true;
+ router.enabled = true;
}
- self.oldHash = self.getPath();
+ router.oldHash = router.getPath();
} );
-}
-OO.mixinClass( Router, OO.EventEmitter );
+};
+
+/* Inheritance */
+
+OO.inheritClass( OO.Router, OO.Registry );
+
+/* Events */
/**
- * Check the current route and run appropriate callback if it matches.
+ * @event popstate
+ */
+
+/**
+ * @event hashchange
+ */
+
+/**
+ * @event route
+ * @param {jQuery.Event} routeEvent
+ */
+
+/* Static Methods */
+
+/**
+ * Determine if current browser supports this router
*
- * @method
+ * @return {boolean} The browser is supported
*/
-Router.prototype.checkRoute = function () {
- var hash = this.getPath();
+OO.Router.static.isSupported = function () {
+ return 'onhashchange' in window;
+};
- $.each( this.routes, function ( id, entry ) {
- return !matchRoute( hash, entry );
- } );
+/* Methods */
+
+/**
+ * Check the current route and run appropriate callback if it matches.
+ */
+OO.Router.prototype.checkRoute = function () {
+ var id, entry, match,
+ hash = this.getPath();
+
+ for ( id in this.registry ) {
+ entry = this.registry[ id ];
+ match = hash.match( entry.path );
+ if ( match ) {
+ entry.callback.apply( this, match.slice( 1 ) );
+ return;
+ }
+ }
};
/**
* Bind a specific callback to a hash-based route, e.g.
*
* @example
- * route( 'alert', function () { alert( 'something' ); } );
- * route( /hi-(.*)/, function ( name ) { alert( 'Hi ' + name ) } );
+ * addRoute( 'alert', function () { alert( 'something' ); } );
+ * addRoute( /hi-(.*)/, function ( name ) { alert( 'Hi ' + name ) } );
+ *
* Note that after defining all available routes it is up to the caller
* to check the existing route via the checkRoute method.
*
- * @method
- * @param {Object} path string or RegExp to match.
+ * @param {string|RegExp} path Path to match, string or regular expression
* @param {Function} callback Callback to be run when hash changes to one
* that matches.
*/
-Router.prototype.route = function ( path, callback ) {
+OO.Router.prototype.addRoute = function ( path, callback ) {
var entry = {
path: typeof path === 'string' ?
- new RegExp( '^' + path.replace( /[\\^$*+?.()|[\]{}]/g, '\\$&' ) + '$' )
- : path,
+ new RegExp( '^' + path.replace( /[\\^$*+?.()|[\]{}]/g, '\\$&' ) + '$' ) :
+ path,
callback: callback
};
- this.routes[ entry.path ] = entry;
+ this.register( entry.path.toString(), entry );
};
+/**
+ * @deprecated Use #addRoute
+ */
+OO.Router.prototype.route = OO.Router.prototype.addRoute;
+
/**
* Navigate to a specific route.
*
- * @method
- * @param {string} path string with a route (hash without #).
+ * @param {string} path String with a route (hash without #).
*/
-Router.prototype.navigate = function ( path ) {
+OO.Router.prototype.navigate = function ( path ) {
var history = window.history;
// Take advantage of `pushState` when available, to clear the hash and
// not leave `#` in the history. An entry with `#` in the history has
}
};
-/**
- * Triggers back on the window
- */
-Router.prototype.goBack = function () {
- window.history.back();
-};
-
/**
* Navigate to the previous route. This is a wrapper for window.history.back
*
- * @method
- * @return {jQuery.Deferred}
+ * @return {jQuery.Promise} Promise which resolves when the back navigation is complete
*/
-Router.prototype.back = function () {
- var deferredRequest = $.Deferred(),
- self = this,
- timeoutID;
+OO.Router.prototype.back = function () {
+ var timeoutID,
+ router = this,
+ deferred = $.Deferred();
this.once( 'popstate', function () {
clearTimeout( timeoutID );
- deferredRequest.resolve();
+ deferred.resolve();
} );
- this.goBack();
+ window.history.back();
// If for some reason (old browser, bug in IE/windows 8.1, etc) popstate doesn't fire,
// resolve manually. Since we don't know for sure which browsers besides IE10/11 have
// See https://connect.microsoft.com/IE/feedback/details/793618/history-back-popstate-not-working-as-expected-in-webview-control
// Give browser a few ms to update its history.
timeoutID = setTimeout( function () {
- self.off( 'popstate' );
- deferredRequest.resolve();
+ router.off( 'popstate' );
+ deferred.resolve();
}, 50 );
- return deferredRequest;
+ return deferred.promise();
};
/**
* Get current path (hash).
*
- * @method
* @return {string} Current path.
*/
-Router.prototype.getPath = function () {
+OO.Router.prototype.getPath = function () {
return window.location.hash.slice( 1 );
};
/**
- * Determine if current browser supports onhashchange event
- *
- * @method
- * @return {boolean}
+ * @deprecated Use static method
*/
-Router.prototype.isSupported = function () {
- return 'onhashchange' in window;
-};
+OO.Router.prototype.isSupported = OO.Router.static.isSupported;
-module.exports = Router;
+if ( typeof module !== 'undefined' && module.exports ) {
+ module.exports = OO.Router;
+}
}( jQuery ) );