var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } (function ($) { 'use strict'; var _defaults = { data: {}, // Autocomplete data set limit: Infinity, // Limit of results the autocomplete shows onAutocomplete: null, // Callback for when autocompleted minLength: 1, // Min characters before autocomplete starts sortFunction: function (a, b, inputString) { // Sort function for sorting autocomplete results return a.indexOf(inputString) - b.indexOf(inputString); } }; /** * @class * */ var Autocomplete = function () { /** * Construct Autocomplete instance * @constructor * @param {Element} el * @param {Object} options */ function Autocomplete(el, options) { _classCallCheck(this, Autocomplete); // If exists, destroy and reinitialize if (!!el.M_Autocomplete) { el.M_Autocomplete.destroy(); } this.el = el; this.$el = $(el); this.el.M_Autocomplete = this; /** * Options for the autocomplete * @member Autocomplete#options * @prop {Number} duration * @prop {Number} dist * @prop {number} shift * @prop {number} padding * @prop {Boolean} fullWidth * @prop {Boolean} indicators * @prop {Boolean} noWrap * @prop {Function} onCycleTo */ this.options = $.extend({}, Autocomplete.defaults, options); // Setup this.isOpen = false; this.count = 0; this.activeIndex = -1; this.oldVal; this.$inputField = this.$el.closest('.input-field'); this.$active = $(); this._setupDropdown(); this._setupEventHandlers(); } _createClass(Autocomplete, [{ key: 'destroy', /** * Teardown component */ value: function destroy() { this._removeEventHandlers(); this._removeDropdown(); this.el.M_Autocomplete = undefined; } /** * Setup Event Handlers */ }, { key: '_setupEventHandlers', value: function _setupEventHandlers() { this._handleInputBlurBound = this._handleInputBlur.bind(this); this._handleInputKeyupAndFocusBound = this._handleInputKeyupAndFocus.bind(this); this._handleInputKeydownBound = this._handleInputKeydown.bind(this); this._handleContainerMousedownAndTouchstartBound = this._handleContainerMousedownAndTouchstart.bind(this); this.el.addEventListener('blur', this._handleInputBlurBound); this.el.addEventListener('keyup', this._handleInputKeyupAndFocusBound); this.el.addEventListener('focus', this._handleInputKeyupAndFocusBound); this.el.addEventListener('keydown', this._handleInputKeydownBound); this.container.addEventListener('mousedown', this._handleContainerMousedownAndTouchstartBound); if (typeof window.ontouchstart !== 'undefined') { this.container.addEventListener('touchstart', this._handleContainerMousedownAndTouchstartBound); } } /** * Remove Event Handlers */ }, { key: '_removeEventHandlers', value: function _removeEventHandlers() { this.el.removeEventListener('blur', this._handleInputBlurBound); this.el.removeEventListener('keyup', this._handleInputKeyupAndFocusBound); this.el.removeEventListener('focus', this._handleInputKeyupAndFocusBound); this.el.removeEventListener('keydown', this._handleInputKeydownBound); this.container.removeEventListener('mousedown', this._handleContainerMousedownAndTouchstartBound); if (typeof window.ontouchstart !== 'undefined') { this.container.removeEventListener('touchstart', this._handleContainerMousedownAndTouchstartBound); } } /** * Setup dropdown */ }, { key: '_setupDropdown', value: function _setupDropdown() { this.container = document.createElement('ul'); $(this.container).addClass('autocomplete-content dropdown-content'); this.$inputField.append(this.container); } /** * Remove dropdown */ }, { key: '_removeDropdown', value: function _removeDropdown() { this.container.parentNode.removeChild(this.container); } /** * Handle Input Blur */ }, { key: '_handleInputBlur', value: function _handleInputBlur() { this._removeAutocomplete(); } /** * Handle Input Keyup and Focus * @param {Event} e */ }, { key: '_handleInputKeyupAndFocus', value: function _handleInputKeyupAndFocus(e) { if (e.type === 'keyup') { Autocomplete._keydown = false; } this.count = 0; var val = this.el.value.toLowerCase(); // Don't capture enter or arrow key usage. if (e.keyCode === 13 || e.keyCode === 38 || e.keyCode === 40) { return; } // Check if the input isn't empty if (this.oldVal !== val) { this._removeAutocomplete(); if (val.length >= this.options.minLength) { this.isOpen = true; this._renderDropdown(this.options.data, val); } } // Update oldVal this.oldVal = val; } /** * Handle Input Keydown * @param {Event} e */ }, { key: '_handleInputKeydown', value: function _handleInputKeydown(e) { Autocomplete._keydown = true; // Arrow keys and enter key usage var keyCode = e.keyCode, liElement = void 0, numItems = $(this.container).children('li').length; // select element on Enter if (keyCode === 13 && this.activeIndex >= 0) { liElement = $(this.container).children('li').eq(this.activeIndex); if (liElement.length) { this.selectOption(liElement); e.preventDefault(); } return; } // Capture up and down key if (keyCode === 38 || keyCode === 40) { e.preventDefault(); if (keyCode === 38 && this.activeIndex > 0) { this.activeIndex--; } if (keyCode === 40 && this.activeIndex < numItems - 1) { this.activeIndex++; } this.$active.removeClass('active'); if (this.activeIndex >= 0) { this.$active = $(this.container).children('li').eq(this.activeIndex); this.$active.addClass('active'); } } } /** * Handle Container Mousedown and Touchstart * @param {Event} e */ }, { key: '_handleContainerMousedownAndTouchstart', value: function _handleContainerMousedownAndTouchstart(e) { var $autocompleteOption = $(e.target).closest('li'); this.selectOption($autocompleteOption); } /** * Highlight partial match */ }, { key: '_highlight', value: function _highlight(string, $el) { var img = $el.find('img'); var matchStart = $el.text().toLowerCase().indexOf("" + string.toLowerCase() + ""), matchEnd = matchStart + string.length - 1, beforeMatch = $el.text().slice(0, matchStart), matchText = $el.text().slice(matchStart, matchEnd + 1), afterMatch = $el.text().slice(matchEnd + 1); $el.html("" + beforeMatch + "" + matchText + "" + afterMatch + ""); if (img.length) { $el.prepend(img); } } /** * Reset current element position */ }, { key: '_resetCurrentElement', value: function _resetCurrentElement() { this.activeIndex = -1; this.$active.removeClass('active'); } /** * Remove autocomplete elements */ }, { key: '_removeAutocomplete', value: function _removeAutocomplete() { $(this.container).empty(); this._resetCurrentElement(); this.oldVal = null; this.isOpen = false; } /** * Select autocomplete option * @param {Element} el Autocomplete option list item element */ }, { key: 'selectOption', value: function selectOption(el) { var text = el.text().trim(); this.el.value = text; this.$el.trigger('change'); this._removeAutocomplete(); // Handle onAutocomplete callback. if (typeof this.options.onAutocomplete === 'function') { this.options.onAutocomplete.call(this, text); } } /** * Render dropdown content * @param {Object} data data set * @param {String} val current input value */ }, { key: '_renderDropdown', value: function _renderDropdown(data, val) { var _this = this; this._removeAutocomplete(); var matchingData = []; // Gather all matching data for (var key in data) { if (data.hasOwnProperty(key) && key.toLowerCase().indexOf(val) !== -1) { // Break if past limit if (this.count >= this.options.limit) { break; } var entry = { data: data[key], key: key }; matchingData.push(entry); this.count++; } } // Sort var sortFunctionBound = function (a, b) { return _this.options.sortFunction(a.key.toLowerCase(), b.key.toLowerCase(), val.toLowerCase()); }; matchingData.sort(sortFunctionBound); // Render for (var i = 0; i < matchingData.length; i++) { var _entry = matchingData[i]; var $autocompleteOption = $('
'); if (!!_entry.data) { $autocompleteOption.append('' + _entry.key + ''); } else { $autocompleteOption.append('' + _entry.key + ''); } $(this.container).append($autocompleteOption); this._highlight(val, $autocompleteOption); } } /** * Update Data * @param {Object} data */ }, { key: 'updateData', value: function updateData(data) { var val = this.el.value.toLowerCase(); this.options.data = data; if (this.isOpen) { this._renderDropdown(data, val); } } }], [{ key: 'init', value: function init($els, options) { var arr = []; $els.each(function () { arr.push(new Autocomplete(this, options)); }); return arr; } /** * Get Instance */ }, { key: 'getInstance', value: function getInstance(el) { var domElem = !!el.jquery ? el[0] : el; return domElem.M_Autocomplete; } }, { key: 'defaults', get: function () { return _defaults; } }]); return Autocomplete; }(); /** * @static * @memberof Autocomplete */ Autocomplete._keydown = false; M.Autocomplete = Autocomplete; if (M.jQueryLoaded) { M.initializeJqueryWrapper(Autocomplete, 'autocomplete', 'M_Autocomplete'); } })(cash);