mirror of
https://github.com/bigskysoftware/htmx.git
synced 2025-10-02 23:35:13 +00:00
support hx-on in shadowroot
This commit is contained in:
parent
81afe922d7
commit
01cb5e0d8d
26
src/htmx.js
26
src/htmx.js
@ -2602,19 +2602,29 @@ var htmx = (function() {
|
|||||||
* @param {Node} elt
|
* @param {Node} elt
|
||||||
* @returns {Element[]}
|
* @returns {Element[]}
|
||||||
*/
|
*/
|
||||||
|
const HX_ON_QUERY = new XPathEvaluator()
|
||||||
|
.createExpression('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' +
|
||||||
|
' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]');
|
||||||
|
|
||||||
|
function processHXOnRoot(elt, elements) {
|
||||||
|
if (shouldProcessHxOn(elt)) {
|
||||||
|
elements.push(asElement(elt))
|
||||||
|
}
|
||||||
|
const iter = HX_ON_QUERY.evaluate(elt)
|
||||||
|
let node = null;
|
||||||
|
while (node = iter.iterateNext()) elements.push(asElement(node))
|
||||||
|
}
|
||||||
|
|
||||||
function findHxOnWildcardElements(elt) {
|
function findHxOnWildcardElements(elt) {
|
||||||
let node = null
|
let node = null
|
||||||
/** @type {Element[]} */
|
/** @type {Element[]} */
|
||||||
const elements = []
|
const elements = []
|
||||||
|
if (elt instanceof DocumentFragment) {
|
||||||
if (!(elt instanceof ShadowRoot)) {
|
for (const child of elt.childNodes) {
|
||||||
if (shouldProcessHxOn(elt)) {
|
processHXOnRoot(child, elements);
|
||||||
elements.push(asElement(elt))
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
const iter = document.evaluate('.//*[@*[ starts-with(name(), "hx-on:") or starts-with(name(), "data-hx-on:") or' +
|
processHXOnRoot(elt, elements);
|
||||||
' starts-with(name(), "hx-on-") or starts-with(name(), "data-hx-on-") ]]', elt)
|
|
||||||
while (node = iter.iterateNext()) elements.push(asElement(node))
|
|
||||||
}
|
}
|
||||||
return elements
|
return elements
|
||||||
}
|
}
|
||||||
|
@ -1,193 +0,0 @@
|
|||||||
describe('hx-on attribute', function() {
|
|
||||||
beforeEach(function() {
|
|
||||||
this.server = makeServer()
|
|
||||||
clearWorkArea()
|
|
||||||
})
|
|
||||||
afterEach(function() {
|
|
||||||
this.server.restore()
|
|
||||||
clearWorkArea()
|
|
||||||
})
|
|
||||||
|
|
||||||
it('can handle basic events w/ no other attributes', function() {
|
|
||||||
var btn = make("<button hx-on='click: window.foo = true'>Foo</button>")
|
|
||||||
btn.click()
|
|
||||||
window.foo.should.equal(true)
|
|
||||||
delete window.foo
|
|
||||||
})
|
|
||||||
|
|
||||||
it('can modify a parameter via htmx:configRequest', function() {
|
|
||||||
this.server.respondWith('POST', '/test', function(xhr) {
|
|
||||||
var params = parseParams(xhr.requestBody)
|
|
||||||
xhr.respond(200, {}, params.foo)
|
|
||||||
})
|
|
||||||
var btn = make("<button hx-on='htmx:configRequest: event.detail.parameters.foo = \"bar\"' hx-post='/test'>Foo</button>")
|
|
||||||
btn.click()
|
|
||||||
this.server.respond()
|
|
||||||
btn.innerText.should.equal('bar')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('can cancel an event via preventDefault for htmx:configRequest', function() {
|
|
||||||
this.server.respondWith('POST', '/test', function(xhr) {
|
|
||||||
xhr.respond(200, {}, '<button>Bar</button>')
|
|
||||||
})
|
|
||||||
var btn = make("<button hx-on='htmx:configRequest: event.preventDefault()' hx-post='/test' hx-swap='outerHTML'>Foo</button>")
|
|
||||||
btn.click()
|
|
||||||
this.server.respond()
|
|
||||||
btn.innerText.should.equal('Foo')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('can respond to kebab-case events', function() {
|
|
||||||
this.server.respondWith('POST', '/test', function(xhr) {
|
|
||||||
var params = parseParams(xhr.requestBody)
|
|
||||||
xhr.respond(200, {}, params.foo)
|
|
||||||
})
|
|
||||||
var btn = make("<button hx-on='htmx:config-request: event.detail.parameters.foo = \"bar\"' hx-post='/test'>Foo</button>")
|
|
||||||
btn.click()
|
|
||||||
this.server.respond()
|
|
||||||
btn.innerText.should.equal('bar')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('has the this symbol set to the element', function() {
|
|
||||||
this.server.respondWith('POST', '/test', function(xhr) {
|
|
||||||
xhr.respond(200, {}, 'foo')
|
|
||||||
})
|
|
||||||
var btn = make("<button hx-on='htmx:config-request: window.elt = this' hx-post='/test'>Foo</button>")
|
|
||||||
btn.click()
|
|
||||||
this.server.respond()
|
|
||||||
btn.innerText.should.equal('foo')
|
|
||||||
btn.should.equal(window.elt)
|
|
||||||
delete window.elt
|
|
||||||
})
|
|
||||||
|
|
||||||
it('can handle multi-line JSON', function() {
|
|
||||||
this.server.respondWith('POST', '/test', function(xhr) {
|
|
||||||
xhr.respond(200, {}, 'foo')
|
|
||||||
})
|
|
||||||
var btn = make("<button hx-on='htmx:config-request: window.elt = {foo: true,\n" +
|
|
||||||
" bar: false}' hx-post='/test'>Foo</button>")
|
|
||||||
btn.click()
|
|
||||||
this.server.respond()
|
|
||||||
btn.innerText.should.equal('foo')
|
|
||||||
var obj = { foo: true, bar: false }
|
|
||||||
obj.should.deep.equal(window.elt)
|
|
||||||
delete window.elt
|
|
||||||
})
|
|
||||||
|
|
||||||
it('can handle multiple event handlers in the presence of multi-line JSON', function() {
|
|
||||||
this.server.respondWith('POST', '/test', function(xhr) {
|
|
||||||
xhr.respond(200, {}, 'foo')
|
|
||||||
})
|
|
||||||
var btn = make("<button hx-on='htmx:config-request: window.elt = {foo: true,\n" +
|
|
||||||
' bar: false}\n' +
|
|
||||||
" htmx:afterRequest: window.foo = true'" +
|
|
||||||
" hx-post='/test'>Foo</button>")
|
|
||||||
btn.click()
|
|
||||||
this.server.respond()
|
|
||||||
btn.innerText.should.equal('foo')
|
|
||||||
|
|
||||||
var obj = { foo: true, bar: false }
|
|
||||||
obj.should.deep.equal(window.elt)
|
|
||||||
delete window.elt
|
|
||||||
|
|
||||||
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) {
|
|
||||||
xhr.respond(200, {}, "<button id='foo' hx-on=\"click: window.tempCount++;\">increment</button>")
|
|
||||||
})
|
|
||||||
var div = make("<div hx-post='/test'>Foo</div>")
|
|
||||||
|
|
||||||
// get response
|
|
||||||
div.click()
|
|
||||||
this.server.respond()
|
|
||||||
|
|
||||||
// click button
|
|
||||||
byId('foo').click()
|
|
||||||
window.tempCount.should.equal(1)
|
|
||||||
|
|
||||||
// get second response
|
|
||||||
div.click()
|
|
||||||
this.server.respond()
|
|
||||||
|
|
||||||
// click button again
|
|
||||||
byId('foo').click()
|
|
||||||
window.tempCount.should.equal(2)
|
|
||||||
|
|
||||||
delete window.tempCount
|
|
||||||
})
|
|
||||||
|
|
||||||
it('is not evaluated when allowEval is false', function() {
|
|
||||||
var calledEvent = false
|
|
||||||
var handler = htmx.on('htmx:evalDisallowedError', function() {
|
|
||||||
calledEvent = true
|
|
||||||
})
|
|
||||||
htmx.config.allowEval = false
|
|
||||||
try {
|
|
||||||
var btn = make("<button hx-on='click: window.foo = true'>Foo</button>")
|
|
||||||
btn.click()
|
|
||||||
should.not.exist(window.foo)
|
|
||||||
} finally {
|
|
||||||
htmx.config.allowEval = true
|
|
||||||
htmx.off('htmx:evalDisallowedError', handler)
|
|
||||||
delete window.foo
|
|
||||||
}
|
|
||||||
calledEvent.should.equal(true)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('can handle event types with dots', function() {
|
|
||||||
var btn = make("<button hx-on='my.custom.event: window.foo = true'>Foo</button>")
|
|
||||||
// IE11 doesn't support `new CustomEvent()` so call htmx' internal utility function
|
|
||||||
btn.dispatchEvent(htmx._('makeEvent')('my.custom.event'))
|
|
||||||
window.foo.should.equal(true)
|
|
||||||
delete window.foo
|
|
||||||
})
|
|
||||||
|
|
||||||
it('can handle being swapped using innerHTML', function() {
|
|
||||||
this.server.respondWith('GET', '/test', function(xhr) {
|
|
||||||
xhr.respond(200, {}, '<button id="bar" hx-on="click: window.bar = true">Bar</button>')
|
|
||||||
})
|
|
||||||
|
|
||||||
make(
|
|
||||||
'<div>' +
|
|
||||||
'<button id="swap" hx-get="/test" hx-target="#baz" hx-swap="innerHTML">Swap</button>' +
|
|
||||||
'<div id="baz"><button id="foo" hx-on="click: window.foo = true">Foo</button></div>' +
|
|
||||||
'</div>'
|
|
||||||
)
|
|
||||||
|
|
||||||
var fooBtn = byId('foo')
|
|
||||||
fooBtn.click()
|
|
||||||
window.foo.should.equal(true)
|
|
||||||
|
|
||||||
var swapBtn = byId('swap')
|
|
||||||
swapBtn.click()
|
|
||||||
this.server.respond()
|
|
||||||
|
|
||||||
var barBtn = byId('bar')
|
|
||||||
barBtn.click()
|
|
||||||
window.bar.should.equal(true)
|
|
||||||
|
|
||||||
delete window.foo
|
|
||||||
delete window.bar
|
|
||||||
})
|
|
||||||
|
|
||||||
it('cleans up all handlers when the DOM updates', function() {
|
|
||||||
// setup
|
|
||||||
window.foo = 0
|
|
||||||
window.bar = 0
|
|
||||||
var div = make("<div hx-on='increment-foo: window.foo++\nincrement-bar: window.bar++'>Foo</div>")
|
|
||||||
make('<div>Another Div</div>') // sole purpose is to update the DOM
|
|
||||||
|
|
||||||
// check there is just one handler against each event
|
|
||||||
htmx.trigger(div, 'increment-foo')
|
|
||||||
htmx.trigger(div, 'increment-bar')
|
|
||||||
window.foo.should.equal(1)
|
|
||||||
window.bar.should.equal(1)
|
|
||||||
|
|
||||||
// teardown
|
|
||||||
delete window.foo
|
|
||||||
delete window.bar
|
|
||||||
})
|
|
||||||
})
|
|
@ -1298,4 +1298,20 @@ describe('Core htmx Shadow DOM Tests', function() {
|
|||||||
this.server.respond()
|
this.server.respond()
|
||||||
values.should.deep.equal({ name: '', outside: '' })
|
values.should.deep.equal({ name: '', outside: '' })
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('can handle basic events w/ no other attributes', function() {
|
||||||
|
var btn = make("<button hx-on:click='window.foo = true'>Foo</button>")
|
||||||
|
btn.click()
|
||||||
|
window.foo.should.equal(true)
|
||||||
|
delete window.foo
|
||||||
|
})
|
||||||
|
|
||||||
|
it('can handle basic events w/ no other attributes in child', function() {
|
||||||
|
var div = make("<div><button id='b1' hx-on:click='window.foo = true'>Foo</button></div>")
|
||||||
|
var btn = div.querySelector("#b1")
|
||||||
|
btn.click()
|
||||||
|
window.foo.should.equal(true)
|
||||||
|
delete window.foo
|
||||||
|
})
|
||||||
|
|
||||||
})
|
})
|
||||||
|
Loading…
x
Reference in New Issue
Block a user