diff --git a/src/ext/response-targets.js b/src/ext/response-targets.js index 35db4e1f6..564a821b6 100644 --- a/src/ext/response-targets.js +++ b/src/ext/response-targets.js @@ -3,43 +3,55 @@ /** @type {import("../htmx").HtmxInternalApi} */ var api; - const targetAttrPrefix = 'hx-target-'; - const targetAttrMinLen = targetAttrPrefix.length - 1; + var 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 */ diff --git a/src/htmx.js b/src/htmx.js index 005da3d7d..d6c12c5cf 100644 --- a/src/htmx.js +++ b/src/htmx.js @@ -3584,7 +3584,7 @@ return (function () { //==================================================================== function ready(fn) { - if (getDocument().readyState !== 'loading') { + if (getDocument().readyState === 'complete') { fn(); } else { getDocument().addEventListener('DOMContentLoaded', fn); diff --git a/test/ext/response-targets.js b/test/ext/response-targets.js index 1c670d664..2384c319b 100644 --- a/test/ext/response-targets.js +++ b/test/ext/response-targets.js @@ -263,4 +263,38 @@ describe("response-targets extension", function() { htmx.config.responseTargetPrefersExisting = false; } }); + + 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 = ''; + // 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('
') + btn.click(); + this.server.respond(); + div1.innerHTML.should.equal("Not found!"); + }); + }); + }); }); diff --git a/www/config.toml b/www/config.toml index 7dc7c9afe..20f42e3fa 100644 --- a/www/config.toml +++ b/www/config.toml @@ -7,7 +7,8 @@ build_search_index = false generate_feed = true taxonomies = [ - { name = "tag", render = false, feed = true } + { name = "tag", render = false, feed = true }, + { name = "author", render = false, feed = false } ] [markdown] @@ -35,4 +36,4 @@ paths_keep_dates = true # Tomorrow # two-dark # visual-studio-dark -# zenburn \ No newline at end of file +# zenburn diff --git a/www/content/attributes/hx-on.md b/www/content/attributes/hx-on.md index af8ffc053..57bc03b33 100644 --- a/www/content/attributes/hx-on.md +++ b/www/content/attributes/hx-on.md @@ -7,11 +7,10 @@ The `hx-on` attribute allows you to embed scripts inline to respond to events di `hx-on` improves upon `onevent` by enabling the handling of any event for enhanced [Locality of Behaviour (LoB)](/essays/locality-of-behaviour/). This also enables you to handle any htmx event. There are two forms of this attribute, one in which you specify the event as part of the attribute name -after a colon (`hx-on:click`, for example), and one that uses the `hx-on` attribute directly. The -latter form should only be used if IE11 support is required. +after a colon (`hx-on:click`, for example), and a deprecated form that uses the `hx-on` attribute directly. The +latter should only be used if IE11 support is required. -### Forms -#### hx-on:* (recommended) +### hx-on:* (recommended) The event name follows a colon `:` in the attribute, and the attribute value is the script to be executed: ```html @@ -40,22 +39,16 @@ events, and omit the "htmx" part: Adding multiple handlers is easy, you just specify additional attributes: ```html ``` -#### hx-on (deprecated, except for IE11 support) +### hx-on (deprecated) The value is an event name, followed by a colon `:`, followed by the script: -```html -
Click
-``` - -And htmx events: - ```html