/** * Represents the most basic and simple form of a Component. * It is mainly a collection of wrapper methods * around the HTMLElement methods to make them chainable. * It serves as base for further functionallity extensions. * @abstract */ class ElementWrapper { /** * The basic HTMLElement the Component is wrapped around. * It will be modified in several ways and in the end returned. * @type {HTMLElement} */ _element; /** * The auto-generated name of the component. * @type {string} */ _compName; /** * The auto-generated name of the component. * @type {string} */ _givenName; /** * @type {Component} */ _parentComponent; /** * Initializes the component * @param {HTMLElement} element the base element * @param {map} attr Specific already known attributes */ constructor(element, attr = {}) { helperFun.fillAttrsInContainerByCb( attr, element, function (k, v, con) { con.setAttribute(k, v); } ); this._compName = Page.autoRegisterComponent(); element.setAttribute('data-autocompel', this._compName); this._element = element; this.addStyleClass(this._compName); } setComponentName(name) { this._givenName = name; this.setAttribute('data-compel', name); Page.registerComponent(name); return this; } /** * (Wrapper) Sets the innerText of the element * @todo add Alignment of text functionality * @param {string} text * @returns {Component} this component object */ text(text) { if (this._element instanceof HTMLInputElement && this._element.type === "text") { this._element.value = text; } else { this._element.innerText = text; } return this; } /** * Wrapper to set the HTMLElement.title attribute * @param {string} text * @returns {Component} */ title(text) { this._element.title = text; return this; } /** * Wrapper for HTMLElement.classList.add() * @param {string} styleClass * @returns {Component} this component object */ addStyleClass(styleClass) { this._element.classList.add(styleClass); return this; } /** * Wrapper for the HTMLElement.setAttribute() method. * @param {string} key * @param {string} value * @returns {Component} this component object */ setAttribute(key, value) { this._element.setAttribute(key, value); return this; } /** * Wrapper for the HTMLElement.addEventListener() * @param {keyof WindowEventMap|CommonEvents} theEvent * @param {Function} theListener * @param {boolean|AddEventListenerOptions} options * @returns {Component} this component object */ addEventListener(theEvent, theListener, options = null) { this._element.addEventListener(theEvent, theListener, options) return this; } } /** * @inheritdoc * @extends ElementWrapper * @abstract */ class ChildbearerComponent extends ElementWrapper { /** * @type {Array} children */ _children; /** * @type {Alignment} alignment */ _alignment; /** * @type {Arrangement} arrangement */ _arrangement; constructor(element, attr = {}) { super(element, attr); this._children = []; } /** * @todo: Unify logic extract modifications into responsible construct * @todo: Make it work as expected, fix docu * @todo: Differentiate between directions (horizontal, vertiacl) * * Sets the alignment (modifications) for this element or more specific for its children. * @param {Alignment} alignment * @returns {Component} this component object */ alignment(alignment) { /* this._modifier._modifications["display"] = "flex"; this._modifier._modifications["align-content"] = alignment; this._modifier._modifications["align-items"] = alignment; this._modifier._modifications["text-align"] = alignment; */ this._alignment = alignment; return this; } /** * @todo: Unify logic extract modifications into responsible construct * @todo: Differentiate between directions (horizontal, vertical) * @todo: Make it work as expected, fix docu * * Sets the arrangement (modifications) for this element or more specific for its children. * @param {Arrangement} arrangement * @returns {Component} this component object */ arrangement(arrangement) { /* this._modifier._modifications["justify-content"] = arrangement; */ this._arrangement = arrangement; return this; } /** * Opens a context to create children elements. * Either as one component or a list/array of components. * @param {Component|Array} component * @returns {Component} this component object */ childContext(component) { if (!component) return this; if (arguments.length > 1) { for (let i = 0; i < arguments.length; i++) { this.childContext(arguments[i]); } } else if (component instanceof Array) { for (let i = 0; i < component.length; i++) { this.childContext(component[i]); } } else { if (!(component instanceof Component)) { this.childContext(component.toComponent()) } else { this._children.push(component.end()); } } return this; } /** * Ends chain for the current component. * Returns the builder object. * The Component that is selected there will be set as child to this one. * * This funciton is a convenience function. * Mainly to offer the possibility to reduce the depth of method chains. * Especially in the case of components with only one child. * * @returns {builder} the given */ chainChild() { return builder._nextComponent(this); } /** * Ends a chainChild - chain. * If components are setup as chainChild * they would be wrongfully taken through childContext(). * Therefore thoose chains are recursively resolved through this method. * @returns {Component} */ end() { let parent = this._parentComponent; if (parent) { this._parentComponent = null; return parent .childContext(this) .end(); } return this; } }