Extracted pager from paged collection presenter

This commit is contained in:
Marcin Kurczewski 2014-10-01 22:18:50 +02:00
parent c124f89b8b
commit 14325b4338
6 changed files with 189 additions and 98 deletions

1
TODO
View file

@ -26,7 +26,6 @@ everything related to posts:
- single post view - single post view
- previous and next post (difficult) - previous and next post (difficult)
- extract Pager from PagedCollectionPresenter
- rename PagedCollectionPresenter to PagerPresenter - rename PagedCollectionPresenter to PagerPresenter
- remember last search - remember last search
- take care of pages - take care of pages

View file

@ -72,6 +72,7 @@
<script type="text/javascript" src="/js/Auth.js"></script> <script type="text/javascript" src="/js/Auth.js"></script>
<script type="text/javascript" src="/js/Util.js"></script> <script type="text/javascript" src="/js/Util.js"></script>
<script type="text/javascript" src="/js/Keyboard.js"></script> <script type="text/javascript" src="/js/Keyboard.js"></script>
<script type="text/javascript" src="/js/Pager.js"></script>
<script type="text/javascript" src="/js/BrowsingSettings.js"></script> <script type="text/javascript" src="/js/BrowsingSettings.js"></script>
<script type="text/javascript" src="/js/Controls/FileDropper.js"></script> <script type="text/javascript" src="/js/Controls/FileDropper.js"></script>
<script type="text/javascript" src="/js/Controls/TagInput.js"></script> <script type="text/javascript" src="/js/Controls/TagInput.js"></script>

109
public_html/js/Pager.js Normal file
View file

@ -0,0 +1,109 @@
var App = App || {};
App.Pager = function(
_,
promise,
api) {
var totalPages;
var pageNumber;
var searchParams;
var url;
function init(args) {
url = args.url;
setSearchParams(args.searchParams);
if (typeof(args.page) !== 'undefined') {
setPage(args.page);
} else {
setPage(1);
}
}
function getPage() {
return pageNumber;
}
function prevPage() {
if (pageNumber > 1) {
setPage(pageNumber - 1);
}
}
function nextPage() {
if (pageNumber < totalPages) {
setPage(pageNumber + 1);
}
}
function setPage(newPageNumber) {
pageNumber = parseInt(newPageNumber);
if (!pageNumber || isNaN(pageNumber)) {
throw new Error('Trying to set page to a non-number (' + newPageNumber + ')');
}
}
function getSearchParams() {
return searchParams;
}
function setSearchParams(newSearchParams) {
setPage(1);
searchParams = newSearchParams;
}
function retrieve() {
return promise.make(function(resolve, reject) {
promise.wait(
api.get(url, _.extend({}, searchParams, {page: pageNumber})))
.then(function(response) {
var pageSize = response.json.pageSize;
var totalRecords = response.json.totalRecords;
totalPages = Math.ceil(totalRecords / pageSize);
resolve({
entities: response.json.data,
totalRecords: totalRecords});
}).fail(function(response) {
reject(response);
});
});
}
function getVisiblePages() {
var pages = [1, totalPages || 1];
var pagesAroundCurrent = 2;
for (var i = -pagesAroundCurrent; i <= pagesAroundCurrent; i ++) {
if (pageNumber + i >= 1 && pageNumber + i <= totalPages) {
pages.push(pageNumber + i);
}
}
if (pageNumber - pagesAroundCurrent - 1 === 2) {
pages.push(2);
}
if (pageNumber + pagesAroundCurrent + 1 === totalPages - 1) {
pages.push(totalPages - 1);
}
return pages.sort(function(a, b) { return a - b; }).filter(function(item, pos) {
return !pos || item !== pages[pos - 1];
});
}
return {
init: init,
getPage: getPage,
prevPage: prevPage,
nextPage: nextPage,
setPage: setPage,
getSearchParams: getSearchParams,
setSearchParams: setSearchParams,
retrieve: retrieve,
getVisiblePages: getVisiblePages,
};
};
App.DI.register('pager', ['_', 'promise', 'api'], App.Pager);

View file

