UNPKG

@oat-sa/tao-core-sdk

Version:
167 lines (156 loc) 6.26 kB
define(['jquery', 'lodash', 'core/router', 'core/eventifier', 'core/statifier', 'core/promise'], function ($, _, router, eventifier, statifier, Promise) { 'use strict'; $ = $ && Object.prototype.hasOwnProperty.call($, 'default') ? $['default'] : $; _ = _ && Object.prototype.hasOwnProperty.call(_, 'default') ? _['default'] : _; router = router && Object.prototype.hasOwnProperty.call(router, 'default') ? router['default'] : router; eventifier = eventifier && Object.prototype.hasOwnProperty.call(eventifier, 'default') ? eventifier['default'] : eventifier; statifier = statifier && Object.prototype.hasOwnProperty.call(statifier, 'default') ? statifier['default'] : statifier; Promise = Promise && Object.prototype.hasOwnProperty.call(Promise, 'default') ? Promise['default'] : Promise; /** * 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; under version 2 * of the License (non-upgradable). * * 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, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * * Copyright (c) 2015-2019 (original work) Open Assessment Technologies SA; */ let historyRouter; const location = `${window.history.location || window.location}`; /** * Create an history router * @exports core/historyRouter * * @example * var router = historyRouter(); * router.trigger('dispatch', url); * * @returns {historyRouter} the router (same instance) */ function historyRouterFactory() { let pendingPromise; if (historyRouter) { return historyRouter; } /** * @typedef historyRouter * @see core/eventifier * @see core/statifier */ historyRouter = eventifier(statifier({ /** * Redirects the page to another controller. Adds a step to the history. * @param {String} url * @returns {Promise} */ redirect(url) { return this.pushState(url); }, /** * Forwards to another controller. Does not change the current location, just loads the target controller. * Will replace the current history state by an obfuscated version that displays the current location but * internally routes to the provided URL. * @param {String} url * @returns {Promise} */ forward(url) { const state = _.isString(url) ? { url: url } : url; window.history.replaceState(state, '', `${window.location}`); return this.dispatch(state, false); }, /** * Forwards to another controller. Replaces the current location and replace the history. * @param {String} url * @returns {Promise} */ replace(url) { return this.dispatch(url, true); }, /** * Dispatch manually and replace the current state if necessary * @param {Object|String} state - the state object or directly the URL * @param {String} state.url - if the state is an object, then it must have an URL to dispatch * @param {Boolean} [replace = false] - if we replace the current state * @returns {Promise} * * @fires historyRouter#dispatching before dispatch * @fires historyRouter#dispatched once dispatch succeed */ dispatch(state, replace) { const doDispatch = () => { if (_.isString(state)) { state = { url: state }; } if (!state || !state.url) { return Promise.reject(new TypeError('The state should contain an URL!')); } /** * @event historyRouter#dispatching * @param {String} url */ this.setState('dispatching').trigger('dispatching', state.url); if (replace === true) { window.history.replaceState(state, '', state.url); } return router.dispatch(state.url).then(() => { /** * @event historyRouter#dispatched * @param {String} url */ this.trigger('dispatched', state.url).setState('dispatching', false); return state.url; }); }; if (pendingPromise) { pendingPromise = pendingPromise.then(doDispatch).catch(doDispatch); } else { pendingPromise = doDispatch(); } return pendingPromise; }, /** * Push a new state. * You can either call pushState or trigger the 'dispatch' event. * @param {Object|String} state - the state object or directly the URL * @param {String} state.url - if the state is an object, then it must have an URL to dispatch * @returns {Promise} */ pushState(state) { if (_.isString(state)) { state = { url: state }; } window.history.pushState(state, '', state.url); return this.dispatch(state); } })); // ensure the current route is in the history window.history.replaceState({ url: location }, '', location); //back & forward button, and push state $(window).on('popstate', function () { historyRouter.dispatch(window.history.state); }); //listen for dispatch event in order to push a state historyRouter.on('dispatch', function (state) { if (state) { this.pushState(state); } }); return historyRouter; } return historyRouterFactory; });