Skip to content

Instantly share code, notes, and snippets.

@alexandrosm
Last active April 19, 2023 14:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save alexandrosm/f06c752dbb3993ac12a6759e544d065a to your computer and use it in GitHub Desktop.
Save alexandrosm/f06c752dbb3993ac12a6759e544d065a to your computer and use it in GitHub Desktop.
class ScriptRunner {
constructor(guidelines, scriptIdentifier) {
this.guidelines = guidelines;
this.scriptIdentifier = scriptIdentifier;
}
addRunButton(el) {
const btn = document.createElement('button');
btn.textContent = 'Run';
btn.style.marginLeft = '5px';
btn.onclick = () => {
try {
this.runScript(el.textContent);
} catch (err) {
alert(`Error: ${err.message}\n\nCode:\n${el.textContent}\n\nGuidelines:\n${this.guidelines}\n\nPlease fix the problem according to the guidelines.`);
}
};
el.parentNode.insertBefore(btn, el.nextSibling);
}
processCodeElements() {
const codeElements = this.mergeCodeBlocks(document.querySelectorAll(`code:not(.processed-${this.scriptIdentifier})`));
codeElements.forEach((el) => {
if (this.checkScript(el.textContent)) {
this.addRunButton(el);
el.classList.add(`processed-${this.scriptIdentifier}`);
}
});
}
mergeCodeBlocks(codeElements) {
const mergedCodeElements = [];
let currentElement = null;
let balance = { '(': 0, '{': 0 };
codeElements.forEach((el) => {
if (!currentElement) {
currentElement = el;
} else {
currentElement.textContent += '\n' + el.textContent;
}
balance = this.updateBalance(balance, el.textContent);
if (balance['('] === 0 && balance['{'] === 0) {
mergedCodeElements.push(currentElement);
currentElement = null;
}
});
if (currentElement) {
mergedCodeElements.push(currentElement);
}
return mergedCodeElements;
}
updateBalance(balance, code) {
for (const char of code) {
if (char === '(') balance['(']++;
else if (char === ')') balance['(']--;
else if (char === '{') balance['{']++;
else if (char === '}') balance['{']--;
}
return balance;
}
observeDOM() {
const observer = new MutationObserver(() => {
setTimeout(() => this.processCodeElements(), 300);
});
observer.observe(document.body, { childList: true, subtree: true });
}
runScript(code) {
throw new Error("runScript method not implemented");
}
checkScript(code) {
throw new Error("checkScript method not implemented");
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment