You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

313 lines
9.7 KiB

/**
* This class defines the Component generator.
* It externalizes all decision making about script or style storage from the component.
* The component stores the generator (if set, if not =default or passed down from parent component).
* The CompelGenerator class enables the setup/definition of storage, generation and distribution.
*
* Further if other frameworks are targeted:
* if the components should be generated in a manner
* that they fullfill the setup/look of other framework-components.
* Only the generator has to be modified, implemented, extended ...
* not the component, modifier or any other of the classes.
*
* Therefore the usages of CompelGenerator-feature-logic resets all style and script storages to local.
* Only towards the end (when "generate()" is called) any of that will be resolved.
*/
class CompelGenerator {
/**
* @param {ExtStorage} styleStore default ExtStoreType.INTERNALIZED_WITHIN
* @param {ExtStorage} functionStore default ExtStoreType.CENTRALIZED_DOC_HEAD
*/
constructor(
styleStore = ExtStoreType.INTERNALIZED_WITHIN
.setOverwriteBehaviour(OverwriteBehaviour.REPLACE),
functionStore = ExtStoreType.CENTRALIZED_DOC_HEAD
.setOverwriteBehaviour(OverwriteBehaviour.REPLACE)
) {
this._styleStore = styleStore;
this._functionStore = functionStore;
}
/**
* Deals with the direct component stylings
* @param {Component} component
* @param {Array<WebTrinity>} childrenWenity
* @param {ExtStorage} extStore
* @returns {Array<SStoreDefinition>}
*/
processStyles(component, extStore = null) {
extStore = (extStore
? extStore
: component._stylesExtStore
)
.setupForGeneralStyling();
let forCollection = [];
let counter = 0;
for (const ssd of component._styles) {
/* Make sure that the type is unified for later processing */
if (ssd._definition instanceof Modifier) {
ssd._definition = ssd._definition._modifications;
}
/* Check/Ensure proper ExtStorageType for following comparison */
/**
* @type {ExtStorage}
*/
let curExtStore = extStore;
if (ssd.hasOwnProperty("_extStore") && ssd._extStore) {
curExtStore = ssd._extStore.setupForGeneralStyling();
}
if (curExtStore.getStylingDistribution()(ssd, component._element, counter)) {
forCollection.push(ssd);
}
}
return forCollection;
}
/**
* First deals with the scripts/functions.
*
* @param {Component} component
* @param {Array<WebTrinity>} childrenWenity
* @param {ExtStorage} extStore
* @returns {Array<SStoreDefinition>}
*/
processFunctions(component, extStore = null) {
extStore = (extStore
? extStore
: component._functionsExtStore
)
.setupForFunctions();
const forCollection = new Map();
const collectForBefore = [];
let counter = 0;
for (const ssd of component._functions) {
/* Make sure that the type is unified for later processing */
let curExtStore = extStore;
if (Object.hasOwn(ssd, "_extStore") && ssd._extStore) {
curExtStore = ssd._extStore.setupForFunctions();
}
if (curExtStore.getFunctionDistribution()(ssd, counter)) {
if (curExtStore._position.BEFORE) {
collectForBefore.push(ssd);
} else {
if (!forCollection.has(curExtStore)) {
forCollection.set(curExtStore, []);
}
forCollection.get(curExtStore).push(ssd);
}
}
}
return forCollection;
}
/**
* checks if the source has the extStoreType
* fills the target extStoreType-array with the corr. elements of source.
* @param {Map<ExtStoreType, Array<SStoreDefinition>>} source
* @param {Map<ExtStoreType, Array<SStoreDefinition>>} target
* @param {ExtStoreType} extStoreType
* @returns
*/
transferCollectedFunctions(source, target, extStoreType) {
if (source) {
if (source.has(extStoreType)) {
if (funcCollections.has(extStoreType)) {
target.get(extStoreType)
.push(source.get(extStoreType))
} else {
target.set(
extStoreType,
source.get(extStoreType)
);
}
}
}
return target;
}
/**
*
*
* @param {Map<ExtStoreType, *>} extFuncMap
* @param {ExtStorageType} extStoreType
*/
dealCollectedFuncs(extFuncMap, extStoreType) {
if (extFuncMap.has(extStoreType)) {
let collectionScriptTag = generateAndFillScriptTag(extFuncMap.get(extStoreType));
if (extStoreType === ExtStoreType.COLLECTED_SEGMENT_BEGIN) {
this._element.insertAdjacentElement(
"afterbegin",
generateAndFillScriptTag(segment)
);
} else {
Page.addElementToPage(
collectionScriptTag,
extStoreType
);
}
}
}
/**
* Generates and appends a child Component.
* @param {Component} parent component the child component to add it.
* @param {Component|WebTrinity|string} child
* @returns {WebTrinity}
*/
appendChildComponent(parent, child) {
let childWT = new WebTrinity();
if (child instanceof Component) {
childWT = child.generate(this);
}
if (child instanceof WebTrinity) {
childWT = child;
}
if (child instanceof HTMLElement) {
console.log("No wenity set - htmlEl was given");
childWT.compext = child;
}
parent._element.append(childWT.compext);
return childWT;
}
/**
* Iterates over the children of the component
* and calls generate on each child.
* The resulting compext (the text of the component) is added/appended accordingly.
* If the generation returns with delegatable scripts or styles
* the WebTrinity object is collected in an array,
* which will be returned.
*
* @param {Component} component
* @returns {Array<WebTrinity>}
*/
resolveChildren(component, styleStore, functionStore) {
/**
* @type {Array<WebTrinity>}
*/
let wenities = [];
for (let child of component._children) {
child = child.generate(this, styleStore, functionStore);
let wenity = this.appendChildComponent(component, child);
if (!wenity.isSSEmpty()) {
wenities.push(wenity);
}
}
return wenities;
}
/**
*
* @param {Component} component
* @param {ExtStorage} [styleStore=null]
* @param {ExtStorage} [functionStore=null]
* @returns {WebTrinity}
*/
generate(component, styleStore = null, functionStore = null) {
if (!styleStore) {
styleStore = component._stylesExtStore;
}
if (!functionStore) {
functionStore = component._functionsExtStore;
}
/**
* DEAL WITH COMPONENT MODIFICATION FIRST
*
* @todo pay attention to the "overwrite" behaviour
* the local modifier styles are the "closest"
* it might be appropriate to use this._styles.unshift(...) instead.
*/
component._styles.push(new SStoreDefinition(
(styleStore._aggregation !== ESAggregation.INTERNALIZED
? "."
: "")
+ component._compName,
component._modifier,
component._stylesExtStore
));
/**
* DEAL WITH CHILDREN
*
* Depending on the setup of the generator/-tion
* The children might return scripts or styles
* that are supposed to be collected
* and dealt with as a collection.
*/
let childrenWenities = this.resolveChildren(component, styleStore, functionStore);
/**
* DEAL WITH STYLES AND SCRIPTS
*/
/**
* @type {Array<SStoreDefinition>}
*/
let styleCollection = this.processStyles(component, styleStore);
/**
* @type {Map<ExtStoreType, Array<SStoreDefinition>>}
*/
let funcCollections = this.processFunctions(component, functionStore);
/**
* DEAL WITH CHILDREN WENITY SCRIPTS
*/
for (const child of childrenWenities) {
if (child.scripts) {
executeOnExtStoreTypeCollectedTriple(
(extstoretype) => this.transferCollectedFunctions(child.scripts, funcCollections, extstoretype)
);
}
}
let wenity = new WebTrinity();
/**
* DEAL WITH CHILDREN WENITY STYLE
*/
if (component._isCompel) {
executeOnExtStoreTypeCollectedTriple((est) => this.dealCollectedFuncs(funcCollections, est));
} else {
wenity.scripts = funcCollections;
wenity.stylings = styleCollection;
}
wenity.compext = component._element
for (const group of component._toRegister) {
Page.subscribeComponentToGroup(group, component._compName);
}
return wenity;
}
}