mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-19 03:32:21 +08:00
178 lines
4.6 KiB
TypeScript
178 lines
4.6 KiB
TypeScript
import {IonicRouter} from './router';
|
|
import * as util from '../util/util';
|
|
|
|
|
|
class UrlStateManager {
|
|
|
|
constructor(window, router) {
|
|
this.location = window.location;
|
|
this.history = window.history;
|
|
this.ls = window.localStorage;
|
|
this.router = router;
|
|
|
|
// overkill for location change listeners, but ensures we
|
|
// know when the location has changed. Only 1 of the listeners
|
|
// will actually do the work, the other will be skipped.
|
|
window.addEventListener('popstate', () => {
|
|
this.onLocationChange();
|
|
});
|
|
window.addEventListener('hashchange', () => {
|
|
this.onLocationChange();
|
|
});
|
|
}
|
|
|
|
load() {
|
|
let paths = [this.getCurrentPath()];
|
|
let savedPaths = this.paths();
|
|
|
|
if (savedPaths[savedPaths.length - 1] == paths[0]) {
|
|
// the last path in the saved paths is the same as the
|
|
// current path, so use the saved paths to rebuild the history
|
|
paths = savedPaths;
|
|
|
|
} else {
|
|
// the current path is not the same as the last path in the
|
|
// saved history, so the saved history is no good, erase it
|
|
this.paths([]);
|
|
}
|
|
|
|
return Promise.resolve({
|
|
paths: paths,
|
|
priority: 0
|
|
});
|
|
}
|
|
|
|
stateChange(path, type, activeView) {
|
|
let savedPaths = this.paths();
|
|
|
|
// check if the given path is different than the current location
|
|
let isDifferentPath = (this.getCurrentPath() !== path);
|
|
|
|
if (type == 'pop') {
|
|
// if the popstate came from the browser's back button (and not Ionic)
|
|
// then we shouldn't force another browser history.back()
|
|
// only do a history.back() if the URL hasn't been updated yet
|
|
if (isDifferentPath) {
|
|
this.history.back();
|
|
}
|
|
|
|
if (savedPaths.length && savedPaths[savedPaths.length - 1] != path) {
|
|
// only if the last item in the saved paths
|
|
// equals this path then it can be removed
|
|
savedPaths.pop();
|
|
}
|
|
|
|
} else {
|
|
|
|
if (this._hasInit) {
|
|
if (isDifferentPath) {
|
|
// push the new state to the history stack since the path
|
|
// isn't already in the location hash
|
|
this.history.pushState(path, '', '#' + path);
|
|
}
|
|
|
|
} else {
|
|
// replace the very first load with the correct entering state info
|
|
this.history.replaceState(path, '', '#' + path);
|
|
this._hasInit = true;
|
|
}
|
|
|
|
if (savedPaths[savedPaths.length - 1] != path) {
|
|
// only if the last item in the saved paths does
|
|
// not equal this path then it can be added
|
|
savedPaths.push(path);
|
|
|
|
// don't allow the history to grow too large
|
|
if (savedPaths.length > MAX_PATH_STORE) {
|
|
savedPaths = savedPaths.slice( savedPaths.length - MAX_PATH_STORE );
|
|
}
|
|
}
|
|
}
|
|
|
|
// save the new path data
|
|
this.paths(savedPaths);
|
|
|
|
// ensure this resets
|
|
this._currentPath = null;
|
|
}
|
|
|
|
stateClear() {
|
|
this.paths([]);
|
|
}
|
|
|
|
onLocationChange() {
|
|
let currentPath = this.getCurrentPath();
|
|
|
|
if (currentPath == this._currentPath) {
|
|
// absolutely no change since last onLocationChange
|
|
return;
|
|
}
|
|
|
|
// keep in-memory the current path to quickly tell if things have changed
|
|
this._currentPath = currentPath;
|
|
|
|
// load up the saved paths
|
|
let savedPaths = this.paths();
|
|
|
|
if (currentPath === savedPaths[savedPaths.length - 1]) {
|
|
// do nothing if the last saved path is
|
|
// the same as the current path
|
|
return;
|
|
}
|
|
|
|
if (currentPath === savedPaths[savedPaths.length - 2]) {
|
|
// the user is moving back
|
|
this.router.pop();
|
|
|
|
} else {
|
|
// the user is moving forward
|
|
this.router.push(currentPath);
|
|
}
|
|
}
|
|
|
|
paths(val) {
|
|
if (arguments.length) {
|
|
// set in-memory data
|
|
this._paths = val;
|
|
|
|
// set localStorage data
|
|
try {
|
|
this.ls.setItem(PATH_STORE_KEY, JSON.stringify(val));
|
|
} catch(e) {}
|
|
|
|
} else {
|
|
|
|
if (!this._paths) {
|
|
// we don't already have data in-memory
|
|
|
|
// see if we have data in localStorage
|
|
try {
|
|
let strData = this.ls.getItem(PATH_STORE_KEY);
|
|
if (strData) {
|
|
this._paths = JSON.parse(strData);
|
|
}
|
|
} catch(e) {}
|
|
|
|
// if not in localStorage yet then create new path data
|
|
if (!this._paths) {
|
|
this._paths = [];
|
|
}
|
|
}
|
|
|
|
// return the in-memory data
|
|
return this._paths;
|
|
}
|
|
}
|
|
|
|
getCurrentPath() {
|
|
// remove leading # to get the path
|
|
return this.location.hash.slice(1);
|
|
}
|
|
|
|
}
|
|
|
|
const PATH_STORE_KEY = 'ionic:history';
|
|
const MAX_PATH_STORE = 20;
|
|
|
|
IonicRouter.registerStateManager('url', UrlStateManager);
|