"use strict"; import {SettingsManager} from "../Managers/SettingsManager.ecma.js"; import {I18NManager} from "../Managers/I18NManager.ecma.js"; import {IdentifiersManager} from "../Managers/IdentifiersManager.ecma.js"; import {Components} from "./Components.ecma.js"; import {Utils} from "../Utils/Utils.ecma.js"; import {Check} from "../Utils/Check.ecma.js"; import {BaseView} from "../Views/BaseView.ecma.js"; import {MainFormView} from "../Views/MainFormView.ecma.js"; import {TestsView} from "../Views/TestsView.ecma.js"; import {UserView} from "../Views/UserView.ecma.js"; import {CookiesManager} from "../Managers/CookiesManager.ecma.js"; /** * @class OpoTests * @constructor * @param {?(Object.|Array.)} inputs * @returns {void} * @access public * @static */ export const OpoTests = (function(){ /** * @callback opo_tests_preload_callback * @param {?HTMLElement} item * @param {!boolean} asynchronous * @param {!boolean} success * @returns {void} */ /** * @callback opo_tests_load_file_callback * @param {?string} responseText * @param {!number} status * @param {!number} readyState * @param {!string} message * @param {!boolean} success * @returns {void} */ /** * @callback opo_tests_load_file_end_callback * @param {!string} message * @returns {void} */ /** * @callback opo_tests_default_callback * @returns {void} */ /** * @callback opo_tests_json_each_callback * @param {!(Object.|Array.)} item * @param {!opo_tests_default_callback} callback * @returns {void} */ /** * @constructs OpoTests * @param {?(Object.|Array.)} inputs * @returns {void} * @access private * @static */ const OpoTests = function(inputs = null){ /** @type {OpoTests} */ const self = this; this.database = []; /** @type {SettingsManager} */ this.settings = new SettingsManager(self, inputs); /** @type {I18NManager} */ this.i18n = new I18NManager(self); /** @type {IdentifiersManager} */ this.identifiers = new IdentifiersManager(self); /** @type {Components} */ this.components = this.comp = new Components(self); /** @type {BaseView} */ this.base = new BaseView(self); /** @type {MainFormView} */ this.main_form = new MainFormView(self); /** @type {TestsView} */ this.tests = new TestsView(self); /** @type {UserView} */ this.user = new UserView(self); this.cookies = new CookiesManager(self); /** * @returns {void} * @access private */ const end_constructor = () => { Utils.execute_array(["default_database_files", "database_files"], (key, next_callback) => { Utils.execute_array(self.settings.get(key, null, []), (file, next_callback) => { self.load_file(file, (data, ..._) => { /** @type {Array.|null} */ const json = data ? JSON.parse(data) : null; if(Check.is_array(json)) load_database(json, () => { next_callback(); }); else next_callback(); }); }, next_callback); }, () => { console.log(["database", self.database]); self.main_form.build(); }); }; /** * @returns {void} * @access private */ const constructor = () => { self.settings.start(() => { self.i18n.start(() => { self.cookies.start(() => { self.preload(self.settings.get("position", null, "body"), (position, asynchronous, success) => { if(success && position){ Utils.html(position, self.base.build()); if(self.cookies.get("ot") == "1") Utils.execute(end_constructor); else self.user.build_login(end_constructor); }; }); }); }); }); }; /** * @param {!(string|HTMLElement)} selector * @param {!opo_tests_preload_callback} callback * @param {?(Object.|Array.)} [inputs = null] * @returns {void} * @access public */ this.preload = (selector, callback, inputs = null) => { if(!Check.is_function(callback)) return; if(Check.is_html_item(selector)) return Utils.execute(callback, selector, false, true); if(!Check.is_string(selector)) return Utils.execute(callback, null, false, false); /** @type {HTMLElement|null} */ let item; try{ item = document.querySelector(selector) }catch(e){ return Utils.execute(callback, null, false, false); }; if(item) return Utils.execute(callback, item, false, true); /** @type {number} */ const date = Date.now(), /** @type {number} */ timeout = self.settings.get(["preload_timeout", "timeout"], inputs, 2000); /** @type {number} */ let interval = setInterval(() => { if(item = document.querySelector(selector)){ clearInterval(interval); Utils.execute(callback, item, true, true); }else if(Date.now() - date >= timeout){ clearInterval(interval); Utils.execute(callback, null, true, false); }; }, 1000 / self.settings.get(["frames_per_second", "fps"], inputs, 24)); }; /** * @param {!string} url * @param {!opo_tests_load_file_callback} callback * @param {?(Object.|Array.)} [inputs = null] * @returns {XMLHttpRequest} * @access public */ this.load_file = (url, callback, inputs = null) => { /** @type {boolean} */ let ended = false; /** @type {XMLHttpRequest} */ const ajax = new XMLHttpRequest(), /** @type {opo_tests_load_file_end_callback} */ end = message => { !ended && (ended = true) && Utils.execute(callback, ajax.responseText, ajax.status, ajax.readyState, message, message == "OK"); }, /** @type {number} */ date = Date.now(), /** @type {number} */ timeout = self.settings.get(["ajax_timeout", "timeout"], inputs, 2000); ajax.open("GET", url, true); ajax.timeout = timeout; ajax.onload = () => { if(ended) return; if(ajax.readyState == 4) end((ajax.status >= 200 && ajax.status < 300) || [301, 302, 304].includes(ajax.status) ? "OK" : "HTTP_ERROR"); else if(Date.now() - date >= timeout) end("FORCED_TIMEOUT"); }; ajax.send(null); ajax.ontimeout = () => end("TIMEOUT"); ajax.onerror = () => end("ERROR"); ajax.onabort = () => end("ABORTED"); return ajax; }; /** * @param {!Array.} files * @param {!opo_tests_default_callback} callback * @returns {void} * @access private */ const load_database = (files, callback) => { Utils.execute_array(Check.is_array(files) ? files : [files], (file, next_callback) => { self.load_file(file, (responseText, status, readyState, message, success) => { if(success && responseText){ try{ self.database.push(...JSON.parse(responseText).map(item => { item.queries = item.queries.filter(Check.is_dictionary); return item; })); }catch(exception){ console.log(responseText); console.error([file, exception]); }; }else console.error([file, responseText, message.toLowerCase(), status, readyState]); next_callback(); }); }, () => { Utils.execute(callback); }); }; /** * @param {!string} message * @param {?opo_tests_default_callback} [callback = null] * @param {?string} [default_text = null] * @return {void} * @access public */ this.alert = (message, callback, default_text = null) => { alert(self.i18n.get(message, null, default_text)); Utils.execute(callback); }; /** * @param {?(Object.|Array.|string)} data * @param {!opo_tests_json_each_callback} each_callback * @param {?opo_tests_default_callback} [end_callback = null] * @param {!boolean} [only_dictionaries = false] * @returns {void} * @access public */ this.load_json = (data, each_callback, end_callback = null, only_dictionaries = false) => { if(Check.is_array(data)){ if(only_dictionaries) Utils.execute_array(data, (item, next_callback) => { self.load_json(item, each_callback, next_callback, only_dictionaries); }, end_callback); else{ Utils.execute(each_callback, data); Utils.execute(end_callback); }; }else if(Check.is_dictionary(data)){ Utils.execute(each_callback, data); Utils.execute(end_callback); }else if(Check.is_string(data)){ /** @type {Array.|Object.|null} */ let json; try{ if(json = JSON.parse(data)){ self.load_json(json, each_callback, end_callback, only_dictionaries); return; }; }catch(exception){}; self.load_file(data, (responseText, status, readyState, message, success) => { if(success && responseText){ try{ if(json = JSON.parse(responseText)){ self.load_json(json, each_callback, end_callback, only_dictionaries); return; }; }catch(exception){}; }; Utils.execute(end_callback); }); }else Utils.execute(end_callback); }; constructor(); }; return OpoTests; })();