Skip to content

Commit

Permalink
Merge pull request #14011 from bcardarella/bc-unique-id-for-history-s…
Browse files Browse the repository at this point in the history
…tates

Track unique history location states
  • Loading branch information
rwjblue authored Jan 21, 2017
2 parents 2706cea + 6ab3170 commit 13c26ed
Show file tree
Hide file tree
Showing 3 changed files with 110 additions and 32 deletions.
3 changes: 2 additions & 1 deletion features.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"ember-testing-resume-test": null,
"ember-factory-for": true,
"ember-no-double-extend": null,
"ember-routing-router-service": null
"ember-routing-router-service": null,
"ember-unique-location-history-state": null
}
}
27 changes: 26 additions & 1 deletion packages/ember-routing/lib/location/history_location.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
get,
set
set,
isFeatureEnabled
} from 'ember-metal';

import { Object as EmberObject } from 'ember-runtime';
Expand All @@ -13,6 +14,19 @@ import EmberLocation from './api';

let popstateFired = false;

let _uuid;

if (isFeatureEnabled('ember-unique-location-history-state')) {
_uuid = function _uuid() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r, v;
r = Math.random() * 16 | 0;
v = c === 'x' ? r : r & 3 | 8;
return v.toString(16);
});
}
}

/**
Ember.HistoryLocation implements the location API using the browser's
history.pushState API.
Expand Down Expand Up @@ -134,6 +148,10 @@ export default EmberObject.extend({
from getState may be null if an iframe has changed a window's
history.
The object returned will contain a `path` for the given state as well
as a unique state `id`. The state index will allow the app to distinguish
between two states with similar paths but should be unique from one another.
@private
@method getState
@return state {Object}
Expand All @@ -155,6 +173,9 @@ export default EmberObject.extend({
*/
pushState(path) {
let state = { path };
if (isFeatureEnabled('ember-unique-location-history-state')) {
state.uuid = _uuid();
}

get(this, 'history').pushState(state, null, path);

Expand All @@ -173,6 +194,10 @@ export default EmberObject.extend({
*/
replaceState(path) {
let state = { path };
if (isFeatureEnabled('ember-unique-location-history-state')) {
state.uuid = _uuid();
}

get(this, 'history').replaceState(state, null, path);

this._historyState = state;
Expand Down
112 changes: 82 additions & 30 deletions packages/ember-routing/tests/location/history_location_test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
import { set, run } from 'ember-metal';
import {
isFeatureEnabled,
set,
run
} from 'ember-metal';
import HistoryLocation from '../../location/history_location';

let FakeHistory, HistoryTestLocation, location;
Expand Down Expand Up @@ -110,48 +114,96 @@ QUnit.test('base URL is removed when retrieving the current pathname', function(
location.initState();
});

QUnit.test('base URL is preserved when moving around', function() {
expect(1);
if (isFeatureEnabled('ember-unique-location-history-state')) {
QUnit.test('base URL is preserved when moving around', function() {
expect(2);

HistoryTestLocation.reopen({
init() {
this._super(...arguments);
HistoryTestLocation.reopen({
init() {
this._super(...arguments);

set(this, 'location', mockBrowserLocation('/base/foo/bar'));
set(this, 'baseURL', '/base/');
}
set(this, 'location', mockBrowserLocation('/base/foo/bar'));
set(this, 'baseURL', '/base/');
}
});

createLocation();
location.initState();
location.setURL('/one/two');

equal(location._historyState.path, '/base/one/two');
ok(location._historyState.uuid);
});

createLocation();
location.initState();
location.setURL('/one/two');
QUnit.test('setURL continues to set even with a null state (iframes may set this)', function() {
expect(2);

equal(location._historyState.path, '/base/one/two');
});
createLocation();
location.initState();

QUnit.test('setURL continues to set even with a null state (iframes may set this)', function() {
expect(1);
FakeHistory.pushState(null);
location.setURL('/three/four');

createLocation();
location.initState();
equal(location._historyState.path, '/three/four');
ok(location._historyState.uuid);
});

FakeHistory.pushState(null);
location.setURL('/three/four');
QUnit.test('replaceURL continues to set even with a null state (iframes may set this)', function() {
expect(2);

equal(location._historyState.path, '/three/four');
});
createLocation();
location.initState();

QUnit.test('replaceURL continues to set even with a null state (iframes may set this)', function() {
expect(1);
FakeHistory.pushState(null);
location.replaceURL('/three/four');

createLocation();
location.initState();
equal(location._historyState.path, '/three/four');
ok(location._historyState.uuid);
});
} else {
QUnit.test('base URL is preserved when moving around', function() {
expect(1);

FakeHistory.pushState(null);
location.replaceURL('/three/four');
HistoryTestLocation.reopen({
init() {
this._super(...arguments);

equal(location._historyState.path, '/three/four');
});
set(this, 'location', mockBrowserLocation('/base/foo/bar'));
set(this, 'baseURL', '/base/');
}
});

createLocation();
location.initState();
location.setURL('/one/two');

equal(location._historyState.path, '/base/one/two');
});

QUnit.test('setURL continues to set even with a null state (iframes may set this)', function() {
expect(1);

createLocation();
location.initState();

FakeHistory.pushState(null);
location.setURL('/three/four');

equal(location._historyState.path, '/three/four');
});

QUnit.test('replaceURL continues to set even with a null state (iframes may set this)', function() {
expect(1);

createLocation();
location.initState();

FakeHistory.pushState(null);
location.replaceURL('/three/four');

equal(location._historyState.path, '/three/four');
});
}

QUnit.test('HistoryLocation.getURL() returns the current url, excluding both rootURL and baseURL', function() {
expect(1);
Expand Down

0 comments on commit 13c26ed

Please sign in to comment.