diff --git a/src/editors/jetbrains/htmx.web-types.json b/src/editors/jetbrains/htmx.web-types.json index c08c6df76..0f160f7b1 100644 --- a/src/editors/jetbrains/htmx.web-types.json +++ b/src/editors/jetbrains/htmx.web-types.json @@ -621,24 +621,24 @@ "doc-url": "https://four.htmx.org/extensions/hx-download#events" }, { - "name": "before:head:merge", + "name": "head:before:merge", "description": "Fires before the hx-head extension processes response `` content. `detail.ctx` is the request context.", - "doc-url": "https://four.htmx.org/extensions/hx-head#htmxbeforeheadmerge" + "doc-url": "https://four.htmx.org/extensions/hx-head#htmxheadbeforemerge" }, { - "name": "before:head:add", + "name": "head:before:add", "description": "Fires before the hx-head extension adds a new head element. `detail.headElement` is the element. Cancel to skip it.", - "doc-url": "https://four.htmx.org/extensions/hx-head#htmxbeforeheadadd" + "doc-url": "https://four.htmx.org/extensions/hx-head#htmxheadbeforeadd" }, { - "name": "before:head:remove", + "name": "head:before:remove", "description": "Fires before the hx-head extension removes a head element. `detail.headElement` is the element. Cancel to keep it.", - "doc-url": "https://four.htmx.org/extensions/hx-head#htmxbeforeheadremove" + "doc-url": "https://four.htmx.org/extensions/hx-head#htmxheadbeforeremove" }, { - "name": "after:head:merge", + "name": "head:after:merge", "description": "Fires after the hx-head extension merges head content. `detail.added`, `detail.kept`, and `detail.removed` list affected elements.", - "doc-url": "https://four.htmx.org/extensions/hx-head#htmxafterheadmerge" + "doc-url": "https://four.htmx.org/extensions/hx-head#htmxheadaftermerge" }, { "name": "history:cache:before:save", diff --git a/src/ext/hx-head.js b/src/ext/hx-head.js index 7238c9304..6926d882e 100644 --- a/src/ext/hx-head.js +++ b/src/ext/hx-head.js @@ -100,7 +100,7 @@ } } else { // if this is a merge, we remove this content since it is not in the new head - if (htmx.trigger(document.body, "htmx:before:head:remove", {headElement: currentHeadElt}) !== false) { + if (htmx.trigger(document.body, "htmx:head:before:remove", {headElement: currentHeadElt}) !== false) { removed.push(currentHeadElt) } } @@ -124,7 +124,7 @@ newNode._preloadHint = hint } } else { - if (htmx.trigger(document.body, "htmx:before:head:add", {headElement: newNode}) !== false) { + if (htmx.trigger(document.body, "htmx:head:before:add", {headElement: newNode}) !== false) { await appendNode(newNode) added.push(newNode) } @@ -134,12 +134,12 @@ // remove all removed elements, after we have appended the new elements to avoid // additional network requests for things like style sheets for (const removedElement of removed) { - if (htmx.trigger(document.body, "htmx:before:head:remove", {headElement: removedElement}) !== false) { + if (htmx.trigger(document.body, "htmx:head:before:remove", {headElement: removedElement}) !== false) { currentHead.removeChild(removedElement) } } - htmx.trigger(document.body, "htmx:after:head:merge", { + htmx.trigger(document.body, "htmx:head:after:merge", { added: added, kept: preserved, removed: removed @@ -160,7 +160,7 @@ let target = ctx.target // TODO - is there a better way to handle this? it used to be based on if the element was boosted let defaultMergeStrategy = target === document.body ? "merge" : "append"; - if (htmx.trigger(document.body, "htmx:before:head:merge", detail)) { + if (htmx.trigger(document.body, "htmx:head:before:merge", detail)) { let realText = ctx.response.raw.text.bind(ctx.response.raw) ctx.response.raw.text = async () => { let text = await realText() diff --git a/test/tests/ext/hx-head.js b/test/tests/ext/hx-head.js index 6017751e5..39afe108a 100644 --- a/test/tests/ext/hx-head.js +++ b/test/tests/ext/hx-head.js @@ -40,7 +40,7 @@ describe('hx-head extension', function() { // Wait for head merge to complete async function afterMerge() { - await waitForEvent('htmx:after:head:merge', 500) + await waitForEvent('htmx:head:after:merge', 500) .catch(() => {}); // no head = no event, that's fine await forRequest(); } @@ -109,14 +109,14 @@ describe('hx-head extension', function() { assert.isNotNull(added, 'new element should be added'); }); - it('fires htmx:before:head:merge and htmx:after:head:merge events', async function() { + it('fires htmx:head:before:merge and htmx:head:after:merge events', async function() { let beforeFired = false; let afterFired = false; let onBefore = () => { beforeFired = true; }; let onAfter = () => { afterFired = true; }; - document.body.addEventListener('htmx:before:head:merge', onBefore); - document.body.addEventListener('htmx:after:head:merge', onAfter); + document.body.addEventListener('htmx:head:before:merge', onBefore); + document.body.addEventListener('htmx:head:after:merge', onAfter); mockResponse('GET', '/page', headResponse('', '
content
')); let div = createProcessedHTML('
click
'); @@ -124,19 +124,19 @@ describe('hx-head extension', function() { div.click(); await afterMerge(); - document.body.removeEventListener('htmx:before:head:merge', onBefore); - document.body.removeEventListener('htmx:after:head:merge', onAfter); + document.body.removeEventListener('htmx:head:before:merge', onBefore); + document.body.removeEventListener('htmx:head:after:merge', onAfter); let added = document.head.querySelector('meta[name="hx-head-test-evt"]'); if (added) addedHeadElts.push(added); - assert.isTrue(beforeFired, 'htmx:before:head:merge should fire'); - assert.isTrue(afterFired, 'htmx:after:head:merge should fire'); + assert.isTrue(beforeFired, 'htmx:head:before:merge should fire'); + assert.isTrue(afterFired, 'htmx:head:after:merge should fire'); }); - it('htmx:before:head:merge cancellation prevents merge', async function() { + it('htmx:head:before:merge cancellation prevents merge', async function() { let onBefore = (e) => { e.preventDefault(); }; - document.body.addEventListener('htmx:before:head:merge', onBefore, {once: true}); + document.body.addEventListener('htmx:head:before:merge', onBefore, {once: true}); mockResponse('GET', '/page', headResponse('', '
content
')); let div = createProcessedHTML('
click
'); @@ -181,7 +181,7 @@ describe('hx-head extension', function() { let onMerge = () => { headMergeTime = Date.now(); }; let onSwap = () => { swapTime = Date.now(); }; - document.body.addEventListener('htmx:after:head:merge', onMerge); + document.body.addEventListener('htmx:head:after:merge', onMerge); document.body.addEventListener('htmx:after:swap', onSwap); mockResponse('GET', '/page', headResponse('', '
swapped
')); @@ -190,7 +190,7 @@ describe('hx-head extension', function() { div.click(); await afterMerge(); - document.body.removeEventListener('htmx:after:head:merge', onMerge); + document.body.removeEventListener('htmx:head:after:merge', onMerge); document.body.removeEventListener('htmx:after:swap', onSwap); let added = document.head.querySelector('meta[name="hx-head-test-timing"]'); diff --git a/www/src/content/extensions/04-hx-head.md b/www/src/content/extensions/04-hx-head.md index 07199773c..a91d28044 100644 --- a/www/src/content/extensions/04-hx-head.md +++ b/www/src/content/extensions/04-hx-head.md @@ -183,24 +183,24 @@ Element events expose: event.detail.headElement // Element being added or removed ``` -### `htmx:before:head:merge` +### `htmx:head:before:merge` Fires before the extension processes a response ``. ```js -document.addEventListener('htmx:before:head:merge', event => { +document.addEventListener('htmx:head:before:merge', event => { if (!shouldUpdateHead(event.detail.ctx)) event.preventDefault() }) ``` The event detail includes the request `ctx`. Cancel the event to skip all head processing for the response. -### `htmx:before:head:add` +### `htmx:head:before:add` Fires before the extension adds a head element. ```js -document.addEventListener('htmx:before:head:add', event => { +document.addEventListener('htmx:head:before:add', event => { if (event.detail.headElement.matches('script[data-untrusted]')) { event.preventDefault() } @@ -209,12 +209,12 @@ document.addEventListener('htmx:before:head:add', event => { Cancel the event to skip that element. -### `htmx:before:head:remove` +### `htmx:head:before:remove` Fires before the extension removes a current `` element. ```js -document.addEventListener('htmx:before:head:remove', event => { +document.addEventListener('htmx:head:before:remove', event => { if (event.detail.headElement.matches('[data-keep]')) { event.preventDefault() } @@ -223,7 +223,7 @@ document.addEventListener('htmx:before:head:remove', event => { Cancel the event to keep that element. -### `htmx:after:head:merge` +### `htmx:head:after:merge` Fires after the extension finishes updating the ``. @@ -236,11 +236,24 @@ event.detail = { ``` ```js -document.addEventListener('htmx:after:head:merge', event => { +document.addEventListener('htmx:head:after:merge', event => { console.log('Head elements added:', event.detail.added.length) }) ``` +## Migration + +### Beta to RC1 + +RC1 namespaces `hx-head` lifecycle events: + +| Beta | RC1 | +|------|-----| +| `htmx:before:head:merge` | [`htmx:head:before:merge`](#htmxheadbeforemerge) | +| `htmx:before:head:add` | [`htmx:head:before:add`](#htmxheadbeforeadd) | +| `htmx:before:head:remove` | [`htmx:head:before:remove`](#htmxheadbeforeremove) | +| `htmx:after:head:merge` | [`htmx:head:after:merge`](#htmxheadaftermerge) | + ## Notes - `