277 lines
7.0 KiB
JavaScript
277 lines
7.0 KiB
JavaScript
|
|
/*
|
||
|
|
Description: DOM Management and HTML builder
|
||
|
|
Date: 2025//3/6
|
||
|
|
Creator: Clemens Schwaighofer
|
||
|
|
*/
|
||
|
|
|
||
|
|
export {
|
||
|
|
HtmlElementCreator,
|
||
|
|
// deprecated name
|
||
|
|
HtmlElementCreator as DomManagement
|
||
|
|
};
|
||
|
|
import { deepCopyFunction, isObject } from './JavaScriptHelpers.mjs';
|
||
|
|
|
||
|
|
class HtmlElementCreator {
|
||
|
|
/**
|
||
|
|
* reates object for DOM element creation flow
|
||
|
|
* @param {String} tag must set tag (div, span, etc)
|
||
|
|
* @param {String} [id=''] optional set for id, if input, select will be used for name
|
||
|
|
* @param {String} [content=''] text content inside, is skipped if sub elements exist
|
||
|
|
* @param {Array} [css=[]] array for css tags
|
||
|
|
* @param {Object} [options={}] anything else (value, placeholder, OnClick, style)
|
||
|
|
* @return {Object} created element as an object
|
||
|
|
*/
|
||
|
|
cel(tag, id = '', content = '', css = [], options = {})
|
||
|
|
{
|
||
|
|
return {
|
||
|
|
tag: tag,
|
||
|
|
id: id,
|
||
|
|
name: options.name, // override name if set [name gets ignored in tree build anyway]
|
||
|
|
content: content,
|
||
|
|
css: css,
|
||
|
|
options: options,
|
||
|
|
sub: []
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* attach a cel created object to another to create a basic DOM tree
|
||
|
|
* @param {Object} base object where to attach/search
|
||
|
|
* @param {Object} attach the object to be attached
|
||
|
|
* @param {String} [id=''] optional id, if given search in base for this id and attach there
|
||
|
|
* @return {Object} "none", technically there is no return needed as it is global attach
|
||
|
|
*/
|
||
|
|
ael(base, attach, id = '')
|
||
|
|
{
|
||
|
|
if (id) {
|
||
|
|
// base id match already
|
||
|
|
if (base.id == id) {
|
||
|
|
// base.sub.push(Object.assign({}, attach));
|
||
|
|
base.sub.push(deepCopyFunction(attach));
|
||
|
|
} else {
|
||
|
|
// sub check
|
||
|
|
if (isObject(base.sub) && base.sub.length > 0) {
|
||
|
|
for (var i = 0; i < base.sub.length; i ++) {
|
||
|
|
// recursive call to sub element
|
||
|
|
this.ael(base.sub[i], attach, id);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
// base.sub.push(Object.assign({}, attach));
|
||
|
|
base.sub.push(deepCopyFunction(attach));
|
||
|
|
}
|
||
|
|
return base;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* directly attach n elements to one master base element
|
||
|
|
* this type does not support attach with optional id
|
||
|
|
* @param {Object} base object to where we attach the elements
|
||
|
|
* @param {...Object} attach attach 1..n: attach directly to the base element those attachments
|
||
|
|
* @return {Object} "none", technically there is no return needed, global attach
|
||
|
|
*/
|
||
|
|
aelx(base, ...attach)
|
||
|
|
{
|
||
|
|
for (var i = 0; i < attach.length; i ++) {
|
||
|
|
// base.sub.push(Object.assign({}, attach[i]));
|
||
|
|
base.sub.push(deepCopyFunction(attach[i]));
|
||
|
|
}
|
||
|
|
return base;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* same as aelx, but instead of using objects as parameters
|
||
|
|
* get an array of objects to attach
|
||
|
|
* @param {Object} base object to where we attach the elements
|
||
|
|
* @param {Array} attach array of objects to attach
|
||
|
|
* @return {Object} "none", technically there is no return needed, global attach
|
||
|
|
*/
|
||
|
|
aelxar(base, attach)
|
||
|
|
{
|
||
|
|
for (var i = 0; i < attach.length; i ++) {
|
||
|
|
// base.sub.push(Object.assign({}, attach[i]));
|
||
|
|
base.sub.push(deepCopyFunction(attach[i]));
|
||
|
|
}
|
||
|
|
return base;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* resets the sub elements of the base element given
|
||
|
|
* @param {Object} base cel created element
|
||
|
|
* @return {Object} returns reset base element
|
||
|
|
*/
|
||
|
|
rel(base)
|
||
|
|
{
|
||
|
|
base.sub = [];
|
||
|
|
return base;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* searches and removes style from css array
|
||
|
|
* @param {Object} _element element to work one
|
||
|
|
* @param {String} css style sheet to remove (name)
|
||
|
|
* @return {Object} returns full element
|
||
|
|
*/
|
||
|
|
rcssel(_element, css)
|
||
|
|
{
|
||
|
|
var css_index = _element.css.indexOf(css);
|
||
|
|
if (css_index > -1) {
|
||
|
|
_element.css.splice(css_index, 1);
|
||
|
|
}
|
||
|
|
return _element;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* adds a new style sheet to the element given
|
||
|
|
* @param {Object} _element element to work on
|
||
|
|
* @param {String} css style sheet to add (name)
|
||
|
|
* @return {Object} returns full element
|
||
|
|
*/
|
||
|
|
acssel(_element, css)
|
||
|
|
{
|
||
|
|
var css_index = _element.css.indexOf(css);
|
||
|
|
if (css_index == -1) {
|
||
|
|
_element.css.push(css);
|
||
|
|
}
|
||
|
|
return _element;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* removes one css and adds another
|
||
|
|
* is a wrapper around rcssel/acssel
|
||
|
|
* @param {Object} _element element to work on
|
||
|
|
* @param {String} rcss style to remove (name)
|
||
|
|
* @param {String} acss style to add (name)
|
||
|
|
* @return {Object} returns full element
|
||
|
|
*/
|
||
|
|
scssel(_element, rcss, acss)
|
||
|
|
{
|
||
|
|
this.rcssel(_element, rcss);
|
||
|
|
this.acssel(_element, acss);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* parses the object tree created with cel/ael and converts it into an HTML string
|
||
|
|
* that can be inserted into the page
|
||
|
|
* @param {Object} tree object tree with dom element declarations
|
||
|
|
* @return {String} HTML string that can be used as innerHTML
|
||
|
|
*/
|
||
|
|
phfo(tree)
|
||
|
|
{
|
||
|
|
let name_elements = [
|
||
|
|
'button',
|
||
|
|
'fieldset',
|
||
|
|
'form',
|
||
|
|
'iframe',
|
||
|
|
'input',
|
||
|
|
'map',
|
||
|
|
'meta',
|
||
|
|
'object',
|
||
|
|
'output',
|
||
|
|
'param',
|
||
|
|
'select',
|
||
|
|
'textarea',
|
||
|
|
];
|
||
|
|
let skip_options = [
|
||
|
|
'id',
|
||
|
|
'name',
|
||
|
|
'class',
|
||
|
|
];
|
||
|
|
let no_close = [
|
||
|
|
'input',
|
||
|
|
'br',
|
||
|
|
'img',
|
||
|
|
'hr',
|
||
|
|
'area',
|
||
|
|
'col',
|
||
|
|
'keygen',
|
||
|
|
'wbr',
|
||
|
|
'track',
|
||
|
|
'source',
|
||
|
|
'param',
|
||
|
|
'command',
|
||
|
|
// only in header
|
||
|
|
'base',
|
||
|
|
'meta',
|
||
|
|
'link',
|
||
|
|
'embed',
|
||
|
|
];
|
||
|
|
// holds the elements
|
||
|
|
var content = [];
|
||
|
|
// main part line
|
||
|
|
var line = '<' + tree.tag;
|
||
|
|
var i;
|
||
|
|
// first id, if set
|
||
|
|
if (tree.id) {
|
||
|
|
line += ' id="' + tree.id + '"';
|
||
|
|
// if anything input (input, textarea, select then add name too)
|
||
|
|
if (name_elements.includes(tree.tag)) {
|
||
|
|
line += ' name="' + (tree.name ? tree.name : tree.id) + '"';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// second CSS
|
||
|
|
if (isObject(tree.css) && tree.css.length > 0) {
|
||
|
|
line += ' class="';
|
||
|
|
for (i = 0; i < tree.css.length; i ++) {
|
||
|
|
line += tree.css[i] + ' ';
|
||
|
|
}
|
||
|
|
// strip last space
|
||
|
|
line = line.slice(0, -1);
|
||
|
|
line += '"';
|
||
|
|
}
|
||
|
|
// options is anything key = "data"
|
||
|
|
if (isObject(tree.options)) {
|
||
|
|
// ignores id, name, class as key
|
||
|
|
for (const [key, item] of Object.entries(tree.options)) {
|
||
|
|
if (!skip_options.includes(key)) {
|
||
|
|
line += ' ' + key + '="' + item + '"';
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// finish open tag
|
||
|
|
line += '>';
|
||
|
|
// push finished line
|
||
|
|
content.push(line);
|
||
|
|
// dive into sub tree to attach sub nodes
|
||
|
|
// NOTES: we can have content (text) AND sub nodes at the same level
|
||
|
|
// CONTENT (TEXT) takes preference over SUB NODE in order
|
||
|
|
if (isObject(tree.sub) && tree.sub.length > 0) {
|
||
|
|
if (tree.content) {
|
||
|
|
content.push(tree.content);
|
||
|
|
}
|
||
|
|
for (i = 0; i < tree.sub.length; i ++) {
|
||
|
|
content.push(this.phfo(tree.sub[i]));
|
||
|
|
}
|
||
|
|
} else if (tree.content) {
|
||
|
|
content.push(tree.content);
|
||
|
|
}
|
||
|
|
// if not input, image or br, then close
|
||
|
|
if (
|
||
|
|
!no_close.includes(tree.tag)
|
||
|
|
) {
|
||
|
|
content.push('</' + tree.tag + '>');
|
||
|
|
}
|
||
|
|
// combine to string
|
||
|
|
return content.join('');
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Create HTML elements from array list
|
||
|
|
* as a flat element without master object file
|
||
|
|
* Is like tree.sub call
|
||
|
|
* @param {Array} list Array of cel created objects
|
||
|
|
* @return {String} HTML String
|
||
|
|
*/
|
||
|
|
phfa(list)
|
||
|
|
{
|
||
|
|
var content = [];
|
||
|
|
for (var i = 0; i < list.length; i ++) {
|
||
|
|
content.push(this.phfo(list[i]));
|
||
|
|
}
|
||
|
|
return content.join('');
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// __EMD__
|