mirror of
https://github.com/bigskysoftware/htmx.git
synced 2025-09-28 05:21:18 +00:00
properly trim ids in `hx-select-oob` and also support hyperscript-style query literals in attributes like `hx-target`
This commit is contained in:
parent
32edfba6f2
commit
6cc92bf12d
21
src/htmx.js
21
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) {
|
function querySelectorAllExt(elt, selector) {
|
||||||
if (selector.indexOf("closest ") === 0) {
|
if (selector.indexOf("closest ") === 0) {
|
||||||
return [closest(elt, selector.substr(8))];
|
return [closest(elt, normalizeSelector(selector.substr(8)))];
|
||||||
} else if (selector.indexOf("find ") === 0) {
|
} 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) {
|
} 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) {
|
} else if (selector.indexOf("previous ") === 0) {
|
||||||
return [scanBackwardsQuery(elt, selector.substr(9))];
|
return [scanBackwardsQuery(elt, normalizeSelector(selector.substr(9)))];
|
||||||
} else if (selector === 'document') {
|
} else if (selector === 'document') {
|
||||||
return [document];
|
return [document];
|
||||||
} else if (selector === 'window') {
|
} else if (selector === 'window') {
|
||||||
return [window];
|
return [window];
|
||||||
} else {
|
} else {
|
||||||
return getDocument().querySelectorAll(selector);
|
return getDocument().querySelectorAll(normalizeSelector(selector));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -770,7 +779,7 @@ return (function () {
|
|||||||
var oobSelectValues = oobSelects.split(",");
|
var oobSelectValues = oobSelects.split(",");
|
||||||
for (let i = 0; i < oobSelectValues.length; i++) {
|
for (let i = 0; i < oobSelectValues.length; i++) {
|
||||||
var oobSelectValue = oobSelectValues[i].split(":", 2);
|
var oobSelectValue = oobSelectValues[i].split(":", 2);
|
||||||
var id = oobSelectValue[0];
|
var id = oobSelectValue[0].trim();
|
||||||
if (id.indexOf("#") === 0) {
|
if (id.indexOf("#") === 0) {
|
||||||
id = id.substring(1);
|
id = id.substring(1);
|
||||||
}
|
}
|
||||||
|
@ -20,6 +20,23 @@ describe("hx-select-oob attribute", function () {
|
|||||||
div2.innerHTML.should.equal("bar");
|
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()
|
it('basic hx-select-oob ignores bad selector', function()
|
||||||
{
|
{
|
||||||
this.server.respondWith("GET", "/test", "<div id='d1'>foo</div><div id='d2'>bar</div>");
|
this.server.respondWith("GET", "/test", "<div id='d1'>foo</div><div id='d2'>bar</div>");
|
||||||
|
@ -48,6 +48,16 @@ describe("hx-target attribute", function(){
|
|||||||
div1.innerHTML.should.equal("Clicked!");
|
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()
|
it('targets a `find` element properly', function()
|
||||||
{
|
{
|
||||||
this.server.respondWith("GET", "/test", "Clicked!");
|
this.server.respondWith("GET", "/test", "Clicked!");
|
||||||
@ -60,6 +70,18 @@ describe("hx-target attribute", function(){
|
|||||||
span2.innerHTML.should.equal("");
|
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()
|
it('targets an inner element properly', function()
|
||||||
{
|
{
|
||||||
this.server.respondWith("GET", "/test", "Clicked!");
|
this.server.respondWith("GET", "/test", "Clicked!");
|
||||||
@ -70,6 +92,15 @@ describe("hx-target attribute", function(){
|
|||||||
div1.innerHTML.should.equal("Clicked!");
|
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()
|
it('handles bad target gracefully', function()
|
||||||
{
|
{
|
||||||
@ -111,6 +142,26 @@ describe("hx-target attribute", function(){
|
|||||||
div3.innerHTML.should.equal("");
|
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()
|
it('targets a `previous` element properly', function()
|
||||||
{
|
{
|
||||||
this.server.respondWith("GET", "/test", "Clicked!");
|
this.server.respondWith("GET", "/test", "Clicked!");
|
||||||
@ -131,4 +182,24 @@ describe("hx-target attribute", function(){
|
|||||||
div3.innerHTML.should.equal("Clicked!");
|
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!");
|
||||||
|
});
|
||||||
|
|
||||||
})
|
})
|
||||||
|
@ -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
|
* `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.
|
* `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)
|
(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.
|
* `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)
|
(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:
|
Here is an example that targets a div:
|
||||||
|
|
||||||
```html
|
```html
|
||||||
|
Loading…
x
Reference in New Issue
Block a user