Skip to content

Commit

Permalink
Support hx-target-5xx syntax, for maximum compatibility (#1564)
Browse files Browse the repository at this point in the history
# Please enter the commit message for your changes. Lines starting
# with '#' will be kept; you may remove them yourself if you want to.
# An empty message aborts the commit.
#
# Date:      Sun Jul 23 16:03:11 2023 -0400
#
# On branch 1564-hx-target-5xx-syntax
# Your branch is up to date with 'origin/1564-hx-target-5xx-syntax'.
#
# Changes to be committed:
#	modified:   src/ext/response-targets.js
#	modified:   test/ext/response-targets.js
#

# Please enter the commit message for your changes. Lines starting
# with '#' will be kept; you may remove them yourself if you want to.
# An empty message aborts the commit.
#
# Date:      Sun Jul 23 16:03:11 2023 -0400
#
# On branch 1564-hx-target-5xx-syntax
# Your branch is up to date with 'origin/1564-hx-target-5xx-syntax'.
#
# Changes to be committed:
#	modified:   src/ext/response-targets.js
#	modified:   test/ext/response-targets.js
#

# Please enter the commit message for your changes. Lines starting
# with '#' will be kept; you may remove them yourself if you want to.
# An empty message aborts the commit.
#
# Date:      Sun Jul 23 16:03:11 2023 -0400
#
# On branch 1564-hx-target-5xx-syntax
# Your branch is up to date with 'origin/1564-hx-target-5xx-syntax'.
#
# Changes to be committed:
#	modified:   src/ext/response-targets.js
#	modified:   test/ext/response-targets.js
#	modified:   www/content/extensions/response-targets.md
#
  • Loading branch information
spiffytech committed Jul 23, 2023
1 parent c59fe79 commit 53bc6d5
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 27 deletions.
64 changes: 38 additions & 26 deletions src/ext/response-targets.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,43 +3,55 @@
/** @type {import("../htmx").HtmxInternalApi} */
var api;

const targetAttrPrefix = 'hx-target-';
const targetAttrMinLen = targetAttrPrefix.length - 1;
const attrPrefix = 'hx-target-';

/**
* @param {HTMLElement} elt
* @param {number} respCode
* @returns {HTMLElement | null}
*/
function getRespCodeTarget(elt, respCode) {
if (!elt || !respCode) return null;
function getRespCodeTarget(elt, respCodeNumber) {
if (!elt || !respCodeNumber) return null;

var targetAttr = targetAttrPrefix + respCode;
var targetStr = api.getClosestAttributeValue(elt, targetAttr);
var respCode = respCodeNumber.toString();

if (targetStr) {
if (targetStr === "this") {
return api.findThisElement(elt, targetAttr);
} else {
return api.querySelectorExt(elt, targetStr);
}
} else {
for (let l = targetAttr.length - 1; l > targetAttrMinLen; l--) {
targetAttr = targetAttr.substring(0, l) + '*';
targetStr = api.getClosestAttributeValue(elt, targetAttr);
if (targetStr) break;
}
}
// '*' is the original syntax, as the obvious character for a wildcard.
// The 'x' alternative was added for maximum compatibility with HTML
// templating engines, due to ambiguity around which characters are
// supported in HTML attributes.
//
// Start with the most specific possible attribute and generalize from
// there.
var attrPossibilities = [
respCode,

respCode.substr(0, 2) + '*',
respCode.substr(0, 2) + 'x',

if (targetStr) {
if (targetStr === "this") {
return api.findThisElement(elt, targetAttr);
} else {
return api.querySelectorExt(elt, targetStr);
respCode.substr(0, 1) + '*',
respCode.substr(0, 1) + 'x',
respCode.substr(0, 1) + '**',
respCode.substr(0, 1) + 'xx',

'*',
'x',
'***',
'xxx',
];

for (var i = 0; i < attrPossibilities.length; i++) {
var attr = attrPrefix + attrPossibilities[i];
var attrValue = api.getClosestAttributeValue(elt, attr);
if (attrValue) {
if (attrValue === "this") {
return api.findThisElement(elt, attr);
} else {
return api.querySelectorExt(elt, attrValue);
}
}
} else {
return null;
}

return null;
}

/** @param {Event} evt */
Expand Down
34 changes: 34 additions & 0 deletions test/ext/response-targets.js
Original file line number Diff line number Diff line change
Expand Up @@ -221,4 +221,38 @@ describe("response-targets extension", function() {
div2.innerHTML.should.equal("");
div3.innerHTML.should.equal("Not found!");
});

describe('status code formatting', function()
{
var attributes = [
"hx-target-404",

"hx-target-40*",
"hx-target-40x",

"hx-target-4*",
"hx-target-4x",
"hx-target-4**",
"hx-target-4xx",

"hx-target-*",
"hx-target-x",
"hx-target-***",
"hx-target-xxx",
];

// String replacement because IE11 doesn't support template literals
var btnMarkup = '<button hx-ext="response-targets" HX_TARGET="#d1" hx-get="/test">Click Me!</button>';
// forEach because IE11 doesn't play nice with closures inside for loops
attributes.forEach(function(attribute) {
it('supports ' + attribute, function() {
this.server.respondWith("GET", "/test", [404, {}, "Not found!"]);
var btn = make(btnMarkup.replace("HX_TARGET", attribute));
var div1 = make('<div id="d1"></div>')
btn.click();
this.server.respond();
div1.innerHTML.should.equal("Not found!");
});
});
});
});
6 changes: 5 additions & 1 deletion www/content/extensions/response-targets.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title = "response-targets"
+++

This extension allows to specify different target elements to be swapped when
This extension allows you to specify different target elements to be swapped when
different HTTP response codes are received.

It uses attribute names in a form of ``hx-target-[CODE]`` where `[CODE]` is a numeric
Expand Down Expand Up @@ -101,6 +101,10 @@ be looked up (in the given order):
* `hx-target-4*`
* `hx-target-*`.


_If you are using tools that do not support asterisks in HTML attributes, you
may instead use the `x` character, e.g., `hx-target-4xx`._

## Notes

* `hx-target-…` is inherited and can be placed on a parent element.
Expand Down

0 comments on commit 53bc6d5

Please sign in to comment.