@ -9,6 +9,7 @@ App.Presenters.PagedCollectionPresenter = function(
api, api,
keyboard, keyboard,
router, router,
pager,
presenterManager, presenterManager,
browsingSettings) { browsingSettings) {
@ -18,24 +19,22 @@ App.Presenters.PagedCollectionPresenter = function(
var endlessScroll = browsingSettings.getSettings().endlessScroll; var endlessScroll = browsingSettings.getSettings().endlessScroll;
var scrollInterval; var scrollInterval;
var template; var template;
var totalPages;
var forceClear = false; var forceClear = false;
var pageNumber;
var searchParams;
var baseUri; var baseUri;
var backendUri;
var updateCallback; var updateCallback;
var failCallback; var failCallback;
function init(args, loaded) { function init(args, loaded) {
baseUri = args.baseUri;
updateCallback = args.updateCallback;
failCallback = args.failCallback;
$target = args.$target; $target = args.$target;
targetContent = jQuery(args.$target).html(); targetContent = jQuery(args.$target).html();
baseUri = args.baseUri; pager.init({url: args.backendUri});
backendUri = args.backendUri; pager.setSearchParams(args.searchParams);
updateCallback = args.updateCallback;
failCallback = args.failCallback;
promise.wait(util.promiseTemplate('pager')) promise.wait(util.promiseTemplate('pager'))
.then(function(html) { .then(function(html) {
@ -46,12 +45,12 @@ App.Presenters.PagedCollectionPresenter = function(
} }
function reinit(args, loaded) { function reinit(args, loaded) {
forceClear = !_.isEqual(args.searchParams, searchParams) || parseInt(args.page) !== pageNumber + 1; forceClear = !_.isEqual(args.searchParams, pager.getSearchParams()) || parseInt(args.page) !== pager.getPage();
searchParams = args.searchParams; pager.setSearchParams(args.searchParams);
pageNumber = parseInt(args.page) || 1; pager.setPage(args.page || 1);
softChangePage(pageNumber) retrieve()
.then(loaded) .then(loaded)
.fail(loaded); .fail(loaded);
@ -62,29 +61,46 @@ App.Presenters.PagedCollectionPresenter = function(
} }
function prevPage() { function prevPage() {
if (pageNumber > 1) { pager.prevPage();
changePage(pageNumber - 1); syncUrl();
}
} }
function nextPage() { function nextPage() {
if (pageNumber < totalPages) { pager.nextPage();
changePage(pageNumber + 1); syncUrl();
}
} }
function nextPageInplace() { function nextPageInplace() {
if (pageNumber < totalPages) { pager.nextPage();
changePageInplace(pageNumber + 1); syncUrlInplace();
}
} }
function changePageInplace(newPageNumber) { function setPage(newPage) {
router.navigateInplace(getPageChangeLink(newPageNumber)); pager.setPage(newPage);
syncUrl();
} }
function changePage(newPageNumber) { function setSearchParams(newSearchParams) {
router.navigate(getPageChangeLink(newPageNumber)); clearContent();
pager.setSearchParams(newSearchParams);
syncUrl();
}
function getUrl() {
return util.compileComplexRouteArgs(
baseUri,
_.extend(
{},
pager.getSearchParams(),
{page: pager.getPage()}));
}
function syncUrl() {
router.navigate(getUrl());
}
function syncUrlInplace() {
router.navigateInplace(getUrl());
} }
function showSpinner() { function showSpinner() {
@ -103,40 +119,34 @@ App.Presenters.PagedCollectionPresenter = function(
} }
} }
function softChangePage(newPageNumber) { function retrieve() {
pageNumber = newPageNumber;
showSpinner(); showSpinner();
return promise.make(function(resolve, reject) { return promise.make(function(resolve, reject) {
promise.wait( pager.retrieve()
api.get(backendUri, _.extend({}, searchParams, {page: pageNumber})))
.then(function(response) { .then(function(response) {
resolve(response); updateCallback(response, forceClear || !endlessScroll);
var pageSize = response.json.pageSize;
var totalRecords = response.json.totalRecords;
totalPages = Math.ceil(totalRecords / pageSize);
updateCallback({
entities: response.json.data,
totalRecords: totalRecords},
forceClear || !endlessScroll);
forceClear = false; forceClear = false;
refreshPageList(); refreshPageList();
hideSpinner(); hideSpinner();
attachNextPageLoader(); attachNextPageLoader();
resolve();
}).fail(function(response) { }).fail(function(response) {
reject(response);
if (typeof(failCallback) !== 'undefined') { if (typeof(failCallback) !== 'undefined') {
failCallback(response); failCallback(response);
} else { } else {
console.log(new Error(response.json && response.json.error || response)); console.log(new Error(response.json && response.json.error || response));
} }
reject();
}); });
}); });
} }
function clearContent() {
updateCallback({entities: [], totalRecords: 0}, true);
}
function attachNextPageLoader() { function attachNextPageLoader() {
if (!endlessScroll) { if (!endlessScroll) {
return; return;
@ -154,10 +164,7 @@ App.Presenters.PagedCollectionPresenter = function(
} }
function refreshPageList() { function refreshPageList() {
if (typeof(totalPages) === 'undefined') { var pages = pager.getVisiblePages();
return;
}
var pages = getVisiblePages();
$pageList.empty(); $pageList.empty();
var lastPage = 0; var lastPage = 0;
_.each(pages, function(page) { _.each(pages, function(page) {
@ -167,10 +174,13 @@ App.Presenters.PagedCollectionPresenter = function(
lastPage = page; lastPage = page;
var $a = jQuery('<a/>'); var $a = jQuery('<a/>');
$a.click(function() {
setPage(page);
});
$a.addClass('big-button'); $a.addClass('big-button');
$a.attr('href', getPageChangeLink(page)); $a.attr('href', '#');
$a.text(page); $a.text(page);
if (page === pageNumber) { if (page === pager.getPage()) {
$a.addClass('active'); $a.addClass('active');
} }
var $li = jQuery('<li/>'); var $li = jQuery('<li/>');
@ -189,42 +199,13 @@ App.Presenters.PagedCollectionPresenter = function(
} }
} }
function getVisiblePages() {
var pages = [1, totalPages || 1];
var pagesAroundCurrent = 2;
for (var i = -pagesAroundCurrent; i <= pagesAroundCurrent; i ++) {
if (pageNumber + i >= 1 && pageNumber + i <= totalPages) {
pages.push(pageNumber + i);
}
}
if (pageNumber - pagesAroundCurrent - 1 === 2) {
pages.push(2);
}
if (pageNumber + pagesAroundCurrent + 1 === totalPages - 1) {
pages.push(totalPages - 1);
}
return pages.sort(function(a, b) { return a - b; }).filter(function(item, pos) {
return !pos || item !== pages[pos - 1];
});
}
function getSearchChangeLink(newSearchParams) {
return util.compileComplexRouteArgs(baseUri, _.extend({}, searchParams, newSearchParams, {page: 1}));
}
function getPageChangeLink(newPageNumber) {
return util.compileComplexRouteArgs(baseUri, _.extend({}, searchParams, {page: newPageNumber}));
}
return { return {
init: init, init: init,
reinit: reinit, reinit: reinit,
changePage: changePage, setPage: setPage,
getSearchChangeLink: getSearchChangeLink, setSearchParams: setSearchParams,
getPageChangeLink: getPageChangeLink
}; };
}; };
App.DI.register('pagedCollectionPresenter', ['_', 'jQuery', 'util', 'promise', 'api', 'keyboard', 'router', 'presenterManager', 'browsingSettings'], App.Presenters.PagedCollectionPresenter); App.DI.register('pagedCollectionPresenter', ['_', 'jQuery', 'util', 'promise', 'api', 'keyboard', 'router', 'pager', 'presenterManager', 'browsingSettings'], App.Presenters.PagedCollectionPresenter);

View file

@ -7,7 +7,6 @@ App.Presenters.UserListPresenter = function(
util, util,
promise, promise,
auth, auth,
router,
pagedCollectionPresenter, pagedCollectionPresenter,
topNavigationPresenter, topNavigationPresenter,
messagePresenter) { messagePresenter) {
@ -56,7 +55,10 @@ App.Presenters.UserListPresenter = function(
searchArgs.order = searchArgs.order || 'name,asc'; searchArgs.order = searchArgs.order || 'name,asc';
updateActiveOrder(searchArgs.order); updateActiveOrder(searchArgs.order);
pagedCollectionPresenter.reinit({page: searchArgs.page, searchParams: {order: searchArgs.order}}); pagedCollectionPresenter.reinit({
page: searchArgs.page,
searchParams: {
order: searchArgs.order}});
} }
function render() { function render() {
@ -91,7 +93,7 @@ App.Presenters.UserListPresenter = function(
e.preventDefault(); e.preventDefault();
var $orderLink = jQuery(this); var $orderLink = jQuery(this);
var activeSearchOrder = $orderLink.attr('data-order'); var activeSearchOrder = $orderLink.attr('data-order');
router.navigate(pagedCollectionPresenter.getSearchChangeLink({order: activeSearchOrder})); pagedCollectionPresenter.setSearchParams({order: activeSearchOrder});
} }
return { return {
@ -102,4 +104,4 @@ App.Presenters.UserListPresenter = function(
}; };
App.DI.register('userListPresenter', ['_', 'jQuery', 'util', 'promise', 'auth', 'router', 'pagedCollectionPresenter', 'topNavigationPresenter', 'messagePresenter'], App.Presenters.UserListPresenter); App.DI.register('userListPresenter', ['_', 'jQuery', 'util', 'promise', 'auth', 'pagedCollectionPresenter', 'topNavigationPresenter', 'messagePresenter'], App.Presenters.UserListPresenter);

View file

@ -42,10 +42,9 @@ App.Util = function(_, jQuery, promise) {
function compileComplexRouteArgs(baseUri, args) { function compileComplexRouteArgs(baseUri, args) {
var result = baseUri + '/'; var result = baseUri + '/';
_.each(args, function(v, k) { _.each(args, function(v, k) {
if (typeof(v) === 'undefined') { if (typeof(v) !== 'undefined') {
return;
}
result += k + '=' + v + ';'; result += k + '=' + v + ';';
}
}); });
result = result.slice(0, -1); result = result.slice(0, -1);
return result; return result;