Skip to content

Commit

Permalink
[added] History.onBeforeChange
Browse files Browse the repository at this point in the history
  • Loading branch information
agundermann authored and mjackson committed Jun 30, 2015
1 parent 23c0aff commit af7eb55
Show file tree
Hide file tree
Showing 3 changed files with 103 additions and 12 deletions.
29 changes: 29 additions & 0 deletions modules/DOMHistory.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ class DOMHistory extends History {
constructor(options={}) {
super(options);
this.getScrollPosition = options.getScrollPosition || getWindowScrollPosition;
this.handleBeforeUnload = this.handleBeforeUnload.bind(this);
}

go(n) {
Expand Down Expand Up @@ -35,6 +36,34 @@ class DOMHistory extends History {
return null;
}

onBeforeChange(listener) {
if (!this.beforeChangeListener && listener) {
if (window.addEventListener) {
window.addEventListener('beforeunload', this.handleBeforeUnload);
} else {
window.attachEvent('onbeforeunload', this.handleBeforeUnload);
}
} else if(this.beforeChangeListener && !listener) {
if (window.removeEventListener) {
window.removeEventListener('beforeunload', this.handleBeforeUnload);
} else {
window.detachEvent('onbeforeunload', this.handleBeforeUnload);
}
}

super.onBeforeChange(listener);
}

handleBeforeUnload(event) {
var message = this.beforeChangeListener.call(this);

if (message != null) {
// cross browser, see https://developer.mozilla.org/en-US/docs/Web/Events/beforeunload
(event || window.event).returnValue = message;
return message;
}
}

pushState(state, path) {
var location = this.location;
if (location && location.state && location.state.key) {
Expand Down
78 changes: 69 additions & 9 deletions modules/History.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ class History {

this.parseQueryString = options.parseQueryString || parseQueryString;
this.changeListeners = [];

this.location = null;
this._pendingLocation = null;
}

_notifyChange() {
Expand All @@ -45,6 +48,10 @@ class History {
});
}

onBeforeChange(listener) {
this.beforeChangeListener = listener;
}

setup(path, entry = {}) {
if (this.location)
return;
Expand All @@ -56,15 +63,30 @@ class History {
if (typeof this.readState === 'function')
state = this.readState(entry.key);

this._update(path, state, entry, NavigationTypes.POP, false);
var location = this._createLocation(path, state, entry, NavigationTypes.POP);
this._update(path, location, false);
}

handlePop(path, entry = {}) {
handlePop(path, entry={}, applyEntry=null) {
var state = null;
if (entry.key && typeof this.readState === 'function')
state = this.readState(entry.key);

this._update(path, state, entry, NavigationTypes.POP);
var location = this._createLocation(path, state, entry, NavigationTypes.POP);

if (!this.beforeChangeListener) {
applyEntry && applyEntry();
this._update(path, location);
} else {
this._pendingLocation = location;
this.beforeChangeListener.call(this, location, () => {
if (this._pendingLocation === location){
this._pendingLocation = null;
applyEntry && applyEntry();
this._update(path, location);
}
});
}
}

createRandomKey() {
Expand All @@ -88,9 +110,27 @@ class History {
}

pushState(state, path) {
var key = this._saveNewState(state);
if (!this.beforeChangeListener) {
this._doPushState(state, path);
} else {
var pendingLocation = this._createLocation(path, state, null, NavigationTypes.PUSH);
this._pendingLocation = pendingLocation;

this.beforeChangeListener.call(this, pendingLocation, () => {
if (this._pendingLocation === pendingLocation) {
this._pendingLocation = null;
this._doPushState(state, path);
return true;
}
return false;
});
}
}

_doPushState(state, path) {
var key = this._saveNewState(state);
var entry = null;

if (this.path === path) {
entry = this.replace(path, key) || {};
} else {
Expand All @@ -103,12 +143,30 @@ class History {
this.constructor.name
);

this._update(path, state, entry, NavigationTypes.PUSH);
var location = this._createLocation(path, state, entry, NavigationTypes.PUSH);
this._update(path, location);
}

replaceState(state, path) {
var key = this._saveNewState(state);
if (!this.beforeChangeListener) {
this._doReplaceState(state, path);
} else {
var pendingLocation = this._createLocation(path, state, null, NavigationTypes.REPLACE);
this._pendingLocation = pendingLocation;

this.beforeChangeListener.call(this, pendingLocation, () => {
if (this._pendingLocation === pendingLocation) {
this._pendingLocation = null;
this._doReplaceState(state, path);
return true;
}
return false;
});
}
}

_doReplaceState(state, path) {
var key = this._saveNewState(state);
var entry = this.replace(path, key) || {};

warning(
Expand All @@ -117,7 +175,8 @@ class History {
this.constructor.name
);

this._update(path, state, entry, NavigationTypes.REPLACE);
var location = this._createLocation(path, state, entry, NavigationTypes.REPLACE);
this._update(path, location);
}

back() {
Expand All @@ -128,9 +187,10 @@ class History {
this.go(1);
}

_update(path, state, entry, navigationType, notify=true) {
_update(path, location, notify=true) {
this.path = path;
this.location = this._createLocation(path, state, entry, navigationType);
this.location = location;
this._pendingLocation = null;

if (notify)
this._notifyChange();
Expand Down
8 changes: 5 additions & 3 deletions modules/MemoryHistory.js
Original file line number Diff line number Diff line change
Expand Up @@ -97,10 +97,12 @@ class MemoryHistory extends History {
this.constructor.name, n
);

this.current += n;
var currentEntry = this.entries[this.current];
var next = this.current + n;
var nextEntry = this.entries[next];

this.handlePop(currentEntry.path, { key: currentEntry.key, current: this.current });
this.handlePop(nextEntry.path, { key: nextEntry.key, current: this.current }, () => {
this.current = next;
});
}

canGo(n) {
Expand Down

0 comments on commit af7eb55

Please sign in to comment.