htmx-response-targets.js RawHistoryFolder
1(function(){
2
3 /** @type {import("../htmx").HtmxInternalApi} */
4 var api;
5
6 var attrPrefix = 'hx-target-';
7
8 /**
9 * @param {HTMLElement} elt
10 * @param {number} respCode
11 * @returns {HTMLElement | null}
12 */
13 function getRespCodeTarget(elt, respCodeNumber) {
14 if (!elt || !respCodeNumber) return null;
15
16 var respCode = respCodeNumber.toString();
17
18 // '*' is the original syntax, as the obvious character for a wildcard.
19 // The 'x' alternative was added for maximum compatibility with HTML
20 // templating engines, due to ambiguity around which characters are
21 // supported in HTML attributes.
22 //
23 // Start with the most specific possible attribute and generalize from
24 // there.
25 var attrPossibilities = [
26 respCode,
27
28 respCode.substr(0, 2) + '*',
29 respCode.substr(0, 2) + 'x',
30
31 respCode.substr(0, 1) + '*',
32 respCode.substr(0, 1) + 'x',
33 respCode.substr(0, 1) + '**',
34 respCode.substr(0, 1) + 'xx',
35
36 '*',
37 'x',
38 '***',
39 'xxx',
40 ];
41
42 for (var i = 0; i < attrPossibilities.length; i++) {
43 var attr = attrPrefix + attrPossibilities[i];
44 var attrValue = api.getClosestAttributeValue(elt, attr);
45 if (attrValue) {
46 if (attrValue === "this") {
47 return api.findThisElement(elt, attr);
48 } else {
49 return api.querySelectorExt(elt, attrValue);
50 }
51 }
52 }
53
54 return null;
55 }
56
57 /** @param {Event} evt */
58 function handleErrorFlag(evt) {
59 if (evt.detail.isError) {
60 if (htmx.config.responseTargetUnsetsError) {
61 evt.detail.isError = false;
62 }
63 } else if (htmx.config.responseTargetSetsError) {
64 evt.detail.isError = true;
65 }
66 }
67
68 htmx.defineExtension('response-targets', {
69
70 /** @param {import("../htmx").HtmxInternalApi} apiRef */
71 init: function (apiRef) {
72 api = apiRef;
73
74 if (htmx.config.responseTargetUnsetsError === undefined) {
75 htmx.config.responseTargetUnsetsError = true;
76 }
77 if (htmx.config.responseTargetSetsError === undefined) {
78 htmx.config.responseTargetSetsError = false;
79 }
80 if (htmx.config.responseTargetPrefersExisting === undefined) {
81 htmx.config.responseTargetPrefersExisting = false;
82 }
83 if (htmx.config.responseTargetPrefersRetargetHeader === undefined) {
84 htmx.config.responseTargetPrefersRetargetHeader = true;
85 }
86 },
87
88 /**
89 * @param {string} name
90 * @param {Event} evt
91 */
92 onEvent: function (name, evt) {
93 if (name === "htmx:beforeSwap" &&
94 evt.detail.xhr &&
95 evt.detail.xhr.status !== 200) {
96 if (evt.detail.target) {
97 if (htmx.config.responseTargetPrefersExisting) {
98 evt.detail.shouldSwap = true;
99 handleErrorFlag(evt);
100 return true;
101 }
102 if (htmx.config.responseTargetPrefersRetargetHeader &&
103 evt.detail.xhr.getAllResponseHeaders().match(/HX-Retarget:/i)) {
104 evt.detail.shouldSwap = true;
105 handleErrorFlag(evt);
106 return true;
107 }
108 }
109 if (!evt.detail.requestConfig) {
110 return true;
111 }
112 var target = getRespCodeTarget(evt.detail.requestConfig.elt, evt.detail.xhr.status);
113 if (target) {
114 handleErrorFlag(evt);
115 evt.detail.shouldSwap = true;
116 evt.detail.target = target;
117 }
118 return true;
119 }
120 }
121 });
122})();