Make browser delete specific history states - javascript

I have an ajax controlled website, where I have two types of pages, displayed to the user. For the simplicity let's call them MAINPAGEs and SUBPAGEs. MAINPAGEs contain information, and SUBPAGEs are all forms, where the user can add or modify existing information of a MAINPAGE for example.
If my site is visited by a user with HTML5 compatible browser, I use HistoryJS to update the url when he/she navigates on my website. Let's pressume the following example:
The user entered my website and navigated to the following pages in the following order, and his history looks something like this:
MAINPAGE(1) --> MAINPAGE(2) --> SUBPAGE(1) --> SUBPAGE(2)
When the user completes the form on SUBPAGE(2), I want to redirect him immediatly to the last MAINPAGE he visited. So for example when the user completes the form, I would like that the users history to be this:
MAINPAGE(1) --> MAINPAGE(2)
Visually, I am able to achieve this, everything works correctly, but afterwards, in a HTML5 browser, if I press the native back key on the browser, the page tries to revert to SUBPAGE(1), the correct back state from the initial history.
Is it achievable, to delete some of the history states, and if yes, how can I do that?
Here's the code I use so far:
ConverserNavigation.prototype.getPreviousMainAction = function() {
// NOTE: the code that deals with non HTML5 compatible browsers,
// was removed because everything works fine there
var startFrom, found=false;
if (this.HistoryJS.status==true) startFrom=History.getState().data.id;
// if browser is HTML5 compatible, get the current state from History object,
// which is a HistoryJS object
while ((!found) && (startFrom>0)) // find the last MAINPAGE visited by user
{
startFrom--;
if (this.historyData[startFrom].pageData.page != 'quickactions') found=true;
}
if (this.HistoryJS.status==true) History.replaceState({id:startFrom}, this.historyData[startFrom].urlData.title, this.historyData[startFrom].urlData.url);
// replace the current history state, with the one to where we want to revert
this.currentNavigationId=startFrom;
this.back(); // render the ui to navigate back to the previous page, works as intended
for (var i=this.currentNavigationId;i<this.historyData.length;i++) delete this.historyData[i]; // delete the unused history data
}

I've managed to solve this issue by modifying my code the following way:
Replaced this line:
if (this.HistoryJS.status==true) History.replaceState({id:startFrom}, this.historyData[startFrom].urlData.title, this.historyData[startFrom].urlData.url);
with this:
if (this.HistoryJS.status==true) {
History.go(goBack); //goBack is the number of states I have to backtrack
this.HistoryJS.manualStateChange=false; // telling the browser to not fire my own UI updating functions
History.back(); // navigating one more state back in the History object
History.pushState({id:startFrom}, this.historyData[startFrom].urlData.title, this.historyData[startFrom].urlData.url); // recreating the original state in the History.
this.HistoryJS.manualStateChange=true; // restarting the UI update functions on pop or push events
}

Related

Add to browser History without changing current URL

I have a 3 step signup process where each step is shown on the page using javascript without a page refresh. What I am trying to do now is add a back reference to what step the user was on so if they click the browser back button they will not lose all of their progress.
So for example, as the user navigates from Step 2 to Step 3 the URL stays at www.example.com. The user then clicks the browser back button. The URL should now be www.example.com?step-2.
I'm thinking that I will somehow need to use the History API to accomplish this but if I use window.history.pushState(null, null, 'www.example.com?step-2'), the current URL would be changed as well.
How would I accomplish adding to the history without changing the current URL?
If your objective is to not change the URL, but to still allow back and forth history state changes, your best bet would be to utilize the window's hashchange event listener. This would of course utilize hash references within the URL, but the base URL won't change:
function locationHashChanged() {
if (location.hash === '#step-2') {
// Do something here
}
}
window.onhashchange = locationHashChanged;
For further info on this, refer to official documentation:
https://developer.mozilla.org/en-US/docs/Web/API/Window/hashchange_event

Define a reference site for the history.back button

