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
----------------------------
[enh] select: support of OPTGROUP via `children` key in source (vitalets)
[enh] checklist: set checked via prop instead of attr (vitalets)

@ -136,17 +136,28 @@
if(!sourceData || value === null) {
return [];
}
//convert to array
if(!$.isArray(value)) {
value = [value];
}
/*jslint eqeq: true*/
var result = $.grep(sourceData, function(o){
return $.grep(value, function(v){ return v == o.value; }).length;
var isValArray = $.isArray(value),
result = [],
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;
},

@ -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'}, {...}]
*/
makeArray: function(data) {
var count, obj, result = [], iterateEl;
var count, obj, result = [], item, iterateItem;
if(!data || typeof data === 'string') {
return null;
}
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};
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++) {
if(typeof data[i] === 'object') {
count = 0;
$.each(data[i], iterateEl);
if(count === 1) {
item = data[i];
if(typeof item === 'object') {
count = 0; //count of keys inside item
$.each(item, iterateItem);
//case: [{val1: 'text1'}, {val2: 'text2} ...]
if(count === 1) {
result.push(obj);
} else if(count > 1 && data[i].hasOwnProperty('value') && data[i].hasOwnProperty('text')) {
result.push(data[i]);
} else {
//data contains incorrect objects
//case: [{value: 1, text: 'text1'}, {value: 2, text: 'text2'}, ...]
} else if(count > 1) {
//removed check of existance: item.hasOwnProperty('value') && item.hasOwnProperty('text')
if(item.children) {
item.children = this.makeArray(item.children);
}
result.push(item);
}
} 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) {
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, {
/**
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.
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).
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
@type string | array | object | function

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

@ -689,6 +689,43 @@ $(function () {
}, 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);
});
});