optgroups

This commit is contained in:
vitalets
2013-01-13 15:26:47 +04:00
parent 0881baeed6
commit d8e08085de
5 changed files with 101 additions and 31 deletions

@ -4,6 +4,7 @@ X-editable changelog
Version 1.4.1 wip Version 1.4.1 wip
---------------------------- ----------------------------
[enh] select: support of OPTGROUP via `children` key in source (vitalets)
[enh] checklist: set checked via prop instead of attr (vitalets) [enh] checklist: set checked via prop instead of attr (vitalets)

@ -136,17 +136,28 @@
if(!sourceData || value === null) { if(!sourceData || value === null) {
return []; return [];
} }
//convert to array
if(!$.isArray(value)) {
value = [value];
}
/*jslint eqeq: true*/ var isValArray = $.isArray(value),
var result = $.grep(sourceData, function(o){ result = [],
return $.grep(value, function(v){ return v == o.value; }).length; that = this;
$.each(sourceData, function(i, o) {
if(o.children) {
result = result.concat(that.itemsByValue(value, o.children));
} else {
/*jslint eqeq: true*/
if(isValArray) {
if($.grep(value, function(v){ return v == o.value; }).length) {
result.push(o);
}
} else {
if(value == o.value) {
result.push(o);
}
}
/*jslint eqeq: false*/
}
}); });
/*jslint eqeq: false*/
return result; return result;
}, },

@ -200,35 +200,45 @@ List - abstract class for inputs that have source option loaded from js array or
* convert data to array suitable for sourceData, e.g. [{value: 1, text: 'abc'}, {...}] * convert data to array suitable for sourceData, e.g. [{value: 1, text: 'abc'}, {...}]
*/ */
makeArray: function(data) { makeArray: function(data) {
var count, obj, result = [], iterateEl; var count, obj, result = [], item, iterateItem;
if(!data || typeof data === 'string') { if(!data || typeof data === 'string') {
return null; return null;
} }
if($.isArray(data)) { //array if($.isArray(data)) { //array
iterateEl = function (k, v) { /*
function to iterate inside item of array if item is object.
Caclulates count of keys in item and store in obj.
*/
iterateItem = function (k, v) {
obj = {value: k, text: v}; obj = {value: k, text: v};
if(count++ >= 2) { if(count++ >= 2) {
return false;// exit each if object has more than one value return false;// exit from `each` if item has more than one key.
} }
}; };
for(var i = 0; i < data.length; i++) { for(var i = 0; i < data.length; i++) {
if(typeof data[i] === 'object') { item = data[i];
count = 0; if(typeof item === 'object') {
$.each(data[i], iterateEl); count = 0; //count of keys inside item
if(count === 1) { $.each(item, iterateItem);
//case: [{val1: 'text1'}, {val2: 'text2} ...]
if(count === 1) {
result.push(obj); result.push(obj);
} else if(count > 1 && data[i].hasOwnProperty('value') && data[i].hasOwnProperty('text')) { //case: [{value: 1, text: 'text1'}, {value: 2, text: 'text2'}, ...]
result.push(data[i]); } else if(count > 1) {
} else { //removed check of existance: item.hasOwnProperty('value') && item.hasOwnProperty('text')
//data contains incorrect objects if(item.children) {
item.children = this.makeArray(item.children);
}
result.push(item);
} }
} else { } else {
result.push({value: data[i], text: data[i]}); //case: ['text1', 'text2' ...]
result.push({value: item, text: item});
} }
} }
} else { //object } else { //case: {val1: 'text1', val2: 'text2, ...}
$.each(data, function (k, v) { $.each(data, function (k, v) {
result.push({value: k, text: v}); result.push({value: k, text: v});
}); });
@ -251,12 +261,16 @@ List - abstract class for inputs that have source option loaded from js array or
List.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, { List.defaults = $.extend({}, $.fn.editabletypes.abstractinput.defaults, {
/** /**
Source data for list. Source data for list.
If **array** - it should be in format: `[{value: 1, text: "text1"}, {...}]` If **array** - it should be in format: `[{value: 1, text: "text1"}, {value: 2, text: "text2"}, ...]`
For compability, object format is also supported: `{"1": "text1", "2": "text2" ...}` but it does not guarantee elements order. For compability, object format is also supported: `{"1": "text1", "2": "text2" ...}` but it does not guarantee elements order.
If **string** - considered ajax url to load items. In that case results will be cached for fields with the same source and name. See also `sourceCache` option. If **string** - considered ajax url to load items. In that case results will be cached for fields with the same source and name. See also `sourceCache` option.
If **function**, it should return data in format above (since 1.4.0). If **function**, it should return data in format above (since 1.4.0).
Since 1.4.1 key `children` supported to render OPTGROUPs (select input only).
Example `[{text: "group1", children: [{value: 1, text: "text1"}, {value: 2, text: "text2"}]}, ...]`.
@property source @property source
@type string | array | object | function @type string | array | object | function

@ -31,14 +31,21 @@ $(function(){
$.extend(Select.prototype, { $.extend(Select.prototype, {
renderList: function() { renderList: function() {
this.$input.empty(); this.$input.empty();
if(!$.isArray(this.sourceData)) {
return;
}
for(var i=0; i<this.sourceData.length; i++) { var fillItems = function($el, data) {
this.$input.append($('<option>', {value: this.sourceData[i].value}).text(this.sourceData[i].text)); if($.isArray(data)) {
} for(var i=0; i<data.length; i++) {
if(data[i].children) {
$el.append(fillItems($('<optgroup>', {label: data[i].text}), data[i].children));
} else {
$el.append($('<option>', {value: data[i].value}).text(data[i].text));
}
}
}
return $el;
};
fillItems(this.$input, this.sourceData);
this.setClass(); this.setClass();

@ -689,6 +689,43 @@ $(function () {
}, timeout); }, timeout);
}, timeout); }, timeout);
}); });
asyncTest("optgroup", function () {
var
selected = 2,
e = $('<a href="#" data-type="select" data-value="'+selected+'" data-url="post.php"></a>').appendTo(fx).editable({
pk: 1,
source: [
{text: 'groups', children: groups},
{value: 'v1', text: 't1', children: ['a', 'b', 'c']},
{value: 'v2', text: 't2'}
]
});
equal(e.text(), groups[selected], 'text shown');
e.click();
var p = tip(e);
ok(p.is(':visible'), 'container visible');
ok(p.find('select').length, 'select exists');
equal(p.find('select').find('option').length, size + 3 + 1, 'options loaded');
equal(p.find('select').val(), e.data('editable').value, 'selected value correct');
equal(p.find('select').find('optgroup').length, 2, 'optgroup loaded');
equal(p.find('select').find('optgroup').eq(0).children().length, size, 'optgroup items ok');
selected = 'a';
p.find('select').val(selected);
p.find('form').submit();
setTimeout(function() {
ok(!p.is(':visible'), 'popover closed')
equal(e.data('editable').value, selected, 'new value saved')
equal(e.text(), 'a', 'new text shown')
e.remove();
start();
}, timeout);
});
}); });