Manually add Browser History Entry (Cross Browser) - javascript

I don't know if it's possible in any way to achieve, what I want to do.
I got single page website with some sections. Something like this:
<div class="page pageOne"></div>
<div class="page pageTwo"></div>
<div class="page pageThree"></div>
<div class="page pageFour"></div>
When you open up the site, pages 2, 3 and 4 got display:none and the first one display:block. When I click a link in my navigation, the current "page" fades out and whatever link you've clicked on, the belonging section fades in. The links look like this:
<a class="pageChange" href=".pageFour">Four</a>
And here's the jQuery code:
$(".pageChange").click(function(e){
e.preventDefault();
var href = $(this).attr("href");
$(".page").fadeOut(200);
setTimeout(function(){
$(href).fadeIn();
}, 200);
});
What's pretty obvious is when I click the browsers back button, it won't fade the previous section in. It will just return to the previous site I've opened.So my question is: Is there a way to add a history entry in the browser, when clicking on a link? So I can press the back button and it fades the previous section in?
To get the visible section before clicking a link, I've done this:
var currentPage = $(".page:visible").attr('class').split(' ')[1];
But unfortunately that's no use to what I want to achieve.
I'd be incredibly happy if someone could provide me some help of how I could approach this (or if it's even possible)

You have to use the browser History API to update the URL. Then you can detect the back and forth movement with onpopstate and call your fadeIn and fadeOut methods accordingly.

I had the super similar situation! The best solution my friend would be to use https://alvarotrigo.com/fullPage/ You can read the code how he's doing on github. Basically you have to record the scrolling and later handle using a function for back and forth browsing.

Related

How to reverse display=none on browser history back click?

On my page I have a javascript function that changes the current URL via pushState and hides a specific div when a user clicks on the text "close". The simplified page looks like this:
<div id='book'>
<a onclick='close();'>close book information</a>
Book Information
</div>
<div id='booklist'>List of all books</div>
<script>
function close() {
/* ... */
document.getElementById("book").style.display = "none";
window.history.pushState({path:newurl},'',newurl);
}
</script>
So the URL is "book.php?id=1" and shows information about one book on top of the books' list. If the user clicks on the close button, the URL changes to "book.php" and the book is hidden.
However, if the user opens other books and then clicks the back button of their browser, the URL will change back to "book.php?id=1" but display=none is still active. How can I reverse the javascript that was done before? Refreshing the page would also be fine. I found this answer but since I cannot change the body tag, it doesn't work for me.
I hope that you might have an idea how to solve this.
Use this:
document.getElementById("book").style.display = location.search ? "block" : "none";

Single Page Site and Back Button Confusion

