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

298 lines (297 loc) 14.3 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.KSLAddButtonElement = void 0; const KSLButtonElement_1 = require("./KSLButtonElement"); const KSLIconElement_1 = require("./KSLIconElement"); const assert_1 = require("../utils/assert"); const KSLPopoverElement_1 = require("./KSLPopoverElement"); const KSLPositionedElement_1 = require("./abstract/KSLPositionedElement"); const KSLContainerElement_1 = require("./KSLContainerElement"); const domElement_1 = require("../utils/domElement"); const IFrameCommunicatorTypes_1 = require("../lib/IFrameCommunicatorTypes"); const Logger_1 = require("../lib/Logger"); const zIndex_1 = require("./tokens/zIndex"); const attributes_1 = require("../utils/dataAttributes/attributes"); const parser_1 = require("../utils/dataAttributes/parser"); 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', this.handleClick); this.buttonRef.tooltipMessage = DefaultTooltipMessage; } disconnectedCallback() { super.disconnectedCallback(); window.removeEventListener('click', this.handleClickOutside, { capture: true }); this.buttonRef.removeEventListener('click', this.handleClick); 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; default: 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; default: 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 || 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 (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', this.handleCreateComponentClick); } if (createLinkedItemButtonRef && elementType === IFrameCommunicatorTypes_1.AddButtonElementType.LinkedItems) { createLinkedItemButtonRef.addEventListener('click', this.handleCreateLinkedItemClick); } if (insertLinkedItemButtonRef) { insertLinkedItemButtonRef.addEventListener('click', this.handleInsertLinkedItemClick); } }; 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