summaryrefslogtreecommitdiff
path: root/www/wiki/resources/lib/oojs-router/oojs-router.js
diff options
context:
space:
mode:
Diffstat (limited to 'www/wiki/resources/lib/oojs-router/oojs-router.js')
-rw-r--r--www/wiki/resources/lib/oojs-router/oojs-router.js205
1 files changed, 205 insertions, 0 deletions
diff --git a/www/wiki/resources/lib/oojs-router/oojs-router.js b/www/wiki/resources/lib/oojs-router/oojs-router.js
new file mode 100644
index 00000000..b136923e
--- /dev/null
+++ b/www/wiki/resources/lib/oojs-router/oojs-router.js
@@ -0,0 +1,205 @@
+/*!
+ * OOjs Router v0.1.0
+ * https://www.mediawiki.org/wiki/OOjs
+ *
+ * Copyright 2011-2016 OOjs Team and other contributors.
+ * Released under the MIT license
+ * http://oojs-router.mit-license.org
+ *
+ * Date: 2016-05-05T19:27:58Z
+ */
+( 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
+ */
+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 = {};
+ this.enabled = true;
+ this.oldHash = this.getPath();
+
+ $( window ).on( 'popstate', function () {
+ self.emit( 'popstate' );
+ } );
+
+ $( window ).on( 'hashchange', function () {
+ self.emit( 'hashchange' );
+ } );
+
+ this.on( 'hashchange', function () {
+ // ev.originalEvent.newURL is undefined on Android 2.x
+ var routeEv;
+
+ if ( self.enabled ) {
+ routeEv = $.Event( 'route', {
+ path: self.getPath()
+ } );
+ self.emit( 'route', routeEv );
+
+ if ( !routeEv.isDefaultPrevented() ) {
+ self.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 );
+ }
+ } else {
+ self.enabled = true;
+ }
+
+ self.oldHash = self.getPath();
+ } );
+}
+OO.mixinClass( Router, OO.EventEmitter );
+
+/**
+ * Check the current route and run appropriate callback if it matches.
+ *
+ * @method
+ */
+Router.prototype.checkRoute = function () {
+ var hash = this.getPath();
+
+ $.each( this.routes, function ( id, entry ) {
+ return !matchRoute( hash, entry );
+ } );
+};
+
+/**
+ * Bind a specific callback to a hash-based route, e.g.
+ *
+ * @example
+ * route( 'alert', function () { alert( 'something' ); } );
+ * route( /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 {Function} callback Callback to be run when hash changes to one
+ * that matches.
+ */
+Router.prototype.route = function ( path, callback ) {
+ var entry = {
+ path: typeof path === 'string' ?
+ new RegExp( '^' + path.replace( /[\\^$*+?.()|[\]{}]/g, '\\$&' ) + '$' )
+ : path,
+ callback: callback
+ };
+ this.routes[ entry.path ] = entry;
+};
+
+/**
+ * Navigate to a specific route.
+ *
+ * @method
+ * @param {string} path string with a route (hash without #).
+ */
+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
+ // the side-effect of resetting the scroll position when navigating the
+ // history.
+ if ( path === '' && history && history.pushState ) {
+ // To clear the hash we need to cut the hash from the URL.
+ path = window.location.href.replace( /#.*$/, '' );
+ history.pushState( null, document.title, path );
+ this.checkRoute();
+ } else {
+ window.location.hash = path;
+ }
+};
+
+/**
+ * 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}
+ */
+Router.prototype.back = function () {
+ var deferredRequest = $.Deferred(),
+ self = this,
+ timeoutID;
+
+ this.once( 'popstate', function () {
+ clearTimeout( timeoutID );
+ deferredRequest.resolve();
+ } );
+
+ this.goBack();
+
+ // 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
+ // this problem, it's better to fall back this way rather than singling out browsers
+ // and resolving the deferred request for them individually.
+ // 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();
+ }, 50 );
+
+ return deferredRequest;
+};
+
+/**
+ * Get current path (hash).
+ *
+ * @method
+ * @return {string} Current path.
+ */
+Router.prototype.getPath = function () {
+ return window.location.hash.slice( 1 );
+};
+
+/**
+ * Determine if current browser supports onhashchange event
+ *
+ * @method
+ * @return {boolean}
+ */
+Router.prototype.isSupported = function () {
+ return 'onhashchange' in window;
+};
+
+module.exports = Router;
+
+}( jQuery ) );