UNPKG

aurelia-history-browser

Version:

An implementation of the Aurelia history interface based on standard browser hash change and push state mechanisms.

300 lines (288 loc) 12 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var aureliaHistory = require('aurelia-history'); var aureliaPal = require('aurelia-pal'); /*! ***************************************************************************** Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. ***************************************************************************** */ /* global Reflect, Promise */ var extendStatics = function(d, b) { extendStatics = Object.setPrototypeOf || ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; return extendStatics(d, b); }; function __extends(d, b) { extendStatics(d, b); function __() { this.constructor = d; } d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); } var LinkHandler = (function () { function LinkHandler() { } LinkHandler.prototype.activate = function (history) { }; LinkHandler.prototype.deactivate = function () { }; return LinkHandler; }()); var DefaultLinkHandler = (function (_super) { __extends(DefaultLinkHandler, _super); function DefaultLinkHandler() { var _this = _super.call(this) || this; _this.handler = function (e) { var _a = DefaultLinkHandler.getEventInfo(e), shouldHandleEvent = _a.shouldHandleEvent, href = _a.href; if (shouldHandleEvent) { e.preventDefault(); _this.history.navigate(href); } }; return _this; } DefaultLinkHandler.prototype.activate = function (history) { if (history._hasPushState) { this.history = history; aureliaPal.DOM.addEventListener('click', this.handler, true); } }; DefaultLinkHandler.prototype.deactivate = function () { aureliaPal.DOM.removeEventListener('click', this.handler, true); }; DefaultLinkHandler.getEventInfo = function (event) { var $event = event; var info = { shouldHandleEvent: false, href: null, anchor: null }; var target = DefaultLinkHandler.findClosestAnchor($event.target); if (!target || !DefaultLinkHandler.targetIsThisWindow(target)) { return info; } if (hasAttribute(target, 'download') || hasAttribute(target, 'router-ignore') || hasAttribute(target, 'data-router-ignore')) { return info; } if ($event.altKey || $event.ctrlKey || $event.metaKey || $event.shiftKey) { return info; } var href = target.getAttribute('href'); info.anchor = target; info.href = href; var leftButtonClicked = $event.which === 1; var isRelative = href && !(href.charAt(0) === '#' || (/^[a-z]+:/i).test(href)); info.shouldHandleEvent = leftButtonClicked && isRelative; return info; }; DefaultLinkHandler.findClosestAnchor = function (el) { while (el) { if (el.tagName === 'A') { return el; } el = el.parentNode; } }; DefaultLinkHandler.targetIsThisWindow = function (target) { var targetWindow = target.getAttribute('target'); var win = aureliaPal.PLATFORM.global; return !targetWindow || targetWindow === win.name || targetWindow === '_self'; }; return DefaultLinkHandler; }(LinkHandler)); var hasAttribute = function (el, attr) { return el.hasAttribute(attr); }; var BrowserHistory = (function (_super) { __extends(BrowserHistory, _super); function BrowserHistory(linkHandler) { var _this = _super.call(this) || this; _this._isActive = false; _this._checkUrlCallback = _this._checkUrl.bind(_this); _this.location = aureliaPal.PLATFORM.location; _this.history = aureliaPal.PLATFORM.history; _this.linkHandler = linkHandler; return _this; } BrowserHistory.prototype.activate = function (options) { if (this._isActive) { throw new Error('History has already been activated.'); } var $history = this.history; var wantsPushState = !!options.pushState; this._isActive = true; var normalizedOptions = this.options = Object.assign({}, { root: '/' }, this.options, options); var rootUrl = this.root = ('/' + normalizedOptions.root + '/').replace(rootStripper, '/'); var wantsHashChange = this._wantsHashChange = normalizedOptions.hashChange !== false; var hasPushState = this._hasPushState = !!(normalizedOptions.pushState && $history && $history.pushState); var eventName; if (hasPushState) { eventName = 'popstate'; } else if (wantsHashChange) { eventName = 'hashchange'; } aureliaPal.PLATFORM.addEventListener(eventName, this._checkUrlCallback); if (wantsHashChange && wantsPushState) { var $location = this.location; var atRoot = $location.pathname.replace(/[^\/]$/, '$&/') === rootUrl; if (!hasPushState && !atRoot) { var fragment = this.fragment = this._getFragment(null, true); $location.replace(rootUrl + $location.search + '#' + fragment); return true; } else if (hasPushState && atRoot && $location.hash) { var fragment = this.fragment = this._getHash().replace(routeStripper, ''); $history.replaceState({}, aureliaPal.DOM.title, rootUrl + fragment + $location.search); } } if (!this.fragment) { this.fragment = this._getFragment(''); } this.linkHandler.activate(this); if (!normalizedOptions.silent) { return this._loadUrl(''); } }; BrowserHistory.prototype.deactivate = function () { var handler = this._checkUrlCallback; aureliaPal.PLATFORM.removeEventListener('popstate', handler); aureliaPal.PLATFORM.removeEventListener('hashchange', handler); this._isActive = false; this.linkHandler.deactivate(); }; BrowserHistory.prototype.getAbsoluteRoot = function () { var $location = this.location; var origin = createOrigin($location.protocol, $location.hostname, $location.port); return "" + origin + this.root; }; BrowserHistory.prototype.navigate = function (fragment, _a) { var _b = _a === void 0 ? {} : _a, _c = _b.trigger, trigger = _c === void 0 ? true : _c, _d = _b.replace, replace = _d === void 0 ? false : _d; var location = this.location; if (fragment && absoluteUrl.test(fragment)) { location.href = fragment; return true; } if (!this._isActive) { return false; } fragment = this._getFragment(fragment || ''); if (this.fragment === fragment && !replace) { return false; } this.fragment = fragment; var url = this.root + fragment; if (fragment === '' && url !== '/') { url = url.slice(0, -1); } if (this._hasPushState) { url = url.replace('//', '/'); this.history[replace ? 'replaceState' : 'pushState']({}, aureliaPal.DOM.title, url); } else if (this._wantsHashChange) { updateHash(location, fragment, replace); } else { location.assign(url); } if (trigger) { return this._loadUrl(fragment); } return true; }; BrowserHistory.prototype.navigateBack = function () { this.history.back(); }; BrowserHistory.prototype.setTitle = function (title) { aureliaPal.DOM.title = title; }; BrowserHistory.prototype.setState = function (key, value) { var $history = this.history; var state = Object.assign({}, $history.state); var _a = this.location, pathname = _a.pathname, search = _a.search, hash = _a.hash; state[key] = value; $history.replaceState(state, null, "" + pathname + search + hash); }; BrowserHistory.prototype.getState = function (key) { var state = Object.assign({}, this.history.state); return state[key]; }; BrowserHistory.prototype.getHistoryIndex = function () { var historyIndex = this.getState('HistoryIndex'); if (historyIndex === undefined) { historyIndex = this.history.length - 1; this.setState('HistoryIndex', historyIndex); } return historyIndex; }; BrowserHistory.prototype.go = function (movement) { this.history.go(movement); }; BrowserHistory.prototype._getHash = function () { return this.location.hash.substr(1); }; BrowserHistory.prototype._getFragment = function (fragment, forcePushState) { var rootUrl; if (!fragment) { if (this._hasPushState || !this._wantsHashChange || forcePushState) { var location_1 = this.location; fragment = location_1.pathname + location_1.search; rootUrl = this.root.replace(trailingSlash, ''); if (!fragment.indexOf(rootUrl)) { fragment = fragment.substr(rootUrl.length); } } else { fragment = this._getHash(); } } return '/' + fragment.replace(routeStripper, ''); }; BrowserHistory.prototype._checkUrl = function () { var current = this._getFragment(''); if (current !== this.fragment) { this._loadUrl(''); } }; BrowserHistory.prototype._loadUrl = function (fragmentOverride) { var fragment = this.fragment = this._getFragment(fragmentOverride); return this.options.routeHandler ? this.options.routeHandler(fragment) : false; }; BrowserHistory.inject = [LinkHandler]; return BrowserHistory; }(aureliaHistory.History)); var routeStripper = /^#?\/*|\s+$/g; var rootStripper = /^\/+|\/+$/g; var trailingSlash = /\/$/; var absoluteUrl = /^([a-z][a-z0-9+\-.]*:)?\/\//i; function updateHash($location, fragment, replace) { if (replace) { var href = $location.href.replace(/(javascript:|#).*$/, ''); $location.replace(href + '#' + fragment); } else { $location.hash = '#' + fragment; } } function createOrigin(protocol, hostname, port) { return protocol + "//" + hostname + (port ? ':' + port : ''); } function configure(config) { var $config = config; $config.singleton(aureliaHistory.History, BrowserHistory); $config.transient(LinkHandler, DefaultLinkHandler); } exports.BrowserHistory = BrowserHistory; exports.DefaultLinkHandler = DefaultLinkHandler; exports.LinkHandler = LinkHandler; exports.configure = configure; //# sourceMappingURL=aurelia-history-browser.js.map