{"version":3,"file":"index.min.js","sources":["../../../SiteBuilderFramework/ClientLib/src/razor/builder.js","../../../SiteBuilderFramework/ClientLib/src/razor/accordion.js","../../../SiteBuilderFramework/ClientLib/src/razor/checkbox.js","../../../SiteBuilderFramework/ClientLib/src/utils/dom.js","../../../SiteBuilderFramework/ClientLib/src/utils/ui.js","../../../SiteBuilderFramework/ClientLib/src/razor/dialog.js","../../../SiteBuilderFramework/ClientLib/src/razor/dropdown.js","../../../SiteBuilderFramework/ClientLib/src/razor/fileupload.js","../../../SiteBuilderFramework/ClientLib/src/razor/inputpin.js","../../../SiteBuilderFramework/ClientLib/src/razor/place.js","../../../SiteBuilderFramework/ClientLib/src/utils/string.js","../../../SiteBuilderFramework/ClientLib/src/directives/tooltip.js","../../../SiteBuilderFramework/ClientLib/src/razor/tooltip.js","../../../SiteBuilderFramework/ClientLib/src/razor/razorUtils.js","../../../SiteBuilderFramework/ClientLib/src/razor/navigation.js","../../../SiteBuilderFramework/ClientLib/src/razor/index.js","../../../SiteBuilderFramework/ClientLib/src/razor/razorForm.js","../../ClientApp/src/website-tenant/index.js"],"sourcesContent":["export default function createRazorBuilder(options) {\r\n const self = {\r\n components: [],\r\n add: (component) => {\r\n console.log(\"builder.add\", component);\r\n self.components.push(component);\r\n // component.selector\r\n // component.create\r\n // component.attach\r\n return self;\r\n },\r\n init: (win) => {\r\n self.components.forEach((compo) => {\r\n Array.from(win.document.querySelectorAll(compo.selector)).forEach((node) => {\r\n compo.attach(node);\r\n console.log(\"attach component\", compo.selector, node);\r\n });\r\n });\r\n },\r\n };\r\n return self;\r\n}\r\n","/*\r\n * Accordion\r\n */\r\nconst showTab = (tab) => {\r\n console.log(\"showTab\", tab);\r\n const panel = tab.querySelector(\".accordion-tab-panel\");\r\n const toogleButton = tab.querySelector(\".accordion-trigger\");\r\n toogleButton.setAttribute(\"aria-expanded\", \"true\");\r\n\r\n tab.classList.add(\"active\");\r\n panel.style.height = \"auto\";\r\n\r\n var height = panel.clientHeight + \"px\";\r\n panel.style.height = \"0px\";\r\n\r\n setTimeout(function () {\r\n panel.style.height = height;\r\n }, 0);\r\n};\r\nconst hideTab = (tab) => {\r\n console.log(\"hideTab\", tab);\r\n const panel = tab.querySelector(\".accordion-tab-panel\");\r\n const toogleButton = tab.querySelector(\".accordion-trigger\");\r\n toogleButton.setAttribute(\"aria-expanded\", \"false\");\r\n\r\n if (parseInt(panel.style.height) > 0) {\r\n panel.style.height = \"0px\";\r\n panel.addEventListener(\"transitionend\", () => tab.classList.remove(\"active\"), { once: true });\r\n } else {\r\n tab.classList.remove(\"active\");\r\n }\r\n};\r\n\r\nconst attachAccordion = (node) => {\r\n const multiple = node.dataset.multiple === \"true\";\r\n const tabs = Array.from(node.querySelectorAll(\".a-accordion-tab\"));\r\n tabs.forEach((tab) => {\r\n if (tab.classList.contains(\"active\")) {\r\n const panel = tab.querySelector(\".accordion-tab-panel\");\r\n panel.style.height = panel.clientHeight + \"px\";\r\n }\r\n\r\n const toogleButton = tab.querySelector(\".accordion-trigger\");\r\n toogleButton.addEventListener(\"mousedown\", (e) => {\r\n e.preventDefault();\r\n if (tab.classList.contains(\"active\")) {\r\n hideTab(tab);\r\n } else {\r\n showTab(tab);\r\n }\r\n if (!multiple) {\r\n tabs.filter((t) => t !== tab).forEach((t) => hideTab(t));\r\n }\r\n });\r\n });\r\n};\r\n\r\nconst createAccordion = (attributes) => {};\r\n\r\nconst razorAccordion = {\r\n selector: \".a-accordion\",\r\n create: createAccordion,\r\n attach: attachAccordion,\r\n};\r\n\r\nexport default razorAccordion;\r\n","/*\r\n * Checkbox\r\n */\r\n\r\nconst attachCheckbox = (node) => {};\r\n\r\nconst createCheckbox = (attributes) => {};\r\n\r\nconst razorCheckbox = {\r\n selector: \".a-checkbox\",\r\n create: createCheckbox,\r\n attach: attachCheckbox,\r\n};\r\n\r\nexport default razorCheckbox;\r\n","const FOCUSABLE_ELEMENTS = [\r\n \"a[href]\",\r\n \"area[href]\",\r\n 'input:not([disabled]):not([type=\"hidden\"]):not([aria-hidden])',\r\n \"select:not([disabled]):not([aria-hidden])\",\r\n \"textarea:not([disabled]):not([aria-hidden])\",\r\n \"button:not([disabled]):not([aria-hidden])\",\r\n \"iframe\",\r\n \"object\",\r\n \"embed\",\r\n \"[contenteditable]\",\r\n '[tabindex]:not([tabindex^=\"-\"])',\r\n];\r\n\r\nexport function findAncestor(el, selector) {\r\n while ((el = el.parentElement) && !el.matches(selector));\r\n return el;\r\n}\r\n\r\nexport function findAncestorOrSelf(el, selector) {\r\n do {\r\n if (el.matches(selector)) {\r\n return true;\r\n }\r\n } while ((el = el.parentElement));\r\n return null;\r\n}\r\n\r\nexport function isVisible(elem) {\r\n return !!(elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length);\r\n}\r\n\r\n// Get absolute offset (top, left) of a node\r\nexport function offset(el) {\r\n // si le noeud est dans un document situé dans une iframe,\r\n // on ajout l'offet de l'iframe\r\n let iframeLeft = 0,\r\n iframeTop = 0;\r\n\r\n if (el.ownerDocument != document) {\r\n const parentIframe = el.ownerDocument.defaultView.frameElement;\r\n const iframeOffset = offset(parentIframe);\r\n iframeLeft = iframeOffset.left;\r\n iframeTop = iframeOffset.top;\r\n }\r\n\r\n const rect = el.getBoundingClientRect();\r\n const scrollLeft = parseInt(window.pageXOffset || document.documentElement.scrollLeft);\r\n const scrollTop = parseInt(window.pageYOffset || document.documentElement.scrollTop);\r\n\r\n return {\r\n top: parseInt(rect.top) + scrollTop + iframeTop,\r\n left: parseInt(rect.left) + scrollLeft + iframeLeft,\r\n right: parseInt(rect.right) + scrollLeft + iframeLeft,\r\n bottom: parseInt(rect.bottom) + scrollTop + iframeTop,\r\n };\r\n}\r\n\r\nexport function fadeIn(element, duration, callback) {\r\n if (element) {\r\n element.style.opacity = 0;\r\n\r\n let last = +new Date();\r\n let opacity = 0;\r\n\r\n let tick = function () {\r\n opacity = +element.style.opacity + (new Date().getTime() - last) / duration;\r\n element.style.opacity = opacity;\r\n last = +new Date();\r\n\r\n if (+opacity < 1) {\r\n (window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);\r\n } else {\r\n callback && callback();\r\n }\r\n };\r\n\r\n tick();\r\n }\r\n}\r\n\r\nexport function fadeOut(element, duration, callback) {\r\n if (element) {\r\n element.style.opacity = 1;\r\n\r\n let last = +new Date();\r\n let opacity = 1;\r\n\r\n let tick = function () {\r\n opacity = +element.style.opacity - (new Date().getTime() - last) / duration;\r\n element.style.opacity = opacity;\r\n last = +new Date();\r\n\r\n if (+opacity > 0) {\r\n (window.requestAnimationFrame && requestAnimationFrame(tick)) || setTimeout(tick, 16);\r\n } else {\r\n callback && callback();\r\n }\r\n };\r\n\r\n tick();\r\n }\r\n}\r\n\r\nexport function getFocusableNodes(node) {\r\n const nodes = node.querySelectorAll(FOCUSABLE_ELEMENTS);\r\n return Array(...nodes);\r\n}\r\n\r\n/// Retain focus in containerNode\r\nexport function retainFocus(event, containerNode) {\r\n let focusableNodes = getFocusableNodes(containerNode);\r\n\r\n if (focusableNodes.length === 0) return;\r\n\r\n focusableNodes = focusableNodes.filter((node) => {\r\n return node.offsetParent !== null;\r\n });\r\n\r\n // if disableFocus is true\r\n if (!containerNode.contains(document.activeElement)) {\r\n focusableNodes[0].focus();\r\n } else {\r\n const focusedItemIndex = focusableNodes.indexOf(document.activeElement);\r\n\r\n if (event.shiftKey && focusedItemIndex === 0) {\r\n focusableNodes[focusableNodes.length - 1].focus();\r\n event.preventDefault();\r\n }\r\n\r\n if (!event.shiftKey && focusableNodes.length > 0 && focusedItemIndex === focusableNodes.length - 1) {\r\n focusableNodes[0].focus();\r\n event.preventDefault();\r\n }\r\n }\r\n}\r\n\r\nexport const getRangeBeforeCursor = (node) => getRangeFromCursor(node, true);\r\nexport const getRangeAfterCursor = (node) => getRangeFromCursor(node, false);\r\nexport const getRangeFromCursor = (node, start = false) => {\r\n var range = window.getSelection().getRangeAt(0);\r\n var clonedRange = range.cloneRange();\r\n clonedRange.collapse(start);\r\n\r\n // Create a new range from the end of the cloned range to the end of the content editable element\r\n var newRange = document.createRange();\r\n newRange.selectNodeContents(node);\r\n start ? newRange.setEnd(clonedRange.startContainer, clonedRange.startOffset) : newRange.setStart(clonedRange.endContainer, clonedRange.endOffset);\r\n\r\n return newRange;\r\n};\r\n\r\nexport const getCursorPosition = () => {\r\n const selection = window.getSelection();\r\n const range = selection.getRangeAt(0);\r\n let rect = range.getBoundingClientRect();\r\n\r\n if (range.collapsed && rect.top === 0 && rect.left === 0) {\r\n let tmpNode = document.createTextNode(\"\\ufeff\");\r\n range.insertNode(tmpNode);\r\n rect = range.getBoundingClientRect();\r\n tmpNode.remove();\r\n }\r\n\r\n return {\r\n left: parseFloat(rect.left),\r\n top: parseFloat(rect.top),\r\n };\r\n};\r\n\r\nexport const setCursorPosition = (node, x, y) => {\r\n var range = null;\r\n if (document.caretPositionFromPoint) {\r\n var position = document.caretPositionFromPoint(x, y);\r\n range = document.createRange();\r\n range.setStart(position.offsetNode, position.offset);\r\n } else if (document.caretRangeFromPoint) {\r\n range = document.caretRangeFromPoint(x, y);\r\n }\r\n\r\n // Set the selection to the new range\r\n var selection = window.getSelection();\r\n selection.removeAllRanges();\r\n selection.addRange(range);\r\n\r\n // Set focus to the content editable element\r\n // node.focus();\r\n};\r\n\r\nexport const isEmptyNode = (node) => (node ? getNodeContentLength(node) == 0 : true);\r\nexport const getNodeContentLength = (node) => node.textContent.length;\r\n\r\n/// getCursorOffset within a contenteditable div\r\nexport const getCursorOffset = (node) => {\r\n if (!node) {\r\n return -1;\r\n }\r\n\r\n var caretOffset = 0;\r\n if (typeof window.getSelection != \"undefined\") {\r\n var range = window.getSelection().getRangeAt(0);\r\n var preCaretRange = range.cloneRange();\r\n preCaretRange.selectNodeContents(node);\r\n preCaretRange.setEnd(range.endContainer, range.endOffset);\r\n caretOffset = preCaretRange.toString().length;\r\n } else if (typeof document.selection != \"undefined\" && document.selection.type != \"Control\") {\r\n var textRange = document.selection.createRange();\r\n var preCaretTextRange = document.body.createTextRange();\r\n preCaretTextRange.moveToElementText(node);\r\n preCaretTextRange.setEndPoint(\"EndToEnd\", textRange);\r\n caretOffset = preCaretTextRange.text.length;\r\n }\r\n return caretOffset;\r\n};\r\n\r\nexport const setCursorOffset = (node, offset) => {\r\n const range = document.createRange();\r\n const sel = window.getSelection();\r\n return __setCursorOffset(node, { sel, range, offset, currentOffset: 0 }, node);\r\n};\r\n\r\nconst __setCursorOffset = (node, context, containerNode) => {\r\n const { range, sel } = context;\r\n\r\n if (node.nodeType === Node.TEXT_NODE) {\r\n const nodeLength = node.length;\r\n if (context.currentOffset + nodeLength >= context.offset) {\r\n range.setStart(node, context.offset - context.currentOffset);\r\n range.collapse(true);\r\n sel.removeAllRanges();\r\n sel.addRange(range);\r\n containerNode.focus();\r\n return true;\r\n }\r\n context.currentOffset += nodeLength;\r\n\r\n /// If node is empty without text node, select it\r\n } else if (node.childNodes.length == 0) {\r\n range.setStart(node, 0);\r\n range.setEnd(node, 0);\r\n sel.removeAllRanges();\r\n sel.addRange(range);\r\n return true;\r\n } else {\r\n for (let i = 0; i < node.childNodes.length; i++) {\r\n if (__setCursorOffset(node.childNodes[i], context, containerNode)) {\r\n return true;\r\n }\r\n }\r\n }\r\n return false;\r\n};\r\n\r\nexport const moveCursorToStart = (node) => moveCursorTo(node, true);\r\nexport const moveCursorToEnd = (node) => moveCursorTo(node, false);\r\nconst moveCursorTo = (node, start) => {\r\n const range = document.createRange();\r\n range.selectNodeContents(node);\r\n range.collapse(start);\r\n const selection = window.getSelection();\r\n selection.removeAllRanges();\r\n selection.addRange(range);\r\n};\r\n\r\n/// Return a rect of all absolute position removing padding\r\nexport const getNodeContentRect = (node) => {\r\n const styles = window.getComputedStyle(node, null);\r\n\r\n const prop = (name) => parseFloat(styles.getPropertyValue(name));\r\n\r\n const extraBottom = prop(\"padding-bottom\") + prop(\"border-bottom-width\");\r\n const extraLeft = prop(\"padding-left\") + prop(\"border-left-width\");\r\n const extraRight = prop(\"padding-right\") + prop(\"border-right-width\");\r\n const extraTop = prop(\"padding-top\") + prop(\"border-top-width\");\r\n\r\n const rect = node.getBoundingClientRect();\r\n return {\r\n top: rect.top + extraTop,\r\n left: rect.left + extraLeft,\r\n right: rect.right - extraRight,\r\n bottom: rect.bottom - extraBottom,\r\n };\r\n};\r\n\r\n/// Return the line height of the node. If no\r\nexport const getLineHeight = (node) => {\r\n const computedStyle = getComputedStyle(node);\r\n const lineHeight = computedStyle.getPropertyValue(\"line-height\");\r\n if ([\"normal\", \"initial\", \"inherit\"].includes(lineHeight)) {\r\n return parseFloat(computedStyle.getPropertyValue(\"font-size\"));\r\n }\r\n return parseFloat(lineHeight);\r\n};\r\n\r\nexport function pasteHtmlAtSelection(html) {\r\n const selection = window.getSelection();\r\n\r\n let range = selection.getRangeAt(0);\r\n range.deleteContents();\r\n\r\n // Range.createContextualFragment() would be useful here but is\r\n // non-standard and not supported in all browsers (IE9, for one)\r\n const el = document.createElement(\"div\");\r\n el.innerHTML = html;\r\n let frag = document.createDocumentFragment(),\r\n node,\r\n lastNode;\r\n while ((node = el.firstChild)) {\r\n lastNode = frag.appendChild(node);\r\n }\r\n range.insertNode(frag);\r\n\r\n // Preserve the selection\r\n if (lastNode) {\r\n range = range.cloneRange();\r\n range.setStartAfter(lastNode);\r\n range.collapse(true);\r\n selection.removeAllRanges();\r\n selection.addRange(range);\r\n }\r\n}\r\n\r\nexport function removeElementsByTagName(node, names) {\r\n if (!node) {\r\n return;\r\n }\r\n if (!Array.isArray(names)) {\r\n names = [names];\r\n }\r\n\r\n if (node.nodeType === Node.ELEMENT_NODE && names.find((name) => node.nodeName === name.toUpperCase())) {\r\n node.replaceWith(...node.childNodes);\r\n } else {\r\n const children = node.childNodes;\r\n for (let i = 0; i < children.length; i++) {\r\n removeElementsByTagName(children[i], names);\r\n }\r\n }\r\n}\r\n\r\nexport const findDomParent = (node, filter) => findDomOrSelfParent(node.parentNode, filter);\r\nexport function findDomOrSelfParent(node, filter) {\r\n if (filter(node)) {\r\n return node;\r\n }\r\n return node.parentNode ? findDomOrSelfParent(node.parentNode, filter) : null;\r\n}\r\n\r\nexport const getRootParent = (node) => findDomParent(node, (n) => !n.parentNode);\r\n\r\nexport const findNodeIndex = (node) => {\r\n let index = 0;\r\n while (node.previousSibling) {\r\n index++;\r\n node = node.previousSibling;\r\n }\r\n return index;\r\n};\r\n\r\n// Helper function to get the XPath of an element\r\nexport function getElementXPath(element) {\r\n const nodes = [];\r\n while (element && element.contentEditable != \"true\" && element.parentNode.nodeType === Node.ELEMENT_NODE) {\r\n const index = findNodeIndex(element);\r\n nodes.unshift(`[${index}]`);\r\n element = element.parentNode;\r\n }\r\n return nodes.length ? `/${nodes.join(\"/\")}` : null;\r\n}\r\n\r\n// Helper function to get an element by XPath\r\nexport function getElementByXPath(path, startingNode) {\r\n const steps = path.split(\"/\");\r\n let node = startingNode ?? document;\r\n for (const step of steps) {\r\n if (step) {\r\n const match = step.match(/^\\[(\\d+)\\]$/);\r\n if (match) {\r\n node = node.childNodes[parseInt(match[1])];\r\n }\r\n }\r\n }\r\n return node;\r\n}\r\n","export function getSeverityIcon(severity) {\r\n switch (severity) {\r\n case \"danger\":\r\n return \"ico-alert\";\r\n case \"info\":\r\n return \"ico-info-circle\";\r\n case \"success\":\r\n return \"ico-check\";\r\n case \"warning\":\r\n return \"ico-alert\";\r\n }\r\n return null;\r\n}\r\n","/*\r\n * Dialog\r\n */\r\nimport { retainFocus } from \"@sitebuilder/utils/dom.js\";\r\nimport { getSeverityIcon } from \"@sitebuilder/utils/ui.js\";\r\n\r\nconst onKeydown = (node) => (e) => {\r\n if (e.code === \"Escape\" && node.dataset.closeOnEscape) {\r\n node.hide();\r\n }\r\n if (e.keyCode === 9) {\r\n // tab\r\n retainFocus(event, node);\r\n }\r\n};\r\n\r\nconst onAnimationEnd = (node) => {\r\n const keydown = onKeydown(node);\r\n return (e) => {\r\n if (e.target !== node) return;\r\n\r\n // on hide\r\n if (node.__isHidding) {\r\n node.__isHidding = false;\r\n node.classList.remove(\"a-dialog-visible\");\r\n window.document.removeEventListener(\"keydown\", keydown);\r\n } else {\r\n window.document.addEventListener(\"keydown\", keydown);\r\n }\r\n };\r\n};\r\n\r\nconst attachDialog = (node) => {\r\n (document.querySelector(node.dataset.appendTo) || document.body).appendChild(node);\r\n\r\n // Set default settings\r\n const ds = node.dataset;\r\n if (typeof ds.closeOnEscape === \"undefined\") {\r\n ds.closeOnEscape = true;\r\n }\r\n\r\n const boxNode = node.querySelector(\".a-dialog-box\");\r\n\r\n node.show = () => {\r\n node.__isHidding = false;\r\n\r\n node.classList.add(\"fadeIn\");\r\n node.classList.remove(\"fadeOut\");\r\n node.classList.add(\"a-dialog-visible\");\r\n\r\n boxNode.classList.add(node.dataset.openingAnimation);\r\n boxNode.classList.remove(node.dataset.closingAnimation);\r\n\r\n node.dispatchEvent(new Event(\"show\"));\r\n };\r\n\r\n node.hide = () => {\r\n node.__isHidding = true;\r\n\r\n node.classList.remove(\"fadeIn\");\r\n node.classList.add(\"fadeOut\");\r\n node.classList.add(\"a-dialog-visible\");\r\n\r\n boxNode.classList.add(node.dataset.closingAnimation);\r\n boxNode.classList.remove(node.dataset.openingAnimation);\r\n\r\n node.dispatchEvent(new Event(\"hide\"));\r\n };\r\n\r\n /// Header close handler\r\n const closeNode = node.querySelector(\".a-dialog-header-close-icon\");\r\n closeNode && closeNode.parentNode.addEventListener(\"click\", () => node.hide());\r\n\r\n /// onhide need to wait for animationEnd()\r\n node.addEventListener(\"animationend\", onAnimationEnd(node));\r\n};\r\n\r\nconst createDialog = (attributes) => {};\r\n\r\nconst razorDialog = {\r\n selector: \".a-dialog\",\r\n create: createDialog,\r\n attach: attachDialog,\r\n};\r\n\r\nexport function alertDialog(title, message, severity) {\r\n\r\n return new Promise((resolve) => {\r\n const parser = new DOMParser();\r\n const id = \"__alert-diag__\";\r\n const existant = document.getElementById(id);\r\n if (existant) {\r\n existant.remove();\r\n }\r\n severity = severity || \"danger\";\r\n const doc = parser.parseFromString(\r\n '