Pages.js is a framework for History pushState. It allows you to manage
pages JS code and forget about low-level APIs.
History pushState is a API to manage user history, it allows you to change
document URL from JS and have full AJAX pages, without # in URL.
For example, user on example.com click on usual link (example.com/conacts),
but browser doesn’t load new URL. JS loads new page by AJAX, changes pages
with some animation and changes URL to example.com/contacts. Of course,
you can use Back button (and go to example.com) or send current URL to your
friend (and friend will open contact’s page directly).
History pushState is supported by modern browsers, but Pages.js will work in
browsers without this API too. They will load pages in an old way with document
reloading.
Wrap your page content (without layout, header and footer) into
<article class="page" data-url="/url" data-title="Page">…</article>
and set page URL to data-url and title to data-title attribute.
Change your server code, to respond AJAX requests without layout.
Just check HTTP_X_REQUESTED_WITH HTTP header to equal "XMLHttpRequest".
For example, in Ruby on Rails add to ApplicationController:
layout :disable_for_ajax
def disable_for_ajax
request.xhr? ? nil : 'application'
end
Add Pages.js library to your pages:
<script src="./pages.js"></script>
See Installing section for details.
That’s all. Now your pages will be changed without document reloading
(and JS interruption) and with simple nice animation.
Of cource, you can customize wrap tags and load method. Quick Start show only
default way.
For Ruby on Rails you can use gem for Assets Pipeline.
Add pagesjs gem to Gemfile:
gem "pagesjs"
Install gems:
bundle install
Include Pages.js to your application.js.coffee:
#= require pages
If you don’t use any assets packaging manager (it’s very bad idea), you can use
already minified version of the library.
Take it from: github.com/ai/pages.js/downloads.
You can register page handler, to run some JS code for special pages:
Pages.add('.comments-page', {
load: function($, $$, page) {
$$('.add').click(function() {
postNewComment();
});
},
open: function($, $$, page) {
page.enableAutoUpdate();
},
close: function($, $$, page) {
page.disableAutoUpdate();
}
});
Pages.add(selector, options) allow you to set options for all pages selected
by selector:
load: function ($, $$, page) which will be called, when page is loadedopen: function ($, $$, page) which will be called, when page becomesclose: function ($, $$, page) which will be called, when page becomesanimation: function (prev) to return animation, depend on previous page.data-page-animation attribute in page or link tags.Callbacks get three arguments:
$: jQuery.$$: jQuery finder only in current page (a little bit faster and more safely$). For example $$('a') is equal to $('a', page).page: jQuery-nodes of selected page.You can pass load as second argument without other options:
Pages.add('.comments-page', function($, $$, page) {
$$('.pagination').ajaxPagination();
});
When Pages.js load new page by AJAX it sets page-loading class to body and
trigger page-loading event on it. When page is loaded, page-loading
class will be removed and page-loaded event will be triggered.
body.page-loading .loader {
display: block;
}
Link, which is clicked to open new page, will get page-loading class and
page-loading, page-loaded events too.
.menu a.page-loading {
background: url(loading.gif);
}
Pages.animations hash contain available animations. You can change current
animation by Pages.animation:
Pages.animation = 'fade';
You can change animation for special page or link by data-page-animation
attribute.
You can create you own animation, just add object with animate function.
When animation ends, you must call done argument.
Pages.animations.cool = {
animate: function(prev, next, done, data) {
prev.coolHiding();
next.coolShowing(function() {
done();
});
}
};
Pages.animation = 'cool';
Argument data contains merged page and link data attributes:
<a href="/" data-direction="right">Home</a>
<a href="/products" class="current">Products</a>
<a href="/contacts" data-direction="left">Contacts</a>
Pages.animations.slide = {
animate: function(prev, next, done, data) {
prev.slideHide(data.direction);
next.slideShow(data.direction, function() {
done();
});
}
};
Pages.animation = 'slide';
If you want to preload some pages, just add them to HTML and hide. For example:
<article class="page" data-url="/products">
<a href="/products/1">Product 1</a>
<a href="/products/2">Product 2</a>
<a href="/products/3">Product 3</a>
</article>
<article class="page" data-url="/products/1" style="display: none"></article>
<article class="page" data-url="/products/2" style="display: none"></article>
<article class="page" data-url="/products/3" style="display: none"></article>
If you want to preload page by JS (for example, after onload event), just use
Pages.preload(url) method. URL can contain several pages, and can be
different from pages URL.
$(document).load(function() {
Pages.preload('/posts/all');
});
I prefer graceful degradation and think, that old browsers should reload full
page by old way. But if you want to add page changes animation to old browser,
you can redefine Pages.isSupported, Pages.getURL, Pages.setURL,
Pages.watchURL and Pages.unwatchURL methods to support any of History API
polyffils.
You can redefine way, that Pages.js use to get/set current page URL.
For example, to synchronize open page between different tabs by Session Storage,
or to support one page sites:
Pages.isSupported = function() {
return true;
};
Pages.setURL = function(url) {
location.hash = url;
};
Pages.getURL = function() {
return location.hash;
};
Pages.watchURL = function(callback) {
$(window).on('hashchange.pages', callback);
};
Pages.unwatchURL = function() {
$(window).off('hashchange.pages');
};
To run tests you need node.js and npm. For example, in Ubuntu run:
sudo apt-get install nodejs npm
Next install npm dependencies:
npm install
Run test server:
./node_modules/.bin/cake server
Open tests in browser: localhost:8000.
Also you can see real usage example in integration test:
localhost:8000/integration.