OpoQuizTiny/Public/OpoQuizTiny.KyMAN.fase2.html

1008 lines
42 KiB
HTML

<!DOCTYPE html>
<html lang="es">
<head>
<title data-i18n="opo_quiz_tiny">OpoQuizTiny</title>
<meta http-equiv="content-type" content="text/html;charset=utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta charset="UTF-8" />
<script data-module="data" data-type="text/javascript" data-lagnuage="ECMAScript 2015" charset="utf-8">
"use strict";
/** @type {Object.<string, any|null>} */
const SETTINGS = {
/** @type {string} */
position : "body"
};
</script>
<script data-module="styles" data-type="text/javascript" data-lagnuage="ECMAScript 2015" charset="utf-8">
"use strict";
/**
* @class SASS
* @constuctor
* @returns {void}
* @access public
* @static
*/
const SASS = (function(){
/**
* @constructs SASS
* @returns {void}
* @access private
* @static
*/
const SASS = function(){};
/**
* @param {!string} string
* @returns {string}
* @access public
* @static
*/
SASS.to_kebab = string => string.replace(/([A-Z]+)|([^a-z0-9]+)/g, (_, upper, special) => upper ? "-" + upper.toLowerCase() : "-");
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
SASS.is_css_block = item => item && item.constructor == Object;
/**
* @param {!Object.<string, any|null>} data
* @returns {void}
* @access public
* @static
*/
SASS.set = data => {
/** @type {HTMLStyleElement} */
let style = document.querySelector("head>style");
if(!style){
style = document.querySelector("head").appendChild(document.createElement("style"));
Object.entries({
data_type : "text/css;charset=utf-8",
data_language : "CSS3",
charset : "utf-8"
}).forEach(([key, value]) => style.setAttribute(SASS.to_kebab(key), (
value === null ? "none" :
value)));
};
style.appendChild(document.createTextNode(SASS.build(data).join("")));
};
/**
* @method build
* @param {!Object.<string, any|null>} data
* @returns {Array<string>}
* @access public
* @static
*/
SASS.build = data => {
/** @type {Arrya.<string>} */
const childs = [];
/** @type {string} */
let css = ``;
Object.entries(data).forEach(([key, value]) => {
if(SASS.is_css_block(value))
childs.push(`\n\n${SASS.to_kebab(key)} {\n${value[0]}}`, ...value.slice(1));
else
css += `\n ${SASS.to_kebab(key)} : ${value};`;
});
return [css, ...childs];
};
return SASS
})();
SASS.set({});
</script>
<script data-module="common" data-type="text/javascript" data-lagnuage="ECMAScript 2015" charset="utf-8">
"use strict";
/**
* @class Utils
* @constructor
* @returns {void}
* @access public
* @static
*/
const Utils = (function(){
/**
* @callback utils_execute_callback
* @param {...(any|null)} [parameters]
* @returns {any|null}
*/
/**
* @callback utils_upload_callback
* @param {...Object.<string, any|null>} data
* @returns {void}
*/
/**
* @callback utils_preload_callback
* @param {?HTMLElement} item
* @param {!number} error
* @param {!boolean} asynchronous
* @returns {void}
*/
/**
* @constructs Utils
* @returns {void}
* @access private
* @static
*/
const Utils = function(){};
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Utils.is_string = item => typeof item == "string";
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Utils.is_key = item => Utils.is_string(item) && /^[a-z_][a-z0-9_]*$/.test(item);
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Utils.is_array = item => item instanceof Array;
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Utils.is_dictionary = item => item && item.constructor == Object;
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Utils.is_function = item => typeof item == "function";
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Utils.is_html_item = item => item && (item.tagName || item.nodeType);
/**
* @param {?any} item
* @returns {boolean}
* @access public
* @static
*/
Utils.is_null_or_undefined = item => item === undefined || item === null;
/**
* @param {!utils_execute_callback} callback
* @param {...(any|null)} [parameters]
* @returns {any|null}
* @access public
* @static
*/
Utils.execute = (callback, ...parameters) => Utils.is_function(callback) ? callback(...parameters) : null;
/**
* @param {...(any|null)} items
* @returns {Array.<string>}
* @access public
* @static
*/
Utils.get_strings = (...items) => items.reduce((strings, item) => (
Utils.is_string(item) ? strings.concat([item]) :
Utils.is_array(item) ? strings.concat(Utils.get_strings(...item)) :
strings), []);
/**
* @param {...(any|null)} items
* @returns {Array.<string>}
* @access public
* @static
*/
Utils.get_keys = (...items) => {
/** @type {Array.<string>} */
const keys = [];
items.forEach(subitem => {
if(Utils.is_key(subitem))
keys.push(subitem);
else if(Utils.is_array(subitem))
keys.push(...Utils.get_keys(...subitem));
});
return keys;
};
/**
* @param {...(any|null)} items
* @returns {Array.<Object.<string, any|null>>}
* @access public
* @static
*/
Utils.get_dictionaries = (...items) => items.reduce((dictionaries, item) => (
Utils.is_dictionary(item) ? dictionaries.concat([item]) :
Utils.is_array(item) ? dictionaries.concat(Utils.get_dictionary(...item)) :
dictionaries), []);
/**
* @param {...(any|null)} items
* @returns {Object.<string, any|null>}
* @access public
* @static
*/
Utils.get_dictionary = (...items) => items.reduce((dictionary, item) => (
Utils.is_dictionary(item) ? Object.assign(dictionary, item) :
Utils.is_array(item) ? Object.assign(dictionary, Utils.get_dictionary(...item)) :
dictionary), {});
/**
* @param {!(string|Array.<string>)} keys
* @param {!(Object.<string, any|null>|Array.<any|null>} inputs
* @param {?any} [_default = null]
* @returns {any|null}
* @access public
* @static
*/
Utils.get_value = (keys, inputs, _default = null) => {
/** @type {number} */
const l = (inputs = Utils.get_dictionaries(inputs)).length,
/** @type {number} */
m = (keys = Utils.get_keys(keys)).length;
for(let i = 0; i < l; i ++)
for(let j = 0; j < m; j ++)
if(inputs[j] && inputs[j][keys[i]] !== undefined)
return inputs[j][keys[i]];
return _default;
};
/**
* @param {!utils_upload_callback} callback
* @param {?(Object.<string, any|null>|Array.<any|null>)} [options = null]
* @returns {void}
* @access public
* @static
*/
Utils.upload = (callback, options = null) => {
/** @type {HTMLInputElement} */
const input = document.createElement("input");
Object.entries({
type : "file",
accept : Utils.get_value("accept", options, "*/*"),
multiple : Utils.get_value("multiple", options, false)
}).forEach(([key, value]) => {
input.setAttribute(key, value);
});
input.addEventListener("change", (event) => {
/* @type {number} */
let loaded = 0;
/** @type {number} */
const l = event.target.files.length,
/** @type {Array.<Object.<string, any|null>>} */
data = [],
/**
* @param {!number} i
* @param {!Object.<string, any|null>} response
* @returns {void}
*/
end = (i, response) => {
data[i] = response;
if(++ loaded == l)
callback(...data);
};
[...event.target.files].forEach((file, i) => {
/** @type {FileReader} */
const reader = new FileReader();
reader.onload = event => {
end(i, {
name : file.name,
mime : file.type,
last_modified : file.lastModified,
data : event.target.result
});
};
reader.readAsText(file);
});
});
input.click();
};
/**
* @param {!string} data
* @returns {?(Object.<string, any|null>|Array.<any|null>)}
* @access public
* @static
*/
Utils.json_decode = data => {
try{
return JSON.parse(data);
}catch(exception){};
return null;
};
/**
* @param {!(string|HTMLElement)} item
* @param {!utils_preload_callback} callback
* @param {?(Object.<string, any|null>|Array.<any|null>)} [options = null]
* @returns {[HTMLElement|null, number, boolean]}
* @access public
* @static
*/
Utils.preload = (selector, callback, options = null) => {
/** @type {number} */
let error = (
!Utils.is_function(callback) ? 1 << 1 :
0),
/** @type {boolean} */
asynchronous = false,
/** @type {HTMLElement|null} */
item = null;
if(!error){
if(Utils.is_string(selector)){
if(selector){
try{
if(item = document.querySelector(selector))
Utils.execute(callback, item, error, asynchronous);
}catch(exception){
error |= 1 << 4;
};
if(asynchronous = !error && !item){
/** @type {number} */
const date = Date.now(),
/** @type {number} */
timeout = Utils.get_value("timeout", options, 2000);
/** @type {number} */
let preload = setInterval(() => {
if(item = document.querySelector(selector)){
clearInterval(preload);
Utils.execute(callback, item, error, asynchronous);
}else if(Date.now() - date > timeout){
clearInterval(preload);
error |= 1 << 5;
Utils.execute(callback, item, error, asynchronous);
};
}, Utils.get_value("timer", options, 100));
};
}else
error |= 1 << 3;
}else if(Utils.is_html_item(selector))
Utils.execute(callback, item = selector, error, asynchronous);
else
error |= 1 << 2;
};
return [item, error, asynchronous];
};
/**
* @param {!string} string
* @returns {string}
* @access public
* @static
*/
Utils.to_kebab = string => string.replace(/([A-Z]+)|([^a-z0-9]+)/g, (_, upper, special) => upper ? "-" + upper.toLowerCase() : "-");
/**
* @param {!HTMLElement} item
* @param {!Object.<string, any>} attributes
* @returns {void}
* @access public
* @static
*/
Utils.attributes = (item, attributes) => {
Object.entries(attributes).forEach(([key, value]) => {
if(/^on[_\_]?/i.test(key)){
item.addEventListener(key.replace(/^on[_\_]?|[_\-]+/gi, ""), event => {
value(item, event);
});
return;
};
key = Utils.to_kebab(key);
if(Utils.is_null_or_undefined(value))
item.hasAttribute(key) && item.removeAttribute(key);
else
item.setAttribute(key, value);
});
};
/**
* @param {!HTMLElement} item
* @param {...[string, Object.<string, any>|null, Array.<any|null>|null]} structure
* @returns {Array.<HTMLElement>}
* @access public
* @static
*/
Utils.html = (item, ...structure) => {
/** @type {Array.<HTMLElement>} */
const items = [];
structure.forEach(subitem => {
if(Utils.is_string(subitem))
item.innerHTML += subitem;
else if(Utils.is_html_item(subitem))
items.push(item.appendChild(subitem));
else if(Utils.is_array(subitem)){
/** @type {[string, Object.<string, any>|null, Array.<any|null>|null]} */
const [tag, attributes, children] = subitem.concat([null, null]),
/** @type {HTMLElement} */
html_item = item.appendChild(document.createElement(tag));
Utils.is_dictionary(attributes) && Utils.attributes(html_item, attributes);
if(Utils.is_array(children))
Utils.html(html_item, ...children);
else if(Utils.is_string(children))
html_item.innerHTML = children;
items.push(html_item);
};
});
return items;
};
/**
* @param {!string} string
* @param {!(Object.<string, any>|Array.<any|null>)} variables
* @param {?any} [_default = null]
* @returns {string}
* @access public
* @static
*/
Utils.string_variables = (string, variables, _default = null) => {
variables = Utils.get_dictionary(variables);
return ("" + string).replace(/\{([^\{\}]+)\}/g, (origin, key) => (
variables[key] !== undefined ? variables[key] :
_default !== null ? _default :
origin));
};
/**
* @param {?any} item
* @param {!number} [i = 0]
* @returns {any|null}
* @access public
* @static
*/
Utils.get = (item, i = 0) => (Utils.is_array(item) ? item : [item])[i];
/**
* @param {?any} item
* @returns {Array.<any|null>}
* @access public
* @static
*/
Utils.get_array = item => Utils.is_array(item) ? item : [item];
return Utils;
})();
</script>
<script data-module="application" data-type="text/javascript" data-lagnuage="ECMAScript 2015" charset="utf-8">
"use strict";
/**
* @class OpoQuizTiny
* @constructor
* @param {?(Object.<string, any|null>|Array.<any|null>)} [customs = null]
* @returns {void}
* @access public
* @static
*/
const OpoQuizTiny = (function(){
/**
* @constructs OpoQuizTiny
* @param {?(Object.<string, any|null>|Array.<any|null>)} [customs = null]
* @returns {void}
* @access private
* @static
*/
const OpoQuizTiny = function(customs = null){
/**
* @callback opo_quiz_tiny_event_callback
* @param {!HTMLElement} item
* @param {!Event} event
* @returns {any|null}
*/
/** @type {OpoQuizTiny} */
const self = this,
/** @type {Array.<string>} */
ids = [],
/** @type {Object.<string, any>} */
subjects = {};
/** @type {string|Array.<string>} */
let id_alphabet = ['1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K', 'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'],
/** @type {number} */
id_length = 11;
/** @type {HTMLDivElement} */
this.item_self;
/**
* @returns {void}
* @access private
*/
const constructor = () => {
Utils.preload(self.get("position"), (position, error, asynchronous) => {
if(error){
console.error("position_error");
return;
};
self.item_self = Utils.html(position, ["div", {
class : "opo-quiz-tiny"
}, [
["header", null, [
["h1", {
class : "logo",
data_i18n : "opo_quiz_tiny",
data_i18n_without : true,
title : self.get_i18n("opo_quiz_tiny", null, "OpoQuizTiny")
}, [
["a", {
href : "#",
target : "_blank"
}, [
["span", {class : "image"}, [
["img", {src : "", data_i18n : "opo_quiz_tiny", data_i18n_without : true, alt : self.get_i18n("opo_quiz_tiny", null, "OpoQuizTiny")}],
["span", {style : "background-image:url('');"}]
]],
self.i18n("opo_quiz_tiny", "span", "OpoQuizTiny")
]]
]]
]],
["main", null, [self.build_main_form()]],
["footer", null, [
["p", {class : "licenses"}, [
["span", {class : "copyright", data_i18n : "copyright", data_i18n_without : true, title : self.get_i18n("copyright", null, "© CopyRight 2025-2026")}, [
self.i18n("copyright", "span", "© CopyRight 2025-2026"),
["span", {class : "kyman"}, "KyMAN"]
]],
["a", {
class : "cc-by-nc-sa-4",
href : "https://creativecommons.org/licenses/by-nc-sa/4.0/",
target : "_blank",
data_i18n : "cc_by_nc_sa_4",
data_i18n_without : true,
title : self.get_i18n("cc_by_nc_sa_4", null, "Creative Commons BY-NC-SA (Attribution-NoCommerce-ShareDAlike) 4.0")
}, [
self.i18n("cc_by_nc_sa_4", "span", "Creative Commons BY-NC-SA (Attribution-NoCommerce-ShareDAlike) 4.0"),
["img", {src : "https://licensebuttons.net/l/by-nc-sa/3.0/88x31.png", alt : "Creative Commons BY-NC-SA 4.0"}]
]]
]]
]]
]])[0];
});
};
/**
* @param {string} keys
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @param {?(Object.<string, any|null>|Array.<any|null>)} [_default = null]
* @returns {any|null}
* @access public
*/
this.get = (keys, inputs = null, _default = null) => Utils.get_value(keys, [inputs, customs, SETTINGS], _default);
/**
* @param {string} keys
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @param {?(Object.<string, any|null>|Array.<any|null>)} [_default = null]
* @returns {any|null}
* @access public
*/
this.get_i18n = (keys, inputs = null, _default = null) => {
/** @type {string} */
const text = _default || Utils.get_strings(keys)[0] || "";
return inputs ? Utils.string_variables(text, inputs) : text;
};
/**
* @param {string} name
* @returns {[string, Object.<string, string>]}
* @access public
*/
this.icon = name => ["span", {data_icon : name}];
/**
* @param {!string} name
* @param {!string} [tag = "span"]
* @param {?string} [text = null]
* @param {?(Object.<string, any|null>|Array.<any|null>)} [inputs = null]
* @returns {[string, Object.<string, string>, string]}
* @access public
*/
this.i18n = (name, tag = "span", text = null, inputs = null) => [tag, {data_i18n : name}, self.get_i18n(name, inputs, text)];
/**
* @param {!string} name
* @param {!opo_quiz_tiny_event_callback} action
* @param {!string} [type = "button"]
* @param {?string} [text = null]
* @returns {[string, Object.<string, any>, Array.<[string, Object.<string, any>, string|null]>]}
* @access public
*/
this.button = (name, action, type = "button", text = null) => ["button", {
type : type,
data_i18n : name,
data_i18n_without : true,
title : self.get_i18n(name, null, text),
...(action ? {on_click : action} : {})
}, [
self.icon(name),
self.i18n(name, "span", text)
]];
/**
* @param {!Object.<string, any|null>} input
* @returns {Array.<any|null>}
* @access public
*/
this.number = input => ["input", {
type : "number",
...[
["id"],
["name"],
["value"],
["min", "minimum"],
["max", "maximum"],
["step"],
["onchange", "on_change", "change"]
].reduce((fields, keys) => {
/** @type {any|null} */
const value = self.get(keys, input);
Utils.is_null_or_undefined(value) || (fields[keys[0]] = value);
return fields;
}, {}),
...(input.i18n || (input.i18n = input.name) ? {data_i18n : input.i18n, data_i18n_without : true} : {}),
...(input.i18n || input.text ? {placeholder : self.get_i18n(input.i18n, input, input.text) + "..." } : {})
}];
/**
* @param {!string} name
* @param {!boolean} [checked = false]
* @param {?opo_quiz_tiny_event_callback} [on_change = null]
* @param {?(Object.<string, any|null>|Array.<any|null>)} [input = null]
* @param {?string} [text = null]
* @returns {Array.<any|null>}
* @access public
*/
this.checkbox = (name, checked = false, on_change = null, input = null, text = null) => ["label", {
class : "checkbox",
data_i18n : name,
data_i18n_without : true,
title : self.get_i18n(name, input, text),
...Utils.get_dictionary(input)
}, [
["input", {
type : "checkbox",
name : name,
...(checked ? {checked : checked} : {}),
...(on_change ? {on_change : on_change} : {})
}],
self.icon("checkbox"),
self.i18n(name, "span", text)
]];
/**
* @returns {string}
* @access public
*/
this.get_id = () => {
/** @type {number} */
let l = id_alphabet.length;
/** @type {string} */
let id;
do{
id = "";
while((id += id_alphabet[Math.random() * l >> 0]).length < id_length);
}while(
ids.includes(id) ||
/^[^a-z]/i.test(id) ||
document.querySelector("." + id + ",#" + id + ",[name=" + id + "]")
);
ids.push(id);
return id;
};
/**
* @param {!string} name
* @param {!Array.<Object.<string, any|null>>} structure
* @param {!Array.<[string, opo_quiz_tiny_event_callback, string|null, string|null]>} actions
* @param {?string} [title = null]
* @param {?string} [text = null]
* @returns {Array}
* @access public
*/
this.create_form = (name, structure, actions, title = null, text = null) => ["form", {
class : Utils.to_kebab(name),
method : "get",
action : "#",
on_submit : (actions.filter(action => action[2] == "submit")[0] || [(item, event) => false])[0]
}, [
["fieldset", null, [
self.i18n(name, "legend", title),
self.i18n(name + "_text", "p", text),
["div", {class : "form-structure"}, structure.map((item, i) => {
/** @type {string} */
const id = item.id || self.get_id();
// Implementar ID para el FOR LABEL.
// item.input && Utils.is_dictionary(item.input[0]) && (item.input[0].id = id);
return ["tr", {data_i : i, data_i18n : item.label, data_i18n_without : true, title : self.get_i18n(item.label, null, item.label)}, [
["label", {for : id}, [
self.i18n(item.label, "span", item.label),
self.i18n(item.label + "_description", "span", item.label + "_description")
]],
["span", {class : "input"}, item.input],
["ul", {class : "errors"}]
]];
})],
["div", {class : "buttons"}, actions.map(action => self.button(...action))]
]]
]];
/**
* @returns {Array.<any|null>}
* @access public
*/
this.build_main_form = () => self.create_form(
"main_form",
[
{label : "subjects", input : [
["nav", null, [
["ul"]
]],
["div", {class : "buttons"}, [
self.button("reset_subjects", reset_subjects, "button", "Restablecer temario"),
self.button("load_subjects", load_subjects, "button", "Cargar temario")
]]
]},
{label : "minimum_questions_number", input : [
self.number({name : "minimum_question_number", step : 1, minimum : 1, maximum : 250, value : 10})
]},
{label : "maximum_questions_number", input : [
self.number({name : "maximum_question_number", step : 1, minimum : 1, maximum : 250, value : 50})
]},
{label : "allow_true_or_false", input : [
self.checkbox("allow_true_or_false", true)
]},
{label : "allow_multianswer", input : [
self.checkbox("allow_multianswer", true)
]},
{label : "allow_negative_answers", input : [
self.checkbox("allow_negative_answers", true)
]},
{label : "minimum_answers_number", input : [
self.number({name : "minimum_answers_number", step : 1, minimum : 2, maximum : 25, value : 2})
]},
{label : "maximum_answers_number", input : [
self.number({name : "maximum_answers_number", step : 1, minimum : 2, maximum : 25, value : 8})
]}
],
[
["clean", null, "reset", "Limpiar"],
["start", build_quiz, "button", "Iniciar"]
],
self.get_i18n("main_form", null, "Formulario de inicio"),
self.get_i18n("main_form_text", null, "Este formulario nos sirve para configurar nuestro nuevo Test y establecer contenidos para el mismo.")
);
/**
* @param {!Object.<string, any>} set
* @param {!number} [i = 0]
* @returns {Array.<Object.<string, any|null>>}
* @access private
*/
const draw_subjects = (set, i = 0) => {
/** @type {Array.<Object.<string, any|null>>} */
const items = [];
for(const id in set){
/** @type {[Object.<string, any|null>, boolean, string]} */
const [data, checked, name] = set[id];
if(i || !data.nested){
items.push(["li", {
data_subject : id,
title : name
}, [
self.checkbox(id, checked, select_subject, null, name),
data.nodes ? ["ul", null, draw_subjects(data.nodes.reduce((subset, id) => {
subjects[id] && (subset[id] = subjects[id]);
return subset;
}, {}), i + 1)] : null
]]);
};
};
return items;
};
/**
* @param {!HTMLElement} item
* @param {!Event} event
* @returns {void}
* @access private
*/
const load_subjects = (item, event) => {
Utils.upload((...data) => {
/** @type {HTMLUListElement} */
const list = item.parentNode.parentNode.querySelector("nav ul");
data.forEach(items => {
Utils.get_array(Utils.json_decode(items.data)).forEach(json => {
json &&
(subjects[json.id || (json.id = self.get_id())] = [json, true, Utils.get(json.name)]);
});
});
Object.entries(subjects).forEach(([id, [subject, ..._]]) => {
subject.parent && Utils.get_array(subject.parent).forEach(parent => {
if(subjects[parent]){
!(subjects[parent][0].nodes || (subjects[parent][0].nodes = [])).includes(id) &&
subjects[parent][0].nodes.push(id);
subject.nested || (subject.nested = true);
};
});
});
list.innerHTML = ``;
Utils.html(list, ...draw_subjects(subjects));
}, {multiple : true});
};
/**
* @param {!HTMLElement} item
* @param {!Event} event
* @returns {void}
* @access private
*/
const reset_subjects = (item, event) => {};
/**
* @param {!HTMLElement} item
* @param {!Event} event
* @returns {void}
* @access private
*/
const build_quiz = (item, event) => {
/** @type {Object.<string, any>} */
const quiz_data = {
subjects : [...self.item_self.querySelectorAll(".main-form tr[data-i18n=subjects] [type=checkbox]:checked")].map(checkbox => checkbox.getAttribute("name")),
...[...self.item_self.querySelectorAll(".main-form tr+tr [name]")].reduce((data, input) => {
/** @type {string} */
const name = input.getAttribute("name");
if(input.type == "checkbox")
data[name] = input.checked;
else if(input.type == "number")
data[name] = Number(input.value);
return data;
}, {})
};
console.log(quiz_data);
};
/**
* @param {!HTMLElement} item
* @param {!Event} event
* @returns {void}
* @access private
*/
const select_subject = (item, event) => {
/** @type {string} */
const id = item.getAttribute("name");
subjects[id] && (subjects[id][1] = item.checked);
item.parentNode.parentNode.querySelectorAll("[type=checkbox]").forEach(checkbox => {
checkbox.checked = item.checked;
});
};
constructor();
};
return OpoQuizTiny;
})();
</script>
<script data-module="starter" data-type="text/javascript" data-lagnuage="ECMAScript 2015" charset="utf-8">
"use strict";
/** @type {OpoQuizTiny} */
const opo_quiz_tiny = new OpoQuizTiny();
</script>
</head>
<body></body>
</html>