Browse Source

STEP,UNSTABLE,REFA: Restructured organization of Component and its ancestry

master
chris 2 months ago
parent
commit
ec298757c2
  1. 44
      src/component.js
  2. 414
      src/componentAncestry/addStyleAndFunctions.js
  3. 74
      src/componentAncestry/modifiableComponent.js
  4. 69
      src/componentAncestry/wrapperComponent.js

44
src/component.js

@ -4,19 +4,47 @@
* @copyright by its creator Christian Martin * @copyright by its creator Christian Martin
*/ */
/**
* 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.
* @property {Map<string, SStoreDefinition>} _style
*/
class Component extends StyleAndScriptStoringComponent {
/**
* @type {boolean}
*/
#isCompel;
/**
* @type {WebTrinity}
*/
_wenity;
/** /**
* A chainable HTMLElement builder. * @type {Array<any>}
*/ */
class Component extends ScriptStoringComponent { _toRegister;
/**
* @type {boolean}
*/
_isContextMenu;
/**
* Initializes the component
* @param {HTMLElement} element the base element
* @param {Map<string,string>} attr Specific already known attributes
*/
constructor(element, attr = {}) { constructor(element, attr = {}) {
super(element, attr); super(element, attr);
this._modifier = new Modifier().margin(new Sides().all(0)); this.#isCompel = false;
var akeys = Object.keys(attr); this._isContextMenu = false;
for (let i = 0; i < akeys.length; i++) {
element.setAttribute(akeys[i], attr[akeys[i]]); this._modifier = new Modifier()
} .margin(new Sides().all(0));
this._element = element; this._modifier._modifications['display'] = "flex";
this._toRegister = []; this._toRegister = [];
} }

414
src/componentAncestry/addStyleAndFunctions.js

@ -8,303 +8,94 @@
* @abstract * @abstract
* @extends ModifiableComponent * @extends ModifiableComponent
*/ */
class StyleStoringComponent extends ModifiableComponent { class StyleAndScriptStoringComponent extends ModifiableComponent {
/** /**
* @property {boolean} _styleStoreInternal * @type {ExtStore}
*/ */
_styleStoreInternal; _styleClassesExtStore
/** /**
* The style-rule collection of this component * @type {ExtStore}
* @property {map<string,map<string,string>>} css
*/ */
#css; _stylesExtStore;
/** /**
* @property {ExtStorageType} cssExtStore * @type {Array<SStoreDefinition>}
*/ */
_cssExtStore; _styles;
/** /**
* @property {HTMLStyleElement} styleTag * @type {ExtStore}
*/ */
#styleTag; _functionsExtStore;
constructor(element, attr = {}) {
super(element, attr);
this.#css = {};
this._styleStoreInternal = true;
this._cssExtStore = ExtStorageType.CENTRALIZED;
this.#css = {};
this.addStyleClass(this._compName);
}
/** /**
* Ads class to classList via HTMLElement.classList.add() method. * @type {Array<SStoreDefinition>}
* Further collects rules in a property until generate is called.
* @override
* @param {string} styleClass
* @param {Modifier} modifier
* @param {OverwriteBehaviour} overwriteBehaviour
* @returns {Componant} this component object
*/ */
addStyleClass(styleClass, modifier = null, overwriteBehaviour = OverwriteBehaviour.REPLACE) { _functions;
this._element.classList.add(styleClass);
let selector = '.' + styleClass; constructor(element, attr = {}) {
super(element, attr);
if (Object.keys(this.#css).includes(selector)) {
selector = resolveOverwrite(selector, this.#css);
}
this.#css[selector] = (modifier this._styleClassesExtStore = new ExtStorage(
? (modifier instanceof Modifier ExtStoreType.CENTRALIZED_DOC_HEAD,
? modifier._modifications OverwriteBehaviour.REPLACE
: modifier
)
: {}
); );
return this; this._stylesExtStore = new ExtStorage(
} ExtStoreType.INTERNALIZED_WITHIN,
OverwriteBehaviour.REPLACE
/**
*
* @param {boolean} storeInternal
* @returns {Component}
*/
setStylingsStorage(storeInternal) {
if (storeInternal) {
this._styleStoreInternal = storeInternal;
}
return this;
}
/**
*
* @param {ExtStorageType} storageType
* @returns {Component}
*/
setCssStorage(storageType) {
if (storageType) {
this._cssExtStore = storageType;
}
return this;
}
/**
* Takes all "collected" styling rules associated to a selector (in #css)
* and inserts them as innerText to a created HTMLStyleElement.
* @returns {HTMLStyleElement}
*/
_generateStyleTag() {
return Object.keys(this.#css)
.reduce((styleTag, selector) => {
let styleRules = this.#css[selector];
let rulesText = Object.keys(styleRules)
.map(key => `${key}:${styleRules[key]}; `)
.join(' ');
styleTag.innerText += `${selector} {${rulesText}} `;
return styleTag;
}, document.createElement('style'));
}
/**
* @override
* @param {StyleStoringComponent|Component|ChainableModifier} component
*/
_appendChildComponent(component) {
if (!(component instanceof Component)) {
component = component.toComponent();
}
let wenity = component.generate();
if (Object.hasOwn(wenity, "css") & wenity.css) {
if (wenity.css instanceof HTMLStyleElement) {
this.#styleTag = wenity.css;
} else {
Object.entries(wenity.css)
.forEach(kv => {
this.#css[kv[0]] = kv[1];
});
}
}
this._element.append(
(wenity instanceof WebTrinity
? wenity.html
: wenity
)
); );
}
/**
* @override
* @param {boolean|null} styleStoreInternal
* @param {ExtStorageType|null} cssStore
* @returns {WebTrinity}
* @class StyleStoringComponent
*/
generate(styleStoreInternal = null, cssStore = null) {
let wenity = new WebTrinity();
/* Sort Styling Storage Types */ this._styles = [];
this.setStylingsStorage(styleStoreInternal);
this.setCssStorage(cssStore);
/* invoke Storage Types/generate Element */ this._functionsExtStore = new ExtStorage(
if (this._styleStoreInternal) { ExtStoreType.CENTRALIZED_DOC_HEAD,
wenity.html = super.generate(); OverwriteBehaviour.REPLACE
} else {
this.addStyleClass(this._compName, this._modifier);
wenity.html = this._element;
}
if (this._cssExtStore === ExtStorageType.CENTRALIZED) {
Object.entries(this.#css)
.forEach(kv => Page.registerStyling(kv[0], kv[1]));
} else {
switch (this._cssExtStore) {
case ExtStorageType.INDIVIDUALLY:
let tag = this._generateStyleTag();
tag.setAttribute('data-compel-for', this._compName);
document.querySelector('head')
.insertAdjacentElement(
"beforeend",
tag
); );
break;
case ExtStorageType.COLLECTED:
wenity.css = this.#css;
break;
}
}
return wenity; this._functions = [];
} }
}
/** /**
* Defines/Sets the general "storage-behaviour" for styling of this component.
* Further for potential css definitions.
* If a styling/modifier/class is passed via the corresponding methods/way,
* an alternative behaviour can be passed as a parameter - which will only be applied on/for that single one.
* *
* @param {ExtStorage|ExtStoreType|OverwriteBehaviour} extStore
* @returns {Component}
*/ */
class FunctionRegistration { setStylingsStorage(extStore) {
/** if (extStore) {
* if (extStore instanceof ExtStorage) {
* @param {Function} func this._stylesExtStore = extStore;
* @param {OverwriteBehaviour} overwriteBehaviour } else if (extStore instanceof ExtStoreType) {
*/ this._stylesExtStore.setExtStoreType(extStore);
constructor(func, overwriteBehaviour = OverwriteBehaviour.RENAME) {
this.fun = func;
this.overwrite = overwriteBehaviour;
}
}
/**
*
*/
class ScriptStoringComponent extends StyleStoringComponent {
/**
* Collection of component associated/used functions
* @property {map<string,FunctionRegistration>} functions
*/
#functions;
/**
* @property {ExtStore}
*/
_funcStore;
/**
* @property {HTMLScriptElement} scriptTag
*/
#scriptTag;
constructor(element, attr = {}) {
super(element, attr);
this.#functions = {};
this._funcStore = StoreExtAs.CENTRALIZED.positionedAt().BEGINNING();
}
/**
* @override
* @param {ScriptStoringComponent|Component|ChainableModifier} component
*/
_appendChildComponent(component) {
if (!(component instanceof Component)) {
component = component.toComponent();
}
let wenity = component.generate();
if (Object.hasOwn(wenity, "js") & wenity.js) {
if (wenity.js instanceof HTMLScriptElement) {
this.#scriptTag = wenity.js;
} else { } else {
Object.entries(wenity.js) this._stylesExtStore.OverwriteBehaviour(extStore);
.forEach(kv => {
this.#functions[kv[0]] = kv[1];
});
} }
}
if (Object.hasOwn(wenity, "css") & wenity.css) {
super._appendChildComponent(wenity);
} else { } else {
this._element.append( console.log("(Style)ExtStore was empty, did nothing");
(wenity instanceof WebTrinity
? wenity.html
: wenity
)
);
}
} }
return this;
/**
*
* @param {string} nameAddition
* @returns
*/
_getFunctionName(nameAddition = "") {
return `func${this.#functions.length}${nameAddition}`;
}
/**
* @todo potential code duplication - and doc
* @returns {HTMLScriptElement}
*/
_generateScriptTag() {
return Object.keys(this.#functions)
.reduce((scriptTag, funName) => {
let funReg = this.#functions[funName];
if (funReg.fun.startsWith('function')) {
let funcNameDeclaration = `function ${funName}`;
scriptTag.innerText += (funReg.fun.startsWith(funcNameDeclaration)
? funReg.fun
: funReg.fun.split('(')
.replace((a, c, i) => (i === 0 ? [funcNameDeclaration] : [...a, c]),)
.join('(')
)
} else {
scriptTag.innerText += `const ${funName} = ${funReg.fun}; `;
}
return scriptTag;
}, document.createElement('script'));
} }
/** /**
* Defines/Sets the general "storage-behaviour" for functions of this component.
* If a function is passed via "registerFunction",
* an alternative behaviour can be passed as a parameter - which will only be applied on/for that single one.
* *
* @param {ExtStore} functionStore * @param {ExtStorage|ExtStoreType|OverwriteBehaviour} extStore
* @returns {Component} * @returns {Component}
*/ */
setFunctionStorage(functionStore) { setFunctionsStorage(extStore) {
if (functionStore) { if (extStore) {
this._funcStore = functionStore; if (extStore instanceof ExtStorage) {
this._stylesExtStore = extStore;
} else if (extStore instanceof ExtStoreType) {
this._stylesExtStore.setExtStoreType(extStore);
} else {
this._stylesExtStore.OverwriteBehaviour(extStore);
} }
if (this._funcStore === ExtStorageType.INTERNALIZED) { } else {
this._funcStore = ExtStorageType.INDIVIDUALLY; console.log("(Function)ExtStore was empty, did nothing");
} }
return this; return this;
} }
@ -313,89 +104,38 @@ class ScriptStoringComponent extends StyleStoringComponent {
* *
* @param {Function} func * @param {Function} func
* @param {string} underTheName * @param {string} underTheName
* @param {OverwriteBehaviour} overwriteBehaviour * @param {ExtStorage|ExtStoreType|ExtStorePosition|OverwriteBehaviour|EXPosConfer|ESOverwriteConfer} extStore
* if a unique definition is desired, all constants or configurator objects are allowed - they will be processed accordingly
* @returns * @returns
*/ */
registerFunction(func, underTheName = "", overwriteBehaviour = OverwriteBehaviour.RENAME) { registerFunction(func, underTheName = "", extStore = null) {
let registrationName = [underTheName.trim(), func.name.trim(), this._getFunctionName()]
.find(e !== '');
/* deal with name already present */ let registrationName = [
let functionNames = Object.keys(this.#functions); underTheName.trim(),
if (functionNames.some(key => key.includes(registrationName))) { func.name.trim(),
registrationName = resolveOverwrite( `func${this._compName}${Object.keys(this._functions).length}`
registrationName, ]
this.#functions .find(e => e !== '');
);
}
this.#functions[registrationName] = new FunctionRegistration(func, overwriteBehaviour);
return this;
}
/** /*
* if (!extStore) {
* @param {boolean} styleStoreInternal extStore = this._functionsExtStore;
* @param {ExtStorageType} cssStore } else if (extStore instanceof ExtStoreConfer) {
* @param {ExtStore} funcStore extStore = extStore.ensureStore();
* @class ScriptStoringComponent } else {
extStore = new ExtStorage().setSingleValueToClone(extStore, this._functionsExtStore);
}
*/ */
generate(styleStoreInternal = null, cssStore = null, funcStore = null) {
let wenity = super.generate(styleStoreInternal, cssStore);
/* Sort Styling Storage Types */ let entry = new SStoreDefinition();
this.setFunctionStorage(funcStore); entry._identifier = registrationName;
entry._definition = func;
entry._extStore = extStore;
if (this._funcStore.type === ExtStorageType.INDIVIDUALLY) { this._functions.push(entry);
let tag = this._generateScriptTag();
switch (this._funcStore.position) { //identifyAndResolveOverwrite(this._functions, registrationName, entry, extStore._overwriteBehaviour);
case ExtStoragePos.WITHIN:
wenity.html.insertAdjacentElement(
"afterbegin",
tag
);
break;
case ExtStoragePos.BEGINNING: return this;
document.querySelector('head')
.insertAdjacentElement(
"beforeend",
tag
);
break;
case ExtStoragePos.END:
document.querySelector('body')
.insertAdjacentElement(
"beforeend",
tag
);
break;
case ExtStoragePos.BEFORE:
case ExtStoragePos.SEGMENT_BEGIN:
default:
wenity.js = tag;
break;
}
} else {
switch (this._funcStore.type) {
case ExtStorageType.COLLECTED:
case ExtStorageType.CENTRALIZED:
default:
/**
* @todo implement difference between collected and centralized in
* generate, appendChild and childContext function-chain
*/
Object.entries(this.#functions)
.forEach(tuple => {
Page.registerPageFunction(
fun = tuple[1].fun,
underTheName = tuple[0],
overwriteBehaviour = tuple[1].overwrite
);
});
//wenity.js = tag;
}
}
return wenity;
} }
} }

74
src/componentAncestry/modifiableComponent.js

@ -4,41 +4,45 @@
* @copyright by its creator Christian Martin * @copyright by its creator Christian Martin
*/ */
/**
*
* @param {map<string,any>} attrs
* @param {Object} intoContainer
* @param {Function<string, any, Object>} cb
* @returns {Object} the filled container
*/
function fillAttrsInContainerByCb(attrs, intoContainer, cb) {
let keys = Object.keys(attrs);
for (let i = 0; i < keys.length; i++) {
cb(keys[i], attrs[keys[i]], intoContainer);
}
return intoContainer;
}
/** /**
* @extends ChildbearerComponent * @extends ChildbearerComponent
* @abstract * @abstract
*/ */
class ModifiableComponent extends ChildbearerComponent { class ModifiableComponent extends ChildbearerComponent {
/**
* @type {Modifier} modifier
*/
_modifier; _modifier;
constructor(element, attr = {}) { constructor(element, attr = {}) {
super(element, attr); super(element, attr);
this._modifier = new Modifier();
} }
/** /**
* Sets, updates or overwrites the Modifier-Object for this component * Sets, updates or overwrites the Modifier-Object for this component
* @param {Modifier} modifier * @param {Modifier} modifier
* @returns {Componant} this component object * @param {boolean|ExtStorage|ExtStoreType|OverwriteBehaviour} [extStore=null]
* @returns {Component} this component object
*/ */
modifier(modifier) { modifier(modifier, underTheName = "", extStore = false) {
if (underTheName === "") {
underTheName = `${this._compName}-style-${this._styles.length}`;
}
if (!extStore) {
this._modifier = this._modifier this._modifier = this._modifier
.join(modifier.ensureModifier()); .join(modifier.ensureModifier());
} else {
this._styles.push(
new SStoreDefinition(
underTheName,
modifier.ensureModifier()
)
);
}
return this; return this;
} }
@ -51,40 +55,4 @@ class ModifiableComponent extends ChildbearerComponent {
return new ChainableModifier(this); return new ChainableModifier(this);
} }
/**
* @inheritdoc
* @override
* @param {Component|ChainableModifier|} component
*/
_appendChildComponent(component) {
this._element.append(
(component instanceof Component
? component
: component.toComponent()
)
.generate()
);
}
/**
* @inheritdoc
* @override
* @returns {HTMLElement}
* @class ModifiableComponent
*/
generate() {
this._modifier._modifications["justify-content"] = this._arrangement;
this._modifier._modifications['display'] = "flex";
this._modifier._modifications["align-content"] = this._alignment;
this._modifier._modifications["align-items"] = this._alignment;
this._modifier._modifications["text-align"] = this._alignment;
fillAttrsInContainerByCb(
this._modifier._modifications,
this._element,
(key, val, el) => { el.style[key] = val; }
);
return this._element;
}
} }

69
src/componentAncestry/wrapperComponent.js

@ -35,13 +35,18 @@ class ElementWrapper {
* @param {map<string,string>} attr Specific already known attributes * @param {map<string,string>} attr Specific already known attributes
*/ */
constructor(element, attr = {}) { constructor(element, attr = {}) {
let akeys = Object.keys(attr); fillAttrsInContainerByCb(
for (let i = 0; i < akeys.length; i++) { attr,
element.setAttribute(akeys[i], attr[akeys[i]]); element,
function cb(k, v, con) {
con.setAttribute(k, v);
} }
this._element = element; );
this._compName = Page.autoRegisterComponent(); this._compName = Page.autoRegisterComponent();
this.setAttribute('data-autocompel', this._compName); element.setAttribute('data-autocompel', this._compName);
this._element = element;
this.addStyleClass(this._compName);
} }
setComponentName(name) { setComponentName(name) {
@ -57,7 +62,11 @@ class ElementWrapper {
* @returns {Component} this component object * @returns {Component} this component object
*/ */
text(text) { text(text) {
if (this._element instanceof HTMLInputElement && this._element.type === "text") {
this._element.value = text;
} else {
this._element.innerText = text; this._element.innerText = text;
}
return this; return this;
} }
@ -103,18 +112,6 @@ class ElementWrapper {
this._element.addEventListener(theEvent, theListener, options) this._element.addEventListener(theEvent, theListener, options)
return this; return this;
} }
/**
* Ends chain.
* Applies all modifications on the element.
* Returns the constructed HTMLElement of this Component.
* @class ElementWrapper
* @returns {HTMLElement}
* @class ElementWrapper
*/
generate() {
return this._element;
}
} }
@ -124,15 +121,23 @@ class ElementWrapper {
*/ */
class ChildbearerComponent extends ElementWrapper { class ChildbearerComponent extends ElementWrapper {
/** /**
* @property {Alignment} alignment * @type {Array<Component>} children
*/
_children;
/**
* @type {Alignment} alignment
*/ */
_alignment; _alignment;
/** /**
* @property {Arrangement} arrangement * @type {Arrangement} arrangement
*/ */
_arrangement; _arrangement;
constructor(element, attr = {}) {
super(element, attr);
this._children = [];
}
/** /**
* @todo: Unify logic extract modifications into responsible construct * @todo: Unify logic extract modifications into responsible construct
@ -171,30 +176,6 @@ class ChildbearerComponent extends ElementWrapper {
return this; return this;
} }
/**
* Defines how a child Component is to be appended.
* @param {Component} component the child component to add it.
*/
_appendChildComponent(component) {
this._element.append(
component.generate()
);
}
/**
* @override
* @inheritdoc
* @class ChildbearerComponent
*/
generate() {
this._element.style.justifyContent = this._arrangement;
this._element.style.display = "flex";
this._element.style.alignContent = this._alignment;
this._element.style.alignItems = this._alignment;
this._element.style.textAlign = this._alignment;
return super.generate();
}
/** /**
* Opens a context to create children elements. * Opens a context to create children elements.
* Either as one component or a list/array of components. * Either as one component or a list/array of components.
@ -211,7 +192,7 @@ class ChildbearerComponent extends ElementWrapper {
this.childContext(component[i]); this.childContext(component[i]);
} }
} else { } else {
this._appendChildComponent(component); this._children.push(component);
} }
return this; return this;
} }

Loading…
Cancel
Save