48 lines
1.6 KiB
TypeScript
48 lines
1.6 KiB
TypeScript
import htmx from "htmx.org";
|
|
|
|
const evalFuncRegex =/__eval_[A-Za-z0-9]+\([a-z]+\)/gm
|
|
|
|
htmx.defineExtension("htmgo", {
|
|
// @ts-ignore
|
|
onEvent: function (name, evt) {
|
|
if(name === "htmx:beforeCleanupElement" && evt.target) {
|
|
removeAssociatedScripts(evt.target as HTMLElement);
|
|
}
|
|
if(name === "htmx:load" && evt.target) {
|
|
invokeOnLoad(evt.target as HTMLElement);
|
|
}
|
|
},
|
|
});
|
|
|
|
/**
|
|
* Browser doesn't support onload for all elements, so we need to manually trigger it
|
|
* this is useful for locality of behavior
|
|
*/
|
|
function invokeOnLoad(element : Element) {
|
|
if(element == null || !(element instanceof HTMLElement)) {
|
|
return
|
|
}
|
|
const ignored = ['SCRIPT', 'LINK', 'STYLE', 'META', 'BASE', 'TITLE', 'HEAD', 'HTML', 'BODY'];
|
|
if(!ignored.includes(element.tagName)) {
|
|
if(element.hasAttribute("onload")) {
|
|
element.onload!(new Event("load"));
|
|
}
|
|
}
|
|
// check its children
|
|
element.querySelectorAll('[onload]').forEach(invokeOnLoad)
|
|
}
|
|
|
|
export function removeAssociatedScripts(element: HTMLElement) {
|
|
const attributes = Array.from(element.attributes)
|
|
for (let attribute of attributes) {
|
|
const matches = attribute.value.match(evalFuncRegex) || []
|
|
for (let match of matches) {
|
|
const id = match.replace("()", "").replace("(this)", "").replace(";", "")
|
|
const ele = document.getElementById(id)
|
|
if(ele && ele.tagName === "SCRIPT") {
|
|
console.debug("removing associated script with id", id)
|
|
ele.remove()
|
|
}
|
|
}
|
|
}
|
|
}
|