Making Horton-Stephens.com

Home > Articles > Making Horton-Stephens.com
 Code, Tutorial
09 Oct 2014

This is a short tutorial on the making of Horton-Stephens.com

Pushstate and Ajax

I wanted the whole site to be Ajax but still useable without Javascript so that it is search engine friendly (the site is a website not a web app). To do this I decided on common areas which would stay static through the site (i.e. header and navigation), so that once loaded they wouldn't be reloaded on a new page request. The content area or pane of the site changes for each new page.

Everytime a main navigation item is clicked the Jquery would pick up the click put it through some menu and cache logic (go into in a bit) and then send the request to my Processwire (PW) template which would then only include the ./head.inc and ./foot.inc files if not ajax request found:

$ajax = $input->post->ajax;
if(!$ajax){
 include("./head.inc");
}

// echo page content here


if(!$ajax){
 include("./foot.inc");
}

PW happens to have a handy ajax request boolean vaiable.

The Ajax request for the new page goes like this:

// navigation clicked -> load new page
$('#page').on('click','a.mainLink',function(e) {
 if(){//menu logic here
 linkClicked( $(this) )
 }
}
function linkClicked(link){
 if(){ // check that the link isn't the current page
 
 // change url to new url from link
 history.pushState('', +linkURL, linkURL);
 linkURL = link.attr('href');
 linkTitle = link.attr('name')
 loadContent(linkTitle, linkURL)
 }
}

function loadContent(title, url){
 if(){ // check page not already cached by client
 // if so load page from cache
 }else{
 $.ajax({ type: "POST", url: url, data: { ajax: true },
 success: function(data,status){
 $pageContent = data;
 },
 error: function(jqXHR, textStatus, errorThrown){
 // do something with error message
 }
 }).done(function(){ 
 // success: load data to dynamic content div, change title to new title
 }
 }
}

On load I add a new content div to the page, add the content to it, fadeOut the previous content and fadeIn the new content. I also use Modernizr to check that the client has history / pushstate otherwise all this logic will fall back to a normal link click, and as there won't be a ajax request the head.inc and foot.inc files will be included.

Also to get the browser back button to work your'll need to include:

window.onpopstate = function(event) {
 // load content to dynmaic content pane
 loadContent(title, location.pathname);
};

However, you may have to add the logic to what it does on a new popstate depending on your impelementation. For me, when the back / forward buttons are pressed I go back in time in my cachedPages array and load the content from there changing the pushstate to reflect the url change.

Client side soft cache

Each time I make a page request using ajax I save the current page data to an array so that if the user navigates back, or to a page they've already incountered they will be served their cached page instead of hitting th server with another request. This is only for the current session so if the user refreshes the page the array will be lost (thinking about adding a localstorage layer in future with a timeout on content).

How it works:

var cachedPages = [];
function cachedPage(url, title, content){
 this.url = url;
 this.title = title;
 this.content = content;
};

I add the current page url, title, and dynamic content area to a new cachedPage object and then add it to the cachedPages array using the title as the key

$currentTitle = $('nav a.active').attr('name');
$currentPageContent = $('.content-container').html();
var currentPage = new cachedPage(window.location.pathname, $currentTitle, $currentPageContent);
cachedPages[$currentTitle] = currentPage;

For each new ajax request I do the same thing with the new page adding it to the cachedPages array. If, however, the clicked link is somewhere you've been in the site (it appears in the list) then I load the data from the array instead - saving on new requests to the server. I cache as mainly of the template files I can, and send everything from the server gzipped, this all makes for a nippy site (even with all the images).

Modules used

  • Images with cropping
  • AIOM+ (All In One Minify)
  • Site-wide File Manager
  • Multisite
  • Pagetree Add New Childs Reverse
  • Pages2Pdf
  • Export Site Profile
  • Page Delete
  • Redirects

PW forum page: https://processwire.com/talk/topic/7140-testings-nearly-finished-photographers-site/

PW modules page

© Ben Byford | website created by Ben Byford using Processwire