/*
* This file is part of Invenio.
* Copyright (C) 2017 CERN.
*
* Invenio 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 2 of the
* License, or (at your option) any later version.
*
* Invenio 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 Invenio; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
*
* In applying this license, CERN does not
* waive the privileges and immunities granted to it by virtue of its status
* as an Intergovernmental Organization or submit itself to any jurisdiction.
*/
/**
* @ngdoc directive
* @name invenioSearchPagination
* @description
* The pagination directive for search
* @namespace invenioSearchPagination
* @example
* Usage:
* <invenio-search-pagination
* show-go-to-first-last='true'
* adjacent-size='4'
* template='TEMPLATE_PATH'>
* ... Any children directives
* </invenio-search-pagination>
*/
function invenioSearchPagination() {
// Functions
/**
* Handle pagination
* @memberof invenioSearchPagination
* @param {service} scope - The scope of this element.
* @param {service} element - Element that this direcive is assigned to.
* @param {service} attrs - Attribute of this element.
* @param {invenioSearchController} vm - Invenio search controller.
*/
function link(scope, element, attrs, vm) {
// Watch when `invenioSearchArgs` changes and fire a new search
scope.paginatePages = [];
scope.adjacentSize = attrs.adjacentSize || 4;
scope.showGoToFirstLast = attrs.showGoToFirstLast || false;
scope.$watch('vm.invenioSearchArgs.page', function(current, next) {
if (current !== next) {
buildPages();
}
});
scope.$watch('vm.invenioSearchResults', function(current, next) {
buildPages();
});
/**
* Add range number for magination
* @memberof link
* @param {int} start - The start of the range.
* @param {int} finish - The end of the range.
*/
function addRange(start, finish) {
// Create the Add Item Function
var _current = current();
var buildItem = function (i) {
return {
value: i,
title: 'Go to page ' + i,
};
};
// Add our items where i is the page number
for (var i = start; i <= finish; i++) {
var item = buildItem(i);
scope.paginatePages.push(item);
}
}
/**
* Calculate the numbers
* @memberof link
*/
function buildPages() {
// Reset pages
scope.paginatePages = [];
// How many neighbours to show before and after the current page
var adjacent = scope.adjacentSize;
// Get total pages based on the results shown by page
var pageCount = total();
// Get the current page
var _current = current();
// Display the adjacent a1 a2 a3 + current + a5 a6 a7
var adjacentSize = (2 * adjacent);
// Pages to show in the pagination
var start, finish;
// Simply display all the pages
if (pageCount <= (adjacentSize + 2)) {
start = 1;
addRange(start, pageCount);
} else {
if (_current - adjacent <= 2) {
start = 1;
finish = 1 + adjacentSize;
addRange(start, finish);
} else if (_current < pageCount - (adjacent + 2)) {
start = _current - adjacent;
finish = _current + adjacent;
addRange(start, finish);
} else {
start = pageCount - adjacentSize;
finish = pageCount;
addRange(start, finish);
}
}
}
/**
* Calculate the total pages
* @memberof link
*/
function total() {
var _total;
try {
_total = vm.invenioSearchResults.hits.total;
} catch (error) {
_total = 0;
}
return Math.ceil(_total/vm.invenioSearchArgs.size);
}
/**
* Calculate the current page
* @memberof link
*/
function current() {
return parseInt(vm.invenioSearchArgs.page) || 1;
}
/**
* Calculate the next page
* @memberof link
*/
function next() {
var _next = current();
var _total = total();
if (_next < _total) {
_next = _next + 1;
}
return _next;
}
/**
* Calculate the previous page
* @memberof link
*/
function previous() {
var _previous = current();
var _total = total();
if (_previous > 1) {
_previous = _previous - 1;
}
return _previous;
}
/**
* Calculate page class if it is active or not
* @memberof link
* @param {int} index - A given page of the array.
*/
function getPageClass(index) {
return index === current() ? 'active' : '';
}
/**
* Calculate the next arrow if it is active or not
* @memberof link
*/
function getNextClass() {
return current() < total() ? '' : 'disabled';
}
/**
* Calculate the previous arrow if it is active or not
* @memberof link
*/
function getPrevClass() {
return current() > 1 ? '' : 'disabled';
}
/**
* Calculate the go to first if it is active or not
* @memberof link
*/
function getFirstClass() {
return current() !== 1 ? '' : 'disabled';
}
/**
* Calculate the go to last if it is active or not
* @memberof link
*/
function getLastClass() {
return current() !== total() ? '' : 'disabled';
}
/**
* Change page to the given index
* @memberof link
* @param {int} index - A given page of the array.
*/
function changePage(index) {
if (index > total()) {
vm.invenioSearchArgs.page = total();
} else if ( index < 1) {
vm.invenioSearchArgs.page = 1;
} else {
vm.invenioSearchArgs.page = index;
}
}
// Pages calculator
scope.paginationHelper = {
changePage: changePage,
current: current,
getFirstClass: getFirstClass,
getLastClass: getLastClass,
getNextClass: getNextClass,
getPageClass: getPageClass,
getPrevClass: getPrevClass,
next: next,
pages: buildPages,
previous: previous,
total: total,
};
}
/**
* Choose template for pagination
* @memberof invenioSearchPagination
* @param {service} element - Element that this direcive is assigned to.
* @param {service} attrs - Attribute of this element.
* @example
* Minimal template `template.html` usage
* <ul class="pagination" ng-if="vm.invenioSearchResults.hits.total">
* <li ng-class="paginationHelper.getPageClass(page.value)"
* ng-repeat="page in paginatePages">
* <a href="#" ng-click="paginationHelper.changePage(page.value)"
* alt="{{ page.title }}">{{ page.value }}</a>
* </li>
* </ul>
*/
function templateUrl(element, attrs) {
return attrs.template;
}
////////////
return {
restrict: 'AE',
scope: false,
require: '^invenioSearch',
templateUrl: templateUrl,
link: link,
};
}
angular.module('invenioSearch.directives')
.directive('invenioSearchPagination', invenioSearchPagination);