jquery .load() with back/forward button without hash - javascript

I am using a jQuery script I wrote to load content on my site without refreshing the page, and everything works fine except the back/forward buttons. I am using hash links and loading in my php files based on that.
....
<li><a id="theShopLink" class="theMainLinks" href="#shopFrame">SHOP</a>
....
$('.theMainLinks').click(function() {
var dest = $(this).prop("hash").substring(1);
$('.theMainLinks').removeClass('active');
$(this).addClass('active');
if ($('#fullFrame > div').is(':visible')) {
$('#homeFrame').addClass('animated fadeOutLeft');
$('#homeFrame').html('');
}
console.log(dest);
$("<style>html { background: #000; }</style>").appendTo("head");
$('#nextFrame').html('<div id="loading"><img id="loading-image" src="/wp-content/uploads/assets/loader.gif" alt="Loading..." /></div>').load('/frames/' + dest + '.php');
});
I tried searching and found some examples using html5 window.history.pushState(); but I'm not sure how to work that with my current code without having to rewrite the script. Also the # in the urls look ugly, anyway around this?
I'm not looking to use any kind of plugins/dependencies besides jQuery, and if possible the cleanest/simplest code. Please explain so I can understand because I will need to do something similar with my sub navigation links within the frames and will reuse the function.
UPDATE
On initial website load or refresh, I use the following function to determine what content to load. -
$(function() {
if (window.location.hash) {
var target = window.location.hash.substring(1);
var hash = window.location.hash;
if (hash.toLowerCase().indexOf("frame") >= 0) {
$('#homeFrame').html('');
$('#homeFrame').html('<div id="loading"><img id="loading-image" src="/wp-content/uploads/assets/loader.gif" alt="Loading..." /></div>').load('/frames/' + target + '.php');
} else if (hash.toLowerCase().indexOf("shop-") >= 0) {
$('#homeFrame').html('');
$('#homeFrame').html('<div id="loading"><img id="loading-image" src="/wp-content/uploads/assets/loader.gif" alt="Loading..." /></div>').load('/frames/shopFrame.php');
} else if (hash.toLowerCase().indexOf("news-") >= 0) {
......etc......
} else if (hash.toLowerCase().indexOf("/") >= 0) {
var newTar = target.split('/');
$('#homeFrame').html('');
$('#homeFrame').html('<div id="loading"><img id="loading-image" src="/wp-content/uploads/assets/loader.gif" alt="Loading..." /></div>').load('/general/' + newTar + ' #patchnotesMain');
} else {
// Fragment doesn't exist
$('#homeFrame').html('<div id="loading"><img id="loading-image" src="/wp-content/uploads/assets/loader.gif" alt="Loading..." /></div>').load('/' + target + ' #newContent');
}
} else {
$('#homeFrame').html('<div id="loading"><img id="loading-image" src="/wp-content/uploads/assets/loader.gif" alt="Loading..." /></div>').load('/frames/homeFrame.php');
}
});

With window.history.pushState() I think you can obtain the desired result without rewriting your script and without using hash. You could try something similar to:
function handleState(state) {
// here the code you need to change the page
// more or less the body of $('.theMainLinks').click(function() {})
// in your question code
}
$('.theMainLinks').click(function(event) {
event.preventDefault();
const state = {/* here setup the state for next step */};
handleState(state);
window.history.pushState(state);
});
$(window).on("popstate", function(event) {
handleState(event.originalEvent.state);
});
Hope this helps.

In my opinion, # is usually used in detect anchor in the page (jump to anywhere in page) and not the way to change which page to load, the reason is it's very hard to detect and process the url. I suggest you could use ? for query url instead of using #. Simple example url can be like this: www.yoururl.com/index.php?page=frame.
For changing url and pushing state of page to history of browser. You can use the below function to change url
function change_url(title, html, urlPath){
document.title = title;
window.history.pushState({"html":html,"title":title},"", urlPath);
}
After change url, use your code to render new html
$('#homeFrame').html('');
$('#homeFrame').html('<div id="loading"><img id="loading-image" src="/wp-content/uploads/assets/loader.gif" alt="Loading..." /></div>').load('/frames/' + target + '.php');
To detect event back/forward button, you can use window.onpopstate = function(e){ ... }. This time, your page has all of data that you've just pushed to history, now you can get the data out easily and assign it to html
window.onpopstate = function(e){
if(e.state){ // if state's data is existed
$('#homeFrame').html('');
$('#homeFrame').html(e.state.html);
document.title = e.state.title;
}
};
Please correct me if I were wrong. Hope this would help

