Attach hx-on handlers before processing nodes (#3131)

This commit is contained in:
Ryan Kilpadi 2025-06-02 16:50:19 -04:00 committed by GitHub
parent e7bb245ef4
commit 5b4d77da6b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 71 additions and 37 deletions

View File

@ -2905,46 +2905,52 @@ var htmx = (function() {
* @param {Element|HTMLInputElement} elt
*/
function initNode(elt) {
if (eltIsDisabled(elt)) {
cleanUpElement(elt)
return
}
// Ensure only valid Elements and not shadow DOM roots are inited
if (!(elt instanceof Element)) return
triggerEvent(elt, 'htmx:beforeProcessNode')
const nodeData = getInternalData(elt)
const attrHash = attributeHash(elt)
if (nodeData.initHash !== attrHash) {
// clean up any previously processed info
deInitNode(elt)
const triggerSpecs = getTriggerSpecs(elt)
const hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs)
nodeData.initHash = attrHash
triggerEvent(elt, 'htmx:beforeProcessNode')
const triggerSpecs = getTriggerSpecs(elt)
const hasExplicitHttpAction = processVerbs(elt, nodeData, triggerSpecs)
if (!hasExplicitHttpAction) {
if (getClosestAttributeValue(elt, 'hx-boost') === 'true') {
boostElement(elt, nodeData, triggerSpecs)
} else if (hasAttribute(elt, 'hx-trigger')) {
triggerSpecs.forEach(function(triggerSpec) {
// For "naked" triggers, don't do anything at all
addTriggerHandler(elt, triggerSpec, nodeData, function() {
})
if (!hasExplicitHttpAction) {
if (getClosestAttributeValue(elt, 'hx-boost') === 'true') {
boostElement(elt, nodeData, triggerSpecs)
} else if (hasAttribute(elt, 'hx-trigger')) {
triggerSpecs.forEach(function(triggerSpec) {
// For "naked" triggers, don't do anything at all
addTriggerHandler(elt, triggerSpec, nodeData, function() {
})
}
})
}
// Handle submit buttons/inputs that have the form attribute set
// see https://developer.mozilla.org/docs/Web/HTML/Element/button
if (elt.tagName === 'FORM' || (getRawAttribute(elt, 'type') === 'submit' && hasAttribute(elt, 'form'))) {
initButtonTracking(elt)
}
nodeData.firstInitCompleted = true
triggerEvent(elt, 'htmx:afterProcessNode')
}
// Handle submit buttons/inputs that have the form attribute set
// see https://developer.mozilla.org/docs/Web/HTML/Element/button
if (elt.tagName === 'FORM' || (getRawAttribute(elt, 'type') === 'submit' && hasAttribute(elt, 'form'))) {
initButtonTracking(elt)
}
nodeData.firstInitCompleted = true
triggerEvent(elt, 'htmx:afterProcessNode')
}
/**
* @param {Element} elt
* @returns {boolean}
*/
function maybeDeInitAndHash(elt) {
// Ensure only valid Elements and not shadow DOM roots are inited
if (!(elt instanceof Element)) {
return false
}
const nodeData = getInternalData(elt)
const hash = attributeHash(elt)
if (nodeData.initHash !== hash) {
deInitNode(elt)
nodeData.initHash = hash
return true
}
return false
}
/**
@ -2960,9 +2966,23 @@ var htmx = (function() {
cleanUpElement(elt)
return
}
initNode(elt)
forEach(findElementsToProcess(elt), function(child) { initNode(child) })
const elementsToInit = []
if (maybeDeInitAndHash(elt)) {
elementsToInit.push(elt)
}
forEach(findElementsToProcess(elt), function(child) {
if (eltIsDisabled(child)) {
cleanUpElement(child)
return
}
if (maybeDeInitAndHash(child)) {
elementsToInit.push(child)
}
})
forEach(findHxOnWildcardElements(elt), processHxOnWildcard)
forEach(elementsToInit, initNode)
}
//= ===================================================================

View File

@ -133,6 +133,20 @@ describe('hx-on:* attribute', function() {
delete window.foo
})
it('should fire when triggered by load', function() {
this.server.respondWith('POST', '/test', 'test')
make("<div hx-trigger='load' hx-post='/test' hx-on:htmx:config-request='foo = true'></div>")
window.foo.should.equal(true)
delete window.foo
})
it('should fire when triggered by revealed', function() {
this.server.respondWith('POST', '/test', 'test')
make("<div hx-trigger='revealed' hx-post='/test' hx-on:htmx:config-request='foo = true' style='position: fixed; top: 1px; left: 1px; border: 3px solid red'></div>")
window.foo.should.equal(true)
delete window.foo
})
it('de-initializes hx-on-* content properly', function() {
window.tempCount = 0
this.server.respondWith('POST', '/test', function(xhr) {