Pages.js
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.
Sponsored by Evil Martians.
Quick Start
- Wrap your page content (without layout, header and footer) into
<article class="page" data-url="/url" data-title="Page">…</article>
and set page URL todata-url
and title todata-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:
html <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.
Installing
Ruby on Rails
For Ruby on Rails you can use gem for Assets Pipeline.
- Add
pagesjs
gem toGemfile
:
gem "pagesjs"
- Install gems:
bundle install
- Include Pages.js to your
application.js.coffee
:
#= require pages
Others
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.
Usage
Events
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 loaded (already contained in document or loaded after by AJAX). Good place to add events handlers to HTML tags.open
:function ($, $$, page)
which will be called, when page becomes visible (it is happened when document ready and when URL is changed).close
:function ($, $$, page)
which will be called, when page becomes hidden (URL changed and another page become to be open).animation
:function (prev)
to return animation, depend on previous page. For simple solution usedata-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 than$
). 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();
});
Loading
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);
}
Animation
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';
Preload
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');
});
History API support
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.
URL Methods
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');
};
Contributing
- 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.