diff --git a/src/htmx.js b/src/htmx.js index 5dc40f17..cabe02e1 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -540,21 +540,30 @@ return (function () { } } + function normalizeSelector(selector) { + var trimmedSelector = selector.trim(); + if (trimmedSelector.startsWith("<") && trimmedSelector.endsWith("/>")) { + return trimmedSelector.substring(1, trimmedSelector.length - 2); + } else { + return trimmedSelector; + } + } + function querySelectorAllExt(elt, selector) { if (selector.indexOf("closest ") === 0) { - return [closest(elt, selector.substr(8))]; + return [closest(elt, normalizeSelector(selector.substr(8)))]; } else if (selector.indexOf("find ") === 0) { - return [find(elt, selector.substr(5))]; + return [find(elt, normalizeSelector(selector.substr(5)))]; } else if (selector.indexOf("next ") === 0) { - return [scanForwardQuery(elt, selector.substr(5))]; + return [scanForwardQuery(elt, normalizeSelector(selector.substr(5)))]; } else if (selector.indexOf("previous ") === 0) { - return [scanBackwardsQuery(elt, selector.substr(9))]; + return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))]; } else if (selector === 'document') { return [document]; } else if (selector === 'window') { return [window]; } else { - return getDocument().querySelectorAll(selector); + return getDocument().querySelectorAll(normalizeSelector(selector)); } } @@ -770,7 +779,7 @@ return (function () { var oobSelectValues = oobSelects.split(","); for (let i = 0; i < oobSelectValues.length; i++) { var oobSelectValue = oobSelectValues[i].split(":", 2); - var id = oobSelectValue[0]; + var id = oobSelectValue[0].trim(); if (id.indexOf("#") === 0) { id = id.substring(1); } diff --git a/test/attributes/hx-select-oob.js b/test/attributes/hx-select-oob.js index dbdc0e0d..570811e8 100644 --- a/test/attributes/hx-select-oob.js +++ b/test/attributes/hx-select-oob.js @@ -20,6 +20,23 @@ describe("hx-select-oob attribute", function () { div2.innerHTML.should.equal("bar"); }); + it('multiple hx-select-oobs works', function() + { + this.server.respondWith("GET", "/test", "
foo
bar
bar
"); + var div = make('
'); + make('
'); + make('
'); + div.click(); + this.server.respond(); + div.innerHTML.should.equal("
foo
"); + + var div2 = byId('d2'); + div2.innerHTML.should.equal("bar"); + + var div3 = byId('d2'); + div3.innerHTML.should.equal("bar"); + }); + it('basic hx-select-oob ignores bad selector', function() { this.server.respondWith("GET", "/test", "
foo
bar
"); diff --git a/test/attributes/hx-target.js b/test/attributes/hx-target.js index da48ea03..2d4cd0b6 100644 --- a/test/attributes/hx-target.js +++ b/test/attributes/hx-target.js @@ -48,6 +48,16 @@ describe("hx-target attribute", function(){ div1.innerHTML.should.equal("Clicked!"); }); + it('targets a `closest` element properly w/ hyperscript syntax', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + var div1 = make('

') + var btn = byId("b1") + btn.click(); + this.server.respond(); + div1.innerHTML.should.equal("Clicked!"); + }); + it('targets a `find` element properly', function() { this.server.respondWith("GET", "/test", "Clicked!"); @@ -60,6 +70,18 @@ describe("hx-target attribute", function(){ span2.innerHTML.should.equal(""); }); + it('targets a `find` element properly w/ hyperscript syntax', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + var div1 = make('
Click Me!
') + div1.click(); + this.server.respond(); + var span1 = byId("s1") + var span2 = byId("s2") + span1.innerHTML.should.equal("Clicked!"); + span2.innerHTML.should.equal(""); + }); + it('targets an inner element properly', function() { this.server.respondWith("GET", "/test", "Clicked!"); @@ -70,6 +92,15 @@ describe("hx-target attribute", function(){ div1.innerHTML.should.equal("Clicked!"); }); + it('targets an inner element properly w/ hyperscript syntax', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + var btn = make('') + var div1 = byId("d1") + btn.click(); + this.server.respond(); + div1.innerHTML.should.equal("Clicked!"); + }); it('handles bad target gracefully', function() { @@ -111,6 +142,26 @@ describe("hx-target attribute", function(){ div3.innerHTML.should.equal(""); }); + it('targets a `next` element properly w/ hyperscript syntax', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + make('
' + + '
' + + ' ' + + '
' + + '
' + + '
') + var btn = byId("b1") + var div1 = byId("d1") + var div2 = byId("d2") + var div3 = byId("d3") + btn.click(); + this.server.respond(); + div1.innerHTML.should.equal("Clicked!"); + div2.innerHTML.should.equal(""); + div3.innerHTML.should.equal(""); + }); + it('targets a `previous` element properly', function() { this.server.respondWith("GET", "/test", "Clicked!"); @@ -131,4 +182,24 @@ describe("hx-target attribute", function(){ div3.innerHTML.should.equal("Clicked!"); }); + it('targets a `previous` element properly w/ hyperscript syntax', function() + { + this.server.respondWith("GET", "/test", "Clicked!"); + make('
' + + '
' + + ' ' + + '
' + + '
' + + '
') + var btn = byId("b1") + var div1 = byId("d1") + var div2 = byId("d2") + var div3 = byId("d3") + btn.click(); + this.server.respond(); + div1.innerHTML.should.equal(""); + div2.innerHTML.should.equal(""); + div3.innerHTML.should.equal("Clicked!"); + }); + }) diff --git a/www/attributes/hx-target.md b/www/attributes/hx-target.md index a53bf9b6..438b2869 100644 --- a/www/attributes/hx-target.md +++ b/www/attributes/hx-target.md @@ -12,9 +12,14 @@ request. The value of this attribute can be: * `this` which indicates that the element that the `hx-target` attribute is on is the target * `closest ` which will find the closest parent ancestor that matches the given CSS selector. (e.g. `closest tr` will target the closest table row to the element) + * `next ` which will find the next element in the DOM from the element that the `hx-target` attribute is on matching the given CSS selector. + * `previous ` which will find the next element in the DOM from the element that the `hx-target` attribute is on matching the given CSS selector. * `find ` which will find the first child descendant element that matches the given CSS selector. (e.g `find tr` will target the first child descendant row to the element) +Note that in all cases, the CSS selector may be wrapped in a `<` and `/>`, mimicking the [query literal](https://hyperscript.org/expressions/query-reference/) syntax of +hyperscript. + Here is an example that targets a div: ```html