diff --git a/join_js_files.sh b/join_js_files.sh index ff9b9c3..550e56f 100644 --- a/join_js_files.sh +++ b/join_js_files.sh @@ -8,11 +8,11 @@ SRC="src" # and thoose that use component. SIZE_SIDE="siding.js shapes.js border.js dimensions.js" -CONTEXT="webTrinity.js extStore.js scriptAndStyleContext.js" +CONTEXT="generalHelpers.js webTrinity.js extStore.js scriptAndStyleContext.js" PRE_ANCESTRY="commonEvents.js context.js" MODIFIERS_LIST="alignment.js arrangement.js modifier.js" COMPONENT_ANCESTRY="wrapperComponent.js modifiableComponent.js addStyleAndFunctions.js" -HIGHER_LIST="component.js baseComponents.js builder.js" +HIGHER_LIST="component.js baseComponents.js builder.js" echo "" > $TARGET echo "/* ## color.js ## */" >> $TARGET diff --git a/src/builder.js b/src/builder.js index 5c32a79..6b49f7c 100644 --- a/src/builder.js +++ b/src/builder.js @@ -234,7 +234,10 @@ const builder = { /** * - * @param {*} innerComponents + * @todo upwards bubbling of js or css is not dealt with yet. + * + * + * @param {Component} innerComponents */ page: function (innerComponents) { let main = document.querySelector('main'); @@ -246,6 +249,7 @@ const builder = { .arrangement(Arrangement.CENTER) .childContext(innerComponents) .generate() + .html ); Page.generate(); main.remove(); diff --git a/src/component.js b/src/component.js index 10a61b4..6cdee27 100644 --- a/src/component.js +++ b/src/component.js @@ -48,6 +48,51 @@ class Component extends StyleAndScriptStoringComponent { this._toRegister = []; } + /** + * Adds a class to classList via HTMLElement.classList.add() method. + * Further collects rules in a property until generate is called. + * + * @CAUGHTION implementation is not safe to use, ignoring extStore is recommended; + * + * @todo difference between stylings and classes, extStore logic in combination with the Page.register... logic + * + * @override + * + * @param {string} styleClass (without the '.' in the front) + * @param {string|Modifier|map} styling + * @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 {Component} this component object + */ + addStyleClass(styleClass, styling = null, extStore = null) { + if (!extStore) { + extStore = this._styleClassesExtStore; + } else if (extStore.isMissing()) { + extStore = extStore.fillBy(this._styleClassesExtStore); + } + + if (styling) { + if (styling instanceof Modifier) { + styling = styling._modifications; + } + + Page.registerStyling('.' + styleClass, styling); + } + + this._element.classList.add(styleClass); + + return this; + } + + /** + * + * @returns {Component} + */ + isHigherComponent() { + this.#isCompel = true; + return this.setAttribute("data-compel-isHCompel", "true") + } + /** * Collects the given List in the _toRegister attribute. * When generate() is called, @@ -61,30 +106,253 @@ class Component extends StyleAndScriptStoringComponent { } + /** + * Defines how a child Component is to be appended. + * @param {Component} component the child component to add it. + * @returns {HTMLElement} + */ + _appendChildComponent(component) { + let child = new WebTrinity(); + if (component instanceof Component) { + child = component.generate(); + } + + if (component instanceof WebTrinity) { + child = component; + } + if (component instanceof HTMLElement) { + console.log("No wenity set - htmlEl was given"); + child.html = component; + } + this._element.append(child.html); + return child; } + + _processStyles(extStore = null) { + if (!extStore) { + extStore = this._stylesExtStore.updateForGeneralStyling(); + } else { + extStore.updateForGeneralStyling(); + } + + /** + * @todo very likely code dupplication - but kept for the time being + * for error tracking. + */ + if (extStore._type === ExtStoreType.INTERNALIZED_WITHIN) { + fillAttrsInContainerByCb( + this._modifier._modifications, + this._element, + (key, val, el) => { el.style[key] = val; } ); + } else { + /* ADDS ELEMENT MODIFIER TO this._styles list for styles processing */ + let modifierSSD = new SStoreDefinition(); + modifierSSD._identifier = this._compName; + modifierSSD._definition = this._modifier._modifications; + modifierSSD._extStore = extStore; + this._styles.unshift(modifierSSD); } + + let forCollection = []; + + let counter = 0; + for (let i = 0; i < this._styles.length; i++) { + const ssd = this._styles[i]; + /* 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 */ + let refESType = ( + ssd._extStore && ssd._extStore._type + ? ssd._extStore.updateForGeneralStyling()._type + : extStore._type ); + + switch (refESType) { + + case ExtStoreType.INTERNALIZED_WITHIN: + fillAttrsInContainerByCb( + ssd._definition, + this._element, + (key, val, el) => { el.style[key] = val; } + ) + break; + + case ExtStoreType.INDIVIDUALLY_DOC_HEAD: + + let container = document.createElement("style"); + container.setAttribute("data-compel-individually-nr", counter++); + + let styleRules = Object.keys(ssd._definition); + + for (let j = 0; j < styleRules.length; j++) { + let rule = styleRules[j]; + container.innerText += `${rule} {${ssd._definition[rule]} } `; + } + Page.addElementToPage(container, refESType); + break; + + case ExtStoreType.COLLECTED_DOC_HEAD: + forCollection.push(ssd); + break; + + case ExtStoreType.CENTRALIZED_DOC_HEAD: + Page.registerStyling(ssd._identifier, ssd._definition); + break; + } } + + return forCollection; } + _processFunctions(extStore = null) { + if (!extStore) { + extStore = this._functionsExtStore.updateForFunctions(); + } else { + extStore.updateForFunctions(); + } + + const forCollection = new Map(); + const collectForBefore = []; + + let counter = 0; + for (let i = 0; i < this._functions.length; i++) { + const ssd = this._functions[i]; + /* Make sure that the type is unified for later processing */ + + let refESType = ( + ssd._extStore && ssd._extStore._type + ? ssd._extStore.updateForFunctions()._type + : extStore._type + ); + + switch (refESType) { + case ExtStoreType.CENTRALIZED_DOC_HEAD: + case ExtStoreType.CENTRALIZED_SEGMENT_BEGIN: + case ExtStoreType.CENTRALIZED_DOC_FOOTER: + Page.registerPageFunction(ssd._identifier, ssd._definition); + break; + + case ExtStoreType.INDIVIDUALLY_WITHIN: + case ExtStoreType.INDIVIDUALLY_BEFORE: + case ExtStoreType.INDIVIDUALLY_SEGMENT_BEGIN: + case ExtStoreType.INDIVIDUALLY_DOC_FOOTER: + case ExtStoreType.INDIVIDUALLY_DOC_HEAD: + + let container = document.createElement("script"); + container.setAttribute("data-compel-individually-nr", counter++); + container.innerText += getScriptTagInjectionText( + clearFunctionDeclarationText(ssd._definition), + ssd._identifier + ); + Page.addElementToPage(container, refESType, this._element); + + break; + + case ExtStoreType.COLLECTED_BEFORE: + collectForBefore.push(ssd); + break; + + case ExtStoreType.COLLECTED_SEGMENT_BEGIN: + case ExtStoreType.COLLECTED_DOC_FOOTER: + case ExtStoreType.COLLECTED_DOC_HEAD: + if (!forCollection.has(refESType)) { + forCollection.set(refESType, []); + } + forCollection.get(refESType).push(ssd); + break; + } + } + + return forCollection; + } /** - * @override - * @class Component - * @inheritdoc + * Ends chain. + * Applies all modifications on the element. + * Processes alls stored additions. + * Returns the constructed HTMLElement of this Component. + * + * + * + * @param {ExtStorage} + * @returns {WebTrinity} the constructed HTMLElement of this Component. */ - generate(styleStoreInternal = null, cssStore = null, funcStore = null) { - let wenity = super.generate(styleStoreInternal, cssStore, funcStore); + generate(styleStore = null, functionStore = null) { + this._wenity = new WebTrinity(); + + /* DEAL WITH COMPONENT MODIFICATION FIRST */ + this._modifier._modifications["justify-content"] = this._arrangement; + this._modifier._modifications["align-content"] = this._alignment; + this._modifier._modifications["align-items"] = this._alignment; + this._modifier._modifications["text-align"] = this._alignment; + - for (let i = 0; i < this._toRegister.length; i++) { - this._toRegister[i].push(wenity.html); + let collectedWenities = []; + + for (let i = 0; i < this._children.length; i++) { + /** + * @type {Component} + */ + let child = this._children[i]; + + if (child instanceof ChainableModifier) { + child = child.toComponent(); + } + + child._modifier._updateDimensionsBy(this._modifier._paddingValues); + child = child.generate(); + + let wenity = this._appendChildComponent(child); + + if (!wenity.isSSEmpty()) { + collectedWenities.push(wenity); + } + } + + + + let styleCollection = this._processStyles(styleStore); + + /* dealing with being the "collecting" one or not + + if (this.#isCompel) { + + let collectedContainer = document.createElement("style"); + collectedContainer.setAttribute("data-compel-collected", counter); + Page.addElementToPage(collectedContainer, extStore, this._element); + + }else{ + this._wenity.css = stylesForCollection; + } + */ + + /** + * @type {Map>} + */ + const funcCollections = this._processFunctions(functionStore); + + if (this.#isCompel) { + funcCollections.get(ExtStoreType.COLLECTED_DOC_FOOTER) + funcCollections.get(ExtStoreType.COLLECTED_DOC_HEAD) + funcCollections.get(ExtStoreType.COLLECTED_SEGMENT_BEGIN) + } else { + this._wenity.js = funcCollections; + this._wenity.css = styleCollection; } - return wenity.html; + + this._wenity.html = this._element; + + return this._wenity; } + + } diff --git a/src/context.js b/src/context.js index 4f4d627..4b5fce3 100644 --- a/src/context.js +++ b/src/context.js @@ -30,6 +30,88 @@ class PageBuilder extends ScriptAndStyleContext { return compName; } + + /** + * + * @param {HTMLElement|Component} element + * @param {extStoreType} extStoreType + * @param {HTMLElement|Component} refElement + */ + addElementToPage(element, extStoreType = ExtStoreType.CENTRALIZED_DOC_HEAD, refElement = null) { + let { insertCallEl, relativePositioning } = {}; + if (!refElement) { + switch (extStoreType) { + case ExtStoreType.INDIVIDUALLY_DOC_HEAD: + case ExtStoreType.CENTRALIZED_DOC_HEAD: + case ExtStoreType.COLLECTED_DOC_HEAD: + insertCallEl = document.querySelector('head'); + break; + + case ExtStoreType.INDIVIDUALLY_DOC_FOOTER: + case ExtStoreType.COLLECTED_DOC_FOOTER: + case ExtStoreType.CENTRALIZED_DOC_FOOTER: + insertCallEl = document.querySelector('footer'); + break; + + case ExtStoreType.INTERNALIZED_WITHIN: + break; + + case ExtStoreType.INDIVIDUALLY_WITHIN: + case ExtStoreType.INDIVIDUALLY_BEFORE: + case ExtStoreType.INDIVIDUALLY_SEGMENT_BEGIN: + case ExtStoreType.COLLECTED_BEFORE: + case ExtStoreType.COLLECTED_SEGMENT_BEGIN: + case ExtStoreType.CENTRALIZED_SEGMENT_BEGIN: + console.log("ExtStorePosition defines a relative position, but no reference Element is given - doing nothing!") + return + } + } else if (refElement instanceof Component) { + refElement = refElement.generate() + } + + let refAttribute = "data-autocompel" + let refNode = document.querySelector(`[${refAttribute}='${refElement.getAttribute(refAttribute)}']`); + + switch (extStoreType) { + case ExtStoreType.INDIVIDUALLY_DOC_HEAD: + case ExtStoreType.CENTRALIZED_DOC_HEAD: + case ExtStoreType.COLLECTED_DOC_HEAD: + relativePositioning = "beforeend"; + break; + + case ExtStoreType.INDIVIDUALLY_DOC_FOOTER: + case ExtStoreType.COLLECTED_DOC_FOOTER: + case ExtStoreType.CENTRALIZED_DOC_FOOTER: + relativePositioning = "beforeend"; + break; + + case ExtStoreType.INTERNALIZED_WITHIN: + + case ExtStoreType.INDIVIDUALLY_WITHIN: + relativePositioning = "afterbegin"; + break + + case ExtStoreType.INDIVIDUALLY_BEFORE: + case ExtStoreType.COLLECTED_BEFORE: + relativePositioning = "beforebegin"; + break; + + case ExtStoreType.INDIVIDUALLY_SEGMENT_BEGIN: + case ExtStoreType.COLLECTED_SEGMENT_BEGIN: + case ExtStoreType.CENTRALIZED_SEGMENT_BEGIN: + insertCallEl = refNode.closest('[data-compel-isHCompel="true"]'); + relativePositioning = "afterbegin"; + break; + + } + + insertCallEl.insertAdjacentElement( + relativePositioning, + element + ); + + } + /** * Determines that the jpc-like-websites libs shouldn't be part of the resulting page. * Therefore the generate() methods will package/generate finalized js, css and html elements diff --git a/src/context/extStore.js b/src/context/extStore.js index 4f7664e..12fcc11 100644 --- a/src/context/extStore.js +++ b/src/context/extStore.js @@ -7,17 +7,30 @@ /** * ExtStorage := Extensions storage (type) * Extensions in this context are stylings and scripts (currently only javascript). - * internalized: the extensions are part of the element code/attributes - only styling + * internalized: the extensions are part of the element code/attributes - works obviously only with styling * individually: an individual tag is created/used * collected: the extension can/will be collected with others in a higher position of the element hierarchy * (but not document - root) * centralized: the extensions are send to the Page to be joined in a centralized tag/position of the document * (either head or footer tag) */ -const ExtStorageType = Object.freeze({ - INDIVIDUALLY: 1, - COLLECTED: 2, - CENTRALIZED: 3, +const ExtStoreType = Object.freeze({ + INTERNALIZED_WITHIN: 0, + + INDIVIDUALLY_WITHIN: 1, + INDIVIDUALLY_BEFORE: 2, + INDIVIDUALLY_SEGMENT_BEGIN: 3, + INDIVIDUALLY_DOC_HEAD: 4, + INDIVIDUALLY_DOC_FOOTER: 5, + + COLLECTED_BEFORE: 6, + COLLECTED_SEGMENT_BEGIN: 7, + COLLECTED_DOC_HEAD: 8, + COLLECTED_DOC_FOOTER: 9, + + CENTRALIZED_DOC_HEAD: 10, + CENTRALIZED_SEGMENT_BEGIN: 11, + CENTRALIZED_DOC_FOOTER: 12, }); /** @@ -27,105 +40,243 @@ const ExtStorageType = Object.freeze({ * Only relevant if ExtStorage is not 'internalized'. * Determines where the tag (if individually) or the extensions are positioned. */ -const ExtStoragePos = Object.freeze({ - WITHIN: 0, - BEFORE: 1, - SEGMENT_BEGIN: 2, - BEGINNING: 3, - END: 4 +const ExtStorePosition = Object.freeze({ + WITHIN: "WITHIN", + BEFORE: "BEFORE", + SEGMENT_BEGIN: "SEGMENT_BEGIN", + DOC_HEAD: "DOC_HEAD", + DOC_FOOTER: "DOC_FOOTER" }); /** - * Extension class for setting the ExternalStorage definitions - * in a chained manner. + * Defines how an identified dupplication should be "resolved"/dealt with. + * REPLACE: + * RENAME: + * RENAME_OLD: + * DROP_NEW: + * MOVE_ELEMENT_SPECIFIC: @ATTENTION implementation pending + */ +const OverwriteBehaviour = Object.freeze({ + REPLACE: "REPLACE", + RENAME: "RENAME", + RENAME_OLD: "RENAME_OLD", + DROP_NEW: "DROP_NEW", + MOVE_ELEMENT_SPECIFIC: "MOVE_ELEMENT_SPECIFIC" +}); + +/** + * Extracted this super class to differentiate between + * internal and external store. */ -class ExtStoragePositioned { - #extStore; +class ExtStorage { + constructor(type = null, behaviour = null) { + /** + * @type {ExtStorageType} + */ + this._type = (!type ? ExtStoreType.INDIVIDUALLY_WITHING : type); + /** + * @type {OverwriteBehaviour} + */ + this._overwriteBehaviour = (!behaviour ? OverwriteBehaviour.REPLACE : behaviour); + } + /** * - * @param {ExtStore} extStore + * @param {OverwriteBehaviour} behave + * @returns {EXPosConfer} */ - constructor(extStore) { - this.#extStore = extStore; - } - - WITHIN() { - this.#extStore.position = ExtStoragePos.WITHIN; - return this.#extStore; + overwriteBehaviour(behave) { + this._overwriteBehaviour = behave; + return this; } - BEFORE() { - this.#extStore.position = ExtStoragePos.BEFORE; - return this.#extStore; - } - SEGMENT_BEGIN() { - this.#extStore.position = ExtStoragePos.SEGMENT_BEGIN; - return this.#extStore; + /** + * + * @param {ExtStoreType} type + */ + setExtStoreType(type) { + this._type = type; + return this; } - BEGINNING() { - this.#extStore.position = ExtStoragePos.BEGINNING; - return this.#extStore; + + /** + * + * @param {ExtStorage} extStore + * @returns {boolean} + */ + equals(extStore = null) { + if (!extStore) return false; + + return extStore._type === this._type + && extStore._overwriteBehaviour === this._overwriteBehaviour; } - END() { - this.#extStore.position = ExtStoragePos.END; - return this.#extStore; + + /** + * + * @returns {boolean} + */ + isMissing() { + return this._type === null || this._overwriteBehaviour === null; } -} -/** - * Extracted this super class to differentiate between - * internal and external store. - */ -class ExtStore { - type; - position; /** * - * @param {string} type + * @param {ExtStorage} otherExtStore + * @returns {ExtStorage} */ - constructor(typeName) { - this.type = typeName; + fillBy(otherExtStore) { + if (this._type === null) { + this._type = otherExtStore._type; + } + + if (this._overwriteBehaviour === null) { + this._overwriteBehaviour = otherExtStore._overwriteBehaviour; + } + + return this; + } + + /** + * Takes the singleValue and an ExtStore object to copy all values from. + * Then the singleValue will be compared to the three enums for the type of value. + * After the type is identified the corresponding (copied) value will be updated. + * @param {ExtStoreType|ExtStorePosition|OverwriteBehaviour} singleValue + * @param {ExtStorage} extStoreToClone + * @returns {ExtStorage} + */ + setSingleValueToClone(singleValue, extStoreToClone) { + this._type = extStoreToClone._type; + this._position = extStoreToClone._position; + this._overwriteBehaviour = extStoreToClone._overwriteBehaviour; + + let target = [ + ...Object.values(ExtStoreType).map(text => Object({ "value": text, "ref": "type" })), + ...Object.values(ExtStorePosition).map(text => Object({ "value": text, "ref": "pos" })), + ...Object.values(OverwriteBehaviour).map(text => Object({ "value": text, "ref": "over" })) + ] + .find(compareObj => compareObj["value"] === singleValue); + + if (target) { + switch (target["ref"]) { + case "type": + this._type = singleValue; + break; + case "pos": + this._position = singleValue; + break; + case "over": + this._overwriteBehaviour = singleValue; + + break; + } + } + + return this; } -} -class InternalExtStore extends ExtStore{ /** * - * @param {string} type + * @returns {ExtStorage} this extStore (updated if rules were used, that don't work for functions) */ - constructor(typeName) { - super(typeName); - this.position = ExtStoragePos.WITHIN; + updateForFunctions() { + if (this._type === ExtStoreType.INTERNALIZED_WITHIN) { + console.log("Updated Functions extstore from INTERNALIZED_WITHIN to INDIVIDUALLY_BEFORE") + this._type = ExtStoreType.INDIVIDUALLY_BEFORE; + } + return this; } -} -class ExtExtStorage extends ExtStore{ /** * - * @param {string} type + * @returns {ExtStorage} */ - constructor(typeName) { - super(typeName); - this.type = typeName; + updateForGeneralStyling() { + switch (this._type) { + + case ExtStoreType.INTERNALIZED_WITHIN: + break; + + case ExtStoreType.INDIVIDUALLY_WITHIN: + case ExtStoreType.INDIVIDUALLY_BEFORE: + case ExtStoreType.INDIVIDUALLY_SEGMENT_BEGIN: + case ExtStoreType.INDIVIDUALLY_DOC_FOOTER: + this._type = ExtStoreType.INDIVIDUALLY_DOC_HEAD; + + case ExtStoreType.INDIVIDUALLY_DOC_HEAD: + break; + + case ExtStoreType.COLLECTED_BEFORE: + case ExtStoreType.COLLECTED_SEGMENT_BEGIN: + case ExtStoreType.COLLECTED_DOC_FOOTER: + this._type = ExtStoreType.COLLECTED_DOC_HEAD; + + case ExtStoreType.COLLECTED_DOC_HEAD: + break; + + case ExtStoreType.CENTRALIZED_SEGMENT_BEGIN: + case ExtStoreType.CENTRALIZED_DOC_FOOTER: + this._type = ExtStoreType.CENTRALIZED_DOC_HEAD; + + case ExtStoreType.CENTRALIZED_DOC_HEAD: + break + } + + return this; } - positionedAt() { - return new ExtStoragePositioned(this); + + /** + * Currently it works the same as the "updateForFunctions()" since the same rules won't work. + * @returns {ExtStorage} this extStore (updated if rules were used, that won't work for StyleClasses) + */ + updateForStyleClass() { + /* + const positionedAfter = [ + COLLECTED_DOC_FOOTER, + INDIVIDUALLY_DOC_FOOTER, + CENTRALIZED_DOC_FOOTER + ]; + + if (positionedAfter.includes(this._type)) { + this._type = ExtStoreType.INTERNALIZED_WITHIN; + } + */ + + return this.updateForGeneralStyling(); } } -const StoreExtAs = Object.freeze({ - INTERNALIZED: new InternalExtStore(ExtStorageType.INTERNALIZED), - INDIVIDUALLY: new ExtExtStorage(ExtStorageType.INDIVIDUALLY), - COLLECTED: new ExtExtStorage(ExtStorageType.COLLECTED), - CENTRALIZED: new ExtExtStorage(ExtStorageType.CENTRALIZED), -}); - +/** + * Style or Script Store Definition + * @property {string} _identifier; + * @property {any} _definition; + * @property {any} _additionaly; + * @property {ExtStorage} _extStore; + */ +class SStoreDefinition { + constructor(identifier, definition, extStore = null, additions = null) { + /** + * Usually the name or the selector + * @type {string} _identifier; + */ + this._identifier = identifier; + /** + * the values + * @type {any} _definition; + */ + this._definition = definition; + /** + * additional values, if needed. E.g. funciton args + * @type {any} _additionaly; + */ + this._additions = additions; + /** + * The corresponding extStore + * @type {ExtStorage} _extStore; + */ + this._extStore = extStore; + } +} -const OverwriteBehaviour = Object.freeze({ - REPLACE: 0, - RENAME: 1, - RENAME_OLD: 2 -}); /** * Resolves an overwrite case for a map/object. @@ -155,3 +306,27 @@ function resolveOverwrite(key, container, overwriteBehaviour) { return key; } + +/** + * Will resolve the compareKey according to the overwriteBehaviour + * and add the newValue to the targetContainer with it. + * @param {Object} targetContainer + * @param {string} compareKey + * @param {Object} newValue + * @param {OverwriteBehaviour} overwriteBehaviour + * @returns {string} the "resolved" compareKey + */ +function identifyAndResolveOverwrite(targetContainer, compareKey, newValue, overwriteBehaviour) { + let keys = Object.keys(targetContainer); + if (keys.includes(compareKey)) { + if (overwriteBehaviour === OverwriteBehaviour.DROP_NEW) { + console.log("Not Adding, because overwrite is set to DROP_NEW"); + return compareKey; + } + + compareKey = resolveOverwrite(compareKey, targetContainer, overwriteBehaviour); + } + + targetContainer[compareKey] = newValue; + return compareKey; +} diff --git a/src/context/generalHelpers.js b/src/context/generalHelpers.js new file mode 100644 index 0000000..cfeb5ac --- /dev/null +++ b/src/context/generalHelpers.js @@ -0,0 +1,23 @@ +/** + * This file is part of the jps-like-websites lib + * URL: https://git.labos.goip.de/chris/jpc-like-websites + * @copyright by its creator Christian Martin + */ + +/** + * Iterates over the keys of attrs, + * extracts the corresponding value + * and applies the callback (cb) on it in the order (key, value, targetContainer) + * @extends StyleAndScriptStoringComponent + * @param {map} attrs + * @param {Object} intoContainer + * @param {Function} 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; +} \ No newline at end of file diff --git a/src/context/scriptAndStyleContext.js b/src/context/scriptAndStyleContext.js index 6d1ffae..c04b5c4 100644 --- a/src/context/scriptAndStyleContext.js +++ b/src/context/scriptAndStyleContext.js @@ -25,7 +25,13 @@ function clearFunctionDeclarationText(func) { ); } -function getPageInjectionText(func, registrationName) { +/** + * + * @param {Function} func + * @param {string} registrationName + * @returns {string} + */ +function getScriptTagInjectionText(func, registrationName) { let funcHasName = func.name && func.name.trim() !== ''; if (func.startWith('function')) { let label = `function ${registrationName}`; @@ -245,7 +251,7 @@ class ScriptAndStyleContext { .forEach(tuple => { let regName = tuple[0]; let fsb = tuple[1]; - funcTag.innerText += getPageInjectionText(fsb.func, regName); + funcTag.innerText += getScriptTagInjectionText(fsb.func, regName); if (fsb.repeats && !fsb.execAfterStart) { repeated[regName] = setInterval(regName, fsb.interval, fsb.args); diff --git a/src/context/webTrinity.js b/src/context/webTrinity.js index 0cee54a..6074322 100644 --- a/src/context/webTrinity.js +++ b/src/context/webTrinity.js @@ -11,12 +11,21 @@ class WebTrinity { /** * * @param {HTMLElement|Component} html - * @param {HTMLScriptElement|map} js - * @param {HTMLStyleElement|map>} css + * @param {HTMLStyleElement|Map} js + * @param {HTMLScriptElement|Array} css */ constructor(html = null, js = null, css = null) { this.html = html; this.js = js; this.css = css; } + + /** + * + * @returns {boolean} + */ + isSSEmpty() { + return (this.js === null || this.js.length === 0) + && (this.css === null || this.css.size === 0); + } } diff --git a/src/modifier.js b/src/modifier.js index 2394be2..612e584 100644 --- a/src/modifier.js +++ b/src/modifier.js @@ -15,6 +15,10 @@ class Modifier { */ _modifications; _shape; + /** + * @property {Sides} paddingValues + */ + _paddingValues; constructor() { this._modifications = new Object(); @@ -36,6 +40,7 @@ class Modifier { */ fillMaxWidth(fraction = 1) { this._modifications["width"] = (100 * fraction) + "%"; + this._modifications["max-width"] = (100 * fraction) + "%"; return this; } @@ -46,6 +51,58 @@ class Modifier { */ fillMaxHeight(fraction = 1) { this._modifications["height"] = (100 * fraction) + "%"; + this._modifications["max-height"] = (100 * fraction) + "%"; + return this; + } + + /** + * + * @param {string} keyWord weither 'height' or 'width' that will be adjusted and looked for + * @param {Sides} parentalPadding + */ + _updateDimensionsBy(parentalPadding) { + function updateDirection(keyWord, parentalAdjustment) { + let refKeys = Object.keys(this._modifications) + .filter(k => k.includes(keyWord)); + + if (refKeys.length > 0) { + for (let i = 0; i < refKeys.length; i++) { + let key = refKeys[i]; + let value = this._modifications[key]; + + if (key.includes("calc")) { + console.log( + `Modifier._updateByParent... ${keyWord + } - unexpected value '${value + }' for '${key + }', skipping...` + ); + } else { + let newValue = `calc(${value} - ${parentalAdjustment}); `; + console.log( + `Modifier._updateByParent... ${keyWord + } - updating value '${value + }' to '${newValue + }', for '${key + }'!` + ); + this._modifications[key] = newValue; + } + } + } + } + + if (parentalPadding) { + let pval = parentalPadding.getValues(); + if (pval["horizontal"] > 0) { + updateDirection("width", pval["horizontal"]); + } + + if (pval["vertical"] > 0) { + updateDirection("height", pval["vertical"]); + } + } + return this; } @@ -70,6 +127,7 @@ class Modifier { * @returns {Modifier} this modifier object */ padding(siding) { + this._paddingValues = siding; let keyToAdd = ""; if (siding instanceof PaddingChain) {