PageSourceSearch

https://wespline.com/static/ws-company-completion.js

js wespline.com collected 2026-10-08 03:32:50 UTC 9,657 bytes, 250 lines download raw bytes

1import { loadjs } from './loadjs.js';
2import { i18n, MultiLang } from './js/i18n/ws-i18n.js';
3
4MultiLang.importFile('/static/lang/ws-company-completion.json').subscribe();
5
6try {
7    loadjs([
8        'https://cdnjs.cloudflare.com/ajax/libs/bootstrap-3-typeahead/4.0.2/bootstrap3-typeahead.min.js'
9    ], 'typeahead');
10} catch(e) {}
11
12export class WsCompanyCompletion {
13    constructor(element, { error = null, autoSelect = false } = {}, filter = []) {
14        this.observers     = [];
15        this._element      = $(element);
16        this._autoSelect   = autoSelect;
17        this._error        = error;
18        this._pristine     = true;
19        this._first_focus  = true;
20        this._toFilter = filter;
21
22        this._element.attr('autocomplete', 'off');
23        this._element.attr('id', '');
24        this._element.attr('name', '');
25        this._element.attr('type', 'search');
26
27        this._element.on('input', () => {
28            this._pristine = false;
29
30            if (this._validator != null) {
31                this._validator.validate(this._element.val(), this._error);
32            }
33        });
34
35        this._element.on('blur', () => {
36            this._first_focus = false;
37
38            setTimeout(() => {
39                if (this._validator != null) {
40                    this._validator.validate(this._element.val(), this._error);
41                }
42            }, 3);
43        });
44    }
45
46    get start() {
47        const WsCompanyCompletionRef = this;
48
49        return Rx.Observable.create(observer => {
50            if (this.observers.length === 0) {
51                this._element.on('blur', () => {
52                    this._timer = setTimeout(() => {
53                        if ((this.value || {}).name !== this._element.val()) {
54                            this.value = { id: null, name: this._element.val() };
55                        }
56
57                        this.observers.forEach(o => o.next(this.value));
58                        this._timer = null;
59                    }, 1);
60                });
61
62                this._element.keydown(e => {
63                    this._timer = setTimeout(() => {
64                        if (e.which == 9 && this._element.val() != '') {
65                            if ((this.value || {}).name !== this._element.val()) {
66                                this.value = { id: null, name: this._element.val() };
67                            }
68
69                            this.observers.forEach(o => o.next(this.value));
70                            this._timer = null;
71                        }
72                    }, 1);
73                });
74
75                this._element.keyup(e => {
76                    this._timer = setTimeout(() => {
77                        if (e.which == 13 && this._element.val() != '') {
78                            if ((this.value || {}).name !== this._element.val()) {
79                                this.value = { id: null, name: this._element.val() };
80                            }
81
82                            this.observers.forEach(o => o.next(this.value));
83                            this._timer = null;
84                        }
85                    }, 1);
86                });
87
88                loadjs.ready('typeahead', () => {
89                     $.fn.typeahead.Constructor.prototype.show = function () {
90                         var pos = $.extend({}, this.$element.position(), {
91                            height: this.$element[0].offsetHeight
92                         })
93                         this.$menu
94                             .insertAfter(this.$element)
95                             .css({
96                                 top: (pos.top + pos.height),
97                                 left: pos.left
98                             })
99                             .show();
100
101                        this.shown = true;
102                        return this;
103                    };
104
105                    this._element.typeahead({
106                        autoSelect: this._autoSelect,
107                        menu: '<ul class="typeahead dropdown-menu" role="listbox" style="z-index: 1050 !important; overflow: hidden"></ul>',
108                        item: '<li style="margin-left: 0 !important"><a class="dropdown-item" href="#" role="option"></a></li>',
109                        source: (query, result) => {
110                            restCall('GET', '/company/api/suggest/' 
110+ query).subscribe(r => result(r.suggestions));
111                        },
112                        render: function(items) {
113                            var that = this;
114                            var self = this;
115                            var activeFound = false;
116                            var data = [];
117                            var _category = that.options.separator;
118
119                            items.forEach((company) => {
120                                function checkIfCompanyAlreadyExists(companyToRemove) {
121                                    return company.id == companyToRemove.id
122                                };
123                                const hasCompany = WsCompanyCompletionRef._toFilter.filter(checkIfCompanyAlreadyExists);
124
125                                if (hasCompany.length === 0) data.push(company);
126                            })
127
128                            items = $(data).map(function (i, item) {
129                                var text = self.displayText(item);
130                                i = $(that.options.item).data('value', item);
131                                i.find('a').html($(`
132                                    <div>
133                                        <span style="border-radius: 100%; display: inline-table; overflow: hidden; margin-right: 5px;">
134                                            <img src="${item.photo}" style="width: 30px; height: 30px;">
135                                        </span>
136                                    </div>
137                                `).append(that.highlighter(text, item)));
138                                i.addClass('notranslate');
139                                if (text == self.$element.val()) {
140                                    i.addClass('active');
141                                    self.$element.data('active', item);
142                                    activeFound = true;
143                                }
144                                return i[0];
145                            });
146                            if (this.autoSelect && !activeFound) {
147                                items.filter(':not(.dropdown-header)').first().addClass('active');
148                                this.$element.data('active', items.first().data('value'));
149                            }
150                            this.$menu.html(items);
151                            return this;
152                        },
153                        matcher: (item) => true,
154                        afterSelect: item => {
155                            if (this._timer != null) {
156                                clearTimeout(this._timer);
157                                this._timer = null;
158                            }
159
160                            this.observers.forEach(o => o.next(item));
161                            this.value = item;
162                            return item;
163                        }
164                    });
165                });
166            }
167
168            this.observers.push(observer);
169            return () => {
170                this.observers = this.observers.filter(o => o !== observer);
171                if (this.observers.length === 0) {
172                    this._element.typeahead('destroy');
173                }
174            }
175        });
176    }
177
178    set value(v) {
179        this._value = v;
180        this._element.val((this._value || {}).name || '');
181    }
182
183    get value() {
184        return this._value || null;
185    }
186
187    clear() {
188        this._value = null;
189        this._element.val('');
190    }
191
192    set visible(v) {
193        if (v) {
194            this._element.show();
195        } else {
196            this._element.hide();
197        }
198    }
199
200    validate(type, { exists = false } = {}) {
201        if (this._validator != null)
202            return this._validator;
203
204        let self = this;
205        this._validator = new function() {
206            const msgEmpty = i18n('ws-company-completion-empty-validator', type);
207            const msgExists = i18n('ws-company-completion-exists-validator', type);
208
209            this.destroy = () => {};
210            this.trigger = () => {
211                self._pristine    = false;
212                self._first_focus = false;
213                return this.validate(self._element.val(), self._error);
214            };
215            
216            this.type = type;
217            this.isVisible = () => self._element.is(':visible');
218
219            this.validate = (val, errorContainer) => {
220                if (self._element.is(':disabled') || !self._element.is(':visible'))
221                    return true;
222
223                if (self._pristine || self._first_focus) {
224                    return false;
225                }
226
227                if (val.length === 0 && errorContainer != null) {
228                    errorContainer.text(msgEmpty);
229                    errorContainer.css('display', 'block');
230
231                    return false;
232                }
233
234                if (exists === true && self.value.id == null) {
235                    errorContainer.text(msgExists);
236                    errorContainer.css('display', 'block');
237
238                    return false;
239                }
240
241                errorContainer.text('');
242                errorContainer.css('display', 'none');
243
244                return true;
245            };
246        }
247
248        return this._validator;
249    }
250}

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.