@kontent-ai/smart-link
Version:
Kontent.ai Smart Link SDK allowing to automatically inject [smart links](https://docs.kontent.ai/tutorials/develop-apps/build-strong-foundation/set-up-editing-from-preview#a-using-smart-links) to Kontent.ai according to manually specified [HTML data attri
150 lines • 6.67 kB
JavaScript
import { logDebug } from '../../lib/Logger';
import { InsertPositionPlacement, } from '../../lib/IFrameCommunicatorTypes';
import { DataAttribute } from './attributes';
import { getHighlightTypeForElement, HighlightType } from './elementHighlight';
/**
* Parses data attributes from an HTML element to extract edit button information.
* The function determines the type of element being edited (element, component, or item)
* and extracts relevant data attributes based on that type.
*/
export function parseEditButtonDataAttributes(target) {
const type = getHighlightTypeForElement(target);
const pattern = getEditButtonDataAttributesPattern(type);
logDebug('Parsing edit button data attributes for element: ', target);
logDebug('Parsing values from data attributes using this pattern: ', pattern);
return parseDataAttributes(pattern, target);
}
/**
* Parses data attributes from an HTML element to extract add button information.
* The function determines the insert position type (fixed or relative) and extracts
* relevant data attributes based on that type.
*/
export function parseAddButtonDataAttributes(target) {
const position = target.getAttribute(DataAttribute.AddButtonInsertPosition);
const pattern = getAddButtonDataAttributesPattern(position);
logDebug('Parsing add button data attributes for element: ', target);
logDebug('Parsing values from data attributes following this pattern: ', pattern);
return parseDataAttributes(pattern, target);
}
function getEditButtonDataAttributesPattern(type) {
switch (type) {
case HighlightType.Element:
return elementEditButtonParserPattern;
case HighlightType.ContentComponent:
return componentEditButtonParserPattern;
case HighlightType.ContentItem:
return itemEditButtonParserPattern;
default:
return baseParserPattern;
}
}
function getAddButtonDataAttributesPattern(position) {
switch (position) {
case InsertPositionPlacement.After:
case InsertPositionPlacement.Before:
return relativeAddButtonParserPattern;
case InsertPositionPlacement.End:
case InsertPositionPlacement.Start:
default:
return fixedAddButtonParserPattern;
}
}
/**
* Creates result from found data attributes on an element.
* This function follow rules:
* - If token is found, it is added to the result
* - If token is not found or the data attribute is already taken, but is optional, it is skipped
* - If token is not found, and is required, the function stops searching as higher precedence tokens cannot be found
*/
function applyPatternToParsedValues(pattern, parsedValues) {
const takenDataAttributes = new Set();
const result = [];
for (const p of pattern) {
const data = parsedValues.find((a) => p.dataAttributes.includes(a.dataAttribute) && !takenDataAttributes.has(a.dataAttribute));
if (!data && p.optional) {
continue;
}
if (!data) {
break;
}
takenDataAttributes.add(data.dataAttribute);
result.push({ token: p.key, value: data.value, dataAttribute: data.dataAttribute });
}
return result;
}
export const parseDataAttributes = (pattern, element) => {
if (!element || pattern.length === 0) {
return { parsed: {}, debugData: [] };
}
const parsedValues = Object.values(DataAttribute)
.map((a) => {
const value = element.getAttribute(a);
return value ? { dataAttribute: a, value } : null;
})
.filter((a) => a !== null);
const result = applyPatternToParsedValues(pattern, parsedValues);
const lastFoundTokenIndex = pattern.findIndex((p) => p.key === result.at(-1)?.token);
const newPattern = pattern.slice(lastFoundTokenIndex + 1);
const parentResult = parseDataAttributes(newPattern, element.parentElement);
return {
parsed: { ...Object.fromEntries(result.map((r) => [r.token, r.value])), ...parentResult.parsed },
debugData: [
...parentResult.debugData,
...(parsedValues.length > 0
? [
{
element,
parsedAttributes: parsedValues
.filter((a) => result.find((r) => r.dataAttribute === a.dataAttribute) !== undefined)
.map((a) => ({
token: result.find((r) => r.dataAttribute === a.dataAttribute).token,
dataAttribute: a.dataAttribute,
value: a.value,
})),
skippedAttributes: parsedValues
.filter((a) => result.find((r) => r.dataAttribute === a.dataAttribute) === undefined)
.map((a) => ({
dataAttribute: a.dataAttribute,
value: a.value,
})),
},
]
: []),
],
};
};
const baseParserPattern = [
{ key: 'languageCodename', dataAttributes: [DataAttribute.LanguageCodename] },
{ key: 'environmentId', dataAttributes: [DataAttribute.EnvironmentId] },
];
// EDIT BUTTON PARSING PATTERNS
const itemEditButtonParserPattern = [
{ key: 'itemId', dataAttributes: [DataAttribute.ItemId] },
...baseParserPattern,
];
const componentEditButtonParserPattern = [
{ key: 'contentComponentId', dataAttributes: [DataAttribute.ComponentId] },
...itemEditButtonParserPattern,
];
const elementEditButtonParserPattern = [
{ key: 'elementCodename', dataAttributes: [DataAttribute.ElementCodename] },
{ key: 'contentComponentId', dataAttributes: [DataAttribute.ComponentId], optional: true },
...itemEditButtonParserPattern,
];
// ADD BUTTON PARSING PATTERNS
const baseAddButtonParserPattern = [
{ key: 'elementCodename', dataAttributes: [DataAttribute.ElementCodename] },
{ key: 'contentComponentId', dataAttributes: [DataAttribute.ComponentId], optional: true },
{ key: 'itemId', dataAttributes: [DataAttribute.ItemId] },
...baseParserPattern,
];
const relativeAddButtonParserPattern = [
{ key: 'placement', dataAttributes: [DataAttribute.AddButtonInsertPosition] },
{ key: 'targetId', dataAttributes: [DataAttribute.ComponentId, DataAttribute.ItemId] },
...baseAddButtonParserPattern,
];
const fixedAddButtonParserPattern = [
{ key: 'placement', dataAttributes: [DataAttribute.AddButtonInsertPosition], optional: true },
...baseAddButtonParserPattern,
];
//# sourceMappingURL=parser.js.map