Skip to content

Commit 2b5564d

Browse files
committed
more htmx standardization
1 parent ba76b4f commit 2b5564d

3 files changed

Lines changed: 91 additions & 1 deletion

File tree

src/core/config.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,5 @@ export const config = {
55
defaultTransition: "all 500ms ease-in",
66
disableSelector: "[disable-scripting], [data-disable-scripting]",
77
hideShowStrategies: {},
8+
logAll: false,
89
}

src/core/runtime/runtime.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -515,6 +515,9 @@ export class Runtime {
515515
detail = detail || {};
516516
detail["sender"] = sender;
517517
var event = this.makeEvent(eventName, detail);
518+
if (config.logAll) {
519+
console.log(eventName, detail, elt);
520+
}
518521
var eventResult = elt.dispatchEvent(event);
519522
return eventResult;
520523
}
@@ -590,6 +593,9 @@ export class Runtime {
590593

591594
cleanup(elt) {
592595
if (!elt._hyperscript) return;
596+
597+
this.triggerEvent(elt, "hyperscript:before:cleanup");
598+
593599
var data = elt._hyperscript;
594600

595601
// Remove registered event listeners
@@ -615,11 +621,14 @@ export class Runtime {
615621

616622
// Recursively clean children
617623
if (elt.querySelectorAll) {
618-
for (var child of elt.querySelectorAll('[_], [data-hs], [hyperscript]')) {
624+
for (var child of elt.querySelectorAll('[data-hyperscript-powered]')) {
619625
this.cleanup(child);
620626
}
621627
}
622628

629+
this.triggerEvent(elt, "hyperscript:after:cleanup");
630+
631+
elt.removeAttribute('data-hyperscript-powered');
623632
delete elt._hyperscript;
624633
}
625634

@@ -637,13 +646,18 @@ export class Runtime {
637646
this.cleanup(elt);
638647
internalData = this.getInternalData(elt);
639648
}
649+
650+
if (!this.triggerEvent(elt, "hyperscript:before:init")) return;
651+
640652
internalData.initialized = true;
641653
internalData.scriptHash = hash;
642654
try {
643655
var tokens = this.#tokenizer.tokenize(src);
644656
var hyperScript = this.#kernel.parseHyperScript(tokens);
645657
if (!hyperScript) return;
646658
hyperScript.apply(target || elt, elt, null, this);
659+
elt.setAttribute('data-hyperscript-powered', 'true');
660+
this.triggerEvent(elt, "hyperscript:after:init");
647661
setTimeout(() => {
648662
this.triggerEvent(target || elt, "load", {
649663
hyperscript: true,

test/core/bootstrap.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,4 +213,79 @@ test.describe("_hyperscript bootstrapping", () => {
213213
});
214214
expect(hasState).toBe(false);
215215
});
216+
217+
test("sets data-hyperscript-powered on initialized elements", async ({html, find}) => {
218+
await html("<div _='on click add .foo'></div>");
219+
await expect(find('div')).toHaveAttribute('data-hyperscript-powered', 'true');
220+
});
221+
222+
test("cleanup removes data-hyperscript-powered", async ({html, find, evaluate}) => {
223+
await html("<div _='on click add .foo'></div>");
224+
await expect(find('div')).toHaveAttribute('data-hyperscript-powered', 'true');
225+
await evaluate(() => {
226+
_hyperscript.cleanup(document.querySelector('#work-area div'));
227+
});
228+
expect(await find('div').getAttribute('data-hyperscript-powered')).toBeNull();
229+
});
230+
231+
test("fires hyperscript:before:init and hyperscript:after:init", async ({html, find, evaluate}) => {
232+
var events = await evaluate(() => {
233+
var events = [];
234+
var wa = document.getElementById('work-area');
235+
wa.addEventListener('hyperscript:before:init', () => events.push('before:init'));
236+
wa.addEventListener('hyperscript:after:init', () => events.push('after:init'));
237+
wa.innerHTML = "<div _='on click add .foo'></div>";
238+
_hyperscript.processNode(wa);
239+
return events;
240+
});
241+
expect(events).toEqual(['before:init', 'after:init']);
242+
});
243+
244+
test("hyperscript:before:init can cancel initialization", async ({html, find, evaluate}) => {
245+
var result = await evaluate(() => {
246+
var wa = document.getElementById('work-area');
247+
wa.addEventListener('hyperscript:before:init', (e) => e.preventDefault(), { once: true });
248+
wa.innerHTML = "<div _='on click add .foo'></div>";
249+
_hyperscript.processNode(wa);
250+
var div = wa.querySelector('div');
251+
return {
252+
initialized: !!div._hyperscript?.initialized,
253+
hasPowered: div.hasAttribute('data-hyperscript-powered'),
254+
};
255+
});
256+
expect(result.initialized).toBe(false);
257+
expect(result.hasPowered).toBe(false);
258+
});
259+
260+
test("fires hyperscript:before:cleanup and hyperscript:after:cleanup", async ({html, find, evaluate}) => {
261+
await html("<div _='on click add .foo'></div>");
262+
var events = await evaluate(() => {
263+
var events = [];
264+
var div = document.querySelector('#work-area div');
265+
div.addEventListener('hyperscript:before:cleanup', () => events.push('before:cleanup'));
266+
div.addEventListener('hyperscript:after:cleanup', () => events.push('after:cleanup'));
267+
_hyperscript.cleanup(div);
268+
return events;
269+
});
270+
expect(events).toEqual(['before:cleanup', 'after:cleanup']);
271+
});
272+
273+
test("logAll config logs events to console", async ({html, find, evaluate}) => {
274+
var logged = await evaluate(() => {
275+
var logs = [];
276+
var origLog = console.log;
277+
console.log = (...args) => logs.push(args[0]);
278+
_hyperscript.config.logAll = true;
279+
try {
280+
var wa = document.getElementById('work-area');
281+
wa.innerHTML = "<div _='on click add .foo'></div>";
282+
_hyperscript.processNode(wa);
283+
} finally {
284+
_hyperscript.config.logAll = false;
285+
console.log = origLog;
286+
}
287+
return logs.some(l => typeof l === 'string' && l.includes('hyperscript:'));
288+
});
289+
expect(logged).toBe(true);
290+
});
216291
});

0 commit comments

Comments
 (0)