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.
653 lines
20 KiB
653 lines
20 KiB
/**
|
|
* ESAggregation := Extensions Storage Aggregation (method)
|
|
*/
|
|
const ESAggregation = Object.freeze({
|
|
INTERNALIZED: "intern",
|
|
INDIVIDUALLY: "individual",
|
|
COLLECTED: "collected",
|
|
CENTRALIZED: "centralized"
|
|
});
|
|
|
|
/**
|
|
* ExtStoragePos := Extensions Storage Position
|
|
*
|
|
* Determines where the extensions are positioned.
|
|
* Only relevant if ExtStorage is not 'internalized'.
|
|
* Determines where the tag (if individually) or the extensions are positioned.
|
|
*/
|
|
const ExtStorePosition = Object.freeze({
|
|
WITHIN: "WITHIN",
|
|
BEFORE: "BEFORE",
|
|
SEGMENT_BEGIN: "SEGMENT_BEGIN",
|
|
DOC_HEAD: "DOC_HEAD",
|
|
DOC_FOOTER: "DOC_FOOTER"
|
|
});
|
|
|
|
/**
|
|
* 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"
|
|
});
|
|
|
|
|
|
/**
|
|
* Is supposed to shrink all empty strings to length 1
|
|
* @param {Function} func
|
|
* @returns {string}
|
|
*/
|
|
function clearFunctionDeclarationText(func) {
|
|
function shrinkEmptyStrings(text) {
|
|
for (let i = 1; i < 10; i++) {
|
|
text = text.replaceAll(" ".slice(i), ' ');
|
|
}
|
|
return text;
|
|
}
|
|
return shrinkEmptyStrings(
|
|
func.toString()
|
|
.replaceAll('\r\n', ' ')
|
|
.replaceAll('\n\r', ' ')
|
|
.replaceAll('\n', ' ')
|
|
.replaceAll('\r', ' ')
|
|
);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {Function} func
|
|
* @param {string} registrationName
|
|
* @returns {string}
|
|
*/
|
|
function getScriptTagInjectionText(func, registrationName) {
|
|
let funcHasName;
|
|
if (typeof func === 'function') {
|
|
funcHasName = ((func.name) && func.name.trim() !== '');
|
|
}
|
|
|
|
if (func.startsWith('function')) {
|
|
let label = ` function ${registrationName}`;
|
|
let isNameInFuncText = func.startsWith(label);
|
|
if (isNameInFuncText) {
|
|
return func;
|
|
} else {
|
|
return [label, '(', func.split('(').slice(1).join('(')].join('')
|
|
}
|
|
} else {
|
|
return ` const ${registrationName} = ${func}; `;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Stores a function until generate is called.
|
|
* Then the additional informations of the store wil be applied
|
|
* and the funcitons added to the page.
|
|
*/
|
|
class FunctionStoreBuffer {
|
|
/**
|
|
* Stores a function until generate is called.
|
|
* Then the additional informations of the store wil be applied
|
|
* and the funcitons added to the page.
|
|
* @param {Function} func the function that will be stored
|
|
* @param {Array<any>} args additional arguments that will be given to the function
|
|
* @param {boolean} repeats weither the funciton is supposed to execute repeatedly
|
|
* @param {number} interval the time in milliseconds between executions
|
|
* @param {boolean} execAfterStart weither the function is supposed to be executed after pageload
|
|
* @param {number} delay the time in milliseconds the execution will be delayed
|
|
*/
|
|
constructor(
|
|
func,
|
|
args = [],
|
|
repeats = false,
|
|
interval = -1,
|
|
execAfterStart = false,
|
|
delay = -1
|
|
) {
|
|
this.func = func;
|
|
this.args = args;
|
|
this.execAfterStart = execAfterStart;
|
|
this.delay = delay;
|
|
this.repeats = repeats;
|
|
this.interval = interval;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Extracted this super class to differentiate between
|
|
* internal and external store.
|
|
*/
|
|
class ExtStorage {
|
|
constructor(
|
|
aggregation = ESAggregation.INTERNALIZED,
|
|
position = ExtStorePosition.WITHIN,
|
|
behaviour = OverwriteBehaviour.DROP_NEW
|
|
) {
|
|
/**
|
|
* @type {ESAggregation}
|
|
*/
|
|
this._aggregation = aggregation;
|
|
/**
|
|
* @type {ExtStorePosition}
|
|
*/
|
|
this._position = position;
|
|
/**
|
|
* @type {OverwriteBehaviour}
|
|
*/
|
|
this._overwriteBehaviour = behaviour;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {ESAggregation} position
|
|
*/
|
|
setExtStoreAggregation(aggregation) {
|
|
this._aggregation = aggregation;
|
|
return this;
|
|
}
|
|
/**
|
|
*
|
|
* @param {ExtStoreType} position
|
|
*/
|
|
setExtStorePosition(position) {
|
|
this._position = position;
|
|
return this;
|
|
}
|
|
/**
|
|
*
|
|
* @param {OverwriteBehaviour} behave
|
|
* @returns {ExtStorage}
|
|
*/
|
|
setOverwriteBehaviour(behave) {
|
|
this._overwriteBehaviour = behave;
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {ExtStorage} extStore
|
|
* @returns {boolean}
|
|
*/
|
|
equals(extStore = null) {
|
|
if (!extStore) return false;
|
|
|
|
return extStore._type === this._type
|
|
&& extStore._overwriteBehaviour === this._overwriteBehaviour;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @returns {boolean}
|
|
*/
|
|
isMissing() {
|
|
return this._type === null || this._overwriteBehaviour === null;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @returns {boolean}
|
|
*/
|
|
isNotInternalOrIndividual() {
|
|
return !(
|
|
this._aggregation === ESAggregation.INTERNALIZED
|
|
|| this._aggregation === ESAggregation.INDIVIDUALLY
|
|
);
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {ExtStorage} otherExtStore
|
|
* @returns {ExtStorage}
|
|
*/
|
|
fillBy(otherExtStore) {
|
|
if (this._type === null) {
|
|
this._type = otherExtStore._type;
|
|
}
|
|
|
|
if (this._overwriteBehaviour === null) {
|
|
this._overwriteBehaviour = otherExtStore._overwriteBehaviour;
|
|
}
|
|
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
* @todo check if still implemented correctly
|
|
* 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;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @returns {ExtStorage} this extStore (updated if rules were used, that don't work for functions)
|
|
*/
|
|
setupForFunctions() {
|
|
if (this._type === ExtStoreType.INTERNALIZED_WITHIN) {
|
|
console.log("Updated Functions extstore from INTERNALIZED_WITHIN to INDIVIDUALLY_BEFORE")
|
|
this._type = ExtStoreType.INDIVIDUALLY_BEFORE;
|
|
}
|
|
return this;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @returns {ExtStorage}
|
|
*/
|
|
setupForGeneralStyling() {
|
|
if (this === ExtStoreType.INTERNALIZED_WITHIN) {
|
|
this._position = ExtStorePosition.WITHIN;
|
|
this._aggregation = ESAggregation.INTERNALIZED;
|
|
return this;
|
|
}
|
|
|
|
this._position = ExtStorePosition.DOC_HEAD;
|
|
|
|
switch (this) {
|
|
case ExtStoreType.INDIVIDUALLY_WITHIN:
|
|
case ExtStoreType.INDIVIDUALLY_BEFORE:
|
|
case ExtStoreType.INDIVIDUALLY_SEGMENT_BEGIN:
|
|
case ExtStoreType.INDIVIDUALLY_DOC_FOOTER:
|
|
case ExtStoreType.INDIVIDUALLY_DOC_HEAD:
|
|
this._aggregation = ESAggregation.INDIVIDUALLY;
|
|
break;
|
|
|
|
case ExtStoreType.COLLECTED_BEFORE:
|
|
case ExtStoreType.COLLECTED_SEGMENT_BEGIN:
|
|
case ExtStoreType.COLLECTED_DOC_FOOTER:
|
|
case ExtStoreType.COLLECTED_DOC_HEAD:
|
|
this._aggregation = ESAggregation.COLLECTED;
|
|
|
|
this._aggregation = ESAggregation.COLLECTED;
|
|
break;
|
|
case ExtStoreType.CENTRALIZED_DOC_HEAD:
|
|
case ExtStoreType.CENTRALIED_SEGMENT_BEGIN:
|
|
case ExtStoreType.CENTRALIZED_DOC_FOOTER:
|
|
default:
|
|
this._aggregation = ESAggregation.CENTRALIZED;
|
|
break
|
|
}
|
|
|
|
return 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)
|
|
*/
|
|
setupForStyleClass() {
|
|
/*
|
|
const positionedAfter = [
|
|
COLLECTED_DOC_FOOTER,
|
|
INDIVIDUALLY_DOC_FOOTER,
|
|
CENTRALIZED_DOC_FOOTER
|
|
];
|
|
|
|
if (positionedAfter.includes(this._type)) {
|
|
this._type = ExtStoreType.INTERNALIZED_WITHIN;
|
|
}
|
|
*/
|
|
|
|
return this.setupForGeneralStyling();
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @returns {InsertPosition}
|
|
*/
|
|
getRelativePositioning() {
|
|
switch (this._position) {
|
|
case ExtStorePosition.BEFORE:
|
|
return "beforebegin"
|
|
case ExtStorePosition.SEGMENT_BEGIN:
|
|
return "afterbegin";
|
|
case ExtStorePosition.DOC_HEAD:
|
|
case ExtStorePosition.DOC_FOOTER:
|
|
return "beforeend"
|
|
case ExtStorePosition.WITHIN:
|
|
default:
|
|
return "afterbegin";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Expects a reference element for the positions before and segment_begin.
|
|
* Otherwise will return head, footer or element accordingly.
|
|
* @param {HTMLLIElement|Component} element
|
|
* @returns {HTMLElement}
|
|
*/
|
|
getRefElement(element = null) {
|
|
let ensuredElement = element;
|
|
if (!element) {
|
|
console.log("ExtStorePosition defines a relative position, but no reference Element is given - using head!")
|
|
return document.querySelector('head');
|
|
}
|
|
|
|
if (element instanceof Component) {
|
|
ensuredElement = element.generate().compext;
|
|
}
|
|
|
|
switch (this._position) {
|
|
case ExtStorePosition.BEFORE:
|
|
case ExtStorePosition.SEGMENT_BEGIN:
|
|
return ensuredElement.closest('[data-compel-isHCompel="true"]');
|
|
case ExtStorePosition.DOC_HEAD:
|
|
return document.querySelector('head');
|
|
case ExtStorePosition.DOC_FOOTER:
|
|
return document.querySelector('footer');
|
|
case ExtStorePosition.WITHIN:
|
|
default:
|
|
return ensuredElement;
|
|
}
|
|
}
|
|
|
|
insertElementAccordingly(element) {
|
|
this.getRefElement(element)
|
|
.insertAdjacentElement(
|
|
this.getRelativePositioning(),
|
|
this.getRefElement(element)
|
|
)
|
|
}
|
|
|
|
/**
|
|
* Returns a function that will setup the distribution of a given styling.
|
|
* @returns {function(SStoreDefinition,HTMLElement,number): boolean}
|
|
*/
|
|
getStylingDistribution() {
|
|
switch (this._aggregation) {
|
|
case ESAggregation.INDIVIDUALLY:
|
|
return function (ssd, orgElement, counter) {
|
|
let container = generateAndFillStyleTag([ssd]);
|
|
container.setAttribute("data-compel-individually-nr", counter++);
|
|
Page.addElementToPage(container, this);
|
|
return false;
|
|
}
|
|
case ESAggregation.COLLECTED:
|
|
return function (ssd, orgElement) {
|
|
return true;
|
|
}
|
|
case ESAggregation.CENTRALIZED:
|
|
return function (ssd, orgElement) {
|
|
Page.registerStyling(ssd._identifier, ssd._definition);
|
|
return false;
|
|
}
|
|
|
|
case ESAggregation.INTERNALIZED:
|
|
default:
|
|
return function (ssd, orgElement) {
|
|
helperFun.fillAttrsInContainerByCb(
|
|
ssd._definition,
|
|
orgElement,
|
|
(key, val, el) => { el.style[key] = val; }
|
|
);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @returns {function(SStoreDefinition, Map<ExtStorage, Array<SStoreDefinition>, number): boolean}
|
|
*/
|
|
getFunctionDistribution() {
|
|
switch (this._aggregation) {
|
|
case ESAggregation.INTERNALIZED:
|
|
case ESAggregation.INDIVIDUALLY:
|
|
return function (ssd, counter) {
|
|
let container = document.createElement("script");
|
|
container.setAttribute("data-compel-individually-nr", counter++);
|
|
container.innerText += getScriptTagInjectionText(
|
|
clearFunctionDeclarationText(ssd._definition),
|
|
ssd._identifier
|
|
);
|
|
Page.addElementToPage(container, refESType);
|
|
return false;
|
|
}
|
|
case ESAggregation.COLLECTED:
|
|
return function () {
|
|
return true;
|
|
}
|
|
|
|
case ESAggregation.CENTRALIZED:
|
|
default:
|
|
return function (ssd) {
|
|
Page.registerPageFunction(ssd._identifier, ssd._definition);
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* 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 - 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 ExtStoreType = Object.freeze({
|
|
INTERNALIZED_WITHIN: new ExtStorage(ESAggregation.INDIVIDUALLY, ExtStorePosition.WITHIN),
|
|
INDIVIDUALLY_WITHIN: new ExtStorage(ESAggregation.INDIVIDUALLY, ExtStorePosition.WITHIN),
|
|
INDIVIDUALLY_BEFORE: new ExtStorage(ESAggregation.INDIVIDUALLY, ExtStorePosition.BEFORE),
|
|
INDIVIDUALLY_SEGMENT_BEGIN: new ExtStorage(ESAggregation.INDIVIDUALLY, ExtStorePosition.SEGMENT_BEGIN),
|
|
INDIVIDUALLY_DOC_HEAD: new ExtStorage(ESAggregation.INDIVIDUALLY, ExtStorePosition.DOC_HEAD),
|
|
INDIVIDUALLY_DOC_FOOTER: new ExtStorage(ESAggregation.INDIVIDUALLY, ExtStorePosition.DOC_FOOTER),
|
|
COLLECTED_BEFORE: new ExtStorage(ESAggregation.COLLECTED, ExtStorePosition.BEFORE),
|
|
COLLECTED_SEGMENT_BEGIN: new ExtStorage(ESAggregation.COLLECTED, ExtStorePosition.SEGMENT_BEGIN),
|
|
COLLECTED_DOC_HEAD: new ExtStorage(ESAggregation.COLLECTED, ExtStorePosition.DOC_HEAD),
|
|
COLLECTED_DOC_FOOTER: new ExtStorage(ESAggregation.COLLECTED, ExtStorePosition.DOC_FOOTER),
|
|
CENTRALIZED_DOC_HEAD: new ExtStorage(ESAggregation.CENTRALIZED, ExtStorePosition.DOC_HEAD),
|
|
CENTRALIZED_SEGMENT_BEGIN: new ExtStorage(ESAggregation.CENTRALIZED, ExtStorePosition.SEGMENT_BEGIN),
|
|
CENTRALIZED_DOC_FOOTER: new ExtStorage(ESAggregation.CENTRALIZED, ExtStorePosition.DOC_FOOTER)
|
|
});
|
|
|
|
/**
|
|
* 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;
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* Resolves an overwrite case for a map/object.
|
|
* @param {string} key
|
|
* @param {Map|Object} container
|
|
* @param {OverwriteBehaviour} overwriteBehaviour
|
|
* @returns {string} the key to be used
|
|
*/
|
|
function resolveOverwrite(key, container, overwriteBehaviour) {
|
|
let dealAsMap = container instanceof Map;
|
|
let occurances = [...(
|
|
dealAsMap
|
|
? container.keys()
|
|
: Object.keys(container)
|
|
)
|
|
.filter(e => e.includes(key)
|
|
)].length;
|
|
|
|
switch (overwriteBehaviour) {
|
|
case OverwriteBehaviour.REPLACE:
|
|
break;
|
|
case OverwriteBehaviour.RENAME_OLD:
|
|
nameForOld = `${key}${occurances}`;
|
|
if (dealAsMap) {
|
|
container.set(nameForOld, container.get(key));
|
|
container.delete(key);
|
|
} else {
|
|
container[nameForOld] = container[key];
|
|
delete container[key];
|
|
}
|
|
break;
|
|
case OverwriteBehaviour.RENAME:
|
|
default:
|
|
key = `${key}${occurances}`;
|
|
break;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
/**
|
|
* Creates a new Script Tag
|
|
* and then fills the given css rules into it.
|
|
* @param {Array<SStoreDefinition>} ssdArray
|
|
* @returns {HTMLScriptElement}
|
|
*/
|
|
function generateAndFillScriptTag(ssdArray) {
|
|
let tag = document.createElement("script");
|
|
tag.setAttribute("data-compel-gen", "true");
|
|
|
|
for (let i = 0; i < ssdArray.length; i++) {
|
|
const ssd = ssdArray[i];
|
|
tag.innerText += getScriptTagInjectionText(
|
|
clearFunctionDeclarationText(ssd._definition),
|
|
ssd._identifier
|
|
);
|
|
}
|
|
|
|
return tag;
|
|
}
|
|
|
|
|
|
/**
|
|
*
|
|
* @param {string} selector
|
|
* @param {Map<string,string>} stylingMap
|
|
* @returns {string}
|
|
*/
|
|
function getStylingInjectionText(selector, stylingMap) {
|
|
function keyValueToString(key) {
|
|
return `${key}: ${stylingMap[key]}; `;
|
|
}
|
|
|
|
return `${selector
|
|
} { ${Object.keys(stylingMap)
|
|
.map(keyValueToString)
|
|
.join(" ")
|
|
} }; `;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param {Array<SStoreDefinition>} ssdArray
|
|
* @returns {HTMLStyleElement}
|
|
*/
|
|
function generateAndFillStyleTag(ssdArray) {
|
|
let tag = document.createElement("style");
|
|
tag.setAttribute("data-compel-gen", "true");
|
|
|
|
for (let i = 0; i < ssdArray.length; i++) {
|
|
const ssd = ssdArray[i];
|
|
tag.innerText += getStylingInjectionText(ssd._identifier, ssd._definition);
|
|
}
|
|
|
|
return tag;
|
|
}
|
|
|
|
|
|
/**
|
|
* Executes the given function upon the delegating ExtStoreTypes
|
|
* @param {Function} func
|
|
* @returns {Map<ExtStoreType, *}
|
|
*/
|
|
function executeOnExtStoreTypeCollectedTriple(func) {
|
|
return new Map([
|
|
{ [ExtStoreType.COLLECTED_SEGMENT_BEGIN]: func(ExtStoreType.COLLECTED_SEGMENT_BEGIN) },
|
|
{ [ExtStoreType.COLLECTED_DOC_HEAD]: func(ExtStoreType.COLLECTED_DOC_HEAD) },
|
|
{ [ExtStoreType.COLLECTED_DOC_FOOTER]: func(ExtStoreType.COLLECTED_DOC_FOOTER) }
|
|
]);
|
|
}
|
|
|