I have been searching for hours about how to do this, trying different things and not succeeding.
All I want to do is make a one-page site that shows/hides divs and does one simple animation. I have already made it do everything I want and look the way I want it to look: When you click a link in my navbar, there is a script that runs that hides one div, shows another, and also changes the size of the header image. This is all done with simple JS and CSS, but the back button doesn't work and the URL does not change even when I make the link a hash anchor. Maybe having all the divs on the index and showing/hiding them isn't even the best way to do this.
The implementation of the HTML5 History API (If I should even be using that) has got me stumpped, and I can't seem to find a simple straightforward working example of this.
Can anyone point me to a fiddle or codepen of something like this working properly?
This is the basics of what I'm doing:
Link:
Work
Function:
function work() {
document.getElementById("work").style.cssText = 'display: block; opacity: 1;'
document.getElementById("about").style.cssText = 'display: none; opacity: 0;'
document.getElementById("hero").style.cssText = 'height: 85px; transition: 200ms ease-in-out;'
document.getElementById("introcontainer").style.cssText = 'visibility: hidden; opacity: 0; transition: visibility 200ms, opacity 200ms linear;';
}
When my "Work" link is clicked, "about" is hidden, "introcontainer" is hidden, height of "hero" is changed, and "work" is displayed. I have two other "pages" and they function the same way.
History API is made just for such scenarios , instead of scanning url hashes and running complex if else you can use pushState to keep track of application state and decide what happens at each state.
The gist of this API is when you push something using pushState it gets returned to you on popState (on hitting back button).
history.pushState(objState,title,Url);
The first argument is where we pass stuff that will help identify application state you can put anything but it has to be enclosed in an object
I will ignore the 2nd one(pass any string). 3rd one is what URL bar would show relative to current path on executing PushState()
Assuming you have nav something like this
<ul id="nav">
<li>About</li>
<li>Contact</li>
<li>Team</li>
</ul>
assign click handlers for pushing state
$('a').click(function(e){
e.preventDefault();
var targetUrl = $(this).attr('href');
history.pushState({url:targetUrl}, targetUrl, targetUrl);
applyState(targetUrl); //will show div associated with this anchor
});
Now when user clicks a link you need to push something related to this say its href or title to identify it later (I've used its href but you are free to use anything) after it gets pushed you may animate and show div associated with this link eg. If I click <a href="work"> then push “work” and show the div that holds your work details(while minimizing/hiding other divs) .Your url reads xyz/work atm
Next if I click <a href="contact"> state for contact gets pushed and same way it's associated div gets highlighted.Your url reads xyz/contact atm
Now when I hit back history will pop and url will change from xyz/contact to xyz/work popping the latest inactive state (wiz. work and not contact!)
If you have assigned handler for onpopstate you can catch the popped content
window.onpopstate = function(e) {
var popie = e.state ? e.state.url : null;
applyState(popie);
}
so popie would be “work” , applyState will do its fancy animation and show work div
applyState might look like
function applyState(url) {
$('#status').text('Current active page ' + url);
switch(url){
case "work": //show work details div hide others
break;
case "about": //show aboutdetails div hide others
break;
}

jQuery toggle not working when back button is hit

I have the following jQuery code:
$(function() {
var linkSet = $('#link1').add('#link2');
linkSet.click(function() {
linkSet.toggle();
if ($(this).attr('id')=='link1'){
$('#frame').attr('src', 'www.google.com');
} else if ($(this).attr('id')=='link2'){
$('#frame').attr('src', 'www.yahoo.com');
}
});
});
On pageload, the link with id link1 is shown while link2 is hidden. When the user click the link1, it will the link1 then show the link2 then vice versa. While toggle takes place, it also changes the source of an iframe which is named frame.
My problem here is when I hit back button, the content of the frame will go back to its previous content BUT the link are not changing. What did I missed here? Thanks in advance!
Note: The links are on a webpage, then inside that webpage is an iframe.
EDIT:
<div id="header">
<ul>
<li><a id="link1" href=#">Link1</a>
<li><a id="link2" href=#">Link2</a>
</ul>
</div>
<div id="iframe">
<iframe id="frame" src="www.google.com"></iframe>
</div>
You mean when pressing the browser's back button right.
If so:
The issue is you need to have an event to trigger when the history changes, as that is the only easy way to respond to changes in history (such as when clicking the back button). Since the iframe url is indeed changing, it is therefore also affected by the back button naturally.
To get other non history based logic to work when pressing the back button and such...
There are two ways to do this. The new one is by using the history API, while the other more supported, and simpler way is by adding a hash to the url.
WHAT DOES THIS MEAN?
When you click the button you change the url with a hash. Like the url can become
'http://domain.com/blah/#myHash'
Then instead of doing your logic in the click, you do it when the hash changes. So this way as the user clicks back and/or forward the logic always runs fully.
I wrote an entire article about this technique a few months ago at http://andresgallo.com/2012/06/08/ajaxifying-the-web-the-easy-way/

History object back button with iframes

I'm having problems with history object and iframes in javascript/html5. I wrote a simple project to describe my problem:
http://dktest.evermight.com/
It's a page with an iframe and a next button. Every time you click next, it loads a new page with an incrementing counter. However, clicking the browser back button doesn't do what I want it to do. Let me explain the problem by breaking this post up into the following sections:
What I'd like to achieve
Undesired results in current project
Post all my code
1. What I'd like to achieve
I want the user to:
Open a new window and go to http://dktest.evermight.com/
Click next page and see a redbox fade in, and to see the url http://dktest.evermight.com/count.html?count=0 appear in both the iframe AND the browser's address bar
Click next page again and see http://dktest.evermight.com/count.html?count=1 in the iframe and browser's address bar
Click browser's back button ONCE and see http://dktest.evermight.com/count.html?count=0 in both the iframe and the browser's address bar
Click browser's back button ONCE and see http://dktest.evermight.com/ in the browser's address bar AND see the red box fade out
2. Undesired results in current project
With my code at http://dktest.evermight.com/, it's currently not performing steps 4 and steps 5 correctly. When I perform step 4, the iframe shows http://dktest.evermight.com/count.html?count=0 but the browser address bar shows http://dktest.evermight.com/count.html?count=1. I have to press the browser's back button again to make the browser address bar show http://dktest.evermight.com/count.html?count=0. When I perform step 5, the red box fades out which is great, but the address bar is still showing http://dktest.evermight.com/count.html?count=0. I have to press back again to make the address bar show http://dktest.evermight.com/.
3. Post all my code
My code is pretty straight forward. You can view source on http://dktest.evermight.com/. I will also post here for convenience.
index.html
<!DOCTYPE html>
<html>
<head>
<title></title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script type="text/javascript">
var count=0;
function clicknext()
{
$('#container').fadeIn();
$('#iframe').attr('src','count.html?count='+count.toString());
$('html title').html(count);
history.pushState({blahblah:'whatgoeshere?'},'i dont know what goes here either','http://dktest.evermight.com/count.html?count='+count);
count++;
}
function hideContainer()
{
$('#container').fadeOut();
var closeurl = 'close.html';
if($('#iframe').attr('src') != closeurl )
$('#iframe').attr('src', closeurl);
}
$(document).ready(function(){
hideContainer();
});
</script>
</head>
<body>
<div id="container" style="display:none; background:red;">
<!-- IMPORTANT
When DOM first created, the iframe.src MUST BE initialize.html
I have some code that I need to fire on that page before the rest
of this document starts
-->
<iframe id="iframe" src="initialize.html"></iframe>
</div>
<input type="button" onclick="clicknext()"; value="next page" />
</body>
</html>
close.html
<!DOCTYPE html>
<html>
<script type="text/javascript">
parent.hideContainer();
</script>
</html>
count.html
I CAN NOT modify the contents of count.html. In my real project, count.html is actually a youtube video, which is on a server I can't directly access.
<html>
<body>Youtube video at url <script type="text/javascript">document.write(location.href);</script></body>
</html>
initialize.html
Perform application specific functionality
Can anyone correct my code to achieve the results of step 4 and step 5 as described in section 1?
UPDATE
Ok, I'm appreciating the problem a bit more based on some experiments I'm doing.
Experiment 1: I tried changing the line:
$('#iframe').attr('src','count.html?count='+count.toString());
to
$('#iframe')[0].contentWindow.location.replace('count.html?count='+count.toString());
This allowed me to perform step 4 correctly. Apparently, contentWindow.location.replace() will not create an entry in the history object. However, this caused some other issues related with the contents of count.html, which is actually a page to youtube/vimeo content. The youtube/vimeo content REQUIRES that you load information via the attr('src') approach instead of .contentWindow.location.replace(). So perhaps the solution is to find a way to make attr('src') NOT create an entry with the history object?
Experiment 2 Another possible solution I tried was changing the order of the attr('src') and history.pushState() call. I tried calling attr('src') first then history.pushState() second, and also history.pushState() first then attr('src') second. But in both cases, when I push the browser's back button, it is the iframe content that goes back first. So there's no way for me to capture pass myself a message via the history object to do a "double back", since information in the history object is available LAST in the sequence of events.
Experiment 3 I also tried working with History.js. It did not do anything to solve my problems above. From what I could tell, it worked exactly like the regular history object.
Does anyone have any thing else I can try? Or suggest modifications to any of the experiments above? I'm going to explore Experiment 1 further as a separate stack overflow question.
I create a new iframe and destroy the iframe when loading new content. That solves the history issues.
I know this is a history problem but if you are still open to other possibilities, I think jquery-pjax is actually more suitable for what you are trying to do.
UPDATE I think this should work.
count.html
<div id="pjax-container">
<a id="pjax" data-pjax href="#">Next Page</a>
</div>
javascript
// get URL parameter (count): http://stackoverflow.com/questions/1403888/get-url-parameter-with-jquery
function getURLParameter(name) {
return decodeURI(
(RegExp(name + '=' + '(.+?)(&|$)').exec(location.search)||[,null])[1]
);
}
$(document).on('pjax:beforeSend', function() {
// your fading code goes here
})
$(document).on('pjax:complete', function() {
// fade out
// and then modify the anchor's href with something like
var new_count = getURLParameter('count') + 1;
$('a#pjax').attr('href', 'count.html?count=?' + new_count);
})
// where the pjaxed content should go
$(document).pjax('a[data-pjax]', '#pjax-container')

Support Middle Clicks on my Fancybox Lightbox

Suppose you have a lightbox, and you want to allow the user to middle-click, which would open a new tab, and the same content that shows-up in the lightbox on left-click is now on a standlone page (complete with header, sidebar, etc).
Anybody have a snippet or technique handy they can share?
Otherwise the technique I was going to try first was just to add a conventional href to the link, then add a click handler that cancels the default action on left click. I think this'll work but I'm not sure so honestly it was easier to pound out a question than to write it up and test it in the 14 browser/os combinations I have to support.
I finally found time to work this out and it was pretty easy:
This is how I made it work using jQuery & FancyBox:
Give your desired link a 'has-overlay' class and give it a custom attribute that will tell it what it should load in the overlay
Login
Be sure you have the overlay code available (this is standard FancyBox stuff)
<div class="hidden" id="loginform"> <!-- Form Goes Here --> </div>
And put this snippet in your on ready event:
$('.has-overlay').bind('click', function(e) {
var overlay = $(this).attr('overlay');
$('').fancybox().trigger('click');
return false;
})
When a user left-clicks, this 'click' handler will be called. It will load the overlay and then return 'false' so the browser won't follow the href in the link.
When a user middle-clicks or right-clicks, the click handler doesn't fire, and it works as a normal link would.

Categories