UNPKG

@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
"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