/**
* Animated pagination widget
*
* Initializes all elements of a specific class as a pages section. Does so
* in accessible way with options for next/prev arrows or tabbed navigation.
*
* This code is licensed under the Mozilla Public License 1.1.
*
* Portions adapted from the jQuery Easing plugin written by Robert Penner and
* used under the following license:
*
* Copyright 2001 Robert Penner
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of the author nor the names of contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @copyright 2007-2010 Mozilla Foundation, 2007-2010 silverorange Inc.
* @license http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1
* @author Michael Gauthier
*/
$(document).ready(function() {
// add easing functions
$.extend($.easing, {
'pagerFadeIn': function (x, t, b, c, d) {
return c * (t /= d) * t + b;
},
'pagerFadeOut': function (x, t, b, c, d) {
return -c * (t /= d) * (t - 2) + b;
}
});
Mozilla.Pager.createPagers(document.body, Mozilla.Pager.rootPagers, null);
// If one or more root pagers have history enabled, check if window
// location changes from back/forward button use. This doesn't matter
// in IE but is nice for Firefox and recent Safari and Opera users.
for (var i = 0; i < Mozilla.Pager.rootPagers.length; i++) {
if (Mozilla.Pager.rootPagers[i].history) {
setInterval(Mozilla.Pager.checkLocation,
Mozilla.Pager.LOCATION_INTERVAL);
break;
}
}
});
// create namespace
if (typeof Mozilla == 'undefined') {
var Mozilla = {};
}
// {{{ Mozilla.Pager
/**
* Pager widget
*
* @param DOMElement container
*/
Mozilla.Pager = function(container, parentPager)
{
this.$container = $(container);
if (!container.id) {
container.id = 'mozilla-pager-' + Mozilla.Pager.currentId;
Mozilla.Pager.currentId++;
}
var pagerContentNodes = this.$container.find('div.pager-content');
if (!pagerContentNodes.length) {
return;
}
this.$pageContainer = $(pagerContentNodes[0]);
this.id = container.id;
this.pagesById = {};
this.pages = [];
this.previousPage = null;
this.currentPage = null;
this.animatingOut = false;
this.childPagers = {};
this.parentPager = parentPager;
this.randomStartPage = (this.$container.hasClass('pager-random'));
if (this.$container.hasClass('pager-with-tabs')) {
var $tabs = this.$container.find('ul.pager-tabs');
if ($tabs.length) {
this.$tabs = $($tabs[0]);
} else {
this.$tabs = null;
}
} else {
this.$tabs = null;
}
if (this.$container.hasClass('pager-with-nav')) {
this.drawNav();
} else {
this.$nav = null;
}
this.history = (!this.$container.hasClass('pager-no-history'));
this.cleartypeFix = (this.$container.hasClass('pager-cleartype-fix'));
// add pages
var page;
var pageNodes = this.$pageContainer.children('div');
if (this.$tabs) {
// initialize pages with tabs
var tabNodes = this.$tabs.children().not('.pager-not-tab');
var index = 0;
for (var i = 0; i < pageNodes.length; i++) {
if (i < tabNodes.length) {
var tabAnchorNodes = $(tabNodes[i]).children('a:first');
if (tabAnchorNodes.length) {
page = new Mozilla.Page(
pageNodes[i],
index,
tabAnchorNodes[0]
);
this.addPage(page);
this.childPagers[page.id] = [];
Mozilla.Pager.createPagers(
page.el,
this.childPagers[page.id],
this
);
index++;
}
}
}
} else {
// initialize pages without tabs
for (var i = 0; i < pageNodes.length; i++) {
page = new Mozilla.Page(pageNodes[i], i);
this.addPage(page);
this.childPagers[page.id] = [];
Mozilla.Pager.createPagers(
page.el,
this.childPagers[page.id],
this
);
}
}
// initialize current page
var currentPage;
if (this.history && !this.parentPager) {
var hash = location.hash;
hash = (hash.substring(0, 1) == '#') ? hash.substring(1) : hash;
// trim leading and tailing slash
hash = hash.replace(/(^\/|\/$)/g, '');
if (hash.length) {
this.setStateFromPath(hash, false, false);
currentPage = this.currentPage;
}
}
if (!currentPage && this.pages.length > 0) {
if (this.randomStartPage) {
this.setPage(this.getPseudoRandomPage());
} else {
var defPage = this.$pageContainer.children('.default-page:first');
if (defPage.length) {
var defId;
if (defPage[0].id.substring(0, 5) == 'page-') {
defId = defPage[0].id.substring(5);
} else {
defId = defPage[0].id;
}
this.setPage(this.pagesById[defId]);
} else {
this.setPage(this.pages[0]);
}
}
}
// initialize auto-rotation of pages
if (this.$container.hasClass('pager-auto-rotate')) {
var that = this;
this.autoRotate = true;
this.startAutoRotate();
// prevent auto-rotate when hovering over container
this.$container.hover(
function(e) { that.stopAutoRotate(); },
function(e) { if (that.autoRotate) { that.startAutoRotate(); } }
);
// prevent auto-rotate when focused on container
this.$container.find('a,input,textarea').each(function (i) {
$(this)
.focus(function(e) {
that.stopAutoRotate();
})
.blur(function(e) {
if (that.autoRotate) { that.startAutoRotate(); }
});
});
} else {
this.autoRotate = false;
}
// add a way to access the object from outside
Mozilla.Pager.pagers[this.id] = this;
}
// }}}
Mozilla.Pager.currentId = 1;
Mozilla.Pager.pagers = {};
Mozilla.Pager.rootPagers = [];
// {{{ createPagers()
Mozilla.Pager.createPagers = function(node, pagers, parentPager)
{
if (/(^pager$|^pager | pager$| pager )/.test(node.className)) {
var pager = new Mozilla.Pager(node, parentPager);
// pager.parentPager = parentPager;
pagers.push(pager);
} else {
for (var i = 0; i < node.childNodes.length; i++) {
if (node.nodeType == 1) {
Mozilla.Pager.createPagers(
node.childNodes[i],
pagers,
parentPager
);
}
}
}
};
// }}}
// {{{ checkLocation()
Mozilla.Pager.checkLocation = function()
{
var hash = location.hash;
hash = (hash.substring(0, 1) == '#') ? hash.substring(1) : hash;
// trim leading and tailing slash
hash = hash.replace(/(^\/|\/$)/g, '');
var pager;
for (var i = 0; i < Mozilla.Pager.rootPagers.length; i++) {
pager = Mozilla.Pager.rootPagers[i];
if (pager.history) {
pager.setStateFromPath(hash, true, true);
}
}
};
// }}}
// {{{ getPseudoRandomPage()
Mozilla.Pager.prototype.getPseudoRandomPage = function()
{
var page = null;
if (this.pages.length > 0) {
var now = new Date();
page = this.pages[now.getSeconds() % this.pages.length];
}
return page;
}
// }}}
Mozilla.Pager.PAGE_DURATION = 150; // milliseconds
Mozilla.Pager.PAGE_AUTO_DURATION = 850; // milliseconds
Mozilla.Pager.LOCATION_INTERVAL = 200; // milliseconds
Mozilla.Pager.NEXT_TEXT = 'Next';
Mozilla.Pager.PREV_TEXT = 'Previous';
Mozilla.Pager.PAGE_NUMBER_TEXT = '%s / %s';
Mozilla.Pager.AUTO_ROTATE_INTERVAL = 10000; // milliseconds
// {{{ setStateFromPath()
Mozilla.Pager.prototype.setStateFromPath = function(path, animate, focus)
{
var base = path, pos = base.indexOf('/');
if (pos !== -1) {
base = base.substr(0, pos);
path = path.substr(pos + 1);
}
var baseParts = base.split('+'), updateSelf, page;
for (var i = 0; i < baseParts.length; i++) {
base = baseParts[i];
page = this.pagesById[base];
updateSelf = (this.currentPage === null || base !== this.currentPage.id);
if (page) {
if (updateSelf) {
if (animate) {
this.setPageWithAnimation(
page,
Mozilla.Pager.PAGE_DURATION
);
} else {
this.setPage(page);
}
}
// check for children
for (var j = 0; j < this.childPagers[base].length; j++) {
this.childPagers[base][j].setStateFromPath(
path,
animate,
focus
);
}
if (updateSelf && focus) {
this.currentPage.focusTab(); // for accessibility
}
break;
}
}
};
// }}}
// {{{ prevPageWithAnimation()
Mozilla.Pager.prototype.prevPageWithAnimation = function(duration)
{
var index = this.currentPage.index - 1;
if (index < 0) {
index = this.pages.length - 1;
}
this.setPageWithAnimation(this.pages[index], duration);
}
// }}}
// {{{ nextPageWithAnimation()
Mozilla.Pager.prototype.nextPageWithAnimation = function(duration)
{
var index = this.currentPage.index + 1;
if (index >= this.pages.length) {
index = 0;
}
this.setPageWithAnimation(this.pages[index], duration);
}
// }}}
// {{{ drawNav()
Mozilla.Pager.prototype.drawNav = function()
{
var that = this;
this.$nav = $('