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. 432
      src/componentAncestry/addStyleAndFunctions.js
  3. 78
      src/componentAncestry/modifiableComponent.js
  4. 75
      src/componentAncestry/wrapperComponent.js

44
src/component.js

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

432
src/componentAncestry/addStyleAndFunctions.js

@ -8,394 +8,134 @@
* @abstract
* @extends ModifiableComponent
*/
class StyleStoringComponent extends ModifiableComponent {
class StyleAndScriptStoringComponent extends ModifiableComponent {
/**
* @property {boolean} _styleStoreInternal
* @type {ExtStore}
*/
_styleStoreInternal;
_styleClassesExtStore
/**
* The style-rule collection of this component
* @property {map<string,map<string,string>>} css
*/
#css;
* @type {ExtStore}
*/
_stylesExtStore;
/**
* @property {ExtStorageType} cssExtStore
* @type {Array<SStoreDefinition>}
*/
_cssExtStore;
_styles;
/**
* @property {HTMLStyleElement} styleTag
*/
#styleTag;
* @type {ExtStore}
*/
_functionsExtStore;
/**
* @type {Array<SStoreDefinition>}
*/
_functions;
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.
* 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) {
this._element.classList.add(styleClass);
this._styleClassesExtStore = new ExtStorage(
ExtStoreType.CENTRALIZED_DOC_HEAD,
OverwriteBehaviour.REPLACE
);
let selector = '.' + styleClass;
this._stylesExtStore = new ExtStorage(
ExtStoreType.INTERNALIZED_WITHIN,
OverwriteBehaviour.REPLACE
);
if (Object.keys(this.#css).includes(selector)) {
selector = resolveOverwrite(selector, this.#css);
}
this._styles = [];
this.#css[selector] = (modifier
? (modifier instanceof Modifier
? modifier._modifications
: modifier
)
: {}
this._functionsExtStore = new ExtStorage(
ExtStoreType.CENTRALIZED_DOC_HEAD,
OverwriteBehaviour.REPLACE
);
return this;
}
/**
*
* @param {boolean} storeInternal
* @returns {Component}
*/
setStylingsStorage(storeInternal) {
if (storeInternal) {
this._styleStoreInternal = storeInternal;
}
return this;
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 {ExtStorageType} storageType
* @param {ExtStorage|ExtStoreType|OverwriteBehaviour} extStore
* @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;
setStylingsStorage(extStore) {
if (extStore) {
if (extStore instanceof ExtStorage) {
this._stylesExtStore = extStore;
} else if (extStore instanceof ExtStoreType) {
this._stylesExtStore.setExtStoreType(extStore);
} else {
Object.entries(wenity.css)
.forEach(kv => {
this.#css[kv[0]] = kv[1];
});
this._stylesExtStore.OverwriteBehaviour(extStore);
}
}
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.setStylingsStorage(styleStoreInternal);
this.setCssStorage(cssStore);
/* invoke Storage Types/generate Element */
if (this._styleStoreInternal) {
wenity.html = super.generate();
} 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;
}
console.log("(Style)ExtStore was empty, did nothing");
}
return wenity;
return this;
}
}
/**
*
*/
class FunctionRegistration {
/**
* 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 {Function} func
* @param {OverwriteBehaviour} overwriteBehaviour
*/
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
* @param {ExtStorage|ExtStoreType|OverwriteBehaviour} extStore
* @returns {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;
setFunctionsStorage(extStore) {
if (extStore) {
if (extStore instanceof ExtStorage) {
this._stylesExtStore = extStore;
} else if (extStore instanceof ExtStoreType) {
this._stylesExtStore.setExtStoreType(extStore);
} else {
Object.entries(wenity.js)
.forEach(kv => {
this.#functions[kv[0]] = kv[1];
});
this._stylesExtStore.OverwriteBehaviour(extStore);
}
}
if (Object.hasOwn(wenity, "css") & wenity.css) {
super._appendChildComponent(wenity);
} else {
this._element.append(
(wenity instanceof WebTrinity
? wenity.html
: wenity
)
);
}
}
/**
*
* @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'));
}
/**
*
* @param {ExtStore} functionStore
* @returns {Component}
*/
setFunctionStorage(functionStore) {
if (functionStore) {
this._funcStore = functionStore;
}
if (this._funcStore === ExtStorageType.INTERNALIZED) {
this._funcStore = ExtStorageType.INDIVIDUALLY;
console.log("(Function)ExtStore was empty, did nothing");
}
return this;
}
/**
*
* @param {Function} func
* @param {string} underTheName
* @param {OverwriteBehaviour} overwriteBehaviour
* @returns
*/
registerFunction(func, underTheName = "", overwriteBehaviour = OverwriteBehaviour.RENAME) {
let registrationName = [underTheName.trim(), func.name.trim(), this._getFunctionName()]
.find(e !== '');
/* deal with name already present */
let functionNames = Object.keys(this.#functions);
if (functionNames.some(key => key.includes(registrationName))) {
registrationName = resolveOverwrite(
registrationName,
this.#functions
);
*
* @param {Function} func
* @param {string} underTheName
* @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
*/
registerFunction(func, underTheName = "", extStore = null) {
let registrationName = [
underTheName.trim(),
func.name.trim(),
`func${this._compName}${Object.keys(this._functions).length}`
]
.find(e => e !== '');
/*
if (!extStore) {
extStore = this._functionsExtStore;
} else if (extStore instanceof ExtStoreConfer) {
extStore = extStore.ensureStore();
} else {
extStore = new ExtStorage().setSingleValueToClone(extStore, this._functionsExtStore);
}
this.#functions[registrationName] = new FunctionRegistration(func, overwriteBehaviour);
return this;
}
/**
*
* @param {boolean} styleStoreInternal
* @param {ExtStorageType} cssStore
* @param {ExtStore} funcStore
* @class ScriptStoringComponent
*/
generate(styleStoreInternal = null, cssStore = null, funcStore = null) {
let wenity = super.generate(styleStoreInternal, cssStore);
*/
/* Sort Styling Storage Types */
this.setFunctionStorage(funcStore);
let entry = new SStoreDefinition();
entry._identifier = registrationName;
entry._definition = func;
entry._extStore = extStore;
if (this._funcStore.type === ExtStorageType.INDIVIDUALLY) {
let tag = this._generateScriptTag();
this._functions.push(entry);
switch (this._funcStore.position) {
case ExtStoragePos.WITHIN:
wenity.html.insertAdjacentElement(
"afterbegin",
tag
);
break;
//identifyAndResolveOverwrite(this._functions, registrationName, entry, extStore._overwriteBehaviour);
case ExtStoragePos.BEGINNING:
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;
return this;
}
}

78
src/componentAncestry/modifiableComponent.js

@ -4,41 +4,45 @@
* @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
* @abstract
*/
class ModifiableComponent extends ChildbearerComponent {
/**
* @type {Modifier} modifier
*/
_modifier;
constructor(element, attr = {}) {
super(element, attr);
this._modifier = new Modifier();
}
/**
* Sets, updates or overwrites the Modifier-Object for this component
* @param {Modifier} modifier
* @returns {Componant} this component object
* @param {boolean|ExtStorage|ExtStoreType|OverwriteBehaviour} [extStore=null]
* @returns {Component} this component object
*/
modifier(modifier) {
this._modifier = this._modifier
.join(modifier.ensureModifier());
modifier(modifier, underTheName = "", extStore = false) {
if (underTheName === "") {
underTheName = `${this._compName}-style-${this._styles.length}`;
}
if (!extStore) {
this._modifier = this._modifier
.join(modifier.ensureModifier());
} else {
this._styles.push(
new SStoreDefinition(
underTheName,
modifier.ensureModifier()
)
);
}
return this;
}
@ -51,40 +55,4 @@ class ModifiableComponent extends ChildbearerComponent {
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;
}
}

75
src/componentAncestry/wrapperComponent.js

@ -35,16 +35,21 @@ class ElementWrapper {
* @param {map<string,string>} attr Specific already known attributes
*/
constructor(element, attr = {}) {
let akeys = Object.keys(attr);
for (let i = 0; i < akeys.length; i++) {
element.setAttribute(akeys[i], attr[akeys[i]]);
}
this._element = element;
fillAttrsInContainerByCb(
attr,
element,
function cb(k, v, con) {
con.setAttribute(k, v);
}
);
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) {
this._givenName = name;
this.setAttribute('data-compel', name);
Page.registerComponent(name);
@ -57,7 +62,11 @@ class ElementWrapper {
* @returns {Component} this component object
*/
text(text) {
this._element.innerText = text;
if (this._element instanceof HTMLInputElement && this._element.type === "text") {
this._element.value = text;
} else {
this._element.innerText = text;
}
return this;
}
@ -103,18 +112,6 @@ class ElementWrapper {
this._element.addEventListener(theEvent, theListener, options)
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 {
/**
* @property {Alignment} alignment
* @type {Array<Component>} children
*/
_children;
/**
* @type {Alignment} alignment
*/
_alignment;
/**
* @property {Arrangement} arrangement
* @type {Arrangement} arrangement
*/
_arrangement;
constructor(element, attr = {}) {
super(element, attr);
this._children = [];
}
/**
* @todo: Unify logic extract modifications into responsible construct
@ -171,30 +176,6 @@ class ChildbearerComponent extends ElementWrapper {
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.
* Either as one component or a list/array of components.
@ -211,7 +192,7 @@ class ChildbearerComponent extends ElementWrapper {
this.childContext(component[i]);
}
} else {
this._appendChildComponent(component);
this._children.push(component);
}
return this;
}

Loading…
Cancel
Save