diff --git a/jquery.flexdatalist.css b/jquery.flexdatalist.css index e4eb68e..45b2b96 100644 --- a/jquery.flexdatalist.css +++ b/jquery.flexdatalist.css @@ -16,9 +16,9 @@ } .flexdatalist-results li { border-bottom: 1px solid #ccc; - padding: 0 15px; + padding: 8px 15px; font-size: 14px; - line-height: 35px; + line-height: 20px; } .flexdatalist-results li span.highlight { font-weight: 700; @@ -40,7 +40,7 @@ .flexdatalist-results li.group { background: #F3F3F4; color: #666; - padding: 0 8px; + padding: 8px 8px; } .flexdatalist-results li .group-name { font-weight: 700; diff --git a/jquery.flexdatalist.js b/jquery.flexdatalist.js index 4d1e795..f7ae050 100644 --- a/jquery.flexdatalist.js +++ b/jquery.flexdatalist.js @@ -135,10 +135,10 @@ jQuery.fn.flexdatalist = function (_option, _value) { * Initialization */ this.init = function () { - this.options.init(); + var options = this.options.init(); this.set.up(); - this.fvalue.set($this.attr('value')).on('after:flexdatalist.value', function () { - _this.fdisabled($this.is('[disabled]')); + this.fvalue.clear()._load(options.originalValue, function () { + _this.fdisabled(options.disabled); }); $alias @@ -270,7 +270,7 @@ jQuery.fn.flexdatalist = function (_option, _value) { var val = $alias.val(), $remove = $alias.data('_remove'); if ($remove) { - $remove.find('.fdl-remove').click(); + _this.fvalue.remove($remove); $alias.data('_remove', null); } else if (val.length === 0 && options.multiple && _this.keyNum(event) === 8) { $alias.data('_remove', $alias.parents('li:eq(0)').prev()); @@ -390,38 +390,18 @@ jQuery.fn.flexdatalist = function (_option, _value) { if ((options.multiple || this.isJSON()) && !asString) { return this.toObj(val); } - return this.toStr(val); + return val; }, /** * Set value. * Parse value if necessary. */ set: function (val, append) { - if (!append) { - this.clear(true); - } - if (!_this.fdisabled() && !_this.isEmpty(val)) { - var _fvalue = this, - args = [val, null, _this.options.get()], - event = append ? 'add' : 'value'; - // Clear keyword - $alias[0].value = ''; - $this.trigger('before:flexdatalist.' + event, args); - this._process(val, function (values) { - if (!_this.isEmpty(values)) { - if ($.isArray(values)) { - $.each(values, function (i, value) { - _fvalue.extract(value, true); - }); - } else { - _fvalue.extract(values, true); - } - $this - .trigger('after:flexdatalist.' + event, args.splice(0, 1, values)) - .trigger('change:flexdatalist', args) - .trigger('change'); - } - }); + if (!_this.fdisabled()) { + if (!append) { + this.clear(true); + } + this._load(val); } return $this; }, @@ -430,8 +410,9 @@ jQuery.fn.flexdatalist = function (_option, _value) { */ add: function (val) { if (_this.options.get('multiple')) { - return this.set(val, true); + this.set(val, true); } + return this; }, /** * Toggle value. @@ -440,74 +421,115 @@ jQuery.fn.flexdatalist = function (_option, _value) { if (!_this.fdisabled()) { this.multiple.toggle(val); } - return $this; + return this; }, /** * Remove value. */ remove: function (val) { if (!_this.fdisabled()) { - this.multiple.remove(val); + val = this.toObj(val); + $this.trigger('before:flexdatalist.remove', [val]); + var result = []; + if ($.isArray(val)) { + $.each(val, function (i, value) { + var removed = _this.fvalue.multiple.remove(value); + if (removed) { + result.push(removed); + } + }); + } else { + var _result = this.multiple.remove(val); + if (_result) { + result.push(_result); + } + } + $this + .trigger('after:flexdatalist.remove', [val, result]) + .trigger('change:flexdatalist', [result, _this.options.get()]) + .trigger('change'); } - return $this; + return this; }, /** - * Normalize value. + * Load (remote?) value(s). */ - _process: function (values, callback) { - var options = _this.options.get(); + _load: function (values, callback) { + var options = _this.options.get(), + _values = this.toStr(values), + _val = this.get(true); + + callback = (callback ? callback : $.noop); + // If nothing changes, return + if (_values.length == 0 && _val.length == 0) { + callback(values); + return; + } values = this.toObj(values); - if (typeof options.valueProperty === 'string' && !this.isJSON(values)) { + if (!_this.isEmpty(values) && typeof options.valueProperty === 'string' && !this.isJSON(values)) { var _searchIn = options.searchIn, _searchEqual = options.searchEqual; options.searchIn = options.valueProperty.split(','); options.searchEqual = true; + // Load data _this.data.load(function (data) { + // Search data _this.search.get(values, data, function (matches) { - callback(matches); + if (!_this.isEmpty(matches)) { + _this.fvalue.extract(matches); + } + callback(values); options.searchIn = _searchIn; options.searchEqual = _searchEqual; }); }, values); return; } + _this.fvalue.extract(values); callback(values); }, /** - * Add value. + * Extract value and text. + */ + extract: function (values) { + var options = _this.options.get(), + result = []; + + $this.trigger('before:flexdatalist.value', [values, options]); + if ($.isArray(values)) { + $.each(values, function (i, value) { + result.push(_this.fvalue._extract(value)); + }); + } else { + result = _this.fvalue._extract(values); + } + $this + .trigger('after:flexdatalist.value', [result, options]) + .trigger('change:flexdatalist', [result, options]) + .trigger('change'); + }, + /** + * @inherited. */ - extract: function (val, ignoreEvent) { + _extract: function (val) { var txt = this.text(val), value = this.value(val), current = $this[0].value, options = _this.options.get(); - if (!_this.isEmpty(val)) { - if (!value) { - return _this.debug('No value found'); - } else if (!txt) { - return _this.debug('No text found'); - } - } - // For allowDuplicateValues - if (_this.isDup(val)) { - return; - } - if (txt) { - _values.push(txt); - } if (options.multiple) { - this.multiple.add(value, txt); + // For allowDuplicateValues + if (!_this.isEmpty(txt)) { + if (_this.isDup(txt)) { + return; + } + _values.push(txt); + this.multiple.add(value, txt); + } } else { this.single(value, txt); } - if (!ignoreEvent) { - $this.trigger('change:flexdatalist', [ - value, - txt, - options - ]).trigger('change'); - } + return {value: value, text: txt}; }, /** * Default input value. @@ -555,68 +577,61 @@ jQuery.fn.flexdatalist = function (_option, _value) { /** * Toggle value. */ - toggle: function ($li) { + toggle: function (val) { var options = _this.options.get(); if (!options.toggleSelected) { return; } - $li = this.findLi($li); - var index = $li.index(), - data = $li.data(), - action = $li.hasClass('disabled') ? 'enable' : 'disable', - current = _this.fvalue.get(), - args = [action, data.value, data.text, options]; - - $this.trigger('before:flexdatalist.toggle', [ - action, - data.value, - data.text, - options - ]); - - if (action === 'enable') { - var value = $li.data('value'); - current.splice(index, 0, value); - $li.removeClass('disabled'); - } else { - current.splice(index, 1); - $li.addClass('disabled'); + var $li = this.findLi(val); + if ($li) { + var index = $li.index(), + data = $li.data(), + action = $li.hasClass('disabled') ? 'enable' : 'disable', + current = _this.fvalue.get(), + args = [{value: data.value, text: data.text, action: action}, options]; + + $this.trigger('before:flexdatalist.toggle', args); + + if (action === 'enable') { + var value = $li.data('value'); + current.splice(index, 0, value); + $li.removeClass('disabled'); + } else { + current.splice(index, 1); + $li.addClass('disabled'); + } + + current = _this.fvalue.toStr(current); + _this.value = current; + + $this + .trigger('after:flexdatalist.toggle', args) + .trigger('change:flexdatalist', args) + .trigger('change'); } - - current = _this.fvalue.toStr(current); - _this.value = current; - - $this - .trigger('after:flexdatalist.toggle', args) - .trigger('change:flexdatalist', args) - .trigger('change'); }, /** * Remove value from input. */ - remove: function ($li) { - $li = this.findLi($li); - var values = _this.fvalue.get(), - index = $li.index(), - data = $li.data(), - options = _this.options.get(), - args = [data.value, data.text, options]; - - $this.trigger('before:flexdatalist.remove', args); - - var val = values.splice(index, 1); - values = _this.fvalue.toStr(values); - $this[0].value = values; - $li.remove(); - - $this - .trigger('after:flexdatalist.remove', args) - .trigger('change:flexdatalist', args) - .trigger('change'); - - // For allowDuplicateValues - _values.splice(index, 1); - _this.fvalue.multiple.checkLimit(); + remove: function (val) { + var $li = this.findLi(val); + if ($li) { + var values = _this.fvalue.get(), + index = $li.index(), + data = $li.data(), + options = _this.options.get(), + arg = {value: data.value, text: data.text}; + + values.splice(index, 1); + values = _this.fvalue.toStr(values); + $this[0].value = values; + $li.remove(); + _this.fvalue.multiple.checkLimit(); + + // For allowDuplicateValues + _values.splice(index, 1); + return arg; + } }, /** * Remove all. @@ -660,7 +675,7 @@ jQuery.fn.flexdatalist = function (_option, _value) { * Get li item from value. */ findLi: function ($li) { - if (typeof $li !== 'object') { + if (!($li instanceof jQuery)) { var val = $li; $li = null; $multiple.find('li:not(.input-container)').each(function () { @@ -670,6 +685,8 @@ jQuery.fn.flexdatalist = function (_option, _value) { return false; } }); + } else if ($li.length === 0) { + $li = null; } return $li; }, @@ -758,17 +775,13 @@ jQuery.fn.flexdatalist = function (_option, _value) { } $this[0].value = ''; if (current !== '') { - $this.trigger('change:flexdatalist', [ - null, - null, - options - ]).trigger('change'); + $this.trigger('change:flexdatalist', [null, options]).trigger('change'); } if (alias) { $alias.val('', true); } _values = []; - return $this; + return this; }, /** * Value to object. @@ -1062,7 +1075,7 @@ jQuery.fn.flexdatalist = function (_option, _value) { _this.debug('Search is disabled!'); return; } - + var matches = _this.cache.read(keywords); if (!matches) { $this.trigger('before:flexdatalist.search', [keywords, data]); @@ -1079,8 +1092,8 @@ jQuery.fn.flexdatalist = function (_option, _value) { matches.push(item); } } - _this.cache.write(keywords, matches, 10); } + _this.cache.write(keywords, matches, 2); $this.trigger('after:flexdatalist.search', [keywords, data, matches]); } callback(matches); @@ -1502,6 +1515,7 @@ jQuery.fn.flexdatalist = function (_option, _value) { } ); this.set(options); + return options; }, get: function (option) { var options = $this.data('flexdatalist'); diff --git a/jquery.flexdatalist.min.css b/jquery.flexdatalist.min.css index 4f23d2b..fafa4e5 100644 --- a/jquery.flexdatalist.min.css +++ b/jquery.flexdatalist.min.css @@ -1 +1 @@ -.flexdatalist-results{position:absolute;top:0;left:0;border:1px solid #444;border-top:none;background:#fff;z-index:100000;max-height:300px;overflow-y:auto;box-shadow:0 4px 5px rgba(0,0,0,.15);color:#333;list-style:none;margin:0;padding:0}.flexdatalist-results li{border-bottom:1px solid #ccc;padding:0 15px;font-size:14px;line-height:35px}.flexdatalist-results li span.highlight{font-weight:700;text-decoration:underline}.flexdatalist-results li.active{background:#2B82C9;color:#fff;cursor:pointer}.flexdatalist-results li.no-results{font-style:italic;color:#888}.flexdatalist-results li.group{background:#F3F3F4;color:#666;padding:0 8px}.flexdatalist-results li .group-name{font-weight:700}.flexdatalist-results li .group-item-count{font-size:85%;color:#777;display:inline-block;padding-left:10px}.flexdatalist-multiple:after,.flexdatalist-multiple:before{content:'';display:block;clear:both}.flexdatalist-multiple{width:100%;margin:0;padding:0;list-style:none;text-align:left;cursor:text}.flexdatalist-multiple.disabled{background-color:#eee;cursor:default}.flexdatalist-multiple li{display:inline-block;position:relative;margin:5px;float:left}.flexdatalist-multiple li.input-container,.flexdatalist-multiple li.input-container input{border:none;width:280px;height:auto;padding:0 0 0 4px;line-height:24px}.flexdatalist-multiple li.value{display:inline-block;padding:2px 25px 2px 5px;background:#eee;border-radius:3px;color:#777;line-height:20px}.flexdatalist-multiple li.toggle{cursor:pointer;transition:opacity ease-in-out .3s}.flexdatalist-multiple li.toggle.disabled{text-decoration:line-through;opacity:.8}.flexdatalist-multiple li.value span.fdl-remove{font-weight:700;padding:2px 5px;font-size:20px;line-height:20px;cursor:pointer;position:absolute;top:0;right:0;opacity:.7}.flexdatalist-multiple li.value span.fdl-remove:hover{opacity:1} \ No newline at end of file +.flexdatalist-results{position:absolute;top:0;left:0;border:1px solid #444;border-top:none;background:#fff;z-index:100000;max-height:300px;overflow-y:auto;box-shadow:0 4px 5px rgba(0,0,0,.15);color:#333;list-style:none;margin:0;padding:0}.flexdatalist-results li{border-bottom:1px solid #ccc;padding:8px 15px;font-size:14px;line-height:20px}.flexdatalist-results li span.highlight{font-weight:700;text-decoration:underline}.flexdatalist-results li.active{background:#2B82C9;color:#fff;cursor:pointer}.flexdatalist-results li.no-results{font-style:italic;color:#888}.flexdatalist-results li.group{background:#F3F3F4;color:#666;padding:8px}.flexdatalist-results li .group-name{font-weight:700}.flexdatalist-results li .group-item-count{font-size:85%;color:#777;display:inline-block;padding-left:10px}.flexdatalist-multiple:after,.flexdatalist-multiple:before{content:'';display:block;clear:both}.flexdatalist-multiple{width:100%;margin:0;padding:0;list-style:none;text-align:left;cursor:text}.flexdatalist-multiple.disabled{background-color:#eee;cursor:default}.flexdatalist-multiple li{display:inline-block;position:relative;margin:5px;float:left}.flexdatalist-multiple li.input-container,.flexdatalist-multiple li.input-container input{border:none;width:280px;height:auto;padding:0 0 0 4px;line-height:24px}.flexdatalist-multiple li.value{display:inline-block;padding:2px 25px 2px 7px;background:#eee;border-radius:3px;color:#777;line-height:20px}.flexdatalist-multiple li.toggle{cursor:pointer;transition:opacity ease-in-out .3s}.flexdatalist-multiple li.toggle.disabled{text-decoration:line-through;opacity:.8}.flexdatalist-multiple li.value span.fdl-remove{font-weight:700;padding:2px 5px;font-size:20px;line-height:20px;cursor:pointer;position:absolute;top:0;right:0;opacity:.7}.flexdatalist-multiple li.value span.fdl-remove:hover{opacity:1} \ No newline at end of file diff --git a/jquery.flexdatalist.min.js b/jquery.flexdatalist.min.js index 342d423..72b9c15 100644 --- a/jquery.flexdatalist.min.js +++ b/jquery.flexdatalist.min.js @@ -1 +1 @@ -jQuery.fn.flexdatalist=function(e,t){"use strict";var i=function(e){e.each(function(){var e=$(this),t=e.data("flexdatalist");e.removeClass("flexdatalist-set").attr("type","text").val(t&&t.originalValue?t.originalValue:"").removeData("flexdatalist").next(".flexdatalist-alias, ul.flexdatalist-multiple").remove()})};if("string"==typeof e&&"reset"!==e){var a=this[0];if("destroy"===e)i($(this));else if("value"===e){if("undefined"==typeof t)return a.fvalue.get();a.fvalue.set(t)}else if("add"===e){if("undefined"==typeof t)return a.debug("Missing value to add!");a.fvalue.add(t)}else if("toggle"===e){if("undefined"==typeof t)return a.debug("Missing value to toggle!");a.fvalue.toggle(t)}else if("remove"===e){if("undefined"==typeof t)return a.debug("Missing value to remove!");a.fvalue.remove(t)}else if("disabled"===e){if("undefined"==typeof t)return a.fdisabled();a.fdisabled(t)}else if("string"==typeof e){if("undefined"==typeof t)return a.options.get(e);a.options.set(e,t)}return this}this&&"undefined"!=typeof this[0]&&"undefined"!=typeof this[0].fvalue&&i($(this));var r=$.extend({url:null,data:[],params:{},relatives:null,chainedRelatives:!1,cache:!0,cacheLifetime:60,minLength:2,groupBy:!1,selectionRequired:!1,focusFirstResult:!1,textProperty:null,valueProperty:null,visibleProperties:[],iconProperty:"thumb",searchIn:["label"],searchContain:!1,searchEqual:!1,searchByWord:!1,searchDisabled:!1,searchDelay:300,normalizeString:null,multiple:null,disabled:null,maxShownResults:100,removeOnBackspace:!0,noResultsText:'No results found for "{keyword}"',toggleSelected:!1,allowDuplicateValues:!1,requestType:"get",requestContentType:"x-www-form-urlencoded",resultsProperty:"results",keywordParamName:"keyword",limitOfValues:0,valuesSeparator:",",debug:!0},e);return this.each(function(e){var t=$(this),i=this,a=null,n=[],s="flex"+e,l=null,o=null;this.init=function(){this.options.init(),this.set.up(),this.fvalue.set(t.attr("value")).on("after:flexdatalist.value",function(){i.fdisabled(t.is("[disabled]"))}),l.on("focusin",function(e){i.action.redoSearchFocus(e),i.action.showAllResults(e),o&&o.addClass("focus")}).on("input keydown",function(e){9===i.keyNum(e)&&i.results.remove(),i.action.keypressValue(e,188),i.action.backSpaceKeyRemove(e)}).on("input keyup",function(e){i.action.keypressValue(e,13),i.action.keypressSearch(e),i.action.copyValue(e),i.action.backSpaceKeyRemove(e)}).on("focusout",function(){o&&o.removeClass("focus")}),window.onresize=function(){i.position()}},this.action={keypressValue:function(e,t){var a=i.keyNum(e),r=l[0].value,n=i.options.get();if(r.length>0&&a===t&&!n.selectionRequired&&n.multiple){var r=l[0].value;e.preventDefault(),i.fvalue.extract(r),i.results.remove()}},keypressSearch:function(e){var t=i.keyNum(e),r=l.val(),n=r.length,s=i.options.get();clearTimeout(a),(0!==s.minLength||0!==n||9!==t&&16!==t)&&(0===n&&s.minLength>0||nt||t>40))&&(i.results.remove(),a=setTimeout(function(){0===s.minLength&&n>0||s.minLength>0&&n>=s.minLength?i.data.load(function(e){i.search.get(r,e,function(e){i.results.show(e)})}):i.results.remove()},s.searchDelay)))},redoSearchFocus:function(e){var t=i.fvalue.get(),a=i.options.get(),r=l.val();(r.length>0&&a.multiple||r.length>0&&0===t.length)&&this.keypressSearch(e)},copyValue:function(e){if(13!==i.keyNum(e)){var t=l.val(),a=i.options.get();a.multiple||(a.selectionRequired?i.fvalue.clear():(i.fvalue.extract(t),0===t.length&&(n=[])))}},backSpaceKeyRemove:function(e){var t=i.options.get();if(t.removeOnBackspace){var a=l.val(),r=l.data("_remove");r?(r.find(".fdl-remove").click(),l.data("_remove",null)):0===a.length&&t.multiple&&8===i.keyNum(e)&&l.data("_remove",l.parents("li:eq(0)").prev())}},showAllResults:function(){var e=l.val();e=$.trim(e),""===e&&0===i.options.get("minLength")&&i.data.load(function(e){i.results.show(e)})}},this.set={up:function(){l=this.alias(),i.options.get("multiple")?o=this.multipleInput(l):l.insertAfter(t),l.attr("autofocus")&&l.focus(),this.chained()},alias:function(){var e=t.clone(!1).attr({list:null,name:t.attr("name")?"flexdatalist-"+t.attr("name"):null,id:t.attr("id")?t.attr("id")+"-flexdatalist":null,value:""}).addClass("flexdatalist-alias").removeClass("flexdatalist").attr("autocomplete","off");return t.addClass("flexdatalist flexdatalist-set").prop("type","hidden"),e},multipleInput:function(e){return o=$('