409 lines
15 KiB
JavaScript
409 lines
15 KiB
JavaScript
"use strict";
|
|
|
|
import {Check} from "../Utils/Check.ecma.js";
|
|
|
|
/**
|
|
* @typedef {import("../Application/OpoTests.ecma.js").OpoTests} OpoTests
|
|
*/
|
|
|
|
/**
|
|
* @class Components
|
|
* @constructor
|
|
* @param {!OpoTests} ot
|
|
* @returns {void}
|
|
* @access public
|
|
* @static
|
|
*/
|
|
export const Components = (function(){
|
|
|
|
/**
|
|
* @callback components_event_callback
|
|
* @param {!HTMLElement} item
|
|
* @param {!Event} event
|
|
* @returns {boolean|void}
|
|
*/
|
|
|
|
/**
|
|
* @constructs Components
|
|
* @param {!OpoTests} ot
|
|
* @returns {void}
|
|
* @access private
|
|
* @static
|
|
*/
|
|
const Components = function(ot){
|
|
|
|
/** @type {Components} */
|
|
const self = this;
|
|
|
|
/**
|
|
* @returns {void}
|
|
* @access private
|
|
*/
|
|
const constructor = () => {};
|
|
|
|
/**
|
|
* @param {!(string|Array.<string>)} i18n
|
|
* @param {!string} [tag = "span"]
|
|
* @param {?string} [_default = null]
|
|
* @returns {[string, Object.<string, string>, string]}
|
|
* @access public
|
|
*/
|
|
this.i18n = (i18n, tag = "span", _default = null) => [tag, {data_i18n : i18n}, ot.i18n.get(i18n, null, _default)];
|
|
|
|
/**
|
|
* @param {!string} name
|
|
* @param {!string} [tag = "span"]
|
|
* @returns {[string, Object.<string, string>]}
|
|
* @access public
|
|
*/
|
|
this.icon = (name, tag = "span") => [tag, {data_icon : name}];
|
|
|
|
/**
|
|
* @param {!string} name
|
|
* @param {?components_event_callback} [on_click = null]
|
|
* @param {!string} [type = "button"]
|
|
* @param {?string} [default_text = null]
|
|
* @returns {[string, Object.<string, (string|function)>, Array.<(string|[string, Object.<string, string>, string])>]}
|
|
* @access public
|
|
*/
|
|
this.button = (name, on_click = null, type = "button", default_text) => ["button", {
|
|
type : type,
|
|
data_i18n : name,
|
|
data_i18n_without : true,
|
|
title : ot.i18n.get(name, null, default_text),
|
|
...(on_click ? {on_click : on_click} : {})
|
|
}, [
|
|
self.icon(name),
|
|
self.i18n(name, "span", default_text)
|
|
]];
|
|
|
|
/**
|
|
* @param {!string} type
|
|
* @param {!string} name
|
|
* @param {!boolean} checked
|
|
* @param {?components_event_callback} on_change
|
|
* @param {?string} default_text
|
|
* @returns {[string, Object.<string, (string|function)>, Array.<(string|[string, Object.<string, string>, string])>]}
|
|
* @access private
|
|
*/
|
|
const select_item = (type, name, checked, on_change, default_text) => {
|
|
|
|
/** @type {string} */
|
|
const id = name.slice(-2) == "[]" ? ot.identifiers.get() : name;
|
|
|
|
return ["label", {
|
|
for : id,
|
|
class : type + "-input",
|
|
data_i18n : name,
|
|
data_i18n_without : true,
|
|
title : ot.i18n.get(name, null, default_text)
|
|
}, [
|
|
["input", {
|
|
type : type,
|
|
id : id,
|
|
name : name,
|
|
...(on_change ? {on_change : on_change} : {}),
|
|
...(checked ? {checked : "checked"} : {})
|
|
}],
|
|
self.icon(type, "span"),
|
|
self.i18n(name, "span", default_text)
|
|
]];
|
|
};
|
|
|
|
/**
|
|
* @param {!string} name
|
|
* @param {!boolean} [checked = false]
|
|
* @param {?components_event_callback} [on_change = null]
|
|
* @param {?string} [default_text = null]
|
|
* @returns {[string, Object.<string, (string|function)>, Array.<(string|[string, Object.<string, string>, string])>]}
|
|
*/
|
|
this.checkbox = (name, checked = false, on_change = null, default_text) => (
|
|
select_item("checkbox", name, checked, on_change, default_text)
|
|
);
|
|
|
|
/**
|
|
* @param {!string} name
|
|
* @param {!boolean} [checked = false]
|
|
* @param {?components_event_callback} [on_change = null]
|
|
* @param {?string} [default_text = null]
|
|
* @returns {[string, Object.<string, (string|function)>, Array.<(string|[string, Object.<string, string>, string])>]}
|
|
*/
|
|
this.radio = (name, checked = false, on_change = null, default_text) => (
|
|
select_item("radio", name, checked, on_change, default_text)
|
|
);
|
|
|
|
/**
|
|
* @param {!string} name
|
|
* @param {?number} [value = null]
|
|
* @param {?number} [minimum = null]
|
|
* @param {?number} [maximum = null]
|
|
* @param {?number} [step = null]
|
|
* @param {?components_event_callback} [on_change = null]
|
|
* @param {?string} [default_text = null]
|
|
* @returns {[string, Object.<string, (string|number|function)>, Array.<(string|[string, Object.<string, string>, string])>]}
|
|
* @access public
|
|
*/
|
|
this.number = (name, value = null, minimum = null, maximum = null, step = null, on_change = null, default_text) => {
|
|
|
|
/** @type {string} */
|
|
const text = ot.i18n.get(name, null, default_text);
|
|
|
|
return ["label", {
|
|
for : name,
|
|
class : "number-input",
|
|
data_i18n : name,
|
|
data_i18n_without : true,
|
|
title : text,
|
|
}, [
|
|
["input", {
|
|
type : "number",
|
|
id : name,
|
|
name : name,
|
|
...(value !== null ? {value : value} : {}),
|
|
...(minimum !== null ? {min : minimum} : {}),
|
|
...(maximum !== null ? {max : maximum} : {}),
|
|
...(step !== null ? {step : step} : {}),
|
|
...(on_change ? {on_change : on_change} : {}),
|
|
data_i18n : name,
|
|
data_i18n_without : true,
|
|
placeholder : text + "..."
|
|
}],
|
|
["span", {class : "minimum"}, minimum || "-∞"],
|
|
["span", {class : "maximum"}, maximum || "∞"]
|
|
]];
|
|
};
|
|
|
|
/**
|
|
* @param {!string} type
|
|
* @param {!string} name
|
|
* @param {?string} [value = null]
|
|
* @param {?number} [maximum_length = null]
|
|
* @param {?string} [pattern = null]
|
|
* @param {?components_event_callback} [on_change = null]
|
|
* @param {?string} [default_text = null]
|
|
* @returns {[string, Object.<string, (string|function)>, Array.<(string|[string, Object.<string, string>, string])>]}
|
|
* @access private
|
|
*/
|
|
const text = (type, name, value = null, maximum_length = null, pattern = null, on_change = null, default_text = null) => {
|
|
|
|
/** @type {string} */
|
|
const text = ot.i18n.get(name, null, default_text);
|
|
|
|
return ["label", {
|
|
for : name,
|
|
class : "input-" + type
|
|
}, [
|
|
["input", {
|
|
type : type,
|
|
id : name,
|
|
name : name,
|
|
...(value !== null ? {value : value} : {}),
|
|
...(pattern !== null ? {pattern : pattern} : {}),
|
|
...(on_change ? {on_input : on_change} : {}),
|
|
data_i18n : name,
|
|
data_i18n_without : true,
|
|
placeholder : text + "..."
|
|
}],
|
|
["span", {class : "length"}, 0],
|
|
...(maximum_length ? [["span", {class : "maximum-length"}, maximum_length || "∞"]] : [])
|
|
]];
|
|
};
|
|
|
|
/**
|
|
* @param {!string} name
|
|
* @param {?string} [value = null]
|
|
* @param {?number} [maximum_length = null]
|
|
* @param {?string} [pattern = null]
|
|
* @param {?components_event_callback} [on_change = null]
|
|
* @param {?string} [default_text = null]
|
|
* @returns {[string, Object.<string, (string|function)>, Array.<(string|[string, Object.<string, string>, string])>]}
|
|
* @access public
|
|
*/
|
|
this.text = (name, value = null, maximum_length = null, pattern = null, on_change = null, default_text = null) => (
|
|
text("text", name, value, maximum_length, pattern, on_change, default_text)
|
|
);
|
|
|
|
/**
|
|
* @param {!string} name
|
|
* @param {?string} [value = null]
|
|
* @param {?number} [maximum_length = null]
|
|
* @param {?string} [pattern = null]
|
|
* @param {?components_event_callback} [on_change = null]
|
|
* @param {?string} [default_text = null]
|
|
* @returns {[string, Object.<string, (string|function)>, Array.<(string|[string, Object.<string, string>, string])>]}
|
|
* @access public
|
|
*/
|
|
this.password = (name, value = null, maximum_length = null, pattern = null, on_change = null, default_text = null) => (
|
|
text("password", name, value, maximum_length, pattern, on_change, default_text)
|
|
);
|
|
|
|
/**
|
|
* @param {...[string, components_event_callback|null, string, string|null]} buttons
|
|
* @returns {[string, Object.<string, string>, Array.<(string|[string, Object.<string, string>, string])>]}
|
|
* @access public
|
|
*/
|
|
this.buttons = (...buttons) => ["div", {class : "buttons"}, buttons.map(button => self.button(...button))];
|
|
|
|
/**
|
|
* @param {!string} name
|
|
* @param {...any} items
|
|
* @returns {[string, Object.<string, string>, Array.<(string|[string, Object.<string, string>, string])>]}
|
|
*/
|
|
this.group = (name, ...items) => ["div", {
|
|
class : "group",
|
|
data_i18n : name,
|
|
data_i18n_without : true,
|
|
title : ot.i18n.get(name)
|
|
}, items];
|
|
|
|
/**
|
|
* @param {!string} name
|
|
* @param {!Array.<any|null>} structure
|
|
* @param {?components_event_callback} on_submit
|
|
* @param {...(components_event_callback|null)} [extra_actions]
|
|
* @returns {[string, Object.<string, (string|function)>, Array.<(string|[string, Object.<string, string>, string])>]}
|
|
* @access public
|
|
*/
|
|
this.form = (name, structure, on_submit, ...extra_actions) => ["form", {
|
|
class : "form",
|
|
data_name : name,
|
|
method : "get",
|
|
action : "#",
|
|
...(on_submit ? {on_submit : on_submit} : {})
|
|
}, [
|
|
["fieldset", {}, [
|
|
self.i18n(name, "legend"),
|
|
self.i18n(name + "_text", "p"),
|
|
["div", {class : "structure"}, structure.map(([type, name, ...item], i) => {
|
|
return ["div", {
|
|
data_i : i,
|
|
data_type : type,
|
|
data_i18n : name,
|
|
data_i18n_without : true,
|
|
title : ot.i18n.get(name, null, item[1] || name)
|
|
}, [
|
|
["label", {for : name}, [
|
|
self.i18n(name),
|
|
self.i18n(name + "_description")
|
|
]],
|
|
["span", {class : "input"}, self[type] ? [self[type](name, ...item)] : item],
|
|
["ul", {class : "errors"}]
|
|
]];
|
|
})],
|
|
["ul", {class : "form-errors"}],
|
|
self.buttons(
|
|
["clean", null, "clean"],
|
|
...extra_actions,
|
|
on_submit ? ["submit", null, "submit"] : null
|
|
)
|
|
]]
|
|
]];
|
|
|
|
/**
|
|
* @param {!HTMLElement} form
|
|
* @returns {HTMLFormElement|null}
|
|
* @access public
|
|
*/
|
|
this.get_form = form => {
|
|
|
|
if(form)
|
|
while(form.tagName.toLowerCase() != "form" && (form = form.parentNode));
|
|
|
|
return form;
|
|
};
|
|
|
|
/**
|
|
* @param {!HTMLElement} form
|
|
* @returns {Object.<string, (string|number|boolean|Array.<(string|number|boolean)>)>}
|
|
* @access public
|
|
*/
|
|
this.get_form_data = form => (
|
|
[...self.get_form(form).querySelectorAll("[name]")].reduce((data, item) => {
|
|
|
|
/** @type {string} */
|
|
let name_value = item.getAttribute("name");
|
|
/** @type {string} */
|
|
const name = name_value.replace(/\[\]$/i, ""),
|
|
/** @type {boolean} */
|
|
is_array = name_value != name;
|
|
|
|
is_array && !(name in data) && (data[name] = []);
|
|
|
|
switch(item.getAttribute("type")){
|
|
case "radio":
|
|
data[name] == [] && (data[name] = false);
|
|
item.checked && (data[name] = Number(item.value));
|
|
break;
|
|
case "checkbox":
|
|
if(is_array)
|
|
data[name].push(item.checked);
|
|
else
|
|
data[name] = item.checked;
|
|
break;
|
|
case "number":
|
|
if(is_array)
|
|
data[name].push(Number(item.value));
|
|
else
|
|
data[name] = Number(item.value);
|
|
break;
|
|
default:
|
|
if(is_array)
|
|
data[name].push(item.value);
|
|
else
|
|
data[name] = item.value;
|
|
break;
|
|
};
|
|
|
|
return data;
|
|
}, {})
|
|
);
|
|
|
|
/**
|
|
* @param {!(string|Array.<string>)} sources
|
|
* @param {?(string|Array.<string>)} [i18n = null]
|
|
* @param {?string} [default_text = null]
|
|
* @returns {[string, Object.<string, (string|number|function)>, (string|[string, Object.<string, string>, string])>]}
|
|
* @access public
|
|
*/
|
|
this.image = (sources, i18n = null, default_text = null) => {
|
|
|
|
/** @type {number} */
|
|
let i = 0;
|
|
|
|
Check.is_array(sources) || (sources = [sources]);
|
|
|
|
return ["span", {
|
|
class : "image",
|
|
data_status : "loading",
|
|
...(
|
|
i18n ? {data_i18n : i18n, title : ot.i18n.get(i18n, null, default_text)} :
|
|
default_text ? {title : default_text} :
|
|
{}),
|
|
}, [
|
|
["img", {
|
|
src : sources[i],
|
|
...(
|
|
i18n ? {data_i18n : i18n, alt : ot.i18n.get(i18n, null, default_text)} :
|
|
default_text ? {alt : default_text} :
|
|
{}),
|
|
on_error : (image, event) => {
|
|
if(i >= sources.length)
|
|
image.parentNode.setAttribute("data-status", "error");
|
|
else
|
|
image.parentNode.setAttribute("src", sources[++ i]);
|
|
},
|
|
on_load : (image, event) => {
|
|
image.parentNode.setAttribute("data-status", "loaded");
|
|
image.parentNode.querySelector("span").style.backgroundImage = "url('" + sources[i] + "')";
|
|
}
|
|
}],
|
|
["span"]
|
|
]];
|
|
};
|
|
|
|
constructor();
|
|
|
|
};
|
|
|
|
return Components;
|
|
})(); |