We want to have a back button in our site
but history.back in javascript does not help us.
We need this function only run on the site and if the user comes from other site, clicking the return button on the previous site should not return.
In fact, we want a return button to run on our site only.
my code is
<i class="fas fa-arrow-left"></i><span class="btn-text">Back</span>
This only works for your own made back button and won't work with the browser back button
There is two ways to achieve that: a simple but not always reliable method and a complex one but always good.
1- The simple method
You use document.referrer and ensure the domain is yours before calling history.back().
2- The complex method
You could register a JavaScript function on page load to get the first URL the internaut land which you could store using history.pushState. Before calling the back function, you could ensure this is not that page. Though, this idea is not complete as the user could probably have landed on this page twice. i.e. Home->Product->Home. I'll let you search for further code that would let you counter this problem.
This code checks the history of back button of the browser on its click event:
$('#backbtn').click(function () {
if (document.referrer.includes(window.location.hostname)) {
window.history.back();
} else {
window.location.href = "/your/path";
}
});

Make jQuery prevent going back on android

I have a simple pop-up contact form script written:
$(document).ready(function(){
var popupButton = $("#contact-popup-button");
var popupBox = $("#pop-up-contact");
var popupBg = $("#pop-up-close-background");
popupButton.on("click", function(){
popupBox.addClass("slide-out");
popupBg.fadeIn(200);
});
popupBg.on("click", function(){
popupBox.removeClass("slide-out");
popupBg.fadeOut(100);
});
Basically when a button is clicked, a div appears and the space behind it gets foggy. If you press the space around the appeared div, it will dissapear.
Now for mobile devices, I'd like there also to be an option to make the div dissapear on clicking the back button. Unfortunately, I can not get it to work in practice at all.
I have tried these answers:
handling back button in android from jquery
Take control of hardware back button jquery mobile
But both seem to fail in this task, and the others use plugins, which I'd like to avoid.
Tested on LG G2 Mini and Sony Xperia Z1
One approach would be to use the HTML5 History API.
When opening the popup you can push a state to the history stack before opening the popup:
history.pushState({popupOpen: false}, "My title", "index.html");
This method automatically updates the page title (which is currently ignored in most browser implementations) and the last part of the url, that will be displayed in the browser bar. In most cases, you can enter your filename here. The first argument is an object containing the data you can access later when popping a state.
As soon as you have pushed a state to the history stack, when pressing the back key, the browser does not return to the last page as usual, but pops the last state on the stack. This applies for all browsers though, if you want the functionality for mobile browsers only, you have to do a browser check before calling history.pushState.
To correctly handle the back event, you need to subscribe to the popstate-Event. This can be done with the following code:
window.addEventListener("popstate", function(event) {
var data = event.state;
if(data.popupOpen === false) {
popupBg.trigger('click');
}
});
You register an event listener that fires as soon as the user navigates back. In the event.state variable the data you passed in when pushing the state can be accessed again.
Good luck!

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:
Clicking the browsers's 'back' button, and
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.
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
Yes, you can distinguish between:
Clicking the back()/forward() browser button, and
Manually editing the location.hash in the browser URL bar
It is also possible to use both alongside in-page HTML element navigation.
Issues:
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

ExtJS app navigation using browser back button

I have an ExtJS (version 4.1.1) application with a single JSP page but multiple screens created using Ext JS components. When I click on the back button in the browser, I want to display the last visited screen within the application, rather than using the browser's default behavior of redirecting to the last visited web page.
How can I achieve this?
You'll want to use the Ext.util.History class, which is designed to track navigation through the browser's "back" and "forward" buttons. The basic idea is that when the user visits a new screen in your application, you call Ext.util.History.add() with an identifier token for that screen. Then, when the user clicks the browser "back" button, a change event is fired with the token of the screen the user has navigated back to, which you would use to re-display that screen in your application.
The ExtJS documentation has a history example showing how this can be done. The key portions of the code look like this:
function onTabChange(tabPanel, tab) {
var newToken;
// ... construct a token for the new tab ...
oldToken = Ext.History.getToken();
if (oldToken === null || oldToken.search(newToken) === -1) {
Ext.History.add(newToken);
}
}
// ...
Ext.History.on('change', function(token) {
if (token) {
// ... set active tab based on token ...
}
});
Using Ext.util.History can often require a lot of boilerplate to set up if there are a lot of screens in your application, so ExtJS 5 added built-in routing to help manage this. There are extensions for ExtJS 4 that are intended to accomplish the same thing, such as Ext.ux.Router by Bruno Tavares.

Categories