@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
328 lines (327 loc) • 15.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.KSLAddButtonElement = void 0;
const IFrameCommunicatorTypes_1 = require("../lib/IFrameCommunicatorTypes");
const Logger_1 = require("../lib/Logger");
const assert_1 = require("../utils/assert");
const attributes_1 = require("../utils/dataAttributes/attributes");
const parser_1 = require("../utils/dataAttributes/parser");
const domElement_1 = require("../utils/domElement");
const KSLPositionedElement_1 = require("./abstract/KSLPositionedElement");
const KSLButtonElement_1 = require("./KSLButtonElement");
const KSLContainerElement_1 = require("./KSLContainerElement");
const KSLIconElement_1 = require("./KSLIconElement");
const KSLPopoverElement_1 = require("./KSLPopoverElement");
const zIndex_1 = require("./tokens/zIndex");
const ContentIsPublishedTooltip = "Content is published";
const DefaultTooltipMessage = "Insert...";
const getCreateLinkedItemTooltip = (canUserCreateLinkedItem) => canUserCreateLinkedItem
? "Create new item"
: "Your role cannot create items from the allowed types";
var PopoverButtonId;
(function (PopoverButtonId) {
PopoverButtonId["CreateComponent"] = "create-component";
PopoverButtonId["CreateLinkedItem"] = "create-linked-item";
PopoverButtonId["InsertLinkedItem"] = "insert-linked-item";
})(PopoverButtonId || (PopoverButtonId = {}));
const getPopoverHtml = ({ elementType, isParentPublished, permissions, }) => {
const canUserCreateLinkedItem = permissions.get(IFrameCommunicatorTypes_1.AddButtonPermission.CreateNew) === IFrameCommunicatorTypes_1.AddButtonPermissionCheckResult.Ok;
return `
<style>
.ksl-add-button__popover-button + .ksl-add-button__popover-button {
margin-left: 4px;
}
</style>
<ksl-button
id="${PopoverButtonId.InsertLinkedItem}"
class="ksl-add-button__popover-button"
type="${KSLButtonElement_1.ButtonType.Quinary}"
tooltip-position="${KSLPositionedElement_1.ElementPositionOffset.Top}"
tooltip-message="${isParentPublished ? ContentIsPublishedTooltip : "Insert existing item"}"
${isParentPublished && "disabled"}
>
<ksl-icon icon-name="${KSLIconElement_1.IconName.Puzzle}"/>
</ksl-button>
<ksl-button
id="${PopoverButtonId.CreateLinkedItem}"
class="ksl-add-button__popover-button"
type="${KSLButtonElement_1.ButtonType.Quinary}"
tooltip-position="${KSLPositionedElement_1.ElementPositionOffset.Top}"
tooltip-message="${isParentPublished
? ContentIsPublishedTooltip
: getCreateLinkedItemTooltip(canUserCreateLinkedItem)}"
${(isParentPublished || !canUserCreateLinkedItem) && "disabled"}
${elementType !== IFrameCommunicatorTypes_1.AddButtonElementType.LinkedItems && "hidden"}
>
<ksl-icon icon-name="${KSLIconElement_1.IconName.PlusPuzzle}"/>
</ksl-button>
<ksl-button
id="${PopoverButtonId.CreateComponent}"
class="ksl-add-button__popover-button"
type="${KSLButtonElement_1.ButtonType.Quinary}"
tooltip-position="${KSLPositionedElement_1.ElementPositionOffset.Top}"
tooltip-message="${isParentPublished ? ContentIsPublishedTooltip : "Insert new component"}"
${isParentPublished && "disabled"}
${elementType !== IFrameCommunicatorTypes_1.AddButtonElementType.RichText && "hidden"}
>
<ksl-icon icon-name="${KSLIconElement_1.IconName.CollapseScheme}"/>
</ksl-button>
`;
};
const templateHTML = `
<style>
:host {
display: inline-block;
position: absolute;
z-index: calc(var(--ksl-z-index, ${zIndex_1.BaseZIndex}) + 20);
pointer-events: all;
touch-action: initial;
}
:host(:focus) {
outline: none;
}
</style>
<ksl-button
type="${KSLButtonElement_1.ButtonType.Primary}"
tooltip-position="${KSLPositionedElement_1.ElementPositionOffset.Top}"
>
<ksl-icon icon-name="${KSLIconElement_1.IconName.Plus}"/>
</ksl-button>
`;
class KSLAddButtonElement extends KSLPositionedElement_1.KSLPositionedElement {
static get is() {
return "ksl-add-button";
}
get position() {
return (this.targetRef?.getAttribute(attributes_1.MetadataAttribute.AddButtonRenderPosition) ??
KSLPositionedElement_1.ElementPositionOffset.Bottom);
}
buttonRef;
popoverRef = null;
constructor() {
super();
(0, assert_1.assert)(this.shadowRoot, 'Shadow root must be available in "open" mode.');
this.buttonRef = this.shadowRoot.querySelector(KSLButtonElement_1.KSLButtonElement.is);
}
static initializeTemplate() {
return (0, domElement_1.createTemplateForCustomElement)(templateHTML);
}
connectedCallback() {
super.connectedCallback();
window.addEventListener("click", this.handleClickOutside, { capture: true });
this.buttonRef.addEventListener("click", (event) => {
void this.handleClick(event);
});
this.buttonRef.tooltipMessage = DefaultTooltipMessage;
}
disconnectedCallback() {
super.disconnectedCallback();
window.removeEventListener("click", this.handleClickOutside, { capture: true });
this.buttonRef.removeEventListener("click", (event) => {
void this.handleClick(event);
});
this.dismissPopover();
}
adjustPosition = () => {
if (!this.targetRef || !this.offsetParent) {
return;
}
if (!(this.offsetParent instanceof KSLContainerElement_1.KSLContainerElement)) {
console.warn("KSLAddButtonElement: should be located inside KSLContainerElement to be positioned properly.");
}
const offsetParentRect = this.offsetParent.getBoundingClientRect();
const targetRect = this.targetRef.getBoundingClientRect();
const thisRect = this.getBoundingClientRect();
const verticalOffset = this.calculateTopOffset(thisRect, targetRect);
const horizontalOffset = this.calculateLeftOffset(thisRect, targetRect);
this.style.top = `${targetRect.top - offsetParentRect.top + verticalOffset}px`;
this.style.left = `${targetRect.left - offsetParentRect.left + horizontalOffset}px`;
};
calculateTopOffset(thisRect, targetRect) {
const offset = super.calculateTopOffset(thisRect, targetRect);
switch (this.position) {
case KSLPositionedElement_1.ElementPositionOffset.TopStart:
case KSLPositionedElement_1.ElementPositionOffset.Top:
case KSLPositionedElement_1.ElementPositionOffset.TopEnd:
return offset / 2;
case KSLPositionedElement_1.ElementPositionOffset.BottomStart:
case KSLPositionedElement_1.ElementPositionOffset.Bottom:
case KSLPositionedElement_1.ElementPositionOffset.BottomEnd:
return offset - thisRect.height / 2;
case KSLPositionedElement_1.ElementPositionOffset.Left:
case KSLPositionedElement_1.ElementPositionOffset.LeftEnd:
case KSLPositionedElement_1.ElementPositionOffset.LeftStart:
case KSLPositionedElement_1.ElementPositionOffset.None:
case KSLPositionedElement_1.ElementPositionOffset.Right:
case KSLPositionedElement_1.ElementPositionOffset.RightEnd:
case KSLPositionedElement_1.ElementPositionOffset.RightStart:
return offset;
}
}
calculateLeftOffset(thisRect, targetRect) {
const offset = super.calculateLeftOffset(thisRect, targetRect);
switch (this.position) {
case KSLPositionedElement_1.ElementPositionOffset.LeftStart:
case KSLPositionedElement_1.ElementPositionOffset.Left:
case KSLPositionedElement_1.ElementPositionOffset.LeftEnd:
return offset / 2;
case KSLPositionedElement_1.ElementPositionOffset.RightStart:
case KSLPositionedElement_1.ElementPositionOffset.Right:
case KSLPositionedElement_1.ElementPositionOffset.RightEnd:
return targetRect.width - thisRect.width / 2;
case KSLPositionedElement_1.ElementPositionOffset.Bottom:
case KSLPositionedElement_1.ElementPositionOffset.BottomEnd:
case KSLPositionedElement_1.ElementPositionOffset.BottomStart:
case KSLPositionedElement_1.ElementPositionOffset.None:
case KSLPositionedElement_1.ElementPositionOffset.Top:
case KSLPositionedElement_1.ElementPositionOffset.TopEnd:
case KSLPositionedElement_1.ElementPositionOffset.TopStart:
return offset;
}
}
handleClick = async (event) => {
if (this.popoverRef) {
return;
}
(0, assert_1.assert)(this.targetRef, "Target node is not set for this add button.");
event.preventDefault();
event.stopPropagation();
this.buttonRef.loading = true;
const data = (0, parser_1.parseAddButtonDataAttributes)(this.targetRef);
try {
const eventData = { data, targetNode: this.targetRef };
const response = await this.dispatchAsyncEvent("ksl:add-button:initial", eventData);
const { permissions } = response;
const isUserMissingPermissions = permissions.get(IFrameCommunicatorTypes_1.AddButtonPermission.ViewParent) !== IFrameCommunicatorTypes_1.AddButtonPermissionCheckResult.Ok ||
permissions.get(IFrameCommunicatorTypes_1.AddButtonPermission.Edit) !== IFrameCommunicatorTypes_1.AddButtonPermissionCheckResult.Ok;
const areComponentsForbidden = permissions.get(IFrameCommunicatorTypes_1.AddButtonPermission.CreateNew) ===
IFrameCommunicatorTypes_1.AddButtonPermissionCheckResult.RteWithForbiddenComponents;
if (isUserMissingPermissions || areComponentsForbidden) {
this.buttonRef.loading = false;
this.buttonRef.disabled = true;
this.buttonRef.tooltipMessage = isUserMissingPermissions
? "You are not allowed to add content here"
: "Components and items can't be added here";
}
else {
this.buttonRef.loading = false;
this.buttonRef.disabled = false;
this.buttonRef.tooltipMessage = DefaultTooltipMessage;
this.displayPopover(response);
}
}
catch (reason) {
(0, Logger_1.logError)(reason);
this.buttonRef.loading = false;
this.buttonRef.disabled = true;
if (typeof reason === "object" &&
reason !== null &&
"message" in reason &&
typeof reason.message === "string") {
this.buttonRef.tooltipMessage = reason.message;
}
else {
this.buttonRef.tooltipMessage = "Something went wrong";
}
}
};
handleClickOutside = (event) => {
if (!this.popoverRef || !(event.target instanceof Element)) {
return;
}
const clickedInside = this.isSameNode(event.target) || this.contains(event.target);
if (!clickedInside) {
this.dismissPopover();
}
};
displayPopover = (response) => {
(0, assert_1.assert)(this.shadowRoot, 'Shadow root must be available in "open" mode.');
if (this.popoverRef) {
this.dismissPopover();
}
this.buttonRef.tooltipPosition = KSLPositionedElement_1.ElementPositionOffset.Bottom;
const popover = document.createElement(KSLPopoverElement_1.KSLPopoverElement.is);
popover.innerHTML = getPopoverHtml(response);
const popoverParent = this.shadowRoot;
this.popoverRef = popoverParent.appendChild(popover);
this.popoverRef.position = KSLPositionedElement_1.ElementPositionOffset.Top;
this.popoverRef.attachTo(this);
this.addPopoverEventListeners(response.elementType);
this.popoverRef.visible = true;
this.popoverRef.adjustPosition();
};
dismissPopover = () => {
this.buttonRef.tooltipPosition = KSLPositionedElement_1.ElementPositionOffset.Top;
if (this.popoverRef) {
this.removePopoverEventListeners();
this.popoverRef.visible = false;
this.popoverRef.remove();
this.popoverRef = null;
}
};
addPopoverEventListeners = (elementType) => {
if (!this.popoverRef) {
return;
}
const createComponentButtonRef = this.popoverRef.querySelector(`#${PopoverButtonId.CreateComponent}`);
const createLinkedItemButtonRef = this.popoverRef.querySelector(`#${PopoverButtonId.CreateLinkedItem}`);
const insertLinkedItemButtonRef = this.popoverRef.querySelector(`#${PopoverButtonId.InsertLinkedItem}`);
if (createComponentButtonRef && elementType === IFrameCommunicatorTypes_1.AddButtonElementType.RichText) {
createComponentButtonRef.addEventListener("click", (event) => {
this.handleCreateComponentClick(event);
});
}
if (createLinkedItemButtonRef && elementType === IFrameCommunicatorTypes_1.AddButtonElementType.LinkedItems) {
createLinkedItemButtonRef.addEventListener("click", (event) => {
this.handleCreateLinkedItemClick(event);
});
}
if (insertLinkedItemButtonRef) {
insertLinkedItemButtonRef.addEventListener("click", (event) => {
this.handleInsertLinkedItemClick(event);
});
}
};
removePopoverEventListeners = () => {
if (!this.popoverRef) {
return;
}
const createComponentButtonRef = this.popoverRef.querySelector(`#${PopoverButtonId.CreateComponent}`);
const createLinkedItemButtonRef = this.popoverRef.querySelector(`#${PopoverButtonId.CreateLinkedItem}`);
const insertLinkedItemButtonRef = this.popoverRef.querySelector(`#${PopoverButtonId.InsertLinkedItem}`);
if (createComponentButtonRef) {
createComponentButtonRef.removeEventListener("click", this.handleCreateComponentClick);
}
if (createLinkedItemButtonRef) {
createLinkedItemButtonRef.removeEventListener("click", this.handleCreateLinkedItemClick);
}
if (insertLinkedItemButtonRef) {
insertLinkedItemButtonRef.removeEventListener("click", this.handleInsertLinkedItemClick);
}
};
handleCreateComponentClick = (event) => {
this.handleAddActionClick(event, IFrameCommunicatorTypes_1.AddButtonAction.CreateComponent);
};
handleCreateLinkedItemClick = (event) => {
this.handleAddActionClick(event, IFrameCommunicatorTypes_1.AddButtonAction.CreateLinkedItem);
};
handleInsertLinkedItemClick = (event) => {
this.handleAddActionClick(event, IFrameCommunicatorTypes_1.AddButtonAction.InsertLinkedItem);
};
handleAddActionClick = (event, action) => {
(0, assert_1.assert)(this.targetRef, "Target node is not set for this add button.");
event.preventDefault();
event.stopPropagation();
const data = (0, parser_1.parseAddButtonDataAttributes)(this.targetRef);
const customEvent = new CustomEvent("ksl:add-button:action", {
detail: {
data: { ...data, action },
targetNode: this.targetRef,
},
});
this.dismissPopover();
this.dispatchEvent(customEvent);
};
}
exports.KSLAddButtonElement = KSLAddButtonElement;
//# sourceMappingURL=KSLAddButtonElement.js.map