|
1 |
| -(function($) { |
2 |
| - 'use strict'; |
| 1 | +import { Component } from "./component"; |
| 2 | +import { M } from "./global"; |
| 3 | +import $ from "cash-dom"; |
| 4 | +import { Dropdown } from "./dropdown"; |
| 5 | +import { Forms } from "./forms"; |
3 | 6 |
|
4 | 7 | let _defaults = {
|
5 |
| - data: [], // Autocomplete data set |
| 8 | + data: {}, // Autocomplete data set |
| 9 | + limit: Infinity, // Limit of results the autocomplete shows |
6 | 10 | onAutocomplete: null, // Callback for when autocompleted
|
7 | 11 | dropdownOptions: {
|
8 | 12 | // Default dropdown options
|
|
11 | 15 | coverTrigger: false
|
12 | 16 | },
|
13 | 17 | minLength: 1, // Min characters before autocomplete starts
|
| 18 | + sortFunction: function(a, b, inputString) { |
| 19 | + // Sort function for sorting autocomplete results |
| 20 | + return a.indexOf(inputString) - b.indexOf(inputString); |
| 21 | + }, |
| 22 | + |
14 | 23 | isMultiSelect: false,
|
15 | 24 | onSearch: function(text, autocomplete) {
|
16 | 25 | const filteredData = autocomplete.options.data.filter(item => {
|
|
24 | 33 | allowUnsafeHTML: false
|
25 | 34 | };
|
26 | 35 |
|
27 |
| - class Autocomplete extends Component { |
| 36 | + /** |
| 37 | + * @class |
| 38 | + * |
| 39 | + */ |
| 40 | + export class Autocomplete extends Component { |
| 41 | + private isOpen: boolean; |
| 42 | + private count: number; |
| 43 | + private activeIndex: number; |
| 44 | + private oldVal: any; |
| 45 | + private $inputField: any; |
| 46 | + private $active: any; |
| 47 | + private _mousedown: boolean; |
| 48 | + private _handleInputBlurBound: any; |
| 49 | + private _handleInputKeyupAndFocusBound: any; |
| 50 | + private _handleInputKeydownBound: any; |
| 51 | + private _handleInputClickBound: any; |
| 52 | + private _handleContainerMousedownAndTouchstartBound: any; |
| 53 | + private _handleContainerMouseupAndTouchendBound: any; |
| 54 | + container: any; |
| 55 | + dropdown: any; |
| 56 | + static _keydown: boolean; |
| 57 | + selectedValues: any[]; |
| 58 | + menuItems: any[]; |
| 59 | + /** |
| 60 | + * Construct Autocomplete instance |
| 61 | + * @constructor |
| 62 | + * @param {Element} el |
| 63 | + * @param {Object} options |
| 64 | + */ |
28 | 65 | constructor(el, options) {
|
29 | 66 | super(Autocomplete, el, options);
|
30 |
| - this.el.M_Autocomplete = this; |
| 67 | + |
| 68 | + (this.el as any).M_Autocomplete = this; |
| 69 | + |
| 70 | + /** |
| 71 | + * Options for the autocomplete |
| 72 | + * @member Autocomplete#options |
| 73 | + * @prop {Number} duration |
| 74 | + * @prop {Number} dist |
| 75 | + * @prop {number} shift |
| 76 | + * @prop {number} padding |
| 77 | + * @prop {Boolean} fullWidth |
| 78 | + * @prop {Boolean} indicators |
| 79 | + * @prop {Boolean} noWrap |
| 80 | + * @prop {Function} onCycleTo |
| 81 | + */ |
31 | 82 | this.options = $.extend({}, Autocomplete.defaults, options);
|
32 | 83 | this.isOpen = false;
|
33 | 84 | this.count = 0;
|
|
54 | 105 | destroy() {
|
55 | 106 | this._removeEventHandlers();
|
56 | 107 | this._removeDropdown();
|
57 |
| - this.el.M_Autocomplete = undefined; |
| 108 | + (this.el as any).M_Autocomplete = undefined; |
58 | 109 | }
|
59 | 110 |
|
60 | 111 | _setupEventHandlers() {
|
|
132 | 183 | if (userOnItemClick && typeof userOnItemClick === 'function')
|
133 | 184 | userOnItemClick.call(this.dropdown, this.el);
|
134 | 185 | };
|
135 |
| - this.dropdown = M.Dropdown.init(this.el, dropdownOptions); |
| 186 | + |
| 187 | + this.dropdown = Dropdown.init(this.el, dropdownOptions); |
| 188 | + |
136 | 189 | // Sketchy removal of dropdown click handler
|
137 | 190 | this.el.removeEventListener('click', this.dropdown._handleClickBound);
|
138 | 191 | // Set Value if already set in HTML
|
139 |
| - if (this.el.value) this.selectOption(this.el.value); |
| 192 | + if ( (this.el as HTMLInputElement).value) this.selectOption((this.el as HTMLInputElement).value); |
140 | 193 | // Add StatusInfo
|
141 | 194 | const div = document.createElement('div');
|
142 | 195 | div.classList.add('status-info');
|
|
156 | 209 | _handleInputKeyupAndFocus(e) {
|
157 | 210 | if (e.type === 'keyup') Autocomplete._keydown = false;
|
158 | 211 | this.count = 0;
|
159 |
| - const actualValue = this.el.value.toLowerCase(); |
| 212 | + const actualValue = (this.el as HTMLInputElement).value.toLowerCase(); |
| 213 | + |
160 | 214 | // Don't capture enter or arrow key usage.
|
161 | 215 | if (e.keyCode === 13 || e.keyCode === 38 || e.keyCode === 40) return;
|
162 | 216 | // Check if the input isn't empty
|
|
167 | 221 | // Value has changed!
|
168 | 222 | if (this.oldVal !== actualValue) {
|
169 | 223 | this._setStatusLoading();
|
170 |
| - this.options.onSearch(this.el.value, this); |
| 224 | + this.options.onSearch( (this.el as HTMLInputElement).value, this); |
171 | 225 | }
|
172 | 226 | // Reset Single-Select when Input cleared
|
173 |
| - if (!this.options.isMultiSelect && this.el.value.length === 0) { |
| 227 | + if (!this.options.isMultiSelect && (this.el as HTMLInputElement).value.length === 0) { |
174 | 228 | this.selectedValues = [];
|
175 | 229 | this._triggerChanged();
|
176 | 230 | }
|
|
221 | 275 | _handleContainerMouseupAndTouchend(e) {
|
222 | 276 | this._mousedown = false;
|
223 | 277 | }
|
| 278 | + |
224 | 279 | _resetCurrentElementPosition() {
|
225 | 280 | this.activeIndex = -1;
|
226 | 281 | this.$active.removeClass('active');
|
|
243 | 298 | return [label.slice(0, start), label.slice(start, end + 1), label.slice(end + 1)];
|
244 | 299 | }
|
245 | 300 |
|
| 301 | + |
| 302 | + |
246 | 303 | _createDropdownItem(entry) {
|
247 | 304 | const item = document.createElement('li');
|
248 | 305 | item.setAttribute('data-id', entry.id);
|
|
268 | 325 | }
|
269 | 326 |
|
270 | 327 | // Text
|
271 |
| - const inputText = this.el.value.toLowerCase(); |
| 328 | + const inputText = (this.el as HTMLInputElement).value.toLowerCase(); |
272 | 329 | const parts = this._highlightPartialText(inputText, (entry.text || entry.id).toString());
|
273 | 330 | const div = document.createElement('div');
|
274 | 331 | div.setAttribute('style', 'line-height:1.2;font-weight:500;');
|
|
335 | 392 | _updateSelectedInfo() {
|
336 | 393 | const statusElement = this.el.parentElement.querySelector('.status-info');
|
337 | 394 | if (statusElement) {
|
338 |
| - if (this.options.isMultiSelect) statusElement.innerHTML = this.selectedValues.length; |
| 395 | + if (this.options.isMultiSelect) |
| 396 | + statusElement.innerHTML = this.selectedValues.length.toString(); |
339 | 397 | else statusElement.innerHTML = '';
|
340 | 398 | }
|
341 | 399 | }
|
342 | 400 | _refreshInputText() {
|
343 | 401 | if (this.selectedValues.length === 1) {
|
344 | 402 | const entry = this.selectedValues[0];
|
345 |
| - this.el.value = entry.text || entry.id; // Write Text to Input |
| 403 | + (this.el as HTMLInputElement).value = entry.text || entry.id; // Write Text to Input |
346 | 404 | }
|
347 |
| - M.updateTextFields(); |
| 405 | + Forms.updateTextFields(); |
348 | 406 | }
|
349 | 407 | _triggerChanged() {
|
350 | 408 | this.$el.trigger('change');
|
|
354 | 412 | }
|
355 | 413 |
|
356 | 414 | open() {
|
357 |
| - const inputText = this.el.value.toLowerCase(); |
| 415 | + const inputText = (this.el as HTMLInputElement).value.toLowerCase(); |
| 416 | + |
358 | 417 | this._resetAutocomplete();
|
359 | 418 | if (inputText.length >= this.options.minLength) {
|
360 | 419 | this.isOpen = true;
|
|
398 | 457 | this.selectedValues = this.selectedValues.filter(
|
399 | 458 | (selectedEntry) => selectedEntry.id !== entry.id
|
400 | 459 | );
|
401 |
| - this.el.focus(); |
| 460 | + (this.el as HTMLInputElement).focus(); |
402 | 461 | } else {
|
403 | 462 | // Single-Select
|
404 | 463 | this.selectedValues = [entry];
|
|
411 | 470 | }
|
412 | 471 | }
|
413 | 472 |
|
414 |
| - Autocomplete._keydown = false; |
415 |
| - M.Autocomplete = Autocomplete; |
416 |
| - if (M.jQueryLoaded) { |
417 |
| - M.initializeJqueryWrapper(Autocomplete, 'autocomplete', 'M_Autocomplete'); |
418 |
| - } |
419 |
| -})(cash); |
| 473 | + |
0 commit comments