properly trim ids in `hx-select-oob` and also support hyperscript-style query literals in attributes like `hx-target`
This commit is contained in:
Carson Gross 2023-04-05 12:47:51 -06:00
parent 32edfba6f2
commit 6cc92bf12d
4 changed files with 108 additions and 6 deletions

View File

@ -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);
}

View File

@ -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", "<div id='d1'>foo</div><div id='d2'>bar</div><div id='d3'>bar</div>");
var div = make('<div hx-get="/test" hx-select="#d1" hx-select-oob="#d2, #d3"></div>');
make('<div id="d2"></div>');
make('<div id="d3"></div>');
div.click();
this.server.respond();
div.innerHTML.should.equal("<div id=\"d1\">foo</div>");
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", "<div id='d1'>foo</div><div id='d2'>bar</div>");

View File

@ -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('<div><p><i><button id="b1" hx-target="closest <div/>" hx-get="/test">Click Me!</button></i></p></div>')
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('<div hx-target="find <span/>" hx-get="/test">Click Me! <div><span id="s1"></span><span id="s2"></span></div></div>')
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('<button hx-target="<#d1/>" hx-get="/test">Click Me!<div id="d1"></div></button>')
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('<div>' +
' <div id="d3"></div>' +
' <button id="b1" hx-target="next <div/>" hx-get="/test">Click Me!</button>' +
' <div id="d1"></div>' +
' <div id="d2"></div>' +
'</div>')
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('<div>' +
' <div id="d3"></div>' +
' <button id="b1" hx-target="previous <div/>" hx-get="/test">Click Me!</button>' +
' <div id="d1"></div>' +
' <div id="d2"></div>' +
'</div>')
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!");
});
})

View File

@ -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 <CSS selector>` 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 <CSS selector>` 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 <CSS selector>` 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 <CSS selector>` 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