/** * Kendo UI v2016.1.112 (http://www.telerik.com/kendo-ui) * Copyright 2016 Telerik AD. All rights reserved. * * Kendo UI commercial licenses may be obtained at * http://www.telerik.com/purchase/license-agreement/kendo-ui-complete * If you do not own a commercial license, this file shall be governed by the trial license terms. */ (function (f, define) { define('kendo.router', ['kendo.core'], f); }(function () { var __meta__ = { id: 'router', name: 'Router', category: 'framework', description: 'The Router class is responsible for tracking the application state and navigating between the application states.', depends: ['core'], hidden: false }; (function ($, undefined) { var kendo = window.kendo, CHANGE = 'change', BACK = 'back', SAME = 'same', support = kendo.support, location = window.location, history = window.history, CHECK_URL_INTERVAL = 50, BROKEN_BACK_NAV = kendo.support.browser.msie, hashStrip = /^#*/, document = window.document; function absoluteURL(path, pathPrefix) { if (!pathPrefix) { return path; } if (path + '/' === pathPrefix) { path = pathPrefix; } var regEx = new RegExp('^' + pathPrefix, 'i'); if (!regEx.test(path)) { path = pathPrefix + '/' + path; } return location.protocol + '//' + (location.host + '/' + path).replace(/\/\/+/g, '/'); } function hashDelimiter(bang) { return bang ? '#!' : '#'; } function locationHash(hashDelimiter) { var href = location.href; if (hashDelimiter === '#!' && href.indexOf('#') > -1 && href.indexOf('#!') < 0) { return null; } return href.split(hashDelimiter)[1] || ''; } function stripRoot(root, url) { if (url.indexOf(root) === 0) { return url.substr(root.length).replace(/\/\//g, '/'); } else { return url; } } var HistoryAdapter = kendo.Class.extend({ back: function () { if (BROKEN_BACK_NAV) { setTimeout(function () { history.back(); }); } else { history.back(); } }, forward: function () { if (BROKEN_BACK_NAV) { setTimeout(function () { history.forward(); }); } else { history.forward(); } }, length: function () { return history.length; }, replaceLocation: function (url) { location.replace(url); } }); var PushStateAdapter = HistoryAdapter.extend({ init: function (root) { this.root = root; }, navigate: function (to) { history.pushState({}, document.title, absoluteURL(to, this.root)); }, replace: function (to) { history.replaceState({}, document.title, absoluteURL(to, this.root)); }, normalize: function (url) { return stripRoot(this.root, url); }, current: function () { var current = location.pathname; if (location.search) { current += location.search; } return stripRoot(this.root, current); }, change: function (callback) { $(window).bind('popstate.kendo', callback); }, stop: function () { $(window).unbind('popstate.kendo'); }, normalizeCurrent: function (options) { var fixedUrl, root = options.root, pathname = location.pathname, hash = locationHash(hashDelimiter(options.hashBang)); if (root === pathname + '/') { fixedUrl = root; } if (root === pathname && hash) { fixedUrl = absoluteURL(hash.replace(hashStrip, ''), root); } if (fixedUrl) { history.pushState({}, document.title, fixedUrl); } } }); function fixHash(url) { return url.replace(/^(#)?/, '#'); } function fixBang(url) { return url.replace(/^(#(!)?)?/, '#!'); } var HashAdapter = HistoryAdapter.extend({ init: function (bang) { this._id = kendo.guid(); this.prefix = hashDelimiter(bang); this.fix = bang ? fixBang : fixHash; }, navigate: function (to) { location.hash = this.fix(to); }, replace: function (to) { this.replaceLocation(this.fix(to)); }, normalize: function (url) { if (url.indexOf(this.prefix) < 0) { return url; } else { return url.split(this.prefix)[1]; } }, change: function (callback) { if (support.hashChange) { $(window).on('hashchange.' + this._id, callback); } else { this._interval = setInterval(callback, CHECK_URL_INTERVAL); } }, stop: function () { $(window).off('hashchange.' + this._id); clearInterval(this._interval); }, current: function () { return locationHash(this.prefix); }, normalizeCurrent: function (options) { var pathname = location.pathname, root = options.root; if (options.pushState && root !== pathname) { this.replaceLocation(root + this.prefix + stripRoot(root, pathname)); return true; } return false; } }); var History = kendo.Observable.extend({ start: function (options) { options = options || {}; this.bind([ CHANGE, BACK, SAME ], options); if (this._started) { return; } this._started = true; options.root = options.root || '/'; var adapter = this.createAdapter(options), current; if (adapter.normalizeCurrent(options)) { return; } current = adapter.current(); $.extend(this, { adapter: adapter, root: options.root, historyLength: adapter.length(), current: current, locations: [current] }); adapter.change($.proxy(this, '_checkUrl')); }, createAdapter: function (options) { return support.pushState && options.pushState ? new PushStateAdapter(options.root) : new HashAdapter(options.hashBang); }, stop: function () { if (!this._started) { return; } this.adapter.stop(); this.unbind(CHANGE); this._started = false; }, change: function (callback) { this.bind(CHANGE, callback); }, replace: function (to, silent) { this._navigate(to, silent, function (adapter) { adapter.replace(to); this.locations[this.locations.length - 1] = this.current; }); }, navigate: function (to, silent) { if (to === '#:back') { this.backCalled = true; this.adapter.back(); return; } this._navigate(to, silent, function (adapter) { adapter.navigate(to); this.locations.push(this.current); }); }, _navigate: function (to, silent, callback) { var adapter = this.adapter; to = adapter.normalize(to); if (this.current === to || this.current === decodeURIComponent(to)) { this.trigger(SAME); return; } if (!silent) { if (this.trigger(CHANGE, { url: to })) { return; } } this.current = to; callback.call(this, adapter); this.historyLength = adapter.length(); }, _checkUrl: function () { var adapter = this.adapter, current = adapter.current(), newLength = adapter.length(), navigatingInExisting = this.historyLength === newLength, back = current === this.locations[this.locations.length - 2] && navigatingInExisting, backCalled = this.backCalled, prev = this.current; if (current === null || this.current === current || this.current === decodeURIComponent(current)) { return true; } this.historyLength = newLength; this.backCalled = false; this.current = current; if (back && this.trigger('back', { url: prev, to: current })) { adapter.forward(); this.current = prev; return; } if (this.trigger(CHANGE, { url: current, backButtonPressed: !backCalled })) { if (back) { adapter.forward(); } else { adapter.back(); this.historyLength--; } this.current = prev; return; } if (back) { this.locations.pop(); } else { this.locations.push(current); } } }); kendo.History = History; kendo.History.HistoryAdapter = HistoryAdapter; kendo.History.HashAdapter = HashAdapter; kendo.History.PushStateAdapter = PushStateAdapter; kendo.absoluteURL = absoluteURL; kendo.history = new History(); }(window.kendo.jQuery)); (function () { var kendo = window.kendo, history = kendo.history, Observable = kendo.Observable, INIT = 'init', ROUTE_MISSING = 'routeMissing', CHANGE = 'change', BACK = 'back', SAME = 'same', optionalParam = /\((.*?)\)/g, namedParam = /(\(\?)?:\w+/g, splatParam = /\*\w+/g, escapeRegExp = /[\-{}\[\]+?.,\\\^$|#\s]/g; function namedParamReplace(match, optional) { return optional ? match : '([^/]+)'; } function routeToRegExp(route, ignoreCase) { return new RegExp('^' + route.replace(escapeRegExp, '\\$&').replace(optionalParam, '(?:$1)?').replace(namedParam, namedParamReplace).replace(splatParam, '(.*?)') + '$', ignoreCase ? 'i' : ''); } function stripUrl(url) { return url.replace(/(\?.*)|(#.*)/g, ''); } var Route = kendo.Class.extend({ init: function (route, callback, ignoreCase) { if (!(route instanceof RegExp)) { route = routeToRegExp(route, ignoreCase); } this.route = route; this._callback = callback; }, callback: function (url, back) { var params, idx = 0, length, queryStringParams = kendo.parseQueryStringParams(url); queryStringParams._back = back; url = stripUrl(url); params = this.route.exec(url).slice(1); length = params.length; for (; idx < length; idx++) { if (typeof params[idx] !== 'undefined') { params[idx] = decodeURIComponent(params[idx]); } } params.push(queryStringParams); this._callback.apply(null, params); }, worksWith: function (url, back) { if (this.route.test(stripUrl(url))) { this.callback(url, back); return true; } else { return false; } } }); var Router = Observable.extend({ init: function (options) { if (!options) { options = {}; } Observable.fn.init.call(this); this.routes = []; this.pushState = options.pushState; this.hashBang = options.hashBang; this.root = options.root; this.ignoreCase = options.ignoreCase !== false; this.bind([ INIT, ROUTE_MISSING, CHANGE, SAME ], options); }, destroy: function () { history.unbind(CHANGE, this._urlChangedProxy); history.unbind(SAME, this._sameProxy); history.unbind(BACK, this._backProxy); this.unbind(); }, start: function () { var that = this, sameProxy = function () { that._same(); }, backProxy = function (e) { that._back(e); }, urlChangedProxy = function (e) { that._urlChanged(e); }; history.start({ same: sameProxy, change: urlChangedProxy, back: backProxy, pushState: that.pushState, hashBang: that.hashBang, root: that.root }); var initEventObject = { url: history.current || '/', preventDefault: $.noop }; if (!that.trigger(INIT, initEventObject)) { that._urlChanged(initEventObject); } this._urlChangedProxy = urlChangedProxy; this._backProxy = backProxy; }, route: function (route, callback) { this.routes.push(new Route(route, callback, this.ignoreCase)); }, navigate: function (url, silent) { kendo.history.navigate(url, silent); }, replace: function (url, silent) { kendo.history.replace(url, silent); }, _back: function (e) { if (this.trigger(BACK, { url: e.url, to: e.to })) { e.preventDefault(); } }, _same: function () { this.trigger(SAME); }, _urlChanged: function (e) { var url = e.url; var back = e.backButtonPressed; if (!url) { url = '/'; } if (this.trigger(CHANGE, { url: e.url, params: kendo.parseQueryStringParams(e.url), backButtonPressed: back })) { e.preventDefault(); return; } var idx = 0, routes = this.routes, route, length = routes.length; for (; idx < length; idx++) { route = routes[idx]; if (route.worksWith(url, back)) { return; } } if (this.trigger(ROUTE_MISSING, { url: url, params: kendo.parseQueryStringParams(url), backButtonPressed: back })) { e.preventDefault(); } } }); kendo.Router = Router; }()); return window.kendo; }, typeof define == 'function' && define.amd ? define : function (a1, a2, a3) { (a3 || a2)(); }));