{"version":3,"file":"live-preview-rails-client-ziGwmt0I.js","names":["Client"],"sources":["../../../app/javascript/live-preview-client/run-scripts.js","../../../app/javascript/live-preview-client/rails.js","../../../app/javascript/entrypoints/live-preview-rails-client.js"],"sourcesContent":["export default function (element) {\n var scripts\n\n // Get the scripts\n scripts = element.getElementsByTagName('script')\n\n // Run them in sequence (remember NodeLists are live)\n continueLoading()\n\n function continueLoading() {\n var script, newscript\n\n // While we have a script to load...\n while (scripts.length) {\n // Get it and remove it from the DOM\n script = scripts[0]\n script.parentNode.removeChild(script)\n\n // Create a replacement for it\n newscript = document.createElement('script')\n\n // External?\n if (script.src) {\n // Yes, we'll have to wait until it's loaded before continuing\n newscript.onerror = continueLoadingOnError\n newscript.onload = continueLoadingOnLoad\n newscript.onreadystatechange = continueLoadingOnReady\n newscript.src = script.src\n newscript.defer = script.defer\n newscript.type = script.type\n } else {\n // No, we can do it right away\n newscript.text = script.text\n newscript.type = script.type\n }\n\n // Start the script\n document.documentElement.appendChild(newscript)\n\n // If it's external, wait for callback\n if (script.src) {\n return\n }\n }\n\n // All scripts loaded\n newscript = undefined\n\n // Callback on most browsers when a script is loaded\n function continueLoadingOnLoad() {\n // Defend against duplicate calls\n if (this === newscript) {\n continueLoading()\n }\n }\n\n // Callback on most browsers when a script fails to load\n function continueLoadingOnError() {\n // Defend against duplicate calls\n if (this === newscript) {\n continueLoading()\n }\n }\n\n // Callback on IE when a script's loading status changes\n function continueLoadingOnReady() {\n // Defend against duplicate calls and check whether the\n // script is complete (complete = loaded or error)\n if (this === newscript && this.readyState === 'complete') {\n continueLoading()\n }\n }\n }\n}\n","import axios from 'axios'\nimport { debounce } from './utils'\nimport runScripts from './run-scripts'\n\nconst parentDocument = window.parent.document\nconst previewDocument = window.document\nconst csrfParam =\n window.location !== window.parent.location\n ? {\n [parentDocument\n .querySelector(\"meta[name='csrf-param']\")\n .getAttribute('content')]: parentDocument\n .querySelector(\"meta[name='csrf-token']\")\n .getAttribute('content'),\n }\n : {}\n\nconst start = () => {\n // Within a Rails site, no need to remove the event listeners\n window.addEventListener('maglev:section:add', addSection)\n window.addEventListener('maglev:section:move', moveSections)\n window.addEventListener('maglev:section:update', updateSection)\n window.addEventListener('maglev:section:remove', removeSection)\n window.addEventListener('maglev:block:add', replaceSection)\n window.addEventListener('maglev:block:move', replaceSection)\n window.addEventListener('maglev:block:update', updateBlock)\n window.addEventListener('maglev:block:remove', replaceSection)\n\n window.addEventListener('maglev:themeSettings:update', updateThemeSettings)\n window.addEventListener('maglev:preview:refresh', softRefreshPreview)\n}\n\nexport default { start }\n\n// === Section related actions ===\n\nconst addSection = (event) => {\n const { content, section, insertAt } = event.detail\n debouncedUpdatePreviewDocument(content, section, insertAt)\n}\n\nconst moveSections = (event) => {\n const { sectionId, targetSectionId, direction } = event.detail\n\n const sectionElement = previewDocument.querySelector(\n `[data-maglev-section-id='${sectionId}']`,\n )\n const targetSectionElement = previewDocument.querySelector(\n `[data-maglev-section-id='${targetSectionId}']`,\n )\n\n if (direction === 'up')\n targetSectionElement.parentNode.insertBefore(\n sectionElement,\n targetSectionElement,\n )\n else\n targetSectionElement.parentNode.insertBefore(\n sectionElement,\n targetSectionElement.nextSibling,\n )\n\n // scroll to the new placement of the section\n sectionElement.scrollIntoView(true)\n}\n\nconst updateSection = (event) => {\n const { content, section, change } = event.detail\n updateSectionOrBlock(content, section, section, change)\n}\n\nconst removeSection = (event) => {\n const { sectionId } = event.detail\n const selector = `[data-maglev-section-id='${sectionId}']`\n let element = previewDocument.querySelector(selector)\n element.remove()\n}\n\n// === Block related actions ===\n\nconst updateBlock = (event) => {\n const { content, section, sectionBlock, change } = event.detail\n updateSectionOrBlock(content, section, sectionBlock, change)\n}\n\nconst replaceSection = (event) => {\n const { content, section } = event.detail\n debouncedUpdatePreviewDocument(content, section)\n}\n\n// === Other actions ===\n\nconst updateThemeSettings = async (event) => {\n const { content, themeSettings } = event.detail\n\n const doc = await getUpdatedDoc({\n page_sections: JSON.stringify(content.pageSections),\n header_sections: JSON.stringify(content.headerSections),\n footer_sections: JSON.stringify(content.footerSections),\n themeSettings: JSON.stringify(themeSettings),\n })\n previewDocument.querySelector('head').innerHTML = doc.querySelector('head').innerHTML\n previewDocument.querySelector('body').innerHTML = doc.querySelector('body').innerHTML\n runScripts(previewDocument.querySelector('head'))\n runScripts(previewDocument.querySelector('body'))\n}\n\n// === Helpers ===\n\nconst updateSectionOrBlock = (content, section, source, change) => {\n const foundSetting = updateSetting(source, change)\n if (!foundSetting) debouncedUpdatePreviewDocument(content, section)\n}\n\nconst updateSetting = (source, change) => {\n switch (change.settingType) {\n case 'text':\n return updateTextSetting(source, change)\n case 'link':\n if (change.settingOptions.withText && change.value)\n return updateTextSetting(source, {\n ...change,\n value: change.value.text,\n settingId: `${change.settingId}.text`,\n })\n break\n default:\n // ok, we can't cherry-pick the modification so we have to refresh the whole section\n break\n }\n return false\n}\n\nconst updateTextSetting = (source, change) => {\n // Liquid variables must go through server-side re-render so they resolve correctly\n if (/^\\s*\\{\\{.+\\}\\}\\s*$/.test(change.value || '')) return false\n const selector = `[data-maglev-id='${source.id}.${change.settingId}']`\n const settings = previewDocument.querySelectorAll(selector)\n settings.forEach(($el) => ($el.innerHTML = change.value))\n return settings.length > 0\n}\n\n// Re-renders a single section (or the whole page body if it's a group section).\n// Always includes header/footer section groups in the POST so the backend can\n// render a complete page and we can locate the updated element anywhere in the DOM.\nconst updatePreviewDocument = async (content, section, insertAt) => {\n const isTemplateSection = content.pageSections?.some((s) => s.id == section.id)\n\n const doc = await getUpdatedDoc({\n // For template sections, only send the changed section to minimise server work.\n // For group sections, send all template sections so the layout renders completely.\n page_sections: JSON.stringify(\n isTemplateSection\n ? [content.pageSections.find((s) => s.id == section.id)]\n : content.pageSections,\n ),\n header_sections: JSON.stringify(content.headerSections || []),\n footer_sections: JSON.stringify(content.footerSections || []),\n })\n\n const selector = `[data-maglev-section-id='${section.id}']`\n const sourceElement = doc.querySelector(selector)\n let targetElement = previewDocument.querySelector(selector)\n\n if (!sourceElement)\n throw new Error(`Maglev section ${section.id} not generated by the server`)\n\n if (targetElement) {\n targetElement.replaceWith(sourceElement)\n } else {\n insertSectionInDOM(sourceElement, insertAt)\n targetElement = previewDocument.querySelector(selector)\n }\n\n runScripts(targetElement)\n targetElement.scrollIntoView(true)\n}\n\nconst debouncedUpdatePreviewDocument = debounce(updatePreviewDocument, 300)\n\nconst insertSectionInDOM = (element, insertAt) => {\n switch (insertAt) {\n case 'top': {\n const parentNode = previewDocument.querySelector('[data-maglev-dropzone]')\n parentNode.prepend(element)\n break\n }\n case 'bottom':\n case undefined:\n case null:\n case '': {\n const parentNode = previewDocument.querySelector('[data-maglev-dropzone]')\n parentNode.appendChild(element)\n break\n }\n default: {\n const selector = `[data-maglev-section-id='${insertAt}']`\n const pivotElement = previewDocument.querySelector(selector)\n pivotElement.parentNode.insertBefore(element, pivotElement.nextSibling)\n }\n }\n}\n\n// Soft-refresh: swaps body.innerHTML without a navigation event (no white flash).\n// If `content` is provided → POST with current unsaved state (for group changes).\n// If no `content` → GET the saved page (for post-DB-write refreshes).\nconst softRefreshPreview = async (event) => {\n const content = event.detail?.content\n try {\n if (content) {\n const doc = await getUpdatedDoc({\n page_sections: JSON.stringify(content.pageSections),\n header_sections: JSON.stringify(content.headerSections || []),\n footer_sections: JSON.stringify(content.footerSections || []),\n })\n previewDocument.querySelector('body').innerHTML = doc.querySelector('body').innerHTML\n runScripts(previewDocument.querySelector('body'))\n } else {\n const { data } = await axios.get(previewDocument.location.href)\n const parser = new DOMParser()\n const doc = parser.parseFromString(data, 'text/html')\n previewDocument.querySelector('body').innerHTML = doc.querySelector('body').innerHTML\n runScripts(previewDocument.querySelector('body'))\n }\n } catch (e) {\n previewDocument.location.reload()\n }\n}\n\nconst getUpdatedDoc = async (attributes) => {\n const { data } = await axios.post(previewDocument.location.href, {\n ...attributes,\n ...csrfParam,\n })\n const parser = new DOMParser()\n const doc = parser.parseFromString(data, 'text/html')\n return doc\n}\n","import Client from '~/live-preview-client/index'\nimport RailsClient from '~/live-preview-client/rails'\n\ndocument.addEventListener('DOMContentLoaded', () => {\n console.log('[Rails] Maglev Live Preview 🚀')\n if (Client.start()) {\n RailsClient.start()\n }\n})\n"],"mappings":"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"}