router.js revision 8868b979badbb9aeed3c32f3fb02eafead9aedfe
f69d245bb21be88752420e834a6b6be37e9b525fTrippYUI.add('router', function(Y) {
f69d245bb21be88752420e834a6b6be37e9b525fTripp
f69d245bb21be88752420e834a6b6be37e9b525fTripp/**
a75ebc38c1de401b679953a9b87bd323f0f48d02TrippProvides URL-based routing using HTML5 `pushState()` or the location hash.
f69d245bb21be88752420e834a6b6be37e9b525fTripp
f69d245bb21be88752420e834a6b6be37e9b525fTripp@submodule router
f69d245bb21be88752420e834a6b6be37e9b525fTripp@since 3.4.0
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp**/
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTrippvar HistoryHash = Y.HistoryHash,
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp QS = Y.QueryString,
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp YArray = Y.Array,
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp win = Y.config.win,
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp location = win.location,
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp origin = location.origin || (location.protocol + '//' + location.host),
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp // We have to queue up pushState calls to avoid race conditions, since the
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp // popstate event doesn't actually provide any info on what URL it's
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp // associated with.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp saveQueue = [],
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp /**
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp Fired when the router is ready to begin dispatching to route handlers.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp You shouldn't need to wait for this event unless you plan to implement some
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp kind of custom dispatching logic. It's used internally in order to avoid
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp dispatching to an initial route if a browser history change occurs first.
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp @event ready
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp @param {Boolean} dispatched `true` if routes have already been dispatched
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp (most likely due to a history change).
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp @fireOnce
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp **/
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp EVT_READY = 'ready';
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp/**
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTrippProvides URL-based routing using HTML5 `pushState()` or the location hash.
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTrippThis makes it easy to wire up route handlers for different application states
a12380a54ea6e3ec3f16a090eee8ec5bf93aed83Trippwhile providing full back/forward navigation support and bookmarkable, shareable
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTrippURLs.
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp@class Router
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp@param {Object} [config] Config properties.
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp @param {Boolean} [config.html5] Overrides the default capability detection
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp and forces this router to use (`true`) or not use (`false`) HTML5
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp history.
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp @param {String} [config.root=''] Root path from which all routes should be
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp evaluated.
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp @param {Array} [config.routes=[]] Array of route definition objects.
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp@constructor
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp@extends Base
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp@since 3.4.0
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp**/
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTrippfunction Router() {
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp Router.superclass.constructor.apply(this, arguments);
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp}
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTrippY.Router = Y.extend(Router, Y.Base, {
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp // -- Protected Properties -------------------------------------------------
422668e1d4513bb870b8b576fd9d828c8872f074Tripp
422668e1d4513bb870b8b576fd9d828c8872f074Tripp /**
422668e1d4513bb870b8b576fd9d828c8872f074Tripp Whether or not `_dispatch()` has been called since this router was
422668e1d4513bb870b8b576fd9d828c8872f074Tripp instantiated.
8209f3939e32e0e5bde64192267fdaf9db6f4fbcTripp
8209f3939e32e0e5bde64192267fdaf9db6f4fbcTripp @property _dispatched
422668e1d4513bb870b8b576fd9d828c8872f074Tripp @type Boolean
422668e1d4513bb870b8b576fd9d828c8872f074Tripp @default undefined
422668e1d4513bb870b8b576fd9d828c8872f074Tripp @protected
422668e1d4513bb870b8b576fd9d828c8872f074Tripp **/
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
422668e1d4513bb870b8b576fd9d828c8872f074Tripp /**
422668e1d4513bb870b8b576fd9d828c8872f074Tripp Whether or not we're currently in the process of dispatching to routes.
422668e1d4513bb870b8b576fd9d828c8872f074Tripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @property _dispatching
422668e1d4513bb870b8b576fd9d828c8872f074Tripp @type Boolean
422668e1d4513bb870b8b576fd9d828c8872f074Tripp @default undefined
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @protected
422668e1d4513bb870b8b576fd9d828c8872f074Tripp **/
422668e1d4513bb870b8b576fd9d828c8872f074Tripp
422668e1d4513bb870b8b576fd9d828c8872f074Tripp /**
422668e1d4513bb870b8b576fd9d828c8872f074Tripp Cached copy of the `html5` attribute for internal use.
422668e1d4513bb870b8b576fd9d828c8872f074Tripp
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp @property _html5
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @type Boolean
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp @protected
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp **/
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp /**
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp Whether or not the `ready` event has fired yet.
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp @property _ready
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @type Boolean
422668e1d4513bb870b8b576fd9d828c8872f074Tripp @default undefined
422668e1d4513bb870b8b576fd9d828c8872f074Tripp @protected
422668e1d4513bb870b8b576fd9d828c8872f074Tripp **/
422668e1d4513bb870b8b576fd9d828c8872f074Tripp
422668e1d4513bb870b8b576fd9d828c8872f074Tripp /**
422668e1d4513bb870b8b576fd9d828c8872f074Tripp Regex used to match parameter placeholders in route paths.
422668e1d4513bb870b8b576fd9d828c8872f074Tripp
422668e1d4513bb870b8b576fd9d828c8872f074Tripp Subpattern captures:
422668e1d4513bb870b8b576fd9d828c8872f074Tripp
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp 1. Parameter prefix character. Either a `:` for subpath parameters that
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp should only match a single level of a path, or `*` for splat parameters
422668e1d4513bb870b8b576fd9d828c8872f074Tripp that should match any number of path levels.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp 2. Parameter name.
422668e1d4513bb870b8b576fd9d828c8872f074Tripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @property _regexPathParam
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @type RegExp
422668e1d4513bb870b8b576fd9d828c8872f074Tripp @protected
422668e1d4513bb870b8b576fd9d828c8872f074Tripp **/
422668e1d4513bb870b8b576fd9d828c8872f074Tripp _regexPathParam: /([:*])([\w\-]+)/g,
422668e1d4513bb870b8b576fd9d828c8872f074Tripp
422668e1d4513bb870b8b576fd9d828c8872f074Tripp /**
422668e1d4513bb870b8b576fd9d828c8872f074Tripp Regex that matches and captures the query portion of a URL, minus the
422668e1d4513bb870b8b576fd9d828c8872f074Tripp preceding `?` character, and discarding the hash portion of the URL if any.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
422668e1d4513bb870b8b576fd9d828c8872f074Tripp @property _regexUrlQuery
422668e1d4513bb870b8b576fd9d828c8872f074Tripp @type RegExp
422668e1d4513bb870b8b576fd9d828c8872f074Tripp @protected
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp **/
422668e1d4513bb870b8b576fd9d828c8872f074Tripp _regexUrlQuery: /\?([^#]*).*$/,
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
422668e1d4513bb870b8b576fd9d828c8872f074Tripp /**
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp Regex that matches everything before the path portion of a URL (the origin).
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp This will be used to strip this part of the URL from a string when we
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp only want the path.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @property _regexUrlOrigin
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @type RegExp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @protected
422668e1d4513bb870b8b576fd9d828c8872f074Tripp **/
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp _regexUrlOrigin: /^(?:[^\/#?:]+:\/\/|\/\/)[^\/]*/,
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp // -- Lifecycle Methods ----------------------------------------------------
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp initializer: function (config) {
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp var self = this;
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp self._html5 = self.get('html5');
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp self._routes = [];
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp // Necessary because setters don't run on init.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp this._setRoutes(config && config.routes ? config.routes :
422668e1d4513bb870b8b576fd9d828c8872f074Tripp this.get('routes'));
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp // Set up a history instance or hashchange listener.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp if (self._html5) {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp self._history = new Y.HistoryHTML5({force: true});
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp Y.after('history:change', self._afterHistoryChange, self);
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp } else {
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp Y.on('hashchange', self._afterHistoryChange, win, self);
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp }
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp // Fire a 'ready' event once we're ready to route. We wait first for all
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp // subclass initializers to finish, then for window.onload, and then an
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp // additional 20ms to allow the browser to fire a useless initial
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp // `popstate` event if it wants to (and Chrome always wants to).
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp self.publish(EVT_READY, {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp defaultFn : self._defReadyFn,
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp fireOnce : true,
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp preventable: false
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp });
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp self.once('initializedChange', function () {
422668e1d4513bb870b8b576fd9d828c8872f074Tripp Y.once('load', function () {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp setTimeout(function () {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp self.fire(EVT_READY, {dispatched: !!self._dispatched});
422668e1d4513bb870b8b576fd9d828c8872f074Tripp }, 20);
422668e1d4513bb870b8b576fd9d828c8872f074Tripp });
422668e1d4513bb870b8b576fd9d828c8872f074Tripp });
422668e1d4513bb870b8b576fd9d828c8872f074Tripp },
422668e1d4513bb870b8b576fd9d828c8872f074Tripp
422668e1d4513bb870b8b576fd9d828c8872f074Tripp destructor: function () {
422668e1d4513bb870b8b576fd9d828c8872f074Tripp if (this._html5) {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp Y.detach('history:change', this._afterHistoryChange, this);
422668e1d4513bb870b8b576fd9d828c8872f074Tripp } else {
422668e1d4513bb870b8b576fd9d828c8872f074Tripp Y.detach('hashchange', this._afterHistoryChange, win);
422668e1d4513bb870b8b576fd9d828c8872f074Tripp }
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp },
422668e1d4513bb870b8b576fd9d828c8872f074Tripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp // -- Public Methods -------------------------------------------------------
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp /**
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp Dispatches to the first route handler that matches the current URL, if any.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp If `dispatch()` is called before the `ready` event has fired, it will
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp automatically wait for the `ready` event before dispatching. Otherwise it
422668e1d4513bb870b8b576fd9d828c8872f074Tripp will dispatch immediately.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @method dispatch
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @chainable
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp **/
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp dispatch: function () {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp this.once(EVT_READY, function () {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp this._ready = true;
422668e1d4513bb870b8b576fd9d828c8872f074Tripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp if (this._html5 && this.upgrade()) {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp return;
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp } else {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp this._dispatch(this._getPath(), this._getURL());
422668e1d4513bb870b8b576fd9d828c8872f074Tripp }
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp });
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp return this;
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp },
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp /**
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp Gets the current route path, relative to the `root` (if any).
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp @method getPath
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @return {String} Current route path.
422668e1d4513bb870b8b576fd9d828c8872f074Tripp **/
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp getPath: function () {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp return this._getPath();
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp },
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp /**
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp Returns `true` if this router has at least one route that matches the
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp specified URL, `false` otherwise.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp This method enforces the same-origin security constraint on the specified
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp `url`; any URL which is not from the same origin as the current URL will
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp always return `false`.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @method hasRoute
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @param {String} url URL to match.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @return {Boolean} `true` if there's at least one matching route, `false`
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp otherwise.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp **/
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp hasRoute: function (url) {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp if (!this._hasSameOrigin(url)) {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp return false;
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp }
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp return !!this.match(this.removeRoot(url)).length;
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp },
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp /**
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp Returns an array of route objects that match the specified URL path.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp This method is called internally to determine which routes match the current
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp path whenever the URL changes. You may override it if you want to customize
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp the route matching logic, although this usually shouldn't be necessary.
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp Each returned route object has the following properties:
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp * `callback`: A function or a string representing the name of a function
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp this router that should be executed when the route is triggered.
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp * `keys`: An array of strings representing the named parameters defined in
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp the route's path specification, if any.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp * `path`: The route's path specification, which may be either a string or
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp a regex.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp * `regex`: A regular expression version of the route's path specification.
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp This regex is used to determine whether the route matches a given path.
cc21b565833307c2b0b06deb4e3ab22c2a94be3eTripp
422668e1d4513bb870b8b576fd9d828c8872f074Tripp @example
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp router.route('/foo', function () {});
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp router.match('/foo');
8209f3939e32e0e5bde64192267fdaf9db6f4fbcTripp // => [{callback: ..., keys: [], path: '/foo', regex: ...}]
8209f3939e32e0e5bde64192267fdaf9db6f4fbcTripp
8209f3939e32e0e5bde64192267fdaf9db6f4fbcTripp @method match
4288e1894e685f74123435d45db06e5cef146e7fTripp @param {String} path URL path to match.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @return {Object[]} Array of route objects that match the specified path.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp **/
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp match: function (path) {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp return YArray.filter(this._routes, function (route) {
f69d245bb21be88752420e834a6b6be37e9b525fTripp return path.search(route.regex) > -1;
8209f3939e32e0e5bde64192267fdaf9db6f4fbcTripp });
422668e1d4513bb870b8b576fd9d828c8872f074Tripp },
422668e1d4513bb870b8b576fd9d828c8872f074Tripp
422668e1d4513bb870b8b576fd9d828c8872f074Tripp /**
422668e1d4513bb870b8b576fd9d828c8872f074Tripp Removes the `root` URL from the front of _url_ (if it's there) and returns
f69d245bb21be88752420e834a6b6be37e9b525fTripp the result. The returned path will always have a leading `/`.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @method removeRoot
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @param {String} url URL.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @return {String} Rootless path.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp **/
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp removeRoot: function (url) {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp var root = this.get('root');
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp // Strip out the non-path part of the URL, if any (e.g.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp // "http://foo.com"), so that we're left with just the path.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp url = url.replace(this._regexUrlOrigin, '');
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp if (root && url.indexOf(root) === 0) {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp url = url.substring(root.length);
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp }
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp return url.charAt(0) === '/' ? url : '/' + url;
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp },
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp /**
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp Replaces the current browser history entry with a new one, and dispatches to
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp the first matching route handler, if any.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp Behind the scenes, this method uses HTML5 `pushState()` in browsers that
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp support it (or the location hash in older browsers and IE) to change the
422668e1d4513bb870b8b576fd9d828c8872f074Tripp URL.
422668e1d4513bb870b8b576fd9d828c8872f074Tripp
422668e1d4513bb870b8b576fd9d828c8872f074Tripp The specified URL must share the same origin (i.e., protocol, host, and
422668e1d4513bb870b8b576fd9d828c8872f074Tripp port) as the current page, or an error will occur.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @example
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp // Starting URL: http://example.com/
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp router.replace('/path/');
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp // New URL: http://example.com/path/
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp router.replace('/path?foo=bar');
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp // New URL: http://example.com/path?foo=bar
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp router.replace('/');
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp // New URL: http://example.com/
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @method replace
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @param {String} [url] URL to set. This URL needs to be of the same origin as
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp the current URL. This can be a URL relative to the router's `root`
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp attribute. If no URL is specified, the page's current URL will be used.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @chainable
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @see save()
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp **/
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp replace: function (url) {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp return this._queue(url, true);
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp },
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp /**
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp Adds a route handler for the specified URL _path_.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp The _path_ parameter may be either a string or a regular expression. If it's
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp a string, it may contain named parameters: `:param` will match any single
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp part of a URL path (not including `/` characters), and `*param` will match
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp any number of parts of a URL path (including `/` characters). These named
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp parameters will be made available as keys on the `req.params` object that's
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp passed to route handlers.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp If the _path_ parameter is a regex, all pattern matches will be made
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp available as numbered keys on `req.params`, starting with `0` for the full
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp match, then `1` for the first subpattern match, and so on.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp Here's a set of sample routes along with URL paths that they match:
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp * Route: `/photos/:tag/:page`
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp * URL: `/photos/kittens/1`, params: `{tag: 'kittens', page: '1'}`
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp * URL: `/photos/puppies/2`, params: `{tag: 'puppies', page: '2'}`
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
f69d245bb21be88752420e834a6b6be37e9b525fTripp * Route: `/file/*path`
8209f3939e32e0e5bde64192267fdaf9db6f4fbcTripp * URL: `/file/foo/bar/baz.txt`, params: `{path: 'foo/bar/baz.txt'}`
8209f3939e32e0e5bde64192267fdaf9db6f4fbcTripp * URL: `/file/foo`, params: `{path: 'foo'}`
8209f3939e32e0e5bde64192267fdaf9db6f4fbcTripp
8209f3939e32e0e5bde64192267fdaf9db6f4fbcTripp If multiple route handlers match a given URL, they will be executed in the
f69d245bb21be88752420e834a6b6be37e9b525fTripp order they were added. The first route that was added will be the first to
f69d245bb21be88752420e834a6b6be37e9b525fTripp be executed.
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @example
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp router.route('/photos/:tag/:page', function (req, res, next) {
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp });
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @method route
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp @param {String|RegExp} path Path to match. May be a string or a regular
e393eced613f9b4a5fb6bdd461d0e0bf5064d5ecTripp expression.
@param {Function|String} callback Callback function to call whenever this
route is triggered. If specified as a string, the named function will be
called on this router instance.
@param {Object} callback.req Request object containing information about
the request. It contains the following properties.
@param {Array|Object} callback.req.params Captured parameters matched by
the route path specification. If a string path was used and contained
named parameters, then this will be a key/value hash mapping parameter
names to their matched values. If a regex path was used, this will be
an array of subpattern matches starting at index 0 for the full match,
then 1 for the first subpattern match, and so on.
@param {String} callback.req.path The current URL path.
@param {Object} callback.req.query Query hash representing the URL query
string, if any. Parameter names are keys, and are mapped to parameter
values.
@param {String} callback.req.url The full URL.
@param {String} callback.req.src What initiated the dispatch. In an
HTML5 browser, when the back/forward buttons are used, this property
will have a value of "popstate".
@param {Object} callback.res Response object containing methods and
information that relate to responding to a request. It contains the
following properties.
@param {Object} callback.res.req Reference to the request object.
@param {Function} callback.next Callback to pass control to the next
matching route. If you don't call this function, then no further route
handlers will be executed, even if there are more that match. If you do
call this function, then the next matching route handler (if any) will
be called, and will receive the same `req` object that was passed to
this route (so you can use the request object to pass data along to
subsequent routes).
@chainable
**/
route: function (path, callback) {
var keys = [];
this._routes.push({
callback: callback,
keys : keys,
path : path,
regex : this._getRegex(path, keys)
});
return this;
},
/**
Saves a new browser history entry and dispatches to the first matching route
handler, if any.
Behind the scenes, this method uses HTML5 `pushState()` in browsers that
support it (or the location hash in older browsers and IE) to change the
URL and create a history entry.
The specified URL must share the same origin (i.e., protocol, host, and
port) as the current page, or an error will occur.
@example
// Starting URL: http://example.com/
router.save('/path/');
// New URL: http://example.com/path/
router.save('/path?foo=bar');
// New URL: http://example.com/path?foo=bar
router.save('/');
// New URL: http://example.com/
@method save
@param {String} [url] URL to set. This URL needs to be of the same origin as
the current URL. This can be a URL relative to the router's `root`
attribute. If no URL is specified, the page's current URL will be used.
@chainable
@see replace()
**/
save: function (url) {
return this._queue(url);
},
/**
Upgrades a hash-based URL to an HTML5 URL if necessary. In non-HTML5
browsers, this method is a noop.
@method upgrade
@return {Boolean} `true` if the URL was upgraded, `false` otherwise.
**/
upgrade: function () {
if (!this._html5) {
return false;
}
// Get the full hash in all its glory!
var hash = HistoryHash.getHash();
if (hash && hash.charAt(0) === '/') {
// This is an HTML5 browser and we have a hash-based path in the
// URL, so we need to upgrade the URL to a non-hash URL. This
// will trigger a `history:change` event, which will in turn
// trigger a dispatch.
this.once(EVT_READY, function () {
this.replace(hash);
});
return true;
}
return false;
},
// -- Protected Methods ----------------------------------------------------
/**
Wrapper around `decodeURIComponent` that also converts `+` chars into
spaces.
@method _decode
@param {String} string String to decode.
@return {String} Decoded string.
@protected
**/
_decode: function (string) {
return decodeURIComponent(string.replace(/\+/g, ' '));
},
/**
Shifts the topmost `_save()` call off the queue and executes it. Does
nothing if the queue is empty.
@method _dequeue
@chainable
@see _queue
@protected
**/
_dequeue: function () {
var self = this,
fn;
// If window.onload hasn't yet fired, wait until it has before
// dequeueing. This will ensure that we don't call pushState() before an
// initial popstate event has fired.
if (!YUI.Env.windowLoaded) {
Y.once('load', function () {
self._dequeue();
});
return this;
}
fn = saveQueue.shift();
return fn ? fn() : this;
},
/**
Dispatches to the first route handler that matches the specified _path_.
If called before the `ready` event has fired, the dispatch will be aborted.
This ensures normalized behavior between Chrome (which fires a `popstate`
event on every pageview) and other browsers (which do not).
@method _dispatch
@param {String} path URL path.
@param {String} url Full URL.
@param {String} src What initiated the dispatch.
@chainable
@protected
**/
_dispatch: function (path, url, src) {
var self = this,
routes = self.match(path),
req, res;
self._dispatching = self._dispatched = true;
if (!routes || !routes.length) {
self._dispatching = false;
return self;
}
req = self._getRequest(path, url, src);
res = self._getResponse(req);
req.next = function (err) {
var callback, matches, route;
if (err) {
Y.error(err);
} else if ((route = routes.shift())) {
matches = route.regex.exec(path);
callback = typeof route.callback === 'string' ?
self[route.callback] : route.callback;
// Use named keys for parameter names if the route path contains
// named keys. Otherwise, use numerical match indices.
if (matches.length === route.keys.length + 1) {
req.params = YArray.hash(route.keys, matches.slice(1));
} else {
req.params = matches.concat();
}
callback.call(self, req, res, req.next);
}
};
req.next();
self._dispatching = false;
return self._dequeue();
},
/**
Gets the current path from the location hash, or an empty string if the
hash is empty.
@method _getHashPath
@return {String} Current hash path, or an empty string if the hash is empty.
@protected
**/
_getHashPath: function () {
return HistoryHash.getHash().replace(this._regexUrlQuery, '');
},
/**
Gets the location origin (i.e., protocol, host, and port) as a URL.
@example
http://example.com
@method _getOrigin
@return {String} Location origin (i.e., protocol, host, and port).
@protected
**/
_getOrigin: function () {
return origin;
},
/**
Gets the current route path, relative to the `root` (if any).
@method _getPath
@return {String} Current route path.
@protected
**/
_getPath: function () {
var path = (!this._html5 && this._getHashPath()) || location.pathname;
return this.removeRoot(path);
},
/**
Gets the current route query string.
@method _getQuery
@return {String} Current route query string.
@protected
**/
_getQuery: function () {
if (this._html5) {
return location.search.substring(1);
}
var hash = HistoryHash.getHash(),
matches = hash.match(this._regexUrlQuery);
return hash && matches ? matches[1] : location.search.substring(1);
},
/**
Creates a regular expression from the given route specification. If _path_
is already a regex, it will be returned unmodified.
@method _getRegex
@param {String|RegExp} path Route path specification.
@param {Array} keys Array reference to which route parameter names will be
added.
@return {RegExp} Route regex.
@protected
**/
_getRegex: function (path, keys) {
if (path instanceof RegExp) {
return path;
}
// Special case for catchall paths.
if (path === '*') {
return /.*/;
}
path = path.replace(this._regexPathParam, function (match, operator, key) {
keys.push(key);
return operator === '*' ? '(.*?)' : '([^/]*)';
});
return new RegExp('^' + path + '$');
},
/**
Gets a request object that can be passed to a route handler.
@method _getRequest
@param {String} path Current path being dispatched.
@param {String} url Current full URL being dispatched.
@param {String} src What initiated the dispatch.
@return {Object} Request object.
@protected
**/
_getRequest: function (path, url, src) {
return {
path : path,
query: this._parseQuery(this._getQuery()),
url : url,
src : src
};
},
/**
Gets a response object that can be passed to a route handler.
@method _getResponse
@param {Object} req Request object.
@return {Object} Response Object.
@protected
**/
_getResponse: function (req) {
// For backwards compatibility, the response object is a function that
// calls `next()` on the request object and returns the result.
var res = function () {
return req.next.apply(this, arguments);
};
res.req = req;
return res;
},
/**
Getter for the `routes` attribute.
@method _getRoutes
@return {Object[]} Array of route objects.
@protected
**/
_getRoutes: function () {
return this._routes.concat();
},
/**
Gets the current full URL.
@method _getURL
@return {String} URL.
@protected
**/
_getURL: function () {
return location.toString();
},
/**
Returns `true` when the specified `url` is from the same origin as the
current URL; i.e., the protocol, host, and port of the URLs are the same.
All host or path relative URLs are of the same origin. A scheme-relative URL
is first prefixed with the current scheme before being evaluated.
@method _hasSameOrigin
@param {String} url URL to compare origin with the current URL.
@return {Boolean} Whether the URL has the same origin of the current URL.
@protected
**/
_hasSameOrigin: function (url) {
var origin = ((url && url.match(this._regexUrlOrigin)) || [])[0];
// Prepend current scheme to scheme-relative URLs.
if (origin && origin.indexOf('//') === 0) {
origin = location.protocol + origin;
}
return !origin || origin === this._getOrigin();
},
/**
Joins the `root` URL to the specified _url_, normalizing leading/trailing
`/` characters.
@example
router.set('root', '/foo');
router._joinURL('bar'); // => '/foo/bar'
router._joinURL('/bar'); // => '/foo/bar'
router.set('root', '/foo/');
router._joinURL('bar'); // => '/foo/bar'
router._joinURL('/bar'); // => '/foo/bar'
@method _joinURL
@param {String} url URL to append to the `root` URL.
@return {String} Joined URL.
@protected
**/
_joinURL: function (url) {
var root = this.get('root');
url = this.removeRoot(url);
if (url.charAt(0) === '/') {
url = url.substring(1);
}
return root && root.charAt(root.length - 1) === '/' ?
root + url :
root + '/' + url;
},
/**
Parses a URL query string into a key/value hash. If `Y.QueryString.parse` is
available, this method will be an alias to that.
@method _parseQuery
@param {String} query Query string to parse.
@return {Object} Hash of key/value pairs for query parameters.
@protected
**/
_parseQuery: QS && QS.parse ? QS.parse : function (query) {
var decode = this._decode,
params = query.split('&'),
i = 0,
len = params.length,
result = {},
param;
for (; i < len; ++i) {
param = params[i].split('=');
if (param[0]) {
result[decode(param[0])] = decode(param[1] || '');
}
}
return result;
},
/**
Queues up a `_save()` call to run after all previously-queued calls have
finished.
This is necessary because if we make multiple `_save()` calls before the
first call gets dispatched, then both calls will dispatch to the last call's
URL.
All arguments passed to `_queue()` will be passed on to `_save()` when the
queued function is executed.
@method _queue
@chainable
@see _dequeue
@protected
**/
_queue: function () {
var args = arguments,
self = this;
saveQueue.push(function () {
if (self._html5) {
if (Y.UA.ios && Y.UA.ios < 5) {
// iOS <5 has buggy HTML5 history support, and needs to be
// synchronous.
self._save.apply(self, args);
} else {
// Wrapped in a timeout to ensure that _save() calls are
// always processed asynchronously. This ensures consistency
// between HTML5- and hash-based history.
setTimeout(function () {
self._save.apply(self, args);
}, 1);
}
} else {
self._dispatching = true; // otherwise we'll dequeue too quickly
self._save.apply(self, args);
}
return self;
});
return !this._dispatching ? this._dequeue() : this;
},
/**
Saves a history entry using either `pushState()` or the location hash.
This method enforces the same-origin security constraint; attempting to save
a `url` that is not from the same origin as the current URL will result in
an error.
@method _save
@param {String} [url] URL for the history entry.
@param {Boolean} [replace=false] If `true`, the current history entry will
be replaced instead of a new one being added.
@chainable
@protected
**/
_save: function (url, replace) {
var urlIsString = typeof url === 'string';
// Perform same-origin check on the specified URL.
if (urlIsString && !this._hasSameOrigin(url)) {
Y.error('Security error: The new URL must be of the same origin as the current URL.');
return this;
}
// Force _ready to true to ensure that the history change is handled
// even if _save is called before the `ready` event fires.
this._ready = true;
if (this._html5) {
this._history[replace ? 'replace' : 'add'](null, {
url: urlIsString ? this._joinURL(url) : url
});
} else {
// Remove the root from the URL before it's set as the hash.
urlIsString && (url = this.removeRoot(url));
// The `hashchange` event only fires when the new hash is actually
// different. This makes sure we'll always dequeue and dispatch,
// mimicking the HTML5 behavior.
if (url === HistoryHash.getHash()) {
this._dispatch(this._getPath(), this._getURL());
} else {
HistoryHash[replace ? 'replaceHash' : 'setHash'](url);
}
}
return this;
},
/**
Setter for the `routes` attribute.
@method _setRoutes
@param {Object[]} routes Array of route objects.
@return {Object[]} Array of route objects.
@protected
**/
_setRoutes: function (routes) {
this._routes = [];
YArray.each(routes, function (route) {
this.route(route.path, route.callback);
}, this);
return this._routes.concat();
},
// -- Protected Event Handlers ---------------------------------------------
/**
Handles `history:change` and `hashchange` events.
@method _afterHistoryChange
@param {EventFacade} e
@protected
**/
_afterHistoryChange: function (e) {
var self = this,
src = e.src;
if (self._ready || src !== 'popstate') {
self._dispatch(self._getPath(), self._getURL(), src);
}
},
// -- Default Event Handlers -----------------------------------------------
/**
Default handler for the `ready` event.
@method _defReadyFn
@param {EventFacade} e
@protected
**/
_defReadyFn: function (e) {
this._ready = true;
}
}, {
// -- Static Properties ----------------------------------------------------
NAME: 'router',
ATTRS: {
/**
Whether or not this browser is capable of using HTML5 history.
Setting this to `false` will force the use of hash-based history even on
HTML5 browsers, but please don't do this unless you understand the
consequences.
@attribute html5
@type Boolean
@initOnly
**/
html5: {
// Android versions lower than 3.0 are buggy and don't update
// window.location after a pushState() call, so we fall back to
// hash-based history for them.
//
// See http://code.google.com/p/android/issues/detail?id=17471
valueFn: function () { return Y.Router.html5; },
writeOnce: 'initOnly'
},
/**
Absolute root path from which all routes should be evaluated.
For example, if your router is running on a page at
`http://example.com/myapp/` and you add a route with the path `/`, your
route will never execute, because the path will always be preceded by
`/myapp`. Setting `root` to `/myapp` would cause all routes to be
evaluated relative to that root URL, so the `/` route would then execute
when the user browses to `http://example.com/myapp/`.
@attribute root
@type String
@default `''`
**/
root: {
value: ''
},
/**
Array of route objects.
Each item in the array must be an object with the following properties:
* `path`: String or regex representing the path to match. See the docs
for the `route()` method for more details.
* `callback`: Function or a string representing the name of a function
on this router instance that should be called when the route is
triggered. See the docs for the `route()` method for more details.
This attribute is intended to be used to set routes at init time, or to
completely reset all routes after init. To add routes after init without
resetting all existing routes, use the `route()` method.
@attribute routes
@type Object[]
@default `[]`
@see route
**/
routes: {
value : [],
getter: '_getRoutes',
setter: '_setRoutes'
}
},
// Used as the default value for the `html5` attribute, and for testing.
html5: Y.HistoryBase.html5 && (!Y.UA.android || Y.UA.android >= 3)
});
/**
The `Controller` class was deprecated in YUI 3.5.0 and is now an alias for the
`Router` class. Use that class instead. This alias will be removed in a future
version of YUI.
@class Controller
@constructor
@extends Base
@deprecated Use `Router` instead.
@see Router
**/
Y.Controller = Y.Router;
}, '@VERSION@' ,{optional:['querystring-parse'], requires:['array-extras', 'base-build', 'history']});