/** * @namespace WORKAREA.pagination */ WORKAREA.registerModule('pagination', (function () { 'use strict'; var paginationButton = JST['workarea/storefront/templates/pagination_button'], // // Utility // appendChildren = function ($pagination, $newChildren) { $('[data-pagination-item]:last', $pagination).after($newChildren); }, findMiddleChild = function ($children) { var index = Math.floor($children.length / 2); return $children.eq(index); }, // // State Management // setSession = function (state) { window.history.replaceState({ pagination: state }, document.title, window.location.href); }, getSession = function () { return window.history.state.pagination; }, saveUIStateToSession = function ($pagination) { var session; if ( ! sessionExists()) { return; } session = getSession(); session.scrollTop = $(window).scrollTop(); session.height = $pagination.height(); setSession(session); }, saveUrlToSession = function (nextPageUrl) { var session = getSession(); session.pages.push(nextPageUrl); setSession(session); }, initSession = function () { window.history.replaceState({ pagination: { pages: [], scrollTop: 0, height: 'auto' } }, document.title, window.location.href); }, sessionExists = function () { var state = window.history.state; return (state && ! _.isEmpty(state.pagination)); }, // // Button Management // bindNextPageButtonClick = function ($pagination) { $('.pagination__button', $pagination) .on('click', _.partial(restartPagination, $pagination)); }, showNextPageButton = function ($pagination, url) { $('.pagination__button', $pagination).replaceWith(paginationButton({ loading: false, nextPageUrl: url })); }, removePaginationButton = function ($pagination) { $('.pagination__button', $pagination).remove(); }, setupPaginationButton = function ($pagination) { $('.pagination__button', $pagination).replaceWith(paginationButton({ loading: true })); }, // // Response Handling // handleResponse = function ($pagination, $trigger, url, response) { var $newPagination = $('[data-pagination]', response), $newChildren = $('[data-pagination-item]', $newPagination), $newTrigger = findMiddleChild($newChildren); WORKAREA.initModules($newPagination); if ($trigger) { destroyWaypoint($trigger); } appendChildren($pagination, $newChildren); saveUrlToSession(url); saveStateToTrigger($newPagination, $newTrigger); initWaypoint($newTrigger); }, requestNextPage = function ($pagination, $trigger, url) { $.get(url) .done(_.partial(handleResponse, $pagination, $trigger, url)) .fail(_.partial(showNextPageButton, $pagination, url)); }, // // Waypoints // destroyWaypoint = function ($trigger) { $trigger.data('paginationWaypoint').destroy(); }, handleWaypoint = function (direction) { var $trigger = $(this.element), $pagination = $trigger.closest('[data-pagination]'), state = $trigger.data('paginationState'); if (direction !== 'down') { return; } if ( ! sessionExists()) { initSession(); } if (state.lastPage) { removePaginationButton($pagination); } else if (state.currentPage % state.pagesToLoad === 0) { showNextPageButton($pagination, state.nextPageUrl); bindNextPageButtonClick($pagination); } else { requestNextPage($pagination, $trigger, state.nextPageUrl); } }, initWaypoint = function ($trigger) { $trigger.data('paginationWaypoint', new Waypoint({ element: $trigger[0], handler: handleWaypoint, offset: 'bottom-in-view' })); }, // // Setup // saveStateToTrigger = function ($pagination, $trigger) { var state = $pagination.data('pagination'); $trigger.data('paginationState', _.merge( {}, state, WORKAREA.config.pagination )); }, restartPagination = function ($pagination, event) { event.preventDefault(); setupPaginationButton($pagination); requestNextPage($pagination, false, event.target.href); }, setup = function ($pagination) { var $children = $('[data-pagination-item]', $pagination), $trigger = findMiddleChild($children); saveStateToTrigger($pagination, $trigger); initWaypoint($trigger); setupPaginationButton($pagination); }, // // State Management // resetUIState = function ($pagination) { $pagination.height('auto'); }, injectFetchedPage = function ($pagination, lastPage, response) { var $newPagination = $('[data-pagination]', response), $newChildren = $('[data-pagination-item]', $newPagination), $newTrigger = findMiddleChild($newChildren); WORKAREA.initModules($newPagination); appendChildren($pagination, $newChildren); if (lastPage) { saveStateToTrigger($newPagination, $newTrigger); initWaypoint($newTrigger); resetUIState($pagination); } }, handleFetchedPages = function (pages, $pagination) { _.forEach(pages, function (page, index) { var lastPage = (index + 1 === pages.length); // Don't use the promise's .done method because there's no // guarantee they will be run in order. injectFetchedPage($pagination, lastPage, page.responseText); }); }, fetchPagesFromSession = function () { return _.map(getSession().pages, function (url) { return $.get(url); }); }, awaitPageResquests = function ($pagination) { var pages = fetchPagesFromSession(); $.when .apply(null, pages) .always(_.partial(handleFetchedPages, pages, $pagination)); }, recallUIState = function ($pagination) { var session = getSession(); $pagination.height(session.height); $(window).scrollTop(session.scrollTop); }, bindPageUnloadEvent = function ($pagination) { $(window).on('unload', _.partial(saveUIStateToSession, $pagination)); }, // // Session Mediator // checkSession = function (index, pagination) { var $pagination = $(pagination); bindPageUnloadEvent($pagination); if (sessionExists()) { recallUIState($pagination); awaitPageResquests($pagination); setupPaginationButton($pagination); } else { setup($pagination); } }, /** * @method * @name init * @memberof WORKAREA.pagination */ init = function ($scope) { $('[data-pagination]', $scope).each(checkSession); }; return { init: init }; }()));