0.1.23 7396d26

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})();

Keyboard shortcuts

Single-key shortcuts are on. ctrl k and esc work whatever this says.

ctrl k :
go to a section, branch, tag, file or repository
?
this list
j k
move the row cursor down / up
enter
open the row under the cursor; on Files, a directory opens or closes in place
↑ ↓ ← → home end
in the file tree (focus on a row): previous / next row, close / open a directory or go to its parent / first entry, first / last row. They never open a file
l h
on Files: open a directory or a file / close a directory or go up to its parent, then to the parent page. Elsewhere: into the side panel (on a merge request, its files) / back to the content; there j k move between its controls
g g G
first / last row
/
filter the list; on Files, find a file anywhere in the repository (esc clears, enter opens the best match)
b
switch branch or tag
g s g f g c g b g m g i g r g a
tabs: summary, files, commits, branches & tags, merge requests, issues, releases, actions (when available)
g h
home
w
wide mode: use the whole width of the screen, or not (remembered)
y
copy a permalink pinned to the commit
d u x
diff: split / unified / collapse or expand all
e E
diff: the whole file in view / every file, with the lines the hunks hide
n
merge request: next note in the diff
esc
close a dialog, leave a field

Branches 7

Tags 106

↑↓ moveenter openesc close