zero-day
zero-day

Reputation: 392

How distinguish between browser back and user manually changing location hash

Question

Given navigation from /page.html#A to /page.html#B, is there a way to distinguish between a user:

  1. Clicking the browsers's 'back' button, and
  2. Manually changing the url back to /page.html#A ?

Background / Context

I'm building a web app, where a single page transitions between multiple slides of content, each identified by a specific location hash, eg '#A', '#B'.

For example, when the user is on slide 'A', and selects option 'B', the location changes from /page.html#A to /page.html#B.

After the transition, location.hash==#B, and back() (either via JS or browser button) would return the user to location.hash==#A.

However, there is nothing to prevent a user from manually changing the hash in the URL bar. In this case the browser would consider this a navigation forward, inserting /page.html#B in the back history. That is, navigation history would be #A > #B > #A and clicking back would now take a user to #B.

I need to distinguish between these two cases so that when I know the user has manually updated the url hash, I can trigger go(N) to synchronise the browser back/next state.

Attempts so far

1) HTML5 popstate event:
I had hoped that the html5 popstate event ( https://developer.mozilla.org/en-US/docs/Web/Events/popstate ) would only be fired for case#1, but I can confirm it fires in both cases.

2) Browser .onhashchange event
I can confirm that if present, the event is fired in both cases

3) jQuery mobile hashChange() I can confirm is fired in both cases

4) Read browser navigation history
My next thought would be to maintain a JS array of hash history, and compare whether the new hash and browser history match the JS array, but JS can't read the browser location history for security reasons.

Thoughts

I know that if I call window.history.forward(), and no page exists, nothing happens. I'm thinking a JS array of hash history, calling forward(), checking the new location.hash (as security now allows it), comparing to JS array, then calling go(N) to synchronise the browser back/next state. But it's a bit messy.

Upvotes: 5

Views: 1994

Answers (2)

zero-day
zero-day

Reputation: 392

Yes, you can distinguish between:

  1. Clicking the back()/forward() browser button, and
  2. Manually editing the location.hash in the browser URL bar

It is also possible to use both alongside in-page HTML element navigation.

Issues:

  1. Browser back(), forward() and go() calls do not immediately update location.hash. It is required to wait ~10ms via setTimeout() to let browser finish the navigation and update location.

Solution (pseudo-code):

  • Maintain an array of backward_history_hashes (note 'backwards' means logically, not temporally)
  • Maintain a value of current_location.hash
  • Maintain an array of forward_history_hashes
  • Maintain a boolean flag for in-page navigation, default to FALSE
  • Maintain a boolean flag whether to ignore_hash_change
  • Create a setTimeout() monitor to check for location.hash changes

In each case, the history arrays are simple string arrays of location.hashes

on_in_page_navigation()

  • set in_page_flag = true
  • trigger browser navigation via back(), forward() or go(N)
  • set in_page_flag = false

on_location_hash_change()

  • set ignore_hash_change = true
  • if( ! in_page_flag) rewrite_browser_history()
  • display content corresponding to new location.hash
  • set ignore_hash_change = false

rewrite_browser_history()

  • just assume that it was a manual URL edit, and use JS history arrays to trigger back() and forward() calls to generate the desired browser-history
  • execute go(N) to desired location.hash to synchronize browser-history with JS history arrays

Upvotes: 0

Ayo K
Ayo K

Reputation: 1774

As there is no back button event in javascript, the best I can recommend is creating your own back button on your page

Look at: How to Detect Browser Back Button event - Cross Browser

Upvotes: 0

Related Questions