Related

Toggle between functions - only execute either one on pageload

I want to toggle between two jQuery functions. It has to be done on page load - and each page load should only execute one of the scripts.
This is what I got so far:
HTML:
<button class=".click">Click me</button>
Script:
$(function() {
if (window.location.href.indexOf("addClass") > -1) {
$("body").addClass("test");
}
else {
$("body").addClass("secondtest");
}
$('.click').on('click', function() {
console.log("Clicked");
var url = window.location.href;
if (url.indexOf('?') > -1) {
url += '?param=addClass'
} else {
url += '?param=1'
}
window.location.href = url;
});
});
This Gets me a bit on the way, the first click adds ?param=1 on the first click - nothing happens - second click it adds the ?param=addClass and the body gets the class. If I click again it adds ?param=addClass every time.
I want one of the script to run as default - then I want the first button click to reload and run the other script instead. If I click once more I want it to reverse the url so the first script loads, like a toggle.
I now there is an easy way to just toggle classes, but I specifically need to run one of two scripts on a new page load.
Update:
$(function() {
if (window.location.href.indexOf("addClass") > -1) {
$("body").addClass("test");
}
else {
$("body").addClass("secondtest");
}
$('.click').on('click', function() {
console.log("Clicked");
var url = window.location.pathname;
var url = window.location.href;
if (url.indexOf('?param=1') > -1) {
url = url.replace("param=1", "")+'param=addClass'
} else {
url = url.replace("?param=addClass", "")+'?param=1'
}
window.location.href = url;
});
});
This set the body class on first page load - then first click ads ?param=1 but doesnt change the body class. Second click replaces ?param=1 with ?param=addClass and changes the body class - after that the toggles works. So How do I make it work from the first click?
This will be the default functionality, if no query string is present then add ?param=1:
var url = window.location.href;
if(url.indexOf('?param=1')==-1 )
{
window.location.href = url+"?param=1";
}
This will be the onclick functionality to toggle the urls as it is replacing the existing functionality.
$('.click').on('click', function() {
var url = window.location.href;
if (url.indexOf('?param=1') > -1) {
url = url.replace("param=1", "")+'param=addClass'
} else {
url = url.replace("?param=addClass", "")+'?param=1'
}
window.location.href = url;
});
If you want to toggle the classes as well you can use .toggleClass("test secondtest")
The issue you have is in this if:
var url = window.location.href;
if (url.indexOf('?') > -1) {
url += '?param=addClass'
} else {
url += '?param=1'
}
Scenario 1: /test.html
indexOf('?') will be negative. You will then redirect the user to /test.html?param=1
Scenario 2: /test.html?param=1
indexOf('?') will then be positive. You will then redirect the user to /test.html?param=1?param=addClass
Scenario 3: /test.html?param=addClass
indexOf('?') will then be positive. You will then redirect the user to /test.html?param=addClass?param=addClass
So... what is wrong?
You are using window.location.href. Excellent for setting the path but bad if you want to actually manage the query parameters.
Solution
var url = window.location.pathname;
var hasParams = window.location.href.indexOf('?') > -1;
if (hasParams) {
url += '?param=addClass'
} else {
url += '?param=1'
}
window.location.href = url;
Since you are redirecting on the same host (seen with your code), you only need the pathname. pathname doesn't include parameters (?key=value&...) and can be used to redirect a user on the same domain.

Wait for all content in AJAX response to be loaded before displaying

