UNPKG

@oarepo/vuex-preloader

Version:

Preloader library (not only) for OARepo

340 lines (276 loc) 10.3 kB
/*! * @oarepo/vuex-preloader v1.3.5 * (c) Miroslav Simek <simeki@vscht.cz> * Released under the MIT License. */ import Vue from 'vue'; function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } function extractActionParams(preloader, match, route, extraProps) { var actionParams = {}; if (preloader.query) { actionParams['query'] = route.query; } var params = preloader.params || null; if (params) { Object.keys(params).forEach(function (k) { actionParams[params[k]] = route.params[k] || extraProps[k]; }); } else { actionParams = Object.assign({}, route.params, {}, extraProps); } return actionParams; } var registerPreloader = function registerPreloader(router, store) { var _ref = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}, injection = _ref.injection, errorHandler = _ref.errorHandler, debug = _ref.debug; // a container with path segment name => jsonified store action parameters. // if these change in navigation, a reload on store is called var storedActionParamsContainer = [{}]; var storedInjectedParamsContainer = {}; // a path segment name => dynamic store name mapping var isolates = {}; var lastLoaded = {}; var reloaderTimers = {}; if (!errorHandler) { errorHandler = function errorHandler(_ref2) { var router = _ref2.router, route = _ref2.route, pathSegment = _ref2.pathSegment, exception = _ref2.exception; console.error('Exception detected'); return false; }; } async function runPreloader(match, storedActionParams, actionParams, preloader, from, to) { var injects = {}; var name = match.name; var reload = preloader.reload || false; var storeModule = preloader.store || ''; var expiration = preloader.expiration; var reloadInterval = preloader.reloadInterval; var action = preloader.action || 'load'; var isolated = preloader.isolated || ''; var key = preloader.key || [name, storeModule, action].filter(function (x) { return !!x; }).map(function (x) { return x.toString(); }).join(':'); if (debug) { console.log("preloader will use key ".concat(key, " for route segment"), match); } var serializedParams = JSON.stringify(actionParams); if (debug) { console.log('checking if reload is needed: serialized params ', serializedParams, 'stored params', storedActionParams[key], 'reload', reload); } var skipReloading = !reload; if (storedActionParams[key] === undefined) { skipReloading = false; } else if (storedActionParams[key] !== serializedParams) { skipReloading = false; } var storeState = store.state; if (storeModule.length) { storeState = storeState[storeModule]; } if (storeState['reloadNeeded']) { skipReloading = false; } if (expiration && lastLoaded[key] && new Date(lastLoaded[key].getTime() + expiration * 1000) < new Date()) { skipReloading = false; } if (skipReloading) { if (injection) { if (debug) { console.log('Injecting cache to component', injects); } Object.keys(storedInjectedParamsContainer[key] || {}).forEach(function (k) { to.params[k] = storedInjectedParamsContainer[key][k]; }); } return _defineProperty({}, key, storedActionParams[key]); } if (isolated) { var storeModuleDef = await isolated({ store: store, match: match, route: to, router: router }); await Vue.nextTick(); storeModule = storeModuleDef.store; delete storeModuleDef[store]; injects = Object.assign({}, injects, {}, storeModuleDef); isolates[key] = storeModule; } async function runReload() { injects['storeModule'] = storeModule; var namespacedAction = storeModule ? "".concat(storeModule, "/").concat(action) : action; if (debug) { console.log('dispatch', namespacedAction, actionParams, 'from', from, 'to', to); } await store.dispatch(namespacedAction, actionParams); lastLoaded[key] = new Date(); } await runReload(); if (reloadInterval) { if (reloaderTimers[key] !== undefined) { clearInterval(reloaderTimers[key]); } reloaderTimers[key] = setInterval(runReload, reloadInterval * 1000); } if (injection) { if (debug) { console.log('Injecting to component', injects); } storedInjectedParamsContainer[key] = {}; Object.keys(injects).forEach(function (k) { to.params[k] = injects[k]; storedInjectedParamsContainer[key][k] = injects[k]; }); } if (debug) { console.log("Called store ".concat(name, ", returning"), _defineProperty({}, key, serializedParams)); } return _defineProperty({}, key, serializedParams); } async function beforeEachHandler(to, from, next) { var storedActionParams = storedActionParamsContainer[0]; var newActionParams = {}; // for each route segment, check if there is a preloader and run it var _iteratorNormalCompletion = true; var _didIteratorError = false; var _iteratorError = undefined; try { for (var _iterator = to.matched[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) { var match = _step.value; var preloaders = match.meta && match.meta.preloader; if (preloaders === undefined) { continue; } var extraProps = {}; if (match.props) { if (match.props["default"] instanceof Function) { extraProps = Object.assign({}, match.props["default"](to)); } else if (Object(match.props["default"]) === match.props["default"]) { extraProps = Object.assign({}, match.props["default"]); } } // the ``preloaders`` are either a single object or an array. If a single object, cast it to an array var _iteratorNormalCompletion2 = true; var _didIteratorError2 = false; var _iteratorError2 = undefined; try { for (var _iterator2 = (Array.isArray(preloaders) ? preloaders : [preloaders])[Symbol.iterator](), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) { var preloader = _step2.value; var actionParams = extractActionParams(preloader, match, to, Object.assign({}, preloader.props || {}, {}, extraProps)); try { // run the preloader. It returns an object {key: actionParams} as a retval. // Extend the new action params with the retval - this way we know which actions // has been found on the path Object.assign(newActionParams, (await runPreloader(match, storedActionParams, actionParams, preloader, from, to))); } catch (e) { // in case of error run the error handler and call its next console.error(e); var res = errorHandler(router, to, match, e) || false; if (res !== true) { next(res); return; } } } } catch (err) { _didIteratorError2 = true; _iteratorError2 = err; } finally { try { if (!_iteratorNormalCompletion2 && _iterator2["return"] != null) { _iterator2["return"](); } } finally { if (_didIteratorError2) { throw _iteratorError2; } } } } } catch (err) { _didIteratorError = true; _iteratorError = err; } finally { try { if (!_iteratorNormalCompletion && _iterator["return"] != null) { _iterator["return"](); } } finally { if (_didIteratorError) { throw _iteratorError; } } } if (debug) { console.log('about tpo remove isolates and timers, current action params', newActionParams); } // clean up isolates that are no more used in path segments Object.keys(isolates).forEach(function (key) { if (newActionParams[key] === undefined) { if (debug) { console.log('Removing isolated store', key); } store.unregisterModule(isolates[key]); delete isolates[key]; // remove stored params as the isolated store has been destroyed if (storedActionParamsContainer[0][key] !== undefined) { delete storedActionParamsContainer[0][key]; } if (storedInjectedParamsContainer[key] !== undefined) { delete storedInjectedParamsContainer[key]; } } }); // clean up all timers that are no more used in path segments Object.keys(reloaderTimers).forEach(function (key) { if (newActionParams[key] === undefined) { if (debug) { console.log('Removing timer', key); } clearInterval(reloaderTimers[key]); delete reloaderTimers[key]; } }); // store parameters for the next route change storedActionParamsContainer[0] = Object.assign({}, storedActionParams, {}, newActionParams); if (debug) { console.log('calling next, stored action params', storedActionParamsContainer[0]); } next(); } router.beforeEach(beforeEachHandler); return { beforeEachHandler: beforeEachHandler }; }; var library = { install: function install(Vue) { var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; var store = options.store; var router = options.router; if (store === undefined) { throw new Error('Pass store to @oarepo/vuex-preloader'); } if (router === undefined) { throw new Error('Pass router to @oarepo/vuex-preloader'); } delete options.store; delete options.router; registerPreloader(router, store, options); } }; export default library; export { registerPreloader };