PageSourceSearch

https://leclub.inforisque.fr/assets/788cba2e/js/humhub/humhub.ui.search.js?v=1790158187

js inforisque.fr collected 2026-10-02 11:13:44 UTC 11,529 bytes, 335 lines download raw bytes

1humhub.module('ui.search', function(module, require, $) {
2    const client = require('client');
3    const loader = require('ui.loader');
4    const Widget = require('ui.widget').Widget;
5    const highlightWords = require('ui.additions').highlightWords;
6
7    const Search = Widget.extend();
8
9    Search.prototype.init = function() {
10        const that = this;
11
12        that.selectors = {
13            toggler: '#search-menu[data-bs-toggle=dropdown]',
14            panel: '#dropdown-search',
15            close: '#dropdown-search-close',
16            list: '.dropdown-search-list',
17            form: '.dropdown-search-form',
18            input: 'input.dropdown-search-keyword',
19            provider: '.search-provider',
20            providerSearched: '.search-provider.provider-searched',
21            providerContent: '.search-provider-content',
22            providerRecord: '.search-provider-record',
23            providerRecordText: '.search-provider-record-text',
24            providerCounter: '.search-provider-title > span',
25            providerShowAll: '.search-provider-show-all',
26            backdrop: '.dropdown-backdrop',
27            additionalToggler: {
28                form: 'form[data-bs-toggle="humhub.ui.search"]',
29                input: 'input[type=text]:first',
30                submit: '[type=submit]'
31            }
32        }
33
34        $(document).on('pjax:end', function () {
35            that.reset();
36        });
37
38        $(document).on('click', that.selectors.panel, function (e) {
39            e.stopPropagation();
40        });
41
42        $(document).on('click', that.selectors.close + ', '
43            + that.selectors.providerRecord + ', '
44            + that.selectors.providerShowAll, function () {
45            that.getBsMenuDropdown().hide();
46        });
47
48        that.getInput().on('keypress', function (e) {
49            if (e.which === 13) {
50                that.search();
51            }
52        }).on('keyup', function () {
53            that.searchTimeout(() => that.search(true));
54        }).on('keydown', function (e) {
55            return that.switchFocus(e.currentTarget.tagName, e.which);
56        });
57
58        that.getList().on('keypress', function () {
59            that.getCurrentInput().focus();
60        }).on('keydown', function (e) {
61            return that.switchFocus(e.currentTarget.tagName, e.which);
62        });
63
64        that.getList().niceScroll({
65            cursorwidth: '7',
66            cursorborder: '',
67            cursorcolor: '#555',
68            cursoropacitymax: '0.2',
69            nativeparentscrolling: false,
70            railpadding: {top: 0, right: 0, left: 0, bottom: 0}
71        });
72
73        that.$.on('shown.bs.dropdown', function () {
74            if (that.getBackdrop().length === 0) {
75                // Add the backdrop
76                that.$.append('<div class="' + that.selectors.backdrop.replace('.', '') + '">').promise().done(function() {
77                    // Close if the backdrop is clicked
78                    that.getBackdrop().on('click', function () {
79                        that.getBsMenuDropdown().hide();
80                    });
81                });
82            }
83            if (that.getList().is(':visible')) {
84                // refresh NiceScroll after reopen it with searched results
85                that.getList().hide().show();
86            }
87            if (that.getInput().is(':visible')) {
88                that.getInput().focus();
89            }
90        })
91
92        const additionalTogglerForm = $(that.selectors.additionalToggler.form);
93        const additionalTogglerInput = additionalTogglerForm.length ? additionalTogglerForm.find(that.selectors.additionalToggler.input) : null;
94
95        that.$.on('hide.bs.dropdown', function (e) {
96            if (!additionalTogglerInput || !additionalTogglerInput.is(':focus') || additionalTogglerInput.val().trim() === '') {
97                that.getBackdrop().remove();
98            }
99        })
100
101        if (additionalTogglerInput) {
102            that.initAdditionalToggle(additionalTogglerForm, additionalTogglerInput);
103        }
104    }
105
106    Search.prototype.initAdditionalToggle = function (form, input) {
107        const that = this;
108        const submit = form.find(that.selectors.additionalToggler.submit);
109
110        const search = function (keyword, forceCurrentSearching) {
111            that.getForm().hide();
112            that.getInput().val(keyword);
113            that.showPanel().search(forceCurrentSearching);
114        }
115
116        submit.on('click', function () {
117            search(input.val());
118            return false;
119        });
120
121        input.on('keypress', function (e) {
122            if (e.which === 13) {
123                e.preventDefault();
124                search($(this).val());
125            }
126        }).on('keyup', function () {
127            that.searchTimeout(() => search($(this).val(), true));
128        }).on('keydown', function (e) {
129            return that.switchFocus(e.currentTarget.tagName, e.which);
130        });
131    }
132
133    Search.prototype.getMenuToggler = function () {
134        return this.$.find(this.selectors.toggler);
135    }
136
137    Search.prototype.getBsMenuDropdown = function () {
138        return new bootstrap.Dropdown(this.getMenuToggler().parent('.dropdown'));
139    }
140
141    Search.prototype.getBackdrop = function () {
142        return this.$.find(this.selectors.backdrop);
143    }
144
145    Search.prototype.getList = function () {
146        return this.$.find(this.selectors.list);
147    }
148
149    Search.prototype.getProviders = function () {
150        return this.$.find(this.selectors.provider);
151    }
152
153    Search.prototype.getForm = function () {
154        return this.$.find(this.selectors.form);
155    }
156
157    Search.prototype.getInput = function () {
158        return this.$.find(this.selectors.input);
159    }
160
161    Search.prototype.hasInput = function () {
162        const input = this.getInput();
163        return input.length === 1 && input.is(':visible');
164    }
165
166    Search.prototype.getAdditionalInput = function () {
167        return $(this.selectors.additionalToggler.form + ' ' + this.selectors.additionalToggler.input);
168    }
169
170    Search.prototype.hasAdditionalInput = function (isVisible) {
171        const input = this.getAdditionalInput();
172        if (input.length === 0) {
173            return false;
174        }
175        return typeof isVisible === 'undefined' || isVisible ? input.is(':visible') : !input.is(':visible');
176    }
177
178    Search.prototype.getCurrentInput = function () {
179        return this.hasAdditionalInput() ? this.getAdditionalInput() : this.getInput();
180    }
181
182    Search.prototype.isVisiblePanel = function () {
183        return $(this.selectors.toggler).hasClass('show');
184    }
185
186    Search.prototype.showPanel = function () {
187        if (!this.isVisiblePanel()) {
188            this.getBsMenuDropdown().show();
189        }
190        return this;
191    }
192
193    Search.prototype.hidePanel = function () {
194        if (this.isVisiblePanel()) {
195            this.getBsMenuDropdown().hide();
196        }
197        return this;
198    }
199
200    Search.prototype.isSearched = function () {
201        return this.$.find(this.selectors.providerSearched).length > 0;
202    }
203
204    Search.prototype.menu = function () {
205        this.getForm().show();
206    }
207
208    Search.prototype.searchTimeout = function (searchFunction) {
209        const that = this;
210
211        if (typeof that.currentSearchTimeout !== 'undefined') {
212            clearTimeout(that.currentSearchTimeout);
213        }
214
215        that.currentSearchTimeout = setTimeout(function () {
216            that.currentSearchTimeout = undefined;
217            searchFunction();
218        }, 500);
219
220        // Run this only to display a search loader immediately,
221        // The real search process will be rejected while currentSearchTimeout is set
222        searchFunction();
223    }
224
225    Search.prototype.search = function (forceCurrentSearching) {
226        const that = this;
227        const data = {
228            provider: null,
229            keyword: that.getInput().val().trim()
230        };
231
232        if (data.keyword === '') {
233            that.getList().hide();
234            that.getInput().val('');
235            that.previousKeyword = '';
236            if (!that.hasInput()) {
237                that.hidePanel();
238            }
239            return;
240        }
241
242        if (that.previousKeyword === data.keyword) {
243            this.getProviders().each(function () {
244                const provider = $(this);
245                provider.removeClass('provider-searching');
246                loader.reset(provider.find(that.selectors.providerContent));
247            });
248            return;
249        }
250
251        if (that.hasAdditionalInput(false)) {
252            that.getAdditionalInput().val(data.keyword);
253        }
254
255        this.getList().show();
256
257        this.getProviders().each(function () {
258            const provider = $(this);
259
260            if (!forceCurrentSearching && provider.hasClass('provider-searching')) {
261                return;
262            }
263
264            provider.addClass('provider-searching').show()
265                .find(that.selectors.providerCounter).hide();
266            loader.set(provider.find(that.selectors.providerContent), {size: '8px', css: {padding: '0px'}});
267
268            if (typeof that.currentSearchTimeout !== 'undefined') {
269                // Don't run the search process while time is not expired,
270                // This action was called only to display the search loader
271                return;
272            }
273
274            data.provider = provider.data('provider');
275            data.route = provider.data('provider-route');
276            client.post(module.config.url, {data}).then(function (response) {
277                if (data.keyword !== that.getInput().val().trim()) {
278                    // Skip this request because other with new keyword was sent
279                    return;
280                }
281
282                // Prepare and set new content
283                const newProviderContent = $(response.html);
284                provider.replaceWith(newProviderContent);
285                const records = newProviderContent.find(that.selectors.providerRecord);
286                if (records.length) {
287                    highlightWords(records.find(that.selectors.providerRecordText), data.keyword);
288                } else if (newProviderContent.data('hide-on-empty') !== undefined) {
289                    newProviderContent.hide();
290                }
291            }).catch(function (e) {
292                module.log.error(e, true);
293                loader.reset(provider.find(that.selectors.providerContent));
294                provider.hide();
295            });
296
297            that.previousKeyword = data.keyword;
298        });
299    }
300
301    Search.prototype.reset = function () {
302        this.getCurrentInput().val('');
303        this.getProviders().hide();
304        this.hidePanel();
305    }
306
307    Search.prototype.switchFocus = function (tag, key) {
308        if (key !== 38 && key !== 40) {
309            return true;
310        }
311
312        const dir = key === 38 ? 'up' : 'down';
313        const links = this.getList().find('a:visible');
314
315        if (tag === 'INPUT') {
316            if (dir === 'down') {
317                links.first().focus();
318                return false;
319            } else if (dir === 'up') {
320                links.last().focus();
321                return false;
322            }
323        } else if (tag === 'UL') {
324            if ((dir === 'down' && links.last().is(':focus')) ||
325                (dir === 'up' && links.first().is(':focus'))) {
326                this.getCurrentInput().focus();
327                return false;
328            }
329        }
330
331        return true;
332    }
333
334    module.export = Search;
335});

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.