function extractSchemaDetails(str) { // Regular expression with named capture groups for name and optional placeholder const regex = /{{(?[^:}]+)(?::(?[^:}]+))?}}/g const results = [] let match while ((match = regex.exec(str)) !== null) { // check if the match is already in the results array if (results.some((result) => result.name === match.groups.name)) { continue } results.push({ name: match.groups.name, placeholder: match.groups.placeholder || null, // If placeholder is undefined, null input: null }) } return results } function replaceDivTextExceptSpan(div, newTextBefore) { // Iterate over child nodes of the div for (const node of div.childNodes) { // Check if the node is a text node if (node.nodeType === Node.TEXT_NODE) { // Check the position of the text node to determine if it's before or after the span if (node.nextSibling && node.nextSibling.tagName === 'SPAN') { // Text node before the span node.nodeValue = newTextBefore; } } } } const main = () => { // select every code block with class language-template document.querySelectorAll('code.language-template').forEach((codeElement) => { // get the code inside the block const codeInnerText = codeElement.innerText const id = Math.random().toString(36).substring(7) const templateContainer = document.createElement('div') templateContainer.id = id; templateContainer.className = "template-container" const title = document.createElement('div') title.className = "template-title" title.innerText = "Template" templateContainer.appendChild(title) const templateVars = extractSchemaDetails(codeInnerText) const renderInputs = () => { let newCode = codeInnerText templateVars.forEach((variable) => { const escapedPlaceholder = variable.name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); const regexPattern = `{{${escapedPlaceholder}(?::[^}]+)?}}`; // Matches {{name}} or {{name:anything}} const regex = new RegExp(regexPattern, 'g'); if (variable.input !== null && variable.input !== "") { newCode = newCode.replace(regex, variable.input) } }) replaceDivTextExceptSpan(codeElement, newCode) } // create input elements templateVars.forEach((variable) => { const inputDiv = document.createElement('div') inputDiv.className = "template-input-div" const label = document.createElement('label') label.for = `${id}-${variable.name}` label.innerText = variable.name const input = document.createElement('input') input.id = `${id}-${variable.name}` input.placeholder = variable.placeholder || variable.name input.value = null input.className = "template-input" input.addEventListener('input', e => { variable.input = e.target.value renderInputs() }) inputDiv.appendChild(label) inputDiv.appendChild(input) templateContainer.appendChild(inputDiv) }) const copyButton = document.createElement('button') copyButton.className = "template-copy-button" copyButton.innerText = "Copy" copyButton.addEventListener('click', () => { navigator.clipboard.writeText(codeElement.innerText.trim()) }) templateContainer.appendChild(copyButton) // get parent element const outerDiv = codeElement.parentElement.parentElement.parentElement const codeBlock = codeElement.parentElement.parentElement // insert the template container before the code block outerDiv.insertBefore(templateContainer, codeElement.parentElement.parentElement) templateContainer.appendChild(codeBlock) }) } window.boot.register("page-ready", () => { main() })