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
JavaScript
'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