I have a search function where on every character it pings the server with a json request to return the results. That part of it all works, but what I'd love to have happen (which I can't figure out) is to also put a loading class on .search-load>.container and then wait for all the images and content that have been requested to load completely before removing the loading class.
Everytime i try and tie a .load function onto the removeClass function it ends up just leaving the loading class on there. Any ideas? Thanks!
$(document).on('keyup','#section-dropdown.search input',function(event){
if(searchTimer !== null){
clearTimeout(searchTimer);
}
var query = this.value;
searchTimer = setTimeout(function(){
$('.search-load > .container').addClass('loading');
$.getJSON('json/search.json?query='+query,function(data){
if(data.length > 0){
var html = '';
for(var i=0,item=data[i];i<data.length;i++){
html +='<a class="entry small search" href="'+item.link+'"><article>';
html +='<div class="image"><img src="'+item.picture+'" alt="'+item.alt+'"></div>';
html +='<div class="content"><h1>'+item.title+'</h1></div></article></a>';
if(i==data.length-1){
$('.search-load > .container').html(html);
$('.search-load > .container').removeClass('loading');
}
}
}
});
},200);
});
Ideally, you would delegate onload event but as it doesn't bubble, you cannot. So you could still capture it if IE8< support isn't an issue.
document.addEventListener(
'load',
function (event) {
var elm = event.target;
if (elm.nodeName.toLowerCase() === 'img' && $(elm).closest('.search-load > .container').length && !$(elm).hasClass('loaded')) { // or any other filtering condition
console.log('image loaded');
$(elm).addClass('loaded');
if ($('.search-load > .container img.loaded').length === $('.search-load > .container img').length) {
// do some stuff
console.log("All images loaded!");
$('.search-load > .container').removeClass('loading');
}
}
},
true // Capture event
);
You can set this snippet in head section of site without any wrapper.
As a side note: jQuery doesn't support capturing phase, that's why you need to use relevant javascript method instead.

onClick event in separate document

I've done a webpage and I would like to keep all my onClick events in a seperate JS document, as I do with the rest of the Javascripts I'm using.
The snippets I'm using atm in the HTML I would like to change at the moment is these:
<a href="http://www.commercial.com" onclick="confirmLeave()" target="_blank">
and
<IMG SRC="picture_small.jpg" alt="Description" onClick="view(this);">
And the connected Javascript code that I keep in a seperate document is this:
function confirmLeave() {
if (confirm("Do you want to leave this page?")) {
return true;
} else {
if (window.event) {
window.event.returnValue = false;
} else {
e.preventDefault();
}
return false;
}
}
And
function view(img) {
imgsrc = img.src.split("_")[0] + "_big.jpg";
viewwin = window.open(imgsrc, 'viewwin', "width=790,height=444,location=0");
viewwin.focus();
}
The first is to ask if the visitors want to leave my page when they click on a link leading to an external site; the other one is to show a bigger version of the picture they clicked on.
You can create a link to an external javascript file like this.
<script src="http://yoururl.com/myjs.js"></script>

Reload JavaScript files without refreshing HTML

I've a HTML which loads several Javascript files:
<script src="assets/js/a.js"></script>
<script src="assets/js/b.js"></script>
<script src="assets/js/jquery.min.js"></script>
As I debug/test my Javascripts in my browser's console, is it possible to reload these Javascript files without the need to reload the entire HTML page?
You could remove and then re-add them:
$('script').each(function() {
if ($(this).attr('src') !== 'assets/js/jquery.min.js') {
var old_src = $(this).attr('src');
$(this).attr('src', '');
setTimeout(function(){ $(this).attr('src', old_src + '?'+new Date()); }, 250);
}
});
Nope (at least not without a hack), in fact - be very careful reloading so much. It's quite possible that your javascripts become cached, which leads to many-a-headache trying to debug, since your updates are not applying.
https://superuser.com/questions/36106/force-refreshing-only-javascript-files-in-firefox-and-chrome
Based on PitaJ's solution.
Reload all javascript in a function. You can call this from anywhere you want.
$('script').each(function () {
if ($(this).attr('src') != undefined && $(this).attr('src').lastIndexOf('jquery') == -1) {
var old_src = $(this).attr('src');
var that = $(this);
$(this).attr('src', '');
setTimeout(function () {
that.attr('src', old_src + '?' + new Date().getTime());
}, 250);
}
});
Tested with jQuery 2.0.3 and chrome 43
function reloadScript(id) {
var $el = $('#' + id);
$('#' + id).replaceWith('<script id="' + id + '" src="' + $el.prop('src') + '"><\/script>');
}
Chrome is complaining, but works:
Synchronous XMLHttpRequest on the main thread is deprecated because of its detrimental effects to the end user's experience. For more help, check http://xhr.spec.whatwg.org/.
Your script tag has to have id.
Call in console:
reloadScript('yourid');
Does not remove event listeners, so for for example button click gets executed twice if once reloaded.

jQuery add target="_blank" for outgoing link

