UNPKG

@anywhichway/lazui

Version:

Single page apps and lazy loading sites with minimal JavaScript or client build processes.

135 lines (129 loc) 6.64 kB
const replaceBetween = (inputString, startDelimiter, endDelimiter, evaluate,inclusive) => { const placeholders = []; let startIndex = inputString.indexOf(startDelimiter), endIndex; while (startIndex !== -1) { endIndex = inputString.indexOf(endDelimiter, startIndex + (inclusive ? startDelimiter.length : 0)); if (endIndex !== -1) { const textBetweenDelimiters = inputString.substring(startIndex + (inclusive ? 0 : startDelimiter.length), endIndex + (inclusive ? endDelimiter.length : 0)); const replacementText = replacementCallback(textBetweenDelimiters,{startDelimiter,endDelimiter,evaluate}); const placeholder = `_PLCHLDR_${placeholders.length}_`; placeholders.push({ placeholder, replacementText }); inputString = inputString.substring(0, startIndex) + placeholder + inputString.substring(endIndex+(inclusive ? endDelimiter.length : 0)); } else { // If the end delimiter is not found, break the loop break; } startIndex = inputString.indexOf(startDelimiter) } // Perform the replacements while(inputString.includes("_PLCHLDR_")) { placeholders.forEach(({ placeholder, replacementText }) => inputString = inputString.replace(placeholder, inclusive ? replacementText : startDelimiter + replacementText + endDelimiter)); } return inputString; } const replaceBetweenAsync =async (inputString, startDelimiter, endDelimiter, evaluate,inclusive) => { const placeholders = []; let startIndex = inputString.indexOf(startDelimiter), endIndex; while (startIndex !== -1) { endIndex = inputString.indexOf(endDelimiter, startIndex + (inclusive ? startDelimiter.length : 0)); if (endIndex !== -1) { const textBetweenDelimiters = inputString.substring(startIndex + (inclusive ? 0 : startDelimiter.length), endIndex + (inclusive ? endDelimiter.length : 0)); const replacementText = await replacementCallback(textBetweenDelimiters,{startDelimiter,endDelimiter,evaluate}); const placeholder = `_PLCHLDR_${placeholders.length}_`; placeholders.push({ placeholder, replacementText }); inputString = inputString.substring(0, startIndex) + placeholder + inputString.substring(endIndex+(inclusive ? endDelimiter.length : 0)); } else { // If the end delimiter is not found, break the loop break; } startIndex = inputString.indexOf(startDelimiter) } // Perform the replacements while(inputString.includes("_PLCHLDR_")) { placeholders.forEach(({ placeholder, replacementText }) => inputString = inputString.replace(placeholder, inclusive ? replacementText : startDelimiter + replacementText + endDelimiter)); } return inputString; } const replacementCallback = (text,{startDelimiter,endDelimiter,evaluate}) => { text = text.replace(startDelimiter,"").replace(endDelimiter,""); return startDelimiter.replace("!","") + text + endDelimiter + evaluate(text); } const replacementCallbackAsync = async (text,{startDelimiter,endDelimiter,evaluate}) => { text = text.replace(startDelimiter,"").replace(endDelimiter,""); return startDelimiter.replace("!","") + text + endDelimiter + await evaluate(text); } const examplify = (input,evaluate={}) => { const type = typeof input; evaluate = { html(text) { return text }, javascript(text) { return "\n<" + `script>${text}</script>`; }, ...evaluate }; let output = input; if(type === "string") { for(const [key,value] of Object.entries(evaluate)) { output = replaceBetween(output, "\`\`\`!"+key, "\`\`\`", value, true); } return output; } else if(type === "object" && input && input.querySelectorAll) { for(const [key,value] of Object.entries(evaluate)) { for(const el of input.querySelectorAll(`code[class*='language-!${key}']`)) { el.classList.remove(`language-!${key}`); el.classList.add(`language-${key}`); const text = value(el.textContent); const nextElementSibling = el.nextElementSibling; el.insertAdjacentHTML("afterend",text); let next = el.nextElementSibling; while(next!==nextElementSibling) { if(next.tagName==="SCRIPT") { const script = document.createElement("script"); script.innerHTML = next.innerHTML; next.replaceWith(script) } next = next.nextElementSibling; } } } return input; } throw new TypeError(`examplify: input must be a string or an object supporting querySelectorAll, not ${type}`); } const examplifyAsync = async (input,evaluate={}) => { const type = typeof input; evaluate = { html(text) { return text }, javascript(text) { return "\n<" + `script>${text}</script>`; }, ...evaluate }; let output = input; if(type === "string") { for(const [key,value] of Object.entries(evaluate)) { output = await replaceBetween(output, "```!"+key, "```", value, true); } return output; } else if(type === "object" && input && input.querySelectorAll) { for(const [key,value] of Object.entries(evaluate)) { for(const el of input.querySelectorAll(`code[class*='language-!${key}']`)) { el.classList.remove(`language-!${key}`); el.classList.add(`language-${key}`); const text = await value(el.textContent); const nextElementSibling = el.nextElementSibling; el.insertAdjacentHTML("afterend",text); let next = el.nextElementSibling; while(next!==nextElementSibling) { if(next.tagName==="SCRIPT") { const script = document.createElement("script"); script.innerHTML = next.innerHTML; next.replaceWith(script) } next = next.nextElementSibling; } } } return input; } throw new TypeError(`examplify: input must be a string or an object supporting querySelectorAll, not ${type}`); } export {examplify, examplify as default}