UNPKG

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