I need some help to create jquery script :)
I have some of link like this on my HTML.
Google
Home
Home
Contact Us
And now i want jQuery to check all of the link on my page. if that link is outside of my server (my server is gusdecool.com). Then add target="_blank". and the result will be like this
Google
Home
Home
Contact Us
assuming that all external links will start with http:// you could do this:
$('a[href^="http://"]').not('a[href*=gusdecool]').attr('target','_blank');
$('a').each(function() {
var a = new RegExp('/' + window.location.host + '/');
if (!a.test(this.href)) {
$(this).attr("target","_blank");
}
});
This was from css-tricks.com, seems to work pretty well.
$('a[href^=http]:not([href^=http://www.gusdecool.com/])').attr('target','_blank');
Of course, this works only if all the external links start with the http protocol. You should adapt this code to suite your needs (suchs as links without protocols, or with different protocols).
UPDATE :
$('a[href^=http]:not([href^=http://www.gusdecool.com],[href^=http://gusdecool.com])')
.add('a[href^=www]:not([href^=www.gusdecool.com])')
.attr('target','_blank');
It selects all the a elements that have their href attribute starting with a web page address (with or without protocol) and do not point to your site's address and changes their target attribute to _blank.
This function seems to be easier if you have a subdomain:
$('a').attr('target', function() {
if(this.host == location.host) return '_self'
else return '_blank'
});
jQuery(document).ready(function(){
target_luar();
});
function target_luar(){
try{
if(top.location != location) {
jQuery("a[href^='http']")
.not("[href*='"+location.host+"']")
.attr('target','_blank');
}
} catch(err) { }
}
Demo : Demo jQuery External Link
Global function to open external links in a new window:
$(function(){ // document ready
$("a").filter(function () {
return this.hostname && this.hostname !== location.hostname;
}).each(function () {
$(this).attr({
target: "_blank",
title: "Visit " + this.href + " (click to open in a new window)"
});
});
});
Putting it all together we get the following.. Wait for it all to load, select only links starting with http or https, check if the link point to the same domain (internal) or another domain (external), add appropriate target if match found..
$(window).load(function() {
$('a[href^="http"]').attr('target', function() {
if(this.host == location.host) return '_self'
else return '_blank'
});
});
You could use jQuery's $.each function to iterate over all Anchor tags, perform the needed check and set the "target" attribute using $(this).attr("target","_blank");
Example (Not tested but should work):
$('a').each(function(index) {
var link = $(this).attr("href");
if(link.substring(0,7) == "http://")
$(this).attr("target", "_blank");
});
Shai.
Here's a fiddle demonstrating an answer using raw JS (not jQuery): http://jsfiddle.net/Xwqmm/
And here's the code:
var as = document.getElementsByTagName('a');
var re = /^https?:\/\/([^\/]*)\//;
for (var i = 0, l = as.length; i < l; i++) {
var href = as[i].href;
var matches = href.match(re);
if (matches[1] && matches[1] != "gusdecool.com") {
as[i].setAttribute("target","_blank");
}
}
This is such a brilliant site I learned so much from it :
If you do it this way you do not need to worry about http or https (handy while developing)
$('a[href^="http"]')
.not('a[href*='+ location.hostname +']')
.attr('target','_blank');
You can see all external link whith http and https
jQuery('a[href^="https://"],a[href^="http://"]').not("a[href*='"+ window.location.host +"']").each(function() {
console.log(jQuery(this).attr('href'))
});
And you can add _blank like this
jQuery('a[href^="https://"],a[href^="http://"]').not("a[href*='"+ window.location.host +"']").attr('_target','blank');
You could use filter -
$("a").filter(function () {
return this.indexOf('http://') > -1 && this.indexOf('gusdecool') == -1
}).attr("target","_blank");
Check each linkobject $(link).attr("href"), if that starts with http:// then its an outgoing link (?). Then assign the .attr("target", "_blank").
$(a).function(){
if($(this).attr("href").substring(0,3) == "http" && <!-- CHECK ITS NOT YOUR SITE URL -->){
$(this).attr("target", "_blank");
}
};
Hope this helps.
Try:
$('a[href^="http://"]')
.not('a[href*='+ location.hostname +']')
.attr('target','_blank');
<div id="myLinks">GoogleHomeHome
Contact Us</div>
<script type="text/javascript">
jQuery(document).ready(function(){
jQuery('#myLinks a').attr('target', '_blank');
});
</script>

Categories