417 lines
11 KiB
JavaScript
417 lines
11 KiB
JavaScript
|
/*!
|
||
|
* jqPagination, a jQuery pagination plugin (obviously)
|
||
|
* Version: 1.3 (26th July 2013)
|
||
|
*
|
||
|
* Copyright (C) 2013 Ben Everard
|
||
|
*
|
||
|
* http://beneverard.github.com/jqPagination
|
||
|
*
|
||
|
* This program is free software: you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation, either version 3 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* This program is distributed in the hope that it will be useful,
|
||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
|
* GNU General Public License for more details.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
(function ($) {
|
||
|
"use strict";
|
||
|
|
||
|
$.jqPagination = function (el, options) {
|
||
|
|
||
|
// To avoid scope issues, use 'base' instead of 'this'
|
||
|
// to reference this class from internal events and functions.
|
||
|
|
||
|
var base = this;
|
||
|
|
||
|
// Access to jQuery and DOM versions of element
|
||
|
base.$el = $(el);
|
||
|
base.el = el;
|
||
|
|
||
|
// get input jQuery object
|
||
|
base.$input = base.$el.find('input');
|
||
|
|
||
|
// Add a reverse reference to the DOM object
|
||
|
base.$el.data("jqPagination", base);
|
||
|
|
||
|
base.init = function () {
|
||
|
|
||
|
base.options = $.extend({}, $.jqPagination.defaultOptions, options);
|
||
|
|
||
|
// if the user hasn't provided a max page number in the options try and find
|
||
|
// the data attribute for it, if that cannot be found, use one as a max page number
|
||
|
|
||
|
if (base.options.max_page === null) {
|
||
|
|
||
|
if (base.$input.data('max-page') !== undefined) {
|
||
|
base.options.max_page = base.$input.data('max-page');
|
||
|
} else {
|
||
|
base.options.max_page = 1;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
// if the current-page data attribute is specified this takes priority
|
||
|
// over the options passed in, so long as it's a number
|
||
|
|
||
|
if (base.$input.data('current-page') !== undefined && base.isNumber(base.$input.data('current-page'))) {
|
||
|
base.options.current_page = base.$input.data('current-page');
|
||
|
}
|
||
|
|
||
|
// remove the readonly attribute as JavaScript must be working by now ;-)
|
||
|
base.$input.removeAttr('readonly');
|
||
|
|
||
|
// set the initial input value
|
||
|
// pass true to prevent paged callback form being fired
|
||
|
|
||
|
base.updateInput(true);
|
||
|
|
||
|
|
||
|
//***************
|
||
|
// BIND EVENTS
|
||
|
|
||
|
base.$input.on('focus.jqPagination mouseup.jqPagination', function (event) {
|
||
|
|
||
|
// if event === focus, select all text...
|
||
|
if (event.type === 'focus') {
|
||
|
|
||
|
var current_page = parseInt(base.options.current_page, 10);
|
||
|
|
||
|
$(this).val(current_page).select();
|
||
|
|
||
|
}
|
||
|
|
||
|
// if event === mouse up, return false. Fixes Chrome bug
|
||
|
if (event.type === 'mouseup') {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
});
|
||
|
|
||
|
base.$input.on('blur.jqPagination keydown.jqPagination', function (event) {
|
||
|
|
||
|
var $self = $(this),
|
||
|
current_page = parseInt(base.options.current_page, 10);
|
||
|
|
||
|
// if the user hits escape revert the input back to the original value
|
||
|
if (event.keyCode === 27) {
|
||
|
$self.val(current_page);
|
||
|
$self.blur();
|
||
|
}
|
||
|
|
||
|
// if the user hits enter, trigger blur event but DO NOT set the page value
|
||
|
if (event.keyCode === 13) {
|
||
|
$self.blur();
|
||
|
}
|
||
|
|
||
|
// only set the page is the event is focusout.. aka blur
|
||
|
if (event.type === 'blur') {
|
||
|
base.setPage($self.val());
|
||
|
}
|
||
|
|
||
|
});
|
||
|
|
||
|
base.$el.on('click.jqPagination', 'a', function (event) {
|
||
|
|
||
|
var $self = $(this);
|
||
|
|
||
|
// we don't want to do anything if we've clicked a disabled link
|
||
|
// return false so we stop normal link action btu also drop out of this event
|
||
|
|
||
|
if ($self.hasClass('disabled')) {
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// for mac + windows (read: other), maintain the cmd + ctrl click for new tab
|
||
|
if (!event.metaKey && !event.ctrlKey) {
|
||
|
event.preventDefault();
|
||
|
base.setPage($self.data('action'));
|
||
|
}
|
||
|
|
||
|
});
|
||
|
|
||
|
};
|
||
|
|
||
|
base.setPage = function (page, prevent_paged) {
|
||
|
|
||
|
// return current_page value if getting instead of setting
|
||
|
if (page === undefined) {
|
||
|
return base.options.current_page;
|
||
|
}
|
||
|
|
||
|
var current_page = parseInt(base.options.current_page, 10),
|
||
|
max_page = parseInt(base.options.max_page, 10);
|
||
|
|
||
|
if (isNaN(parseInt(page, 10))) {
|
||
|
|
||
|
switch (page) {
|
||
|
/*
|
||
|
case 'first':
|
||
|
page = 1;
|
||
|
break;
|
||
|
|
||
|
case 'prev':
|
||
|
case 'previous':
|
||
|
page = current_page - 1;
|
||
|
break;
|
||
|
*/
|
||
|
case 'next':
|
||
|
page = current_page + 1;
|
||
|
break;
|
||
|
/*
|
||
|
case 'last':
|
||
|
page = max_page;
|
||
|
break;
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
page = parseInt(page, 10);
|
||
|
|
||
|
// reject any invalid page requests
|
||
|
if (isNaN(page) || page < 1 || page > max_page) {
|
||
|
|
||
|
// update the input element
|
||
|
base.setInputValue(current_page);
|
||
|
|
||
|
return false;
|
||
|
|
||
|
}
|
||
|
|
||
|
// update current page options
|
||
|
base.options.current_page = page;
|
||
|
base.$input.data('current-page', page);
|
||
|
|
||
|
// update the input element
|
||
|
base.updateInput( prevent_paged );
|
||
|
|
||
|
};
|
||
|
|
||
|
base.setMaxPage = function (max_page, prevent_paged) {
|
||
|
|
||
|
// return the max_page value if getting instead of setting
|
||
|
if (max_page === undefined) {
|
||
|
return base.options.max_page;
|
||
|
}
|
||
|
|
||
|
// ignore if max_page is not a number
|
||
|
if (!base.isNumber(max_page)) {
|
||
|
console.error('jqPagination: max_page is not a number');
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// ignore if max_page is less than the current_page
|
||
|
if (max_page < base.options.current_page) {
|
||
|
console.error('jqPagination: max_page lower than current_page');
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
// set max_page options
|
||
|
base.options.max_page = max_page;
|
||
|
base.$input.data('max-page', max_page);
|
||
|
|
||
|
// update the input element
|
||
|
base.updateInput( prevent_paged );
|
||
|
|
||
|
};
|
||
|
|
||
|
// ATTN this isn't really the correct name is it?
|
||
|
base.updateInput = function (prevent_paged) {
|
||
|
|
||
|
var current_page = parseInt(base.options.current_page, 10);
|
||
|
|
||
|
// set the input value
|
||
|
base.setInputValue(current_page);
|
||
|
|
||
|
// set the link href attributes
|
||
|
base.setLinks(current_page);
|
||
|
|
||
|
// we may want to prevent the paged callback from being fired
|
||
|
if (prevent_paged !== true) {
|
||
|
|
||
|
// fire the callback function with the current page
|
||
|
base.options.paged(current_page);
|
||
|
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
base.setInputValue = function (page) {
|
||
|
|
||
|
var page_string = base.options.page_string,
|
||
|
max_page = base.options.max_page;
|
||
|
|
||
|
// this looks horrible :-(
|
||
|
page_string = page_string
|
||
|
.replace("{current_page}", page)
|
||
|
.replace("{max_page}", max_page);
|
||
|
|
||
|
base.$input.val(page_string);
|
||
|
|
||
|
};
|
||
|
|
||
|
base.isNumber = function(n) {
|
||
|
return !isNaN(parseFloat(n)) && isFinite(n);
|
||
|
};
|
||
|
|
||
|
base.setLinks = function (page) {
|
||
|
|
||
|
var link_string = base.options.link_string,
|
||
|
current_page = parseInt(base.options.current_page, 10),
|
||
|
max_page = parseInt(base.options.max_page, 10);
|
||
|
|
||
|
if (link_string !== '') {
|
||
|
|
||
|
// set initial page numbers + make sure the page numbers aren't out of range
|
||
|
|
||
|
var previous = current_page - 1;
|
||
|
if (previous < 1) {
|
||
|
previous = 1;
|
||
|
}
|
||
|
|
||
|
var next = current_page + 1;
|
||
|
if (next > max_page) {
|
||
|
next = max_page;
|
||
|
}
|
||
|
|
||
|
// apply each page number to the link string, set it back to the element href attribute
|
||
|
base.$el.find('a.first').attr('href', link_string.replace('{page_number}', '1'));
|
||
|
base.$el.find('a.prev, a.previous').attr('href', link_string.replace('{page_number}', previous));
|
||
|
base.$el.find('a.next').attr('href', link_string.replace('{page_number}', next));
|
||
|
base.$el.find('a.last').attr('href', link_string.replace('{page_number}', max_page));
|
||
|
|
||
|
}
|
||
|
|
||
|
// set disable class on appropriate links
|
||
|
base.$el.find('a').removeClass('disabled');
|
||
|
|
||
|
if (current_page === max_page) {
|
||
|
base.$el.find('.next, .last').addClass('disabled');
|
||
|
}
|
||
|
|
||
|
if (current_page === 1) {
|
||
|
base.$el.find('.previous, .first').addClass('disabled');
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
base.callMethod = function (method, key, value) {
|
||
|
|
||
|
switch (method.toLowerCase()) {
|
||
|
|
||
|
case 'option':
|
||
|
|
||
|
// set default object to trigger the paged event (legacy opperation)
|
||
|
var options = {'trigger': true},
|
||
|
result = false;
|
||
|
|
||
|
// if the key passed in is an object
|
||
|
if($.isPlainObject(key) && !value){
|
||
|
$.extend(options, key)
|
||
|
}
|
||
|
else{ // make the key value pair part of the default object
|
||
|
options[key] = value;
|
||
|
}
|
||
|
|
||
|
var prevent_paged = (options.trigger === false);
|
||
|
|
||
|
// if max_page property is set call setMaxPage
|
||
|
if(options.max_page !== undefined){
|
||
|
result = base.setMaxPage(options.max_page, prevent_paged);
|
||
|
}
|
||
|
|
||
|
// if current_page property is set call setPage
|
||
|
if(options.current_page !== undefined){
|
||
|
result = base.setPage(options.current_page, prevent_paged);
|
||
|
}
|
||
|
|
||
|
// if we've not got a result fire an error and return false
|
||
|
if( result === false ) console.error('jqPagination: cannot get / set option ' + key);
|
||
|
return result;
|
||
|
|
||
|
break;
|
||
|
|
||
|
case 'destroy':
|
||
|
|
||
|
base.$el
|
||
|
.off('.jqPagination')
|
||
|
.find('*')
|
||
|
.off('.jqPagination');
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
|
||
|
// the function name must not exist
|
||
|
console.error('jqPagination: method "' + method + '" does not exist');
|
||
|
return false;
|
||
|
|
||
|
}
|
||
|
|
||
|
};
|
||
|
|
||
|
// Run initializer
|
||
|
base.init();
|
||
|
|
||
|
};
|
||
|
|
||
|
$.jqPagination.defaultOptions = {
|
||
|
current_page : 1,
|
||
|
link_string : '',
|
||
|
max_page : null,
|
||
|
page_string : 'Question {current_page} of {max_page}',
|
||
|
paged : function () {}
|
||
|
};
|
||
|
|
||
|
$.fn.jqPagination = function () {
|
||
|
|
||
|
// get any function parameters
|
||
|
var self = this,
|
||
|
args = Array.prototype.slice.call(arguments),
|
||
|
result = false;
|
||
|
|
||
|
// if the first argument is a string call the desired function
|
||
|
// note: we can only do this to a single element, and not a collection of elements
|
||
|
|
||
|
if (typeof args[0] === 'string') {
|
||
|
|
||
|
// if we're dealing with multiple elements, set for all
|
||
|
$.each(self, function(){
|
||
|
var $plugin = $(this).data('jqPagination');
|
||
|
|
||
|
result = $plugin.callMethod(args[0], args[1], args[2]);
|
||
|
});
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
// if we're not dealing with a method, initialise plugin
|
||
|
self.each(function () {
|
||
|
(new $.jqPagination(this, args[0]));
|
||
|
});
|
||
|
|
||
|
};
|
||
|
|
||
|
})(jQuery);
|
||
|
|
||
|
// polyfill, provide a fallback if the console doesn't exist
|
||
|
if (!console) {
|
||
|
|
||
|
var console = {},
|
||
|
func = function () { return false; };
|
||
|
|
||
|
console.log = func;
|
||
|
console.info = func;
|
||
|
console.warn = func;
|
||
|
console.error = func;
|
||
|
|
||
|
}
|