--- /dev/null
+/**
+ * jQuery Flexdatalist.
+ * Autocomplete for input fields with support for datalists.
+ *
+ * Version:
+ * 1.8.0
+ *
+ * Depends:
+ * jquery.js 1.7+
+ *
+ * Demo and Documentation:
+ * http://projects.sergiodinislopes.pt/flexdatalist/
+ *
+ * Github:
+ * https://github.com/sergiodlopes/jquery-flexdatalist/
+ *
+ */
+
+jQuery.fn.flexdatalist = function (options, value) {
+ 'use strict';
+ var $document = $(document),
+ $input = $(this),
+ input,
+ _this = this;
+
+/**
+ * Each iteration.
+ */
+ input = function () {
+ var $this = $(this),
+ _cache = {},
+ _previousText = '',
+ _requestTimeout = null,
+ _inputName = $this.attr('name');
+
+ if ($this.hasClass('flexdatalist-set')) {
+ _this._destroy($this);
+ }
+
+ /**
+ * Option management.
+ */
+ $this._options = function (option, _value) {
+ var _options = $this.data('flexdatalist');
+ if (!_this._isDefined(option)) {
+ return $this.data('flexdatalist');
+ } else if (_this._isDefined(_value)) {
+ _options[option] = _value;
+ } else if (!_this._isObject(option)) {
+ return (_this._isDefined(_options, option) ? _options[option] : null);
+ } else {
+ _options = option;
+ }
+
+ _options.searchIn = _this._csvToArray(_options.searchIn);
+ _options.relatives = _options.relatives && $(_options.relatives).length > 0 ? $(_options.relatives) : null;
+ _options.textProperty = _options.textProperty === null ? _options.searchIn[0] : _options.textProperty;
+ _options.visibleProperties = _this._csvToArray(_options.visibleProperties, _options.searchIn);
+ $this.data('flexdatalist', _options);
+ return $this;
+ }
+
+ $this._options($.extend({
+ url: null,
+ data: [],
+ params: {},
+ relatives: null,
+ chainedRelatives: false,
+ cache: true,
+ minLength: 2,
+ groupBy: false,
+ selectionRequired: false,
+ focusFirstResult: false,
+ textProperty: null,
+ valueProperty: null,
+ visibleProperties: [],
+ searchIn: ['label'],
+ searchContain: false,
+ searchEqual: false,
+ searchDisabled: false, // New
+ normalizeString: null,
+ multiple: $this.attr('multiple'),
+ maxShownResults: 100,
+ noResultsText: 'No results found for "{keyword}"',
+ toggleSelected: false, // New
+ _values: []
+ }, options, $this.data())
+ );
+
+ // Handle multiple values
+ var $_this = $this
+ .clone(false)
+ .attr({
+ 'list': null,
+ 'name': null,
+ 'id': ($this.attr('id') ? $this.attr('id') + '-flexdatalist' : null)
+ })
+ .addClass('flexdatalist-alias')
+ .removeClass('flexdatalist');
+ if ($this._options('multiple')) {
+ var $ulMultiple = $('<ul>')
+ .addClass('flexdatalist-multiple')
+ .css({
+ 'background-color': $this.css('background-color'),
+ 'border-color': $this.css('border-left-color'),
+ 'border-width': $this.css('border-left-width'),
+ 'border-style': $this.css('border-left-style'),
+ 'border-radius': $this.css('border-top-left-radius')
+ })
+ .insertAfter($this).click(function () {
+ $(this).find('input').focus();
+ });
+ var $li = $('<li class="input-container">')
+ .addClass('flexdatalist-multiple-value')
+ .append($_this)
+ .appendTo($ulMultiple);
+ } else {
+ $_this.insertAfter($this);
+ }
+ $this.addClass('flexdatalist').attr('type', 'hidden');
+
+ /**
+ * Initialize.
+ */
+ $this._init = function () {
+ var _options = $this._options();
+ // Listen to parent input key presses and state events.
+ $_this.on('input keydown', function (event) {
+ var val = $this._keyword();
+ // Comma separated values
+ if (_this._keyNum(event) === 188 && !_options.selectionRequired && _options.multiple) {
+ event.preventDefault();
+ $this._value(val);
+ $this._removeResults();
+ // Remove results on tab away
+ } else if (_this._keyNum(event) === 9) {
+ $this._removeResults();
+ // Check if is to remove previous value on backspace key
+ } else if (val.length === 0 && _options.multiple && _this._keyNum(event) === 8) {
+ $_this.data('_remove', $_this.parents('li:eq(0)').prev());
+ }
+ }).on('input keyup', function (event) {
+ if ($this._changed() && _this._keyNum(event) !== 13) {
+ var keyword = $this._keyword();
+ if (keyword.length >= _options.minLength) {
+ $this._search(function (matches) {
+ $this._showResults(matches);
+ });
+ } else {
+ $this._removeResults();
+ }
+ if (!_options.multiple) {
+ if (!_options.selectionRequired) {
+ $this._value(keyword);
+ } else {
+ $this._value('');
+ }
+ }
+ }
+ // Remove previous value on backspace key
+ var $remove = $_this.data('_remove');
+ if ($remove) {
+ $remove.find('.fdl-remove').click();
+ $_this.data('_remove', null);
+ }
+ _previousText = $this._keyword();
+ }).focus(function () {
+ var val = $this._keyword();
+ if (_options.minLength === 0) {
+ if (val === '') {
+ $this._tdata(function (data) {
+ $this._showResults(data);
+ });
+ }
+ // Redo search on focus if not selected yet
+ } else if (val.length >= _options.minLength && !$this._selected()) {
+ $this._search(function (matches) {
+ $this._showResults(matches);
+ });
+ }
+ })
+ .attr('autocomplete', 'off');
+
+ // Respect autofocus attribute
+ if ($_this.attr('autofocus')) {
+ $_this.focus();
+ }
+ window.onresize = function (event) {
+ $this._position();
+ };
+ $this.addClass('flexdatalist-set');
+ }
+
+ /**
+ * Check if field's text has changed.
+ */
+ $this._changed = function () {
+ return _previousText !== $this._keyword();
+ }
+
+ /**
+ * Check chained relatives.
+ */
+ $this._chained = function () {
+ var _options = $this._options();
+ if (!_options.relatives || !_options.chainedRelatives) {
+ return;
+ }
+ var toggle = function (init) {
+ _options.relatives.each(function () {
+ var disabled = _this._isEmpty($(this).val()),
+ empty = _this._isEmpty($this.val());
+ $_this.prop('disabled', disabled);
+ if (!init && (disabled || !empty)) {
+ $this._value('');
+ $_this.val('');
+ if (_options.multiple) {
+ $ulMultiple.find('li .remove').click();
+ }
+ }
+ });
+ }
+ _options.relatives.on('change', function () {
+ toggle();
+ _cache = {};
+ });
+ toggle(true);
+ }
+
+ /**
+ * Process value in input on init.
+ */
+ $this._initValue = function () {
+ var value = $this.attr('value');
+ if (_this._isEmpty(value)) {
+ return;
+ }
+ $this._options('originalValue', $this.val());
+ $this._parseValue(value, function (values) {
+ $this.val('', true);
+ $_this.val('');
+ if (!_this._isEmpty(values)) {
+ $this._values(values);
+ }
+ _previousText = $this._keyword();
+ });
+ }
+
+ /**
+ * Parse initial value.
+ */
+ $this._parseValue = function (data, callback) {
+ var _options = $this._options();
+ if ($this._toJSON()) {
+ try {
+ callback(JSON.parse(data));
+ } catch (e) {}
+ } else if ($this._toCSV() || typeof _options.valueProperty === 'string') {
+ var values = data.split(',');
+ if (typeof _options.valueProperty === 'string') {
+ var _searchIn = _options.searchIn;
+ _options.searchIn = _options.valueProperty.split(',');
+ _options.searchEqual = true;
+ $this._search(function (matches) {
+ if (matches.length > 0) {
+ callback(matches);
+ }
+ _options.searchIn = _searchIn;
+ _options.searchEqual = false;
+ }, values);
+ } else {
+ callback(values);
+ }
+ } else {
+ callback(data);
+ }
+ }
+
+ /**
+ * Get data.
+ */
+ $this._tdata = function (callback) {
+ $this.trigger('before:flexdatalist.data');
+ $this._url(function (remoteData) {
+ $this._data(function (data) {
+ data = data.concat(remoteData);
+ // Check for already set values
+ var values = $this._options('_values');
+ for (var i = 0; i < data.length; i++) {
+ var item = data[i];
+ if (values && values.indexOf($this._getText(item)) > -1) {
+ delete data[i];
+ }
+ }
+ $this.trigger('after:flexdatalist.data', [data]);
+ callback(data);
+ });
+ });
+ }
+
+ /**
+ * Get static data.
+ */
+ $this._data = function (callback) {
+ var _options = $this._options();
+ if (typeof _options.data === 'string') {
+ $this._remote({
+ url: _options.data,
+ success: function (data) {
+ var _data = $this._getRemoteData(data);
+ _options.data = _data;
+ callback(_data);
+ }
+ });
+ } else {
+ callback(_options.data);
+ }
+ }
+
+ /**
+ * Get remote data.
+ */
+ $this._url = function (callback) {
+ var _options = $this._options(),
+ keyword = $this._keyword(),
+ value = $this.val(),
+ cacheKey = keyword;
+
+ if (_this._isEmpty(_options.url)) {
+ return callback([]);
+ }
+
+ clearTimeout(_requestTimeout);
+ _requestTimeout = setTimeout(function () {
+ if (_options.cache && _options.cache !== 2) {
+ cacheKey = keyword.substring(0, (_options.minLength > 0 ? _options.minLength : 1));
+ }
+
+ // Check cache
+ var cachedData = $this._cache(cacheKey);
+ if (cachedData) {
+ callback(cachedData);
+ return;
+ }
+
+ $this._remote({
+ url: _options.url,
+ data: $.extend($this._relativesData(), _options.params, {
+ keyword: keyword,
+ contain: _options.searchContain,
+ selected: value
+ }
+ ),
+ success: function (data) {
+ var _data = $this._getRemoteData(data),
+ _keyword = $this._keyword();
+ if (_keyword.length > keyword.length) {
+ $this._search(function (matches) {
+ $this._showResults(matches);
+ });
+ } else {
+ callback(_data);
+ }
+ $this._cache(cacheKey, _data);
+ }
+ });
+ }, 200);
+ }
+
+ /**
+ * AJAX request.
+ */
+ $this._remote = function (options) {
+ // Prevent get data when pressing back button
+ if ($this.hasClass('flexdatalist-loading')) {
+ return;
+ }
+ $this.addClass('flexdatalist-loading');
+ options = $.extend({
+ type: 'post',
+ dataType: 'json',
+ complete: function () {
+ $this.removeClass('flexdatalist-loading');
+ }
+ }, options);
+ $.ajax(options);
+ }
+
+ /**
+ * Extract remote data from server response.
+ */
+ $this._getRemoteData = function (data) {
+ var _data = data.results ? data.results : data;
+ if (typeof _data === 'string' && _data.indexOf('[{') === 0) {
+ _data = JSON.parse(_data);
+ }
+ if (_this._isObject(_data)) {
+ return _data;
+ }
+ return [];
+ }
+
+ /**
+ * Get relatives data.
+ */
+ $this._relativesData = function () {
+ var relatives = $this._options('relatives'),
+ data = {};
+ if (relatives) {
+ data['relatives'] = {};
+ relatives.each(function () {
+ var $input = $(this);
+ data['relatives'][$input.attr('name')] = $input.val();
+ });
+ }
+ return data;
+ }
+
+ /**
+ * Set datalist data, if exists.
+ */
+ $this._datalist = function () {
+ var _options = $this._options(),
+ list = $this.attr('list');
+ if (!_this._isEmpty(list)) {
+ _options.data = [];
+ $('#' + list).find('option').each(function () {
+ var val = $(this).val();
+ _options.data.push({
+ label: val,
+ value: val
+ });
+ });
+ }
+ return $this;
+ }
+
+ /**
+ * Cached data.
+ */
+ $this._cache = function (key, data) {
+ if ($this._options('cache')) {
+ key = $this._normalizeString(key);
+ if (!_this._isDefined(data)) {
+ if (_this._isDefined(_cache, key)) {
+ data = _cache[key];
+ }
+ return data;
+ }
+ _cache[key] = data;
+ }
+ return null;
+ }
+
+ /**
+ * Search for keywords in data and return matches.
+ */
+ $this._search = function (callback, keywords) {
+ $this._tdata(function (data) {
+ var matches = [],
+ _options = $this._options();
+ // If search disabled, return
+ if (_options.searchDisabled) {
+ return callback(data);
+ }
+ if (!_this._isDefined(keywords)) {
+ keywords = $this._keyword();
+ }
+ if (typeof keywords === 'string') {
+ keywords = [keywords];
+ }
+ $this.trigger('before:flexdatalist.search', [keywords, data]);
+ for (var kwindex = 0; kwindex < keywords.length; kwindex++) {
+ var keyword = keywords[kwindex];
+ for (var index = 0; index < data.length; index++) {
+ var _data = $this._matches(data[index], keyword, _options.values);
+ if (!_data) {
+ continue;
+ }
+ matches.push(_data);
+ }
+ }
+ $this.trigger('after:flexdatalist.search', [keywords, data, matches]);
+ callback(matches);
+ });
+ }
+
+ /**
+ * Match against searchable properties.
+ */
+ $this._matches = function (item, keyword, values) {
+ var hasMatches = false,
+ _item = $.extend({}, item),
+ _options = $this._options(),
+ searchIn = _options.searchIn;
+
+ for (var index = 0; index < searchIn.length; index++) {
+ var searchProperty = searchIn[index];
+ if (!_this._isDefined(item, searchProperty) || !item[searchProperty]) {
+ continue;
+ }
+ var text = item[searchProperty].toString();
+ if ($this._find(keyword, text)) {
+ _item[searchProperty + '_highlight'] = $this._highlight(keyword, text);
+ hasMatches = true;
+ }
+ }
+ return hasMatches ? _item : null;
+ }
+
+ /**
+ * Wrap found keyword with span.highlight.
+ */
+ $this._highlight = function (keyword, text) {
+ return text.replace(
+ new RegExp(keyword, ($this._options('searchContain') ? "ig" : "i")),
+ '<span class="highlight">$&</span>'
+ );
+ }
+
+ /**
+ * Search for keyword in string.
+ */
+ $this._find = function (keyword, text) {
+ var _options = $this._options();
+ text = $this._normalizeString(text),
+ keyword = $this._normalizeString(keyword);
+ if (_options.searchEqual) {
+ return text == keyword;
+ }
+ return (_options.searchContain ? (text.indexOf(keyword) >= 0) : (text.indexOf(keyword) === 0));
+ }
+
+ /**
+ * Show results.
+ */
+ $this._showResults = function (data) {
+ $this._removeResults(true);
+ var _options = $this._options();
+
+ if (data.length === 0) {
+ //$this._noResults(_options.noResultsText);
+ //return;
+
+ // extended for insipid usage.
+ // allow the not found one as new ones.
+ var kw = $this._keyword();
+ data = [{
+ label: kw,
+ value: kw,
+ label_highlight: '<span class="highlight">'+kw+'</span>'
+ }];
+ }
+
+ var $ul = $this._getResultsContainer();
+ if (!_options.groupBy) {
+ console.log(data);
+ $this._items(data, $ul);
+ } else {
+ data = $this._groupData(data);
+ Object.keys(data).forEach(function (groupName, index) {
+ var items = data[groupName],
+ property = _options.groupBy,
+ groupText = $this._getHighlight(items[0], property, groupName);
+
+ var $li = $('<li>')
+ .addClass('group')
+ .append($('<span>')
+ .addClass('group-name')
+ .html(groupText)
+ )
+ .append($('<span>')
+ .addClass('group-item-count')
+ .text(' ' + items.length)
+ )
+ .appendTo($ul);
+
+ $this._items(items, $ul);
+ });
+ }
+
+ var $li = $ul.find('li:not(.group)');
+ $li.on('click', function (event) {
+ var item = $(this).data('item');
+ if (item) {
+ $this._selected(true)._removeResults()._value(item);
+ $this.trigger('select:flexdatalist', [item, _options]);
+ }
+ }).hover(function () {
+ $li.removeClass('active');
+ $(this).addClass('active');
+ }, function () {
+ $(this).removeClass('active');
+ });
+
+ if (_options.focusFirstResult) {
+ $li.filter(':first').addClass('active');
+ }
+ }
+
+ /**
+ * No results found text.
+ */
+ $this._noResults = function (text) {
+ if (_this._isEmpty(text)) {
+ return;
+ }
+ var $container = $this._getResultsContainer(),
+ keyword = $this._keyword();
+
+ text = text.split('{keyword}').join(keyword);
+ $('<li>')
+ .addClass('item no-results')
+ .append(text)
+ .appendTo($container)
+ }
+
+ /**
+ * Group data by property name.
+ */
+ $this._groupData = function (items) {
+ var data = [],
+ groupProperty = $this._options('groupBy');
+ for (var index = 0; index < items.length; index++) {
+ var _data = items[index];
+ if (_this._isDefined(_data, groupProperty)) {
+ var propertyValue = _data[groupProperty];
+ if (!_this._isDefined(data, propertyValue)) {
+ data[propertyValue] = [];
+ }
+ data[propertyValue].push(_data);
+ }
+ }
+ return data;
+ }
+
+ /**
+ * Items iteration.
+ */
+ $this._items = function (items, $resultsContainer) {
+ var max = $this._options('maxShownResults');
+ $this.trigger('show:flexdatalist.results', [items]);
+ for (var index = 0; index < items.length; index++) {
+ if (max > 0 && max === index) {
+ break;
+ }
+ $this._item(items[index]).appendTo($resultsContainer);
+ }
+ $this.trigger('shown:flexdatalist.results', [items]);
+ }
+
+ /**
+ * Result item creation.
+ */
+ $this._item = function (item) {
+ var $li = $('<li>')
+ .data('item', item)
+ .addClass('item'),
+ _options = $this._options(),
+ visibleProperties = _options.visibleProperties;
+
+ for (var index = 0; index < visibleProperties.length; index++) {
+ var visibleProperty = visibleProperties[index];
+ if (_options.groupBy && _options.groupBy === visibleProperty || !_this._isDefined(item, visibleProperty)) {
+ continue;
+ }
+ var $item = {};
+ if (visibleProperty === 'thumb') {
+ // Thumbnail image
+ $item = $('<img>')
+ .addClass('item item-' + visibleProperty)
+ .attr('src', item[visibleProperty]);
+ } else {
+ var propertyText = $this._getHighlight(item, visibleProperty);
+ // Other text properties
+ $item = $('<span>')
+ .addClass('item item-' + visibleProperty)
+ .html(propertyText + ' ');
+ }
+ $item.appendTo($li);
+ }
+ return $li;
+ }
+
+ /**
+ * Check if highlighted property value exists,
+ * if true, return it, if not, fallback to given string
+ */
+ $this._getHighlight = function (item, property, fallback) {
+ if (_this._isDefined(item, property + '_highlight')) {
+ return item[property + '_highlight'];
+ }
+ return (_this._isDefined(item, property) ? item[property] : fallback);
+ }
+
+ /**
+ * Get/create list container.
+ */
+ $this._getResultsContainer = function () {
+ var $target = $this;
+ if ($this._options('multiple')) {
+ $target = $ulMultiple;
+ }
+ var $container = $('ul.flexdatalist-results');
+ if ($container.length === 0) {
+ $container = $('<ul>')
+ .addClass('flexdatalist-results')
+ .appendTo('body')
+ .css({
+ 'border-color': $target.css("border-left-color"),
+ 'border-width': '1px',
+ 'border-bottom-left-radius': $target.css("border-bottom-left-radius"),
+ 'border-bottom-right-radius': $target.css("border-bottom-right-radius")
+ }).data('target', $_this);
+ $this._position();
+ }
+ return $container;
+ }
+
+ /**
+ * Remove results.
+ */
+ $this._removeResults = function (itemsOnly) {
+ var selector = 'ul.flexdatalist-results';
+ if (itemsOnly) {
+ selector = 'ul.flexdatalist-results li';
+ }
+ $(selector).remove();
+ return $this;
+ }
+
+ /**
+ * Check if is selected or set field as selected.
+ */
+ $this._selected = function (selected) {
+ var className = 'flexdatalist-selected';
+ if (!_this._isDefined(selected)) {
+ return $this.hasClass(className);
+ }
+ selected ? $this.addClass(className) : $this.removeClass(className);
+ return $this;
+ }
+
+ /**
+ * Set multiple values.
+ */
+ $this._values = function (values) {
+ if ($.isArray(values) && !_this._isEmpty(values)) {
+ $.each(values, function (i, value) {
+ $this._value(value);
+ });
+ return;
+ }
+ $this._value(values);
+ }
+
+ /**
+ * Set value on item selection.
+ */
+ $this._value = function (val) {
+ var _options = $this._options(),
+ text = $this._getText(val),
+ value = $this._getValue(val);
+
+ if (text.length > 0) {
+ _options._values.push(text);
+ }
+
+ if (_options.multiple) {
+ if (val === '') {
+ return $this;
+ }
+ $_this.val('');
+ var $li = $('<li>')
+ .addClass('value' + (_options.toggleSelected ? ' toggle' : ''))
+ .append('<span class="text">' + text + '</span>')
+ .append('<span class="fdl-remove">×</span>')
+ .insertBefore($ulMultiple.find('li.input-container'));
+
+ $li.find('span.fdl-remove').click(function () {
+ var $container = $(this).parent(),
+ index = $container.index();
+ if (!$container.hasClass('disabled') && ($this._toJSON() || $this._toCSV())) {
+ var currentValue = $this._inputValue();
+ currentValue.splice(index, 1);
+ _options._values.splice(index, 1);
+ $this._inputValue(currentValue);
+ }
+ $container.remove();
+ });
+ // Toggle selected option
+ if (_options.toggleSelected) {
+ $li.click(function () {
+ var $clicked = $(this),
+ currentValue = $this._inputValue(),
+ index = $clicked.index();
+ if ($clicked.hasClass('disabled')) {
+ var value = $clicked.data('_value');
+ currentValue.splice(index, 0, value);
+ _options._values.splice(index, 0, $this._getText(value));
+ $clicked.removeClass('disabled');
+ } else {
+ var value = currentValue.splice(index, 1);
+ $clicked.data('_value', value[0]);
+ _options._values.splice(index, 1);
+ $clicked.addClass('disabled');
+ }
+ $this._inputValue(currentValue, text);
+ });
+ }
+ } else if (text && text !== $_this.val()) {
+ $_this.val(text);
+ }
+ $this._inputValue(value, text);
+ _previousText = $this._keyword();
+ return $this;
+ }
+
+ /**
+ * Get/Set input value.
+ */
+ $this._inputValue = function (value, text) {
+ var isJSON = $this._toJSON(),
+ isCSV = $this._toCSV();
+
+ if (!_this._isDefined(value)) {
+ value = $this.val();
+ if (value) {
+ if (isJSON) {
+ value = JSON.parse(value);
+ } else if (isCSV) {
+ value = value.split(',');
+ }
+ } else if (isJSON || isCSV) {
+ value = [];
+ }
+ return value;
+ }
+
+ if (_this._isObject(value)) {
+ if (isJSON && !_this._isEmpty(value)) {
+ value = JSON.stringify(value);
+ } else if (isCSV) {
+ value = value.join(',');
+ }
+ }
+ if (value === '') {
+ $this._options('_values', []);
+ }
+ $this.val(value, true);
+ $this.trigger('change:flexdatalist', [value, text, $this._options()]).trigger('change');
+ return value;
+ }
+
+ /**
+ * Get text that will be shown to user on input field.
+ */
+ $this._getText = function (item) {
+ var text = item,
+ _options = $this._options();
+
+ if (_this._isObject(item)) {
+ text = item[_options.searchIn[0]];
+ if (_this._isDefined(item, _options.textProperty)) {
+ text = item[_options.textProperty];
+ } else {
+ text = $this._replacePlaceholders(item, _options.textProperty, text);
+ }
+ }
+ return $('<div>').html(text).text();
+ }
+
+ /**
+ * Get the value that will be added to hidden input.
+ * This is the value that eventually will be sent on form submittion.
+ */
+ $this._getValue = function (item) {
+ var value = item,
+ _options = $this._options();
+ if (_this._isObject(item)) {
+ value = item[_options.searchIn[0]];
+ if (_options.valueProperty === '*') {
+ value = item;
+ } else if (_this._isDefined(item, _options.valueProperty)) {
+ value = item[_options.valueProperty];
+ } else if ($this._toJSON()) {
+ var value = {},
+ properties = _options.valueProperty,
+ textProperty = _options.textProperty;
+
+ // Add placeholder properties to list
+ if (textProperty) {
+ var _properties = textProperty;
+ if (typeof textProperty === 'string') {
+ _properties = $this._parsePlaceholders(textProperty);
+ }
+ if (_this._isObject(_properties)) {
+ $.each(_properties, function (string, property) {
+ properties.push(property);
+ });
+ }
+ } else if (_this._isDefined(item, textProperty)) {
+ properties.push(textProperty);
+ }
+
+ $.each(properties, function (i, property) {
+ if (_this._isDefined(item, property)) {
+ value[property] = item[property];
+ }
+ });
+ }
+ }
+ if (_options.multiple && ($this._toJSON() || $this._toCSV())) {
+ var currentValue = $this._inputValue();
+ if (!_this._isEmpty(value) && _this._isObject(currentValue)) {
+ currentValue.push(value);
+ value = currentValue;
+ }
+ }
+ return value;
+ }
+
+ /**
+ * Replace placeholders ('{property_name}') in text
+ * with respective property value.
+ */
+ $this._replacePlaceholders = function (item, pattern, value) {
+ if (_this._isObject(item) && typeof pattern === 'string') {
+ var properties = $this._parsePlaceholders(pattern);
+ if (!_this._isEmpty(item) && properties) {
+ $.each(properties, function (string, property) {
+ if (_this._isDefined(item, property)) {
+ pattern = pattern.replace(string, item[property]);
+ }
+ });
+ return pattern;
+ }
+ }
+ return value;
+ }
+
+ /**
+ * Extract placeholders property names.
+ */
+ $this._parsePlaceholders = function (pattern) {
+ var matches = pattern.match(/\{.+?\}/g);
+ if (matches) {
+ var properties = {};
+ matches.map(function (string) {
+ properties[string] = string.slice(1, -1);
+ });
+ return properties;
+ }
+ return false;
+ }
+
+ /**
+ * Normalize string to a consistent one to perform the search/match.
+ */
+ $this._normalizeString = function (string) {
+ if (typeof string === 'string') {
+ var normalizeString = $this._options('normalizeString');
+ if (typeof normalizeString === 'function') {
+ string = normalizeString(string);
+ }
+ return string.toUpperCase();
+ }
+ return string;
+ }
+
+ /**
+ * Get keyword with left trim.
+ */
+ $this._keyword = function () {
+ return $_this.val().replace(/^\s+/, "");
+ }
+
+ /**
+ * Check if input value must be a JSON string.
+ */
+ $this._toJSON = function () {
+ var valueProperty = $this._options('valueProperty');
+ return _this._isObject(valueProperty) || valueProperty === '*';
+ }
+
+ /**
+ * Check if input value must be a CSV string.
+ */
+ $this._toCSV = function () {
+ return (!$this._toJSON() && $this._options('multiple'));
+ }
+
+ /**
+ * Position results below parent element.
+ */
+ $this._position = function () {
+ var $target = $_this;
+ if ($this._options('multiple')) {
+ $target = $ulMultiple;
+ }
+ // Set some required CSS properties
+ $('ul.flexdatalist-results').css({
+ 'width': $target.outerWidth() + 'px',
+ 'top': (($target.offset().top + $target.outerHeight())) + 'px',
+ 'left': $target.offset().left + 'px',
+ 'z-index': ($target.css('z-index') + 1)
+ });
+ }
+ // Set datalist data
+ $this._datalist();
+ // Process default value
+ $this._initValue();
+ // Handle chained fields
+ $this._chained();
+ // Initialize
+ $this._init();
+ };
+
+/**
+ * Destroy.
+ */
+ this._destroy = function ($_input) {
+ if (!$_input) {
+ $_input = $input;
+ }
+ $_input.each(function () {
+ var data = $(this).data('flexdatalist');
+ $(this).removeClass('flexdatalist-set')
+ .attr('type', 'text')
+ .val((data && data.originalValue ? data.originalValue : ''))
+ .data('flexdatalist', null)
+ .next('.flexdatalist-alias, ul.flexdatalist-multiple')
+ .remove();
+ });
+ }
+
+/**
+ * Reset.
+ */
+ this._reset = function () {
+ this._destroy();
+ }
+
+/**
+ * Get key code from event.
+ */
+ this._keyNum = function (event) {
+ return event.which || event.keyCode;
+ }
+
+ // Handle selection list keyboard shortcuts and events.
+ if (!$document.data('flexdatalist')) {
+ // Remove results on outside click
+ $(document).mouseup(function (event) {
+ var $container = $('.flexdatalist-results'),
+ $target = $container.data('target');
+ if ((!$target || !$target.is(':focus')) && !$container.is(event.target) && $container.has(event.target).length === 0) {
+ $container.remove();
+ }
+ // Keyboard navigation
+ }).keydown(function (event) {
+ var $ul = $('.flexdatalist-results'),
+ $li = $ul.find('li'),
+ $active = $li.filter('.active'),
+ index = $active.index(),
+ length = $li.length,
+ keynum = _this._keyNum(event);
+
+ if (length === 0) {
+ return;
+ }
+
+ // Enter key
+ if (keynum === 13) {
+ event.preventDefault();
+ $active.click();
+ // Up/Down key
+ } else if (keynum === 40 || keynum === 38) {
+ event.preventDefault();
+ // Down key
+ if (keynum === 40) {
+ if (index < length && $active.nextAll('.item').first().length > 0) {
+ $active = $active.removeClass('active').nextAll('.item').first().addClass('active');
+ } else {
+ $active = $li.removeClass('active').filter('.item:first').addClass('active');
+ }
+ // Up key
+ } else if (keynum === 38) {
+ if (index > 0 && $active.prevAll('.item').first().length > 0) {
+ $active = $active.removeClass('active').prevAll('.item').first().addClass('active');
+ } else {
+ $active = $li.removeClass('active').filter('.item:last').addClass('active');
+ }
+ }
+
+ // Scroll to
+ var position = ($active.prev().length === 0 ? $active : $active.prev()).position().top;
+ $ul.animate({
+ scrollTop: position + $ul.scrollTop()
+ }, 100);
+ }
+ }).data('flexdatalist', true);
+ }
+
+/**
+ * Is variable empty.
+ */
+ this._isEmpty = function (value) {
+ if (!_this._isDefined(value)) {
+ return true;
+ } else if (value === null) {
+ return true;
+ } else if (value === true) {
+ return false;
+ } else if (this._length(value) === 0) {
+ return true;
+ } else if ($.trim(value) === '') {
+ return true;
+ }
+ return false;
+ }
+
+/**
+ * Is variable an object.
+ */
+ this._isObject = function (value) {
+ return (value && typeof value === 'object');
+ }
+
+/**
+ * To array.
+ */
+ this._csvToArray = function (value, _default) {
+ if (value.length === 0) {
+ return _default;
+ }
+ return typeof value === 'string' ? value.split(',') : value;
+ }
+
+/**
+ * Get length of variable.
+ */
+ this._length = function (value) {
+ if (this._isObject(value)) {
+ return Object.keys(value).length;
+ } else if (typeof value.length === 'number') {
+ return value.length;
+ }
+ return 0;
+ }
+/**
+ * Check if variable (and optionally property) is defined.
+ */
+ this._isDefined = function (variable, property) {
+ var _variable = (typeof variable !== 'undefined');
+ if (_variable && typeof property !== 'undefined') {
+ return (typeof variable[property] !== 'undefined');
+ }
+ return _variable;
+ }
+
+/**
+ * Handle options.
+ */
+ if (typeof options === 'string') {
+ if (typeof this['_' + options] === 'function') {
+ if (!this['_' + options]()) {
+ return this;
+ }
+ } else if (!value) {
+ var _data = $input.data('flexdatalist');
+ return _data[options];
+ // set value programmatically
+ } else if (options === 'value') {
+ var _data = $input.data('flexdatalist');
+ _data['originalValue'] = value;
+ _this._destroy();
+ $input.data('flexdatalist', _data);
+ } else {
+ var _data = $input.data('flexdatalist');
+ _data[options] = value;
+ $input.data('flexdatalist', _data);
+ return this;
+ }
+ }
+
+ return this.each(input);
+}
+
+var _defaultValFunc = jQuery.fn.val;
+jQuery.fn.val = function (value, _flexdatalist) {
+ if (!_flexdatalist && $(this).hasClass('flexdatalist-set') && typeof value !== 'undefined') {
+ $(this).flexdatalist('value', value);
+ }
+ return _defaultValFunc.apply(this, arguments);
+};
+
+$(function () {
+ $('input.flexdatalist:not(.flexdatalist-set)').flexdatalist();
+});
\ No newline at end of file
--- /dev/null
+jQuery.fn.flexdatalist=function(e,t){"use strict";var a,i=$(document),s=$(this),r=this;if(a=function(){var t=$(this),a={},i="",s=null;t.attr("name");t.hasClass("flexdatalist-set")&&r._destroy(t),t._options=function(e,a){var i=t.data("flexdatalist");if(!r._isDefined(e))return t.data("flexdatalist");if(r._isDefined(a))i[e]=a;else{if(!r._isObject(e))return r._isDefined(i,e)?i[e]:null;i=e}return i.searchIn=r._csvToArray(i.searchIn),i.relatives=i.relatives&&$(i.relatives).length>0?$(i.relatives):null,i.textProperty=null===i.textProperty?i.searchIn[0]:i.textProperty,i.visibleProperties=r._csvToArray(i.visibleProperties,i.searchIn),t.data("flexdatalist",i),t},t._options($.extend({url:null,data:[],params:{},relatives:null,chainedRelatives:!1,cache:!0,minLength:2,groupBy:!1,selectionRequired:!1,focusFirstResult:!1,textProperty:null,valueProperty:null,visibleProperties:[],searchIn:["label"],searchContain:!1,searchEqual:!1,searchDisabled:!1,normalizeString:null,multiple:t.attr("multiple"),maxShownResults:100,noResultsText:'No results found for "{keyword}"',toggleSelected:!1,_values:[]},e,t.data()));var l=t.clone(!1).attr({list:null,name:null,id:t.attr("id")?t.attr("id")+"-flexdatalist":null}).addClass("flexdatalist-alias").removeClass("flexdatalist");if(t._options("multiple")){var n=$("<ul>").addClass("flexdatalist-multiple").css({"background-color":t.css("background-color"),"border-color":t.css("border-left-color"),"border-width":t.css("border-left-width"),"border-style":t.css("border-left-style"),"border-radius":t.css("border-top-left-radius")}).insertAfter(t).click(function(){$(this).find("input").focus()});$('<li class="input-container">').addClass("flexdatalist-multiple-value").append(l).appendTo(n)}else l.insertAfter(t);t.addClass("flexdatalist").attr("type","hidden"),t._init=function(){var e=t._options();l.on("input keydown",function(a){var i=t._keyword();188===r._keyNum(a)&&!e.selectionRequired&&e.multiple?(a.preventDefault(),t._value(i),t._removeResults()):9===r._keyNum(a)?t._removeResults():0===i.length&&e.multiple&&8===r._keyNum(a)&&l.data("_remove",l.parents("li:eq(0)").prev())}).on("input keyup",function(a){if(t._changed()&&13!==r._keyNum(a)){var s=t._keyword();s.length>=e.minLength?t._search(function(e){t._showResults(e)}):t._removeResults(),e.multiple||(e.selectionRequired?t._value(""):t._value(s))}var n=l.data("_remove");n&&(n.find(".fdl-remove").click(),l.data("_remove",null)),i=t._keyword()}).focus(function(){var a=t._keyword();0===e.minLength?""===a&&t._tdata(function(e){t._showResults(e)}):a.length>=e.minLength&&!t._selected()&&t._search(function(e){t._showResults(e)})}).attr("autocomplete","off"),l.attr("autofocus")&&l.focus(),window.onresize=function(e){t._position()},t.addClass("flexdatalist-set")},t._changed=function(){return i!==t._keyword()},t._chained=function(){var e=t._options();if(e.relatives&&e.chainedRelatives){var i=function(a){e.relatives.each(function(){var i=r._isEmpty($(this).val()),s=r._isEmpty(t.val());l.prop("disabled",i),a||!i&&s||(t._value(""),l.val(""),e.multiple&&n.find("li .remove").click())})};e.relatives.on("change",function(){i(),a={}}),i(!0)}},t._initValue=function(){var e=t.attr("value");r._isEmpty(e)||(t._options("originalValue",t.val()),t._parseValue(e,function(e){t.val("",!0),l.val(""),r._isEmpty(e)||t._values(e),i=t._keyword()}))},t._parseValue=function(e,a){var i=t._options();if(t._toJSON())try{a(JSON.parse(e))}catch(s){}else if(t._toCSV()||"string"==typeof i.valueProperty){var r=e.split(",");if("string"==typeof i.valueProperty){var l=i.searchIn;i.searchIn=i.valueProperty.split(","),i.searchEqual=!0,t._search(function(e){e.length>0&&a(e),i.searchIn=l,i.searchEqual=!1},r)}else a(r)}else a(e)},t._tdata=function(e){t.trigger("before:flexdatalist.data"),t._url(function(a){t._data(function(i){i=i.concat(a);for(var s=t._options("_values"),r=0;r<i.length;r++){var l=i[r];s&&s.indexOf(t._getText(l))>-1&&delete i[r]}t.trigger("after:flexdatalist.data",[i]),e(i)})})},t._data=function(e){var a=t._options();"string"==typeof a.data?t._remote({url:a.data,success:function(i){var s=t._getRemoteData(i);a.data=s,e(s)}}):e(a.data)},t._url=function(e){var a=t._options(),i=t._keyword(),l=t.val(),n=i;return r._isEmpty(a.url)?e([]):(clearTimeout(s),void(s=setTimeout(function(){a.cache&&2!==a.cache&&(n=i.substring(0,a.minLength>0?a.minLength:1));var s=t._cache(n);return s?void e(s):void t._remote({url:a.url,data:$.extend(t._relativesData(),a.params,{keyword:i,contain:a.searchContain,selected:l}),success:function(a){var s=t._getRemoteData(a),r=t._keyword();r.length>i.length?t._search(function(e){t._showResults(e)}):e(s),t._cache(n,s)}})},200)))},t._remote=function(e){t.hasClass("flexdatalist-loading")||(t.addClass("flexdatalist-loading"),e=$.extend({type:"post",dataType:"json",complete:function(){t.removeClass("flexdatalist-loading")}},e),$.ajax(e))},t._getRemoteData=function(e){var t=e.results?e.results:e;return"string"==typeof t&&0===t.indexOf("[{")&&(t=JSON.parse(t)),r._isObject(t)?t:[]},t._relativesData=function(){var e=t._options("relatives"),a={};return e&&(a.relatives={},e.each(function(){var e=$(this);a.relatives[e.attr("name")]=e.val()})),a},t._datalist=function(){var e=t._options(),a=t.attr("list");return r._isEmpty(a)||(e.data=[],$("#"+a).find("option").each(function(){var t=$(this).val();e.data.push({label:t,value:t})})),t},t._cache=function(e,i){if(t._options("cache")){if(e=t._normalizeString(e),!r._isDefined(i))return r._isDefined(a,e)&&(i=a[e]),i;a[e]=i}return null},t._search=function(e,a){t._tdata(function(i){var s=[],l=t._options();if(l.searchDisabled)return e(i);r._isDefined(a)||(a=t._keyword()),"string"==typeof a&&(a=[a]),t.trigger("before:flexdatalist.search",[a,i]);for(var n=0;n<a.length;n++)for(var o=a[n],u=0;u<i.length;u++){var d=t._matches(i[u],o,l.values);d&&s.push(d)}t.trigger("after:flexdatalist.search",[a,i,s]),e(s)})},t._matches=function(e,a,i){for(var s=!1,l=$.extend({},e),n=t._options(),o=n.searchIn,u=0;u<o.length;u++){var d=o[u];if(r._isDefined(e,d)&&e[d]){var f=e[d].toString();t._find(a,f)&&(l[d+"_highlight"]=t._highlight(a,f),s=!0)}}return s?l:null},t._highlight=function(e,a){return a.replace(new RegExp(e,t._options("searchContain")?"ig":"i"),'<span class="highlight">$&</span>')},t._find=function(e,a){var i=t._options();return a=t._normalizeString(a),e=t._normalizeString(e),i.searchEqual?a==e:i.searchContain?a.indexOf(e)>=0:0===a.indexOf(e)},t._showResults=function(e){t._removeResults(!0);var a=t._options();if(0===e.length){var i=t._keyword();e=[{label:i,value:i,label_highlight:'<span class="highlight">'+i+"</span>"}]}var s=t._getResultsContainer();a.groupBy?(e=t._groupData(e),Object.keys(e).forEach(function(i,r){var l=e[i],n=a.groupBy,o=t._getHighlight(l[0],n,i);$("<li>").addClass("group").append($("<span>").addClass("group-name").html(o)).append($("<span>").addClass("group-item-count").text(" "+l.length)).appendTo(s);t._items(l,s)})):(console.log(e),t._items(e,s));var r=s.find("li:not(.group)");r.on("click",function(e){var i=$(this).data("item");i&&(t._selected(!0)._removeResults()._value(i),t.trigger("select:flexdatalist",[i,a]))}).hover(function(){r.removeClass("active"),$(this).addClass("active")},function(){$(this).removeClass("active")}),a.focusFirstResult&&r.filter(":first").addClass("active")},t._noResults=function(e){if(!r._isEmpty(e)){var a=t._getResultsContainer(),i=t._keyword();e=e.split("{keyword}").join(i),$("<li>").addClass("item no-results").append(e).appendTo(a)}},t._groupData=function(e){for(var a=[],i=t._options("groupBy"),s=0;s<e.length;s++){var l=e[s];if(r._isDefined(l,i)){var n=l[i];r._isDefined(a,n)||(a[n]=[]),a[n].push(l)}}return a},t._items=function(e,a){var i=t._options("maxShownResults");t.trigger("show:flexdatalist.results",[e]);for(var s=0;s<e.length&&!(i>0&&i===s);s++)t._item(e[s]).appendTo(a);t.trigger("shown:flexdatalist.results",[e])},t._item=function(e){for(var a=$("<li>").data("item",e).addClass("item"),i=t._options(),s=i.visibleProperties,l=0;l<s.length;l++){var n=s[l];if((!i.groupBy||i.groupBy!==n)&&r._isDefined(e,n)){var o={};if("thumb"===n)o=$("<img>").addClass("item item-"+n).attr("src",e[n]);else{var u=t._getHighlight(e,n);o=$("<span>").addClass("item item-"+n).html(u+" ")}o.appendTo(a)}}return a},t._getHighlight=function(e,t,a){return r._isDefined(e,t+"_highlight")?e[t+"_highlight"]:r._isDefined(e,t)?e[t]:a},t._getResultsContainer=function(){var e=t;t._options("multiple")&&(e=n);var a=$("ul.flexdatalist-results");return 0===a.length&&(a=$("<ul>").addClass("flexdatalist-results").appendTo("body").css({"border-color":e.css("border-left-color"),"border-width":"1px","border-bottom-left-radius":e.css("border-bottom-left-radius"),"border-bottom-right-radius":e.css("border-bottom-right-radius")}).data("target",l),t._position()),a},t._removeResults=function(e){var a="ul.flexdatalist-results";return e&&(a="ul.flexdatalist-results li"),$(a).remove(),t},t._selected=function(e){var a="flexdatalist-selected";return r._isDefined(e)?(e?t.addClass(a):t.removeClass(a),t):t.hasClass(a)},t._values=function(e){return $.isArray(e)&&!r._isEmpty(e)?void $.each(e,function(e,a){t._value(a)}):void t._value(e)},t._value=function(e){var a=t._options(),s=t._getText(e),r=t._getValue(e);if(s.length>0&&a._values.push(s),a.multiple){if(""===e)return t;l.val("");var o=$("<li>").addClass("value"+(a.toggleSelected?" toggle":"")).append('<span class="text">'+s+"</span>").append('<span class="fdl-remove">×</span>').insertBefore(n.find("li.input-container"));o.find("span.fdl-remove").click(function(){var e=$(this).parent(),i=e.index();if(!e.hasClass("disabled")&&(t._toJSON()||t._toCSV())){var s=t._inputValue();s.splice(i,1),a._values.splice(i,1),t._inputValue(s)}e.remove()}),a.toggleSelected&&o.click(function(){var e=$(this),i=t._inputValue(),r=e.index();if(e.hasClass("disabled")){var l=e.data("_value");i.splice(r,0,l),a._values.splice(r,0,t._getText(l)),e.removeClass("disabled")}else{var l=i.splice(r,1);e.data("_value",l[0]),a._values.splice(r,1),e.addClass("disabled")}t._inputValue(i,s)})}else s&&s!==l.val()&&l.val(s);return t._inputValue(r,s),i=t._keyword(),t},t._inputValue=function(e,a){var i=t._toJSON(),s=t._toCSV();return r._isDefined(e)?(r._isObject(e)&&(i&&!r._isEmpty(e)?e=JSON.stringify(e):s&&(e=e.join(","))),""===e&&t._options("_values",[]),t.val(e,!0),t.trigger("change:flexdatalist",[e,a,t._options()]).trigger("change"),e):(e=t.val(),e?i?e=JSON.parse(e):s&&(e=e.split(",")):(i||s)&&(e=[]),e)},t._getText=function(e){var a=e,i=t._options();return r._isObject(e)&&(a=e[i.searchIn[0]],a=r._isDefined(e,i.textProperty)?e[i.textProperty]:t._replacePlaceholders(e,i.textProperty,a)),$("<div>").html(a).text()},t._getValue=function(e){var a=e,i=t._options();if(r._isObject(e))if(a=e[i.searchIn[0]],"*"===i.valueProperty)a=e;else if(r._isDefined(e,i.valueProperty))a=e[i.valueProperty];else if(t._toJSON()){var a={},s=i.valueProperty,l=i.textProperty;if(l){var n=l;"string"==typeof l&&(n=t._parsePlaceholders(l)),r._isObject(n)&&$.each(n,function(e,t){s.push(t)})}else r._isDefined(e,l)&&s.push(l);$.each(s,function(t,i){r._isDefined(e,i)&&(a[i]=e[i])})}if(i.multiple&&(t._toJSON()||t._toCSV())){var o=t._inputValue();!r._isEmpty(a)&&r._isObject(o)&&(o.push(a),a=o)}return a},t._replacePlaceholders=function(e,a,i){if(r._isObject(e)&&"string"==typeof a){var s=t._parsePlaceholders(a);if(!r._isEmpty(e)&&s)return $.each(s,function(t,i){r._isDefined(e,i)&&(a=a.replace(t,e[i]))}),a}return i},t._parsePlaceholders=function(e){var t=e.match(/\{.+?\}/g);if(t){var a={};return t.map(function(e){a[e]=e.slice(1,-1)}),a}return!1},t._normalizeString=function(e){if("string"==typeof e){var a=t._options("normalizeString");return"function"==typeof a&&(e=a(e)),e.toUpperCase()}return e},t._keyword=function(){return l.val().replace(/^\s+/,"")},t._toJSON=function(){var e=t._options("valueProperty");return r._isObject(e)||"*"===e},t._toCSV=function(){return!t._toJSON()&&t._options("multiple")},t._position=function(){var e=l;t._options("multiple")&&(e=n),$("ul.flexdatalist-results").css({width:e.outerWidth()+"px",top:e.offset().top+e.outerHeight()+"px",left:e.offset().left+"px","z-index":e.css("z-index")+1})},t._datalist(),t._initValue(),t._chained(),t._init()},this._destroy=function(e){e||(e=s),e.each(function(){var e=$(this).data("flexdatalist");$(this).removeClass("flexdatalist-set").attr("type","text").val(e&&e.originalValue?e.originalValue:"").data("flexdatalist",null).next(".flexdatalist-alias, ul.flexdatalist-multiple").remove()})},this._reset=function(){this._destroy()},this._keyNum=function(e){return e.which||e.keyCode},i.data("flexdatalist")||$(document).mouseup(function(e){var t=$(".flexdatalist-results"),a=t.data("target");a&&a.is(":focus")||t.is(e.target)||0!==t.has(e.target).length||t.remove()}).keydown(function(e){var t=$(".flexdatalist-results"),a=t.find("li"),i=a.filter(".active"),s=i.index(),l=a.length,n=r._keyNum(e);if(0!==l)if(13===n)e.preventDefault(),i.click();else if(40===n||38===n){e.preventDefault(),40===n?i=l>s&&i.nextAll(".item").first().length>0?i.removeClass("active").nextAll(".item").first().addClass("active"):a.removeClass("active").filter(".item:first").addClass("active"):38===n&&(i=s>0&&i.prevAll(".item").first().length>0?i.removeClass("active").prevAll(".item").first().addClass("active"):a.removeClass("active").filter(".item:last").addClass("active"));var o=(0===i.prev().length?i:i.prev()).position().top;t.animate({scrollTop:o+t.scrollTop()},100)}}).data("flexdatalist",!0),this._isEmpty=function(e){return r._isDefined(e)?null===e?!0:e===!0?!1:0===this._length(e)?!0:""===$.trim(e)?!0:!1:!0},this._isObject=function(e){return e&&"object"==typeof e},this._csvToArray=function(e,t){return 0===e.length?t:"string"==typeof e?e.split(","):e},this._length=function(e){return this._isObject(e)?Object.keys(e).length:"number"==typeof e.length?e.length:0},this._isDefined=function(e,t){var a="undefined"!=typeof e;return a&&"undefined"!=typeof t?"undefined"!=typeof e[t]:a},"string"==typeof e)if("function"==typeof this["_"+e]){if(!this["_"+e]())return this}else{if(!t){var l=s.data("flexdatalist");return l[e]}if("value"!==e){var l=s.data("flexdatalist");return l[e]=t,s.data("flexdatalist",l),this}var l=s.data("flexdatalist");l.originalValue=t,r._destroy(),s.data("flexdatalist",l)}return this.each(a)};var _defaultValFunc=jQuery.fn.val;jQuery.fn.val=function(e,t){return!t&&$(this).hasClass("flexdatalist-set")&&"undefined"!=typeof e&&$(this).flexdatalist("value",e),_defaultValFunc.apply(this,arguments)},$(function(){$("input.flexdatalist:not(.flexdatalist-set)").flexdatalist()});
\ No newline at end of file