GamUsino = function(custom){ const self = this, default_settings = { nulls : false, default_value : null, autostart : true, timeout : 2000 }, settings = {}, fragments = {}; let started = false, ajax_timeout = 2000, preload_timeout = 2000; const constructor = () => { self.settings("autostart") && self.start(); }; this.start = callback => { const end = status => typeof callback == "function" && callback(status); if(started){ end(false); return false; }; started = true; ajax_timeout = self.settings(["ajax_timeout", "timeout"]); preload_timeout = self.settings(["preload_timeout", "timeout"]); self.send({action : "load_polls"}, data => { self.preload(".polls-box>.polls", () => { let html = document.querySelector(".html-structure-fragments").innerHTML, matches; while(matches = html.match(/<\!\-{2}\s*\[{2}([^\[\]]+)\]{2}\s*\-{2}>/)){ const key = matches[1]; let l; html = html.substring(matches.index + matches[0].length); if((l = html.indexOf(matches[0])) == -1) continue; fragments[key] = html.substring(0, l); html = html.substring(l + matches[0].length); }; build_polls(data.content); }); end(true); }); return true; }; this.nulls = nulls => typeof nulls == "boolean" ? nulls : self.settings("nulls", null, false, false); this.default_value = (_default, nulls) => _default !== undefined && (self.nulls(nulls) || _default !== null) ? _default : self.settings("default_value", null, null, true); this.settings = (keys, inputs, _default, nulls) => { const m = (keys = (typeof keys == "object" && keys instanceof Array ? keys : [keys]).filter(key => key && typeof key == "string")).length; if(m){ const l = (inputs = (typeof inputs == "object" ? inputs instanceof Array ? inputs : [inputs] : []).concat(custom, settings, default_settings)).length; nulls = self.nulls(nulls); for(let i = 0; i < l; i ++) if(inputs[i] && typeof inputs[i] == "object") for(let j = 0; j < m; j ++) if(inputs[i][keys[j]] !== undefined && (nulls || inputs[i][keys[j]] !== null)) return inputs[i][keys[j]]; }; return self.default_value(_default, nulls); }; this.send = (data, callback) => { let ended = false; const ajax = new XMLHttpRequest(), date = Date.now(), end = error => { if(ended) return; ended = true; if(typeof callback != "function") return; let data = ajax.responseText; try{ data = JSON.parse(data); }catch(exception){ data = ajax.responseText; }; callback(data, ajax.status, ajax.readyState, error == "OK", error); }; ajax.open("post", "/api.php", true); ajax.timeout = ajax_timeout; ajax.setRequestHeader("content-type", "application/x-www-form-urlencoded,charset=utf-8"); ajax.onreadystatechange = () => { if(ended) return; if(ajax.readyState == 4) end([301, 302, 304].includes(ajax.stauts) || (ajax.status >= 200 && ajax.status < 300) ? "OK" : "HTTP_ERROR"); else if(Date.now() - date > ajax_timeout) end("FORCED_TIMEOUT"); }; ajax.send("GamUsino=" + btoa(JSON.stringify(data))); ajax.onabort = () => end("ABORTED"); ajax.ontimeout = () => end("TIMEOUT"); ajax.onerror = () => end("ERROR"); return ajax; }; this.confirm = (message, ok_action, no_action) => { const action = confirm(message) ? ok_action : no_action; typeof action == "function" && action(); }; this.preload = (selector, callback) => { if(!selector){ callback(null, false); return; }; if(selector.nodeName || selector.tagName){ callback(selector, false); return; }; if(typeof selector != "string"){ callback(false, false); return; }; let item; try{ if(item = document.querySelector(selector)){ callback(item, false); return; }; }catch(exception){ callback(null, false); return; }; const date = Date.now(); let preload = setInterval(() => { if(item = document.querySelector(selector)){ clearInterval(preload); callback(item, true); return; }else if(Date.now() - date > preload_timeout){ clearInterval(preload); callback(null, true); return; }; }, 1000 / frames_per_second); }; this.string_variables = (string, variables, _default) => { const l = (variables = ( typeof variables == "object" ? variables instanceof Array ? variables : [variables] : [] ).filter(subset => subset && typeof subset == "object")).length; return string.replace(/\{([^\{\}]+)\}/g, (all, key) => { for(let i = 0; i < l; i ++) if(variables[i][key] !== undefined) return variables[i][key]; return _default !== undefined ? _default : all; }); }; const build_polls = polls => { const text = document.querySelector(".polls-box [type=text]").value.trim(); document.querySelector(".polls-box>.polls>ul").innerHTML = polls.map((poll, i) => self.string_variables(fragments.poll_menu_fragment, { ...poll, i : i, visible : !text || poll.name.includes(text) })).join(""); }; this.add_poll = (item, event) => { const poll_name = item.parentNode.parentNode.querySelector("input").value; poll_name && self.confirm("add_poll_sure", () => { self.send({ action : "add_poll", name : poll_name }, data => build_polls(data.content)); }); }; this.show_poll = (item, event) => { const i = Number(item.getAttribute("data-i")); document.querySelectorAll(".polls-box>.polls [data-seleted=true]").forEach(item => item.setAttribute("data-selected", false)); item.setAttribute("data-selected", true); self.send({ action : "get_poll", i : i }, data => { console.log(data); document.querySelector(".poll-box>.poll").innerHTML = self.string_variables(fragments.poll_box, { ...data.content, i : i, maximum_points : data.content.options.length ? Math.max(...data.content.options.map(option => option.points)) : 0, options : data.content.options.map((option, j) => self.string_variables(fragments.option_item, { ...option, i : j })).join("") }); }); }; this.add_option = (item, event) => { const text = item.parentNode.parentNode.querySelector("textarea").value, i = Number(document.querySelector(".polls-box>.polls [data-selected=true]").getAttribute("data-i")); !isNaN(i) && text && self.confirm("add_option_sure", () => { self.send({ action : "add_option", i : i, text : text }, data => build_options(data.content)); }); }; const build_options = options => { const text = document.querySelector(".poll-box textarea").value.trim(); document.querySelector(".poll-box>.poll .options>ul").innerHTML = options.map((option, k) => self.string_variables(fragments.option_item, { ...option, i : k, visible : !text || option.text.includes(text) })).join(""); }; this.select_option = (item, event) => {}; constructor(); };