Preload page on hover and link on click - javascript

I'm playing around with a possibility to preload a page using ajax on hover over a button and have this page available quicker on click on this button. I'm quite at the beginning and can't really find a good solution for this / might be totally wrong. Here is what I have tried, looks like a little promissing for me:
document.getElementById('link').addEventListener('mouseover',function() {
var r = new XMLHttpRequest();
r.open("POST", "index.php", true);
r.onreadystatechange = function () {
if (r.readyState != 4 || r.status != 200) return;
document.getElementById('link').addEventListener('click',function() {
window.location.assign('index.php');
});
};
r.send('');
});
But I don't think that does it.
Can someone point me in a direction without sharing code/solutions? I'm mainly interested in how I can achieve this by myself - is ajax the right way to start?
I'm looking for a javascript only solution

You'll need a bit of a framework for subbing out the page content and managing what's in the URL without sending another request to the server and reloading the page.
Push state can help with the URL manipulation.
You would need to replace the body of your page (or less, depending on your markup, maybe just everything inside #container or whatever you have on the page) when you received a partial of HTML from your server via AJAX.
Look into how something like Rails' TurboLinks uses an approach called PJAX to quickly navigate pages. Then the prefetching on hover could be layered on top of an approach like that.
More reading: http://pjax.herokuapp.com/

Related

How to keep elements non-refreshed

The main goal is to keep non-refreshed the logotext <div class="small-7 medium-4 columns logo"> and the menu <nav class="pagedMenu" role="navigation">,without clipping on page refresh or while the content is loading from a page to another. Also, the menu state should be preserved from a page to another.
I've found here a possible solution that could solve the problem (you could use ajax to fetch the updated content and use jQuery to put the new content on the page and avoid the refresh entirely. Doing it that way, the existing data in the page would remain untouched. said #jfriend00)
So, I have tried to use an Ajax plugin (called AWS). In the AWS option page, I (suppose) that I've done the right thing pointing wrapper as Ajax container ID and also pagedMenu as Menu container class, Transition Effect Enabled, No ajax container IDs blank, no loader selected, having already a pulse loader implemented in the theme.
At this point, all I got it's a menu / side-menu (shiftnav) / pulse dot loader / content loading malfunction, generated perhaps by the wrong defined Ajax container id and/or menu container class(?) OR by a conflict with an existing JS / jQuery code, not so sure.
Also in Chrome console there is an error:
Uncaught SyntaxError: Unexpected token ;
(anonymous function) # ajaxify.js?ver=4.3.1:175
n.extend.each # jquery-2.1.4.min.js?ver=2.1.4:2
n.fn.n.each # jquery-2.1.4.min.js?ver=2.1.4:2
$.bind.$.ajax.success # ajaxify.js?ver=4.3.1:169
n.Callbacks.j # jquery-2.1.4.min.js?ver=2.1.4:2
n.Callbacks.k.fireWith # jquery-2.1.4.min.js?ver=2.1.4:2
x # jquery-2.1.4.min.js?ver=2.1.4:4
n.ajaxTransport.k.cors.a.crossDomain.send.b # jquery-2.1.4.min.js?ver=2.1.4:4
Everything is getting back to normal on page refresh but doesn't help at all, being useless.
I also have to mention that for the menu I've tried to keep the state using jQuery-Storage-API and storage=jQuery.sessionStorage; as you can see in mynewmenu.js file but that will not solve the non-refreshing elements problem.
The menu jsfiddle only, if this helps to have the whole picture, here thanks to #Diego Betto.
You can use this live link as example; there is a similar situation with the above described - Ajax implementation right(?) - and regarding the appearance, menu is kept non-refreshed from one page to another; if you browse Books, Works etc, menu sections you'll see; if there is a model that could be implemented here, I'll be glad to find it.
LE: meanwhile, I've tried another ajaxify solution made by #arvgta - special thanks - without success yet but as far as I've found from the Author, the defined elements should be div's with id's not classes. So, I'll try to find a way to modify somehow the code in order to have id instead on classes.
Also, I'll try to transform and implement in ajaxify.min.js file, the page-container element; jQuery('#page-container').ajaxify(); I'll come back with news.
LE2: I've tried to implement the solution using id's instead of classes but still, the pages are not loading correctly.
At this point we have ajax.min.js file updated with these lines:
(function($){
jQuery(document).ready(function(){
jQuery('#page-container').ajaxify({requestDelay:400,forms:false});
});
})(jQuery);
Also, I've modified the theme file to have id=page-container instead if class=page-container.
In these conditions, on menu click, the links are changed (like it should), menu/ logotext elements seems to working almost fine (sometimes get skippy changing position), but the content is not loading correctly in all cases; Same here, everything is getting back to normal on manual page refresh (f5), but doesn't help.
LE3: It looks like the conflict is (at least) between Revolution Slider plugin and Ajaxify.
errormessage="Revolution Slider Error: You have some jquery.js library include that comes after the revolution files js include." ;="" +=" This includes make eliminates the revolution slider libraries, and make it not work." "<="" span="">"
Site live link here. Any thoughts / alternative in this area? (not interested in using other different platforms, different WordPress themes, etc. just a workaround in this existing situation)
LE4: As far as I can see, there are many users that voted up the Jake Bown answer that could be indeed a solution; but I can't find the reason that didn't work correctly implemented into my theme (without errors) live link here The elements logotext / menu are still fading on refresh, are not kept non-refreshed. Any thoughts #Jake Bown / anyone?
LE final.
Buzinas delivered the closest answer for my needs, taking in consideration my site environment (plugins installed, etc).
From what you said I think I might have found the solution you're looking for - you want to load content dynamically whilst keeping the logo and navigation untouched? If so, this might be what you're looking for.
In the example, the pages are loaded in from a div within the page but could be used to load another URL or file:
$('.viewport ul li a').on('click', function(e) {
e.preventDefault();
var link = this.hash.substring(1, this.hash.length);
if($('.'+link).length) {
$('.viewport span.body').html($('.'+link).html());
}
});
TL;DR
I've created a plunker for you, take a look, and play with it as long as you can. You'll learn a lot from it!
I think you're trying too many things here, but didn't try the simplest:
The main goal is to keep non-refreshed the logotext and the menu ,without clipping on page refresh or while the content is loading from a page to another. Also the menu state should be preserved from a page to another.
If you want to do that, there are a few steps:
Create a 'master' page, that we're going to call index.html from now on.
So, our index must have the static part of our page, e.g menu, logo, footer etc.
Then, our 'subpages' must be cut down (no html, head, body, script, style tags, only the content that should be showed into our master page).
That done, now we must change our links to use AJAX instead of doing full refresh:
/* we add a 'click' event handler to our menu */
document.getElementById('menu-menu-2').addEventListener('click', function(e) {
var el = e.target;
/* then, we see if the element that was clicked is a anchor */
if (el.tagName === 'A') {
/* we prevent the default functionality of the anchor (i.e redirect to the page) */
e.preventDefault();
/* we show our spinner, so the user can see that something is loading */
spinner.classList.remove('hidden');
/* and we call our AJAX function, passing a function as the callback */
ajax(el.href, function(xhr) {
/* we get our main div, and we replace its HTML to the response that came
from the AJAX request */
document.getElementById('main').innerHTML = xhr.responseText;
/* since the request was finished, we hide our spinner again */
spinner.classList.add('hidden');
});
}
});
Ok, now our pages are already working via AJAX, and not reloading our static content.
But now, we see that we have some issues. For example, if someone tries to open one of our pages directly via URL, he'll see unstyled page, without the menu/logo etc. So, what should we do?
We have a few more steps now:
Simulate that our links are effectively transfering between pages using the History API:
/* inside our ajax callback, we save the fake-redirect we made into the pushState */
ajax(el.href, function(xhr) {
document.getElementById('main').innerHTML = xhr.responseText;
/* save the new html, so when the user uses the back button, we can load it again */
history.pushState({
html: main.innerHTML,
title: el.textContent + '| neuegrid'
}, '', el.href);
/* (...) */
});
/* and outside it, we add a 'popstate' event handler */
window.addEventListener('popstate', function(e) {
/* so, if we've saved the state before, we can restore it now */
if (e.state) {
document.getElementById('main').innerHTML = e.state.html;
document.title = e.state.title;
}
});
And we need that when the user enters directly to another page, e.g about-us, we redirect him to the index.html, and then load the about-us page from there.
So we create a redirect.js file, and we reference it in all of our
subpages:
/* save the page that the user tried to load into the sessionStorage */
sessionStorage.setItem('page', location.pathname);
/* and them, we redirect him to our main page */
location.replace('/');
And then, in our index.html page, we see if there is any page in the sessionStorage, and we load it, if there is, otherwise we load our home page.
var page = sessionStorage.getItem('page') || 'home';
/* we look into the menu items, and find which has an href attribute
ending with the page's URL we wanna load */
document.querySelector('#menu-menu-2 > li > a[href$="' + page + '"').click();
And that's it, we're done now. Take a look at the plunker I've been making to you.
And play with it as long as you can, so you'll learn a lot from it.
I hope I could help you! :)
Note: Just for reference, this is our ajax function:
function ajax(url, callback, method, params) {
if (!method) method = 'GET';
var xhr = new XMLHttpRequest();
xhr.open(method, url);
if (callback) xhr.addEventListener('load', function() {
callback.call(this, xhr);
});
if (params) {
params = Object.keys(params).map(function(key) {
return encodeURIComponent(key) + '=' + encodeURIComponent(params[key]);
}).join('&');
xhr.send(params);
} else {
xhr.send();
}
}
GOING AJAXED WITH WORDPRESS
demo: http://so.devilmaycode.it/how-to-keep-elements-non-refreshed/
follow these simple steps (let's take as example theme "twentyfifteen" on the WP templates folder):
edit single.php, page.php, index.php and all other pages having get_header() and get_footer() functions and replace it respectively with below code:
NOTE: this is important because if someone (ex: search-engine) reach your pages directly from the link, it is still fully available and 100% working. (useful for SEO)
<?php
//get_header()
if(!isset($_REQUEST['ajax'])){
get_header();
}
?>
<!-- other code --->
<?php
//get_footer()
if(!isset($_REQUEST['ajax'])){
get_footer();
}
?>
open the header.php add the below code inside the <head> section at the very end
<script>
!(function($) {
$(function() {
$('.menu-item a, .widget-area a, .page_item a').on('click', function(e) {
e.preventDefault();
var href = this.href;
var query = href ? (href + (!/\?/g.test(href) ? '?' : '&') + 'ajax=1') : window.location;
/* IMPLEMENT SOME LOGIG HERE BEFORE PAGE LOAD */
/* ex: kill instance of running plugins */
$('#content').hide().empty().load(query, function() {
/* IMPLEMENT SOME LOGIG HERE AFTER PAGE IS LOADED */
/* ex: refresh or run a new plugin instance for this page */
jQuery(this).show();
});
});
});
})(jQuery);
</script>
in the header.php file put the code below at the end of the file, 90% of times you need it under the navigation. In this case we already have this on the "twentyfifteen" theme.
NB: most probably you have the opening tag <div id="content" class="site-content"> inside the header.php file and the closing tag </div> on the footer.php file, this doesn't matter, you can leave it as is.
<div id="content"></div>
NOTE: consider this a proof of concept; it may work as is, but you still need to tailor it to suit your needs; you may need to:
Add a menu (in case it is not already set) by going under Appeareace > Menus > [check Primary Menu] > Save Menu in order to activate the menu. it's tested and working.
You may want to add some other class to the jQuery function like .widget-area a in order to ajax also widget links.
if you are using 3d party plugins you may need to ensure that all dependencies of each plugin are loaded also on the main page from where you want everything is displayed without refreshing content.
you may need to check and kill those 3d party plugin before a new page load and run or refresh plugin needed in the loaded page.

Load external page on div and getting a specific url at the same time

I am developing a new website and while I want to get it done as easy to navigate as possible, I also wanted to use some kind of navegation with overlapping pages.
My idea was to have articles on the current page that will open on a floating div over the rest when clicked. That´s not really the problem because using jquery .load() it gets quite easy to do, but my problem is that it doesn't modify the current url, so it remains as www.myweb.com for example and I would like to have it like www.myweb.com/current-article when the article is opened. Once you have that specific url to the article, if it is shared, whoever open that link will get to the website with the article opened over the it.
I hope it all makes sense, but a good example can be found in USA Today or Play.Spotify
I am using umbraco 7 and javascript for the site. Any idea of how it could be done?
its called hash base navigation
location.hash = "#myHash"; //sets the url plus hash
Below is fired if user manually changes the URL or by using the back button
window.onhashchange = function()
{
if (location.hash === "#myHash")
{
doSomething();
}
}
This is actually a big and complex task to implement correctly.
I would advise you to use Backbone.Router http://backbonejs.org/#Router. It use history api in "new" browsers, with a fallback to hashtags in older browsers.
Some pseudo code:
First define your route. It will catch all pages under www.myweb.com/articles/*
var MyRouter = Backbone.Router.extend({
routes: {
"articles/:page": "loadPage"
},
loadPage: function() {
var div = $("#overlay");
div.html($.load("your page"))
div.show()
}
});
You would need to implement some logic to test if the loaded page is not under articles/.*
Init MyRouter when the page is loaded:
var router = new MyRouter();
router.start()
The overlay page will now open when you hit www.myweb.com/articles/cool-article
If you want to open the page from a parent page, simply call
$("button").click(function(){
router.navigate("articles/cool-article", {trigger: true});
});

How to change URL path when paging using ajax + jQuery

I am using ajax post requests for doing paging on a feed in my site. When getting the post request data I am reforming the page by clearing previous data and rendering the new data that came from the request. I want to be able to change the URL as well so saving the new page link will get the user to the current page.
Example:
User on page example.com/feed - seeing content of page #1
User clicking to get to page #2 -> ajax post is send and data on the page is changed using js (no refresh)
URL is still example.com/feed but the content is of example.com/feed?page=2
How can I set the URL to point to the new page without triggering a refresh (no redirect) ?
I am using Nodejs + express.
I understand you are aiming at a single page application.
While keeping the url is nice, note you might want distinct urls for directly accessing different parts of your application. Still, you can load content with AJAX and keep a smooth application. The way to go is using the hash part of the location.
The Sammy.js framework gives you a nice base to build upon, you can try it out.
You can use history pushstate but some browsers does not support.
history.pushState({id: 'SOME ID'}, '', 'myurl.html');
And don't forget about window.onpopstate, it pops if user clicks back button.
Redirect the user to an anchor point.
Page 2
And in your document.ready:
if (window.location.hash.length > 1){
var pageNumber = window.location.hash.substring(1);
loadPage(parseInt(pageNumber));
} else{
loadPage(0);
}
I don't believe it is possible to change the query part of the URL without triggering a refresh (probably due to security issues). However you may change the anchor and use an event listener to detect when the anchor is being changed.
//Listener
$(window).on('hashchange', function() {
if(loaction.hash.length > 1) {
//The anchor has been changed.
loadPageWithAjax("example.com/feed.php?page=" + location.hash.substring(1));
} else {
//Load standard page
...
}
});
Change the anchor to load new feed
Page 2
Remember to not use an anchor that is used as an id, since this makes the browser scroll to that element.

What to do if $(window).load(function(){}); is too early

I need to trigger a piece of code after every single bits are done downloading. The script works if injected after everything is loaded, but how do I trigger that automaticly?
My script is:
var divId = "jwplayer-0_wrapper";
if ($('#' + divId).length == 1) {
myReg = /https?:\/\/www\.youtube\.com\/watch\?v=[^"]+/;
var plainText = $('#' + divId).parent().children('script').text();
var url = plainText.match(myReg);
if (url !== null) {
window.location = url;
};
};
It is used to skip certain site that decide to use the JW player witch I find horribly buggy. So it looks for a div with the indication of the JW player and if there's one, it finds the link to the original youtube video and directly goes there.
Its triggered By Google Chrome Add-on named Javascript Injector and I apply the script on every page I visit. The plug in work perfectly well on sites like www.ayoye.co and www.veuxturire.com. But on other sites, that uses the same pathern, it seems that the script is triggerd too early. For example there www.mondedestars.com and www.lesautos.ca triggers it too early.
If I use the "inject now" fonction of the Add on after the page is really done loading, then it redirects me to the youtube page as expected. I am lost on the why it works some where and not were else.
I'm not trying to understand every single website here, I'd prefer make it dynamicly triggered after the page has done loading everything from its php, ajax, script, flash, html and CSS.
I've tryed to look to the JWplayer API, but since its terribly unclear to me, over the fact that its partialy in flash, it woudl be simpler if there was a way to trigger it after, or maybe just triggering it after i hover over the body, since every sites has a body. It cant be specific to one page.
Use something like this
var timer;
function injectYouTube() {
// DO YOUR STUFF HERE
// ONCE DONE CALL clearInterval(timer);
clearInterval(timer);
}
timer = setInterval(injectYouTube, 2000);
I am not saying this will be called after everything is loaded but instead you can make sure your code is executed when you want it to.
The JWPlayer API are not that difficult. You can retrive the informations you need even not knowing the container id.
This is an example:
var player = jwplayer(0); // get the first jwplayer element of the page
var video = player.getPlaylistItem(); // get the player video
var url = video.file // retrieve the video url
I think the setTimeout or setInterval are unreliable.
Setting up a listener on jwplayer onReady event would be better.
The pessimistic answer to this is that you can't wait until a page has finished all AJAX operations etc. because web pages can continue loading new content indefinitely if they wish.
What you might consider is running your code every time a new HTML element is added to the page. This way, you can be certain to catch JWPlayer the moment it is inserted into the page.
document.addEventListener("DOMNodeInserted", yourRemovalFunction);

How to write a Google Content Experiment that disables a stylesheet?

I am currently trying to setup a Client Side Experiment without Redirects as opposed to the default Content Experiment A/B testing. All I want to do is for half my visitors disable one of two existing stylesheets on a page.
To me it doesn't make sense to do this the default A/B way because then I would have to setup a second page with the stylesheet disabled for every page on my site.
There is also Running a Server-side Experiment but to me that is too heavy handed for something I think should be somewhat simple.
I have the js all setup, I just need to be able to tell the page that when there is a given variation disable the stylesheet or don't render the stylesheet before the DOM loads.
One thing I considered is, given a certain variation, redirect to the same page but append a url query parameter like &stylesheet_disabled=true then I would simply not render the stylesheet on the server side but when I briefly looked at that I ran into a redirect loop but perhaps someone has a better way to write the js.
Any help greatly appreciated.
You could do something like this:
<head>
...
<script>
if (cxApi.chooseVariation() != 1) { // not in the experiment
document.write('<link href="... />'); // add the stylesheet
}
</script>
...
Only use document.write while the page is still being loaded.
This is all client-side, so no need for redirects and extra server work.
Here is how I did it:
<head>
<script src="//www.google-analytics.com/cx/api.js?experiment=EXPERIMENT_ID"></script>
<script>
// Ask Google Analytics which variation to show the visitor.
var chosenVariation = cxApi.chooseVariation();
function redirectVariation($variation) {
var url = window.location.href;
if ($variation === 1) {
var queryString = document.location.search;
if (queryString.indexOf("stylesheet_disabled=true") == -1) {
if (Boolean(queryString)) {
url += "&stylesheet_disabled=true";
} else {
url += "?stylesheet_disabled=true";
}
window.location.href = url;
}
}
}
redirectVariation(chosenVariation);
</script>
This is only setup for one different variation but could easily be modified for more. Then you just have your application on the server side detect the presence of the querystring parameter and execute whatever logic you like, in my case not displaying a stylesheet.
Theoretically this could be used to do any kind of server side logic with GA Content Experiment Client Side Redirects. Hopefully this helps someone else.

Categories

Resources