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.
 
 

204 lines
7.6 KiB

/**
* 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
*/
/**
* @abstract
* Class adds function and style storing properties to the context (PageBuilder).
*/
class ScriptAndStyleContext {
/**
* @property {Map<string, Map<string, string>>} #css
* @type {Map<string, Map<string, string>>} #css
*/
#css;
/**
* @property {Map<string, FunctionStoreBuffer>} #functions
* @type {Map<string, FunctionStoreBuffer>} #functions
*/
#functions;
constructor() {
this.#functions = new Map();
this.#css = new Map();
}
/**
*
* @param {string} nameAddition text that will be added to the end of the generated name
* @returns a name for a function (e.g. for storing)
*/
getFunctionName(nameAddition = "") {
return `func${this.#functions.size}${nameAddition}`;
}
/**
* Registers a function to be added later in a script tag in the head of the document.
* @ATTENTION Be careful with intended empty strings (e.g. in variable values),
* empty strings within the function code will be shrunk.
*
* @param {Function} fun The function that will be registered
* @param {string} underTheName (alternative) name for the registration of the function,
* if none the name of the function will be used, if that is missing a name will be generated.
* @param {OverwriteBehaviour} overwriteBehaviour defines what to do,
* if the registration name already exists (default: OverwriteBehaviour.RENAME - adds a nr to the name)
* @returns {string} the name under witch the function is registered (and therefore can be called from)
*/
registerPageFunction(fun, underTheName = '', overwriteBehaviour = OverwriteBehaviour.RENAME) {
/* Find name-root */
let registrationName = [
underTheName.trim(),
fun.name.trim(),
this.getFunctionName()
].find(e => e !== '');
/* deal with name already present */
let functionNames = this.#functions.keys;
if (functionNames.includes(registrationName)) {
registrationName = resolveOverwrite(registrationName, this.#functions, overwriteBehaviour);
}
/* clear function text */
let clearedFuncText = clearFunctionDeclarationText(fun);
this.#functions.set(registrationName, new FunctionStoreBuffer(clearedFuncText));
return registrationName;
}
/**
*
* @experimental Attention is adviced, registration mechanism doesn't work yet
* @param {Function} fun The function that is supposed to be executed repeatedly
* @param {number} interval the time in ms between executions
* @param {string} underTheName the name the interval will be tied to
* @param {OverwriteBehaviour} overwriteBehaviour defines what to do,
* if the registration name already exists (default: OverwriteBehaviour.RENAME - adds a nr to the name)
*/
registerRepeatingFunction(fun, interval, underTheName = '', overwriteBehaviour = OverwriteBehaviour.RENAME, args = []) {
let registrationName = this.registerPageFunction(fun, underTheName, overwriteBehaviour);
let fsb = this.#functions.get(registrationName);
fsb.repeats = true;
fsb.interval = interval;
fsb.args = args;
return registrationName;
}
/**
* Registeres a function to be executed after page-load
* @param {Function} func the function that will be executed
* @param {number} delay the time in ms the execution is delayed after load
* @param {string} name if provided the function will be registered as well
* @param {Array<any>} args arguments for the function
* @param {boolean} repeat defines if the function is supposed to be repeated as well
* @param {number} interval if the function is supposed to repeat, this defines the interval of repetition
*/
executeAfterLoad(fun, delay = 1000, underTheName = '', overwriteBehaviour = OverwriteBehaviour.RENAME, interval = -1, args = []) {
let registrationName = this.registerPageFunction(fun, underTheName, overwriteBehaviour);
let fsb = this.#functions.get(registrationName);
fsb.execAfterStart = true;
fsb.delay = delay;
fsb.args = args;
if (interval > 0) {
fsb.repeats = true;
fsb.interval = interval;
}
return registrationName;
}
/**
*
* @param {string} nameAddition text that will be added to the end of the generated name
* @returns a name for a styling (e.g. for storing)
*/
getStyleName(nameAddition = "") {
return `styling${this.#css.size}${nameAddition}`;
}
/**
* Adds the styling rules to the element identifiers into the style tag.
* An element definition can only be used once, repeated use will be ignored.
*
* @todo implement extStore logic
*
* @param {string} elementIdentifier The element identifier
* @param {map<string, string>|Modifier} styleRuleMap The Styling rules/values
*/
registerStyling(elementIdentifier, styleRuleMap) {
if (styleRuleMap instanceof Modifier) {
styleRuleMap = styleRuleMap._modifications;
}
if (!this.#css.has(elementIdentifier)) {
this.#css.set(elementIdentifier, styleRuleMap);
}
return elementIdentifier;
}
/**
* Adds into the (head) document.
* - script tag
* - function tag(s)
* - sets and registers repeatedly executed functions
* - sets (timeout and) functions that are supposed to be executed after load
* @class ScriptAndStyleContext
*/
generate() {
let head = document.querySelector('head');
/* generate style tag and fill it with stored stylings */
let styleTag = document.createElement('style');
for (const tuple of this.#css.entries()) {
styleTag.innerText += `${tuple[0]} {${Object.entries(tuple[1])
.map(style => style[0] + ": " + style[1] + "; ")
.join(" ")
}} `;
}
head.appendChild(styleTag);
/*
generate script tag(s) and fill it with stored functions
for now there will be 3 script tags, so interval, execAfterStart and normal functions are sepperated.
*/
let containersTag = document.createElement('script');
containersTag.setAttribute("data-compel-mech-script", "main");
containersTag.innerText = 'const delayed = {}; ';
containersTag.innerText += 'const repeated = {}; ';
head.appendChild(containersTag);
if (this.#functions.size > 0) {
let funcTag = document.createElement('script');
for (const tuple of this.#functions.entries) {
let regName = tuple[0];
let fsb = tuple[1];
funcTag.innerText += getScriptTagInjectionText(fsb.func, regName);
if (fsb.repeats && !fsb.execAfterStart) {
repeated[regName] = setInterval(regName, fsb.interval, fsb.args);
}
if (!fsb.repeats && fsb.execAfterStart) {
delayed[regName] = setTimeout(regName, fsb.interval, fsb.args);
}
if (fsb.repeats && fsb.execAfterStart) {
repeated[regName] = setInterval(regName, fsb.interval, fsb.args);
delayed[regName] = setTimeout(repeated[regName], fsb.delay, fsb.args);
}
}
head.appendChild(funcTag);
}
}
}