-
-
Notifications
You must be signed in to change notification settings - Fork 4.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Track unique history location states #14011
Track unique history location states #14011
Conversation
@@ -150,7 +151,8 @@ export default EmberObject.extend({ | |||
@param path {String} | |||
*/ | |||
pushState(path) { | |||
let state = { path: path }; | |||
let id = guidFor(`${path}-${new Date()}`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think using guidFor
on a string is very useful, if the idea is that all new states have a unique id
I think this may be easier/better:
let state = { path, id: ++stateCounter };
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah I figured that was hairy. I'll go about the stateCounter
@rwjblue updated |
@@ -33,6 +33,7 @@ export default EmberObject.extend({ | |||
set(this, 'location', get(this, 'location') || window.location); | |||
|
|||
this._popstateHandler = undefined; | |||
this.stateCounter = 0; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems private, this._stateCounter
would be preferable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
@bcardarella this also adds public API to Generally seems reasonable. |
@@ -150,7 +151,8 @@ export default EmberObject.extend({ | |||
@param path {String} | |||
*/ | |||
pushState(path) { | |||
let state = { path: path }; | |||
let id = `${this.stateCounter++}`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can this just be the integer?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I feel like I had a good reason to force it to a string. Let me go back and see why I did that. It might not be necessary now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is something that I can handle upstream. Moving to just int
@mixonic updated per your suggestions |
There is some question here if feature flagging and/or an RFC is needed here. I think the quick summary is that If this is introducing public API, then we should flag it (and potentially create a small and quick RFC for it)... |
The counter itself is private as @mixonic suggested. The unique value added to the history states is not an API |
OK, so no new public API is being added here then. c/d? |
That's what I believe, but of course not my call ;) |
@bcardarella yeah the return value from a public API is of course at best public API itself, or at the worst intimate. For modern things that are properties but private API we've started using symbols and non-enumerable getters, but that obviously hasn't propagated through the whole codebase. The use-case you described seems reasonable, but a socialized RFC would help gather other use cases that may be related. It would be good to hear from some other community members. If you can draft something I'm happy to help edit and champion this with you 🙇 |
@mixonic finally got around to this: emberjs/rfcs#186 |
thanks @bcardarella ! |
After reading through the RFC and then commenting on it, i realized I believe this can already be implemented via map or WeakMap, but maybe we should talk about it on the RFC itself, no changes to ember required |
@stefanpenner session state is serialized for browser crash recovery including the history state, so if you don't map the id to session storage or the sequence your app will be broken if someone chooses to recover their session after a crash. In fact this PR should really store the id sequence start in session storage. |
@stefanpenner @krisselden should this conversation take place in the RFC? |
@bcardarella I'll copy & paste it |
@krisselden ya, i came to this conclusion in the linked discussion. |
☔ The latest upstream changes (presumably #14821) made this pull request unmergeable. Please resolve the merge conflicts. |
@@ -150,7 +155,8 @@ export default EmberObject.extend({ | |||
@param path {String} | |||
*/ | |||
pushState(path) { | |||
let state = { path: path }; | |||
let id = this._stateCounter++; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We should update this to use a UUID more details here
@stefanpenner updated |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The RFC for this was just merged (:tada:), so now this is ready for some more work.
Basic steps to land are:
- add new feature to
feature.json
withnull
value - feature flag API changes (
if (isFeatureEnabled('new-feature-name') { }
etc) - feature flag tests
@rwjblue I wrapped the private scope if (isFeatureEnabled('ember-unique-location-history-state')) {
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);
});
}
} but am getting the following error: 18:3 error Move function declaration to program root no-inner-declarations How should I resolve? |
I think generally we do something like this: let _uuid;
if (isFeatureEnabled('ember-unique-location-history-state')) {
_uuid = function _uuid() { /* implementation here */ };
} |
All set |
This PR will allow the HistoryLocation API to keep track of unique state IDs for each state that is pushed/replaced. This change should not break backwards compatibility and can allow for other libraries to use this information to set proper scroll position. The path alone does not provide enough information. For example, if you visit page A, scroll down, then click on a link to page B, then click on a link back to page A. Your actual browser history stack is [A, B, A]. Each of those nodes in the history should have their own unique scroll position. In order to record this position we need an ID that is unique for each node in the history. Moved from stateCounter to uuid Set under Feature Flag
Now that emberjs/ember.js#14011 has landed it would be best to align this library with the new implementation in anticipation of deprecating the RouterScroll for Ember 2.13 and eventually removing it in Ember 3.0.
Can this be used in 2.14 or is the addon by DollarShaveClub still necessary? |
The addon is still necessary as it makes use of the token for the scroll positioning. If you have a use outside of the addon this functionality is in the HistoryLocation class in 2.14 |
This PR will allow the HistoryLocation API to keep track of unique
state UUIDs for each state that is pushed/replaced. This change should not
break backwards compatibility and can allow for other libraries to use
this information to set proper scroll position.
The path alone does not provide enough information. For example, if you
visit page A, scroll down, then click on a link to page B, then click on
a link back to page A. Your actual browser history stack is [A, B, A].
Each of those nodes in the history should have their own unique scroll
position. In order to record this position we need an ID that is unique
for each node in the history.