"use strict"; import {Common} from "../Utils/Common.ecma.js"; import {RouteModel} from "../Models/RouteModel.ecma.js"; import {Check} from "../Utils/Checks.ecma.js"; import {RE} from "../Utils/Patterns.ecma.js"; /** * @typedef {import("../AnP.ecma.js").AnP} AnP */ /** * @class RoutesManager * @constructor * @param {!AnP} anp * @return {void} * @access public * @static */ export const RoutesManager = (function(){ /** * @callback continue_callback * @param {!boolean} ok * @return {boolean} */ /** * @callback default_callback * @return {void} */ /** * @constructs RoutesManager * @param {!AnP} anp * @return {void} * @access private * @static */ const RoutesManager = function(anp){ /** @type {RoutesManager} */ const self = this, /** @type {Array.} */ routes = []; /** @type {boolean} */ let started = false, /** @type {string} */ last_url = "", /** @type {number|null} */ thread = null; /** * @returns {void} * @access private */ const constructor = () => { thread = anp.threads.add(thread_method, { bucle : true, autoplay : true }); }; /** * @returns {void} * @access private */ const thread_method = () => { /** @type {string} */ const current_url = window.location.hash.substring(1); if(last_url != current_url){ last_url = current_url; self.refresh(); }; }; /** * @returns {void} * @access public */ this.refresh = () => { self.go(last_url); }; /** * @param {?continue_callback} callback * @returns {boolean} * @access public */ this.update = (callback = null) => { Common.execute_array(["default_routes_files", "routes_files", "default_routes", "routes"], (key, next) => { self.add(anp.settings.get(key), true, next); }, callback, true); }; /** * @param {?continue_callback} callback * @returns {boolean} * @access public */ this.reset = (callback = null) => { routes.splice(0, routes.length); self.update(callback); }; /** * @param {?continue_callback} callback * @returns {boolean} * @access public */ this.start = (callback = null) => { /** @type {continue_callback} */ const end = ok => Common.execute(callback, ok); if(started){ end(false); return false; }; started = true; self.update(() => end(true)); return true; }; /** * @param {?continue_callback} callback * @returns {boolean} * @access public */ this.close = (callback = null) => { /** @type {continue_callback} */ const end = ok => Common.execute(callback, ok); if(!started){ end(false); return false; }; started = false; end(true); return true; }; /** * @param {!(string|RegExp)} route_path * @param {!string} view * @param {!boolean} overwrite * @returns {boolean} * @access private */ const set_new = (route_path, view, permissions, overwrite) => { /** @type {RouteModel} */ const route = new RouteModel(route_path, view, permissions); let i = null; if(!routes.some((exists, j) => { if(exists.route.source == route.route.source){ i = j; return true; }; return false; })){ if(i === null) routes.push(route); else if(overwrite) routes[i] = route; return true; }; return false; }; /** * @param {?any} inputs * @param {!boolean} [overwrite = false] * @param {?default_callback} [callback = null] * @returns {void} * @access public */ this.add = (inputs, overwrite = false, callback = null) => { if(Check.is_string(inputs)){ /** @type {RegExpMatchArray} */ const matches = (inputs = inputs.trim()).match(RE.ROUTES); if(matches){ set_new(matches[1], matches[2], matches[3] ? matches[3].split(",") : [], overwrite); Common.execute(callback); }else if(Check.is_json(inputs)) self.add(JSON.parse(inputs), overwrite, callback); else anp.files.load_json(inputs, data => { self.add(data, overwrite, callback); }); }else if(Check.is_array(inputs)){ if(inputs.length >= 2 && inputs.length <= 3 && ( Check.is_string(inputs[0]) && inputs[0] == inputs[0].trim() && Check.is_key(inputs[1]) && !inputs[2] || (Check.is_array(inputs[2]) && inputs[2].every(Check.is_key)) )){ set_new(inputs[0], inputs[1], inputs[3], overwrite); Common.execute(callback); return; }; /** @type {number} */ let i = 0; /** @type {number} */ const l = inputs.length, /** @type {default_callback} */ end = () => ++ i == l && Common.execute(callback); inputs.forEach(subinputs => { self.add(subinputs, overwrite, end); }); }else if(Check.is_dictionary(inputs)){ set_new(inputs.route, inputs.view, inputs.permissions || [], overwrite); Common.execute(callback); }else Common.execute(callback); }; /** * @param {!string} path * @returns {void} * @access public */ this.go = path => { const main = anp.item_self.querySelector("main"); if(!main) return; main.innerHTML = ""; for(const route of routes){ /** @type {[boolean, Object.]} */ const [ok, variables] = route.check(path); if(ok){ Common.HTML("main", anp.views.get(route.view, variables)) break; }; }; }; constructor(); }; return RoutesManager; })();