wiki-js-customization/srv/js/template-engine.js

121 lines
4.1 KiB
JavaScript
Raw Permalink Normal View History

2024-03-14 18:13:52 +00:00
function extractSchemaDetails(str) {
// Regular expression with named capture groups for name and optional placeholder
const regex = /{{(?<name>[^:}]+)(?::(?<placeholder>[^:}]+))?}}/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()
})