/**
|
* combobox - jQuery EasyUI
|
*
|
* Copyright (c) 2009-2013 www.jeasyui.com. All rights reserved.
|
*
|
* Licensed under the GPL or commercial licenses
|
* To use it on other terms please contact us: info@jeasyui.com
|
* http://www.gnu.org/licenses/gpl.txt
|
* http://www.jeasyui.com/license_commercial.php
|
*
|
* Dependencies:
|
* combo
|
*
|
*/
|
(function($){
|
function findRowBy(target, value, param, isGroup){
|
var state = $.data(target, 'combobox');
|
var opts = state.options;
|
if (isGroup){
|
return _findRow(state.groups, param, value);
|
} else {
|
return _findRow(state.data, (param ? param : state.options.valueField), value);
|
}
|
|
function _findRow(data,key,value){
|
for(var i=0; i<data.length; i++){
|
var row = data[i];
|
if (row[key] == value){return row}
|
}
|
return null;
|
}
|
}
|
|
/**
|
* scroll panel to display the specified item
|
*/
|
function scrollTo(target, value){
|
var panel = $(target).combo('panel');
|
var row = findRowBy(target, value);
|
if (row){
|
var item = $('#'+row.domId);
|
if (item.position().top <= 0){
|
var h = panel.scrollTop() + item.position().top;
|
panel.scrollTop(h);
|
} else if (item.position().top + item.outerHeight() > panel.height()){
|
var h = panel.scrollTop() + item.position().top + item.outerHeight() - panel.height();
|
panel.scrollTop(h);
|
}
|
}
|
}
|
|
function nav(target, dir){
|
var opts = $.data(target, 'combobox').options;
|
var panel = $(target).combobox('panel');
|
var item = panel.children('div.combobox-item-hover');
|
if (!item.length){
|
item = panel.children('div.combobox-item-selected');
|
}
|
item.removeClass('combobox-item-hover');
|
var firstSelector = 'div.combobox-item:visible:not(.combobox-item-disabled):first';
|
var lastSelector = 'div.combobox-item:visible:not(.combobox-item-disabled):last';
|
if (!item.length){
|
item = panel.children(dir=='next' ? firstSelector : lastSelector);
|
// item = panel.children('div.combobox-item:visible:' + (dir=='next'?'first':'last'));
|
} else {
|
if (dir == 'next'){
|
item = item.nextAll(firstSelector);
|
// item = item.nextAll('div.combobox-item:visible:first');
|
if (!item.length){
|
item = panel.children(firstSelector);
|
// item = panel.children('div.combobox-item:visible:first');
|
}
|
} else {
|
item = item.prevAll(firstSelector);
|
// item = item.prevAll('div.combobox-item:visible:first');
|
if (!item.length){
|
item = panel.children(lastSelector);
|
// item = panel.children('div.combobox-item:visible:last');
|
}
|
}
|
}
|
if (item.length){
|
item.addClass('combobox-item-hover');
|
var row = findRowBy(target, item.attr('id'), 'domId');
|
if (row){
|
scrollTo(target, row[opts.valueField]);
|
if (opts.selectOnNavigation){
|
select(target, row[opts.valueField]);
|
}
|
}
|
}
|
}
|
|
/**
|
* select the specified value
|
*/
|
function select(target, value){
|
var opts = $.data(target, 'combobox').options;
|
var values = $(target).combo('getValues');
|
if ($.inArray(value+'', values) == -1){
|
if (opts.multiple){
|
values.push(value);
|
} else {
|
values = [value];
|
}
|
setValues(target, values);
|
opts.onSelect.call(target, findRowBy(target, value));
|
}
|
}
|
|
/**
|
* unselect the specified value
|
*/
|
function unselect(target, value){
|
var opts = $.data(target, 'combobox').options;
|
var values = $(target).combo('getValues');
|
var index = $.inArray(value+'', values);
|
if (index >= 0){
|
values.splice(index, 1);
|
setValues(target, values);
|
opts.onUnselect.call(target, findRowBy(target, value));
|
}
|
}
|
|
/**
|
* set values
|
*/
|
function setValues(target, values, remainText){
|
var opts = $.data(target, 'combobox').options;
|
var panel = $(target).combo('panel');
|
|
panel.find('div.combobox-item-selected').removeClass('combobox-item-selected');
|
var vv = [], ss = [];
|
for(var i=0; i<values.length; i++){
|
var v = values[i];
|
var s = v;
|
var row = findRowBy(target, v);
|
if (row){
|
s = row[opts.textField];
|
$('#'+row.domId).addClass('combobox-item-selected');
|
}
|
vv.push(v);
|
ss.push(s);
|
}
|
|
$(target).combo('setValues', vv);
|
if (!remainText){
|
$(target).combo('setText', ss.join(opts.separator));
|
}
|
}
|
|
/**
|
* load data, the old list items will be removed.
|
*/
|
var itemIndex = 1;
|
function loadData(target, data, remainText){
|
var state = $.data(target, 'combobox');
|
var opts = state.options;
|
state.data = opts.loadFilter.call(target, data);
|
state.groups = [];
|
data = state.data;
|
|
var selected = $(target).combobox('getValues');
|
var dd = [];
|
var group = undefined;
|
for(var i=0; i<data.length; i++){
|
var row = data[i];
|
var v = row[opts.valueField]+'';
|
var s = row[opts.textField];
|
var g = row[opts.groupField];
|
|
if (g){
|
if (group != g){
|
group = g;
|
var grow = {value:g, domId:('_easyui_combobox_'+itemIndex++)};
|
state.groups.push(grow);
|
dd.push('<div id="' + grow.domId + '" class="combobox-group">');
|
dd.push(opts.groupFormatter ? opts.groupFormatter.call(target, g) : g);
|
dd.push('</div>');
|
}
|
} else {
|
group = undefined;
|
}
|
|
var cls = 'combobox-item' + (row.disabled ? ' combobox-item-disabled' : '') + (g ? ' combobox-gitem' : '');
|
row.domId = '_easyui_combobox_' + itemIndex++;
|
dd.push('<div id="' + row.domId + '" class="' + cls + '">');
|
dd.push(opts.formatter ? opts.formatter.call(target, row) : s);
|
dd.push('</div>');
|
|
// if (item['selected']){
|
// (function(){
|
// for(var i=0; i<selected.length; i++){
|
// if (v == selected[i]) return;
|
// }
|
// selected.push(v);
|
// })();
|
// }
|
if (row['selected'] && $.inArray(v, selected) == -1){
|
selected.push(v);
|
}
|
}
|
$(target).combo('panel').html(dd.join(''));
|
|
if (opts.multiple){
|
setValues(target, selected, remainText);
|
} else {
|
setValues(target, selected.length ? [selected[selected.length-1]] : [], remainText);
|
}
|
|
opts.onLoadSuccess.call(target, data);
|
}
|
|
/**
|
* request remote data if the url property is setted.
|
*/
|
function request(target, url, param, remainText){
|
var opts = $.data(target, 'combobox').options;
|
if (url){
|
opts.url = url;
|
}
|
// if (!opts.url) return;
|
param = param || {};
|
|
if (opts.onBeforeLoad.call(target, param) == false) return;
|
|
opts.loader.call(target, param, function(data){
|
loadData(target, data, remainText);
|
}, function(){
|
opts.onLoadError.apply(this, arguments);
|
});
|
}
|
|
/**
|
* do the query action
|
*/
|
function doQuery(target, q){
|
var state = $.data(target, 'combobox');
|
var opts = state.options;
|
|
if (opts.multiple && !q){
|
setValues(target, [], true);
|
} else {
|
setValues(target, [q], true);
|
}
|
|
if (opts.mode == 'remote'){
|
request(target, null, {q:q}, true);
|
} else {
|
var panel = $(target).combo('panel');
|
panel.find('div.combobox-item,div.combobox-group').hide();
|
var data = state.data;
|
var group = undefined;
|
for(var i=0; i<data.length; i++){
|
var row = data[i];
|
if (opts.filter.call(target, q, row)){
|
var v = row[opts.valueField];
|
var s = row[opts.textField];
|
var g = row[opts.groupField];
|
var item = $('#'+row.domId).show();
|
if (s.toLowerCase() == q.toLowerCase()){
|
// setValues(target, [v], true);
|
setValues(target, [v]);
|
item.addClass('combobox-item-selected');
|
}
|
if (opts.groupField && group != g){
|
var grow = findRowBy(target, g, 'value', true);
|
if (grow){
|
$('#'+grow.domId).show();
|
}
|
group = g;
|
}
|
}
|
}
|
}
|
}
|
|
function doEnter(target){
|
var t = $(target);
|
var opts = t.combobox('options');
|
var panel = t.combobox('panel');
|
var item = panel.children('div.combobox-item-hover');
|
if (!item.length){
|
item = panel.children('div.combobox-item-selected');
|
}
|
if (!item.length){return}
|
var row = findRowBy(target, item.attr('id'), 'domId');
|
if (!row){return}
|
var value = row[opts.valueField];
|
if (opts.multiple){
|
if (item.hasClass('combobox-item-selected')){
|
t.combobox('unselect', value);
|
} else {
|
t.combobox('select', value);
|
}
|
} else {
|
t.combobox('select', value);
|
t.combobox('hidePanel');
|
}
|
var vv = [];
|
var values = t.combobox('getValues');
|
for(var i=0; i<values.length; i++){
|
if (findRowBy(target, values[i])){
|
vv.push(values[i]);
|
}
|
}
|
t.combobox('setValues', vv);
|
}
|
|
/**
|
* create the component
|
*/
|
function create(target){
|
var opts = $.data(target, 'combobox').options;
|
$(target).addClass('combobox-f');
|
$(target).combo($.extend({}, opts, {
|
onShowPanel: function(){
|
$(target).combo('panel').find('div.combobox-item,div.combobox-group').show();
|
scrollTo(target, $(target).combobox('getValue'));
|
opts.onShowPanel.call(target);
|
}
|
}));
|
|
$(target).combo('panel').unbind().bind('mouseover', function(e){
|
$(this).children('div.combobox-item-hover').removeClass('combobox-item-hover');
|
var item = $(e.target).closest('div.combobox-item');
|
if (!item.hasClass('combobox-item-disabled')){
|
item.addClass('combobox-item-hover');
|
}
|
e.stopPropagation();
|
}).bind('mouseout', function(e){
|
$(e.target).closest('div.combobox-item').removeClass('combobox-item-hover');
|
e.stopPropagation();
|
}).bind('click', function(e){
|
var item = $(e.target).closest('div.combobox-item');
|
if (!item.length || item.hasClass('combobox-item-disabled')){return}
|
var row = findRowBy(target, item.attr('id'), 'domId');
|
if (!row){return}
|
var value = row[opts.valueField];
|
if (opts.multiple){
|
if (item.hasClass('combobox-item-selected')){
|
unselect(target, value);
|
} else {
|
select(target, value);
|
}
|
} else {
|
select(target, value);
|
$(target).combo('hidePanel');
|
}
|
e.stopPropagation();
|
});
|
}
|
|
$.fn.combobox = function(options, param){
|
if (typeof options == 'string'){
|
var method = $.fn.combobox.methods[options];
|
if (method){
|
return method(this, param);
|
} else {
|
return this.combo(options, param);
|
}
|
}
|
|
options = options || {};
|
return this.each(function(){
|
var state = $.data(this, 'combobox');
|
if (state){
|
$.extend(state.options, options);
|
create(this);
|
} else {
|
state = $.data(this, 'combobox', {
|
options: $.extend({}, $.fn.combobox.defaults, $.fn.combobox.parseOptions(this), options),
|
data: []
|
});
|
create(this);
|
var data = $.fn.combobox.parseData(this);
|
if (data.length){
|
loadData(this, data);
|
}
|
}
|
if (state.options.data){
|
loadData(this, state.options.data);
|
}
|
request(this);
|
});
|
};
|
|
|
$.fn.combobox.methods = {
|
options: function(jq){
|
var copts = jq.combo('options');
|
return $.extend($.data(jq[0], 'combobox').options, {
|
originalValue: copts.originalValue,
|
disabled: copts.disabled,
|
readonly: copts.readonly
|
});
|
},
|
getData: function(jq){
|
return $.data(jq[0], 'combobox').data;
|
},
|
setValues: function(jq, values){
|
return jq.each(function(){
|
setValues(this, values);
|
});
|
},
|
setValue: function(jq, value){
|
return jq.each(function(){
|
setValues(this, [value]);
|
});
|
},
|
clear: function(jq){
|
return jq.each(function(){
|
$(this).combo('clear');
|
var panel = $(this).combo('panel');
|
panel.find('div.combobox-item-selected').removeClass('combobox-item-selected');
|
});
|
},
|
reset: function(jq){
|
return jq.each(function(){
|
var opts = $(this).combobox('options');
|
if (opts.multiple){
|
$(this).combobox('setValues', opts.originalValue);
|
} else {
|
$(this).combobox('setValue', opts.originalValue);
|
}
|
});
|
},
|
loadData: function(jq, data){
|
return jq.each(function(){
|
loadData(this, data);
|
});
|
},
|
reload: function(jq, url){
|
return jq.each(function(){
|
request(this, url);
|
});
|
},
|
select: function(jq, value){
|
return jq.each(function(){
|
select(this, value);
|
});
|
},
|
unselect: function(jq, value){
|
return jq.each(function(){
|
unselect(this, value);
|
});
|
}
|
};
|
|
$.fn.combobox.parseOptions = function(target){
|
var t = $(target);
|
return $.extend({}, $.fn.combo.parseOptions(target), $.parser.parseOptions(target,[
|
'valueField','textField','groupField','mode','method','url'
|
]));
|
};
|
|
$.fn.combobox.parseData = function(target){
|
var data = [];
|
var opts = $(target).combobox('options');
|
$(target).children().each(function(){
|
if (this.tagName.toLowerCase() == 'optgroup'){
|
var group = $(this).attr('label');
|
$(this).children().each(function(){
|
_parseItem(this, group);
|
});
|
} else {
|
_parseItem(this);
|
}
|
});
|
return data;
|
|
function _parseItem(el, group){
|
var t = $(el);
|
var row = {};
|
row[opts.valueField] = t.attr('value')!=undefined ? t.attr('value') : t.html();
|
row[opts.textField] = t.html();
|
row['selected'] = t.is(':selected');
|
row['disabled'] = t.is(':disabled');
|
if (group){
|
opts.groupField = opts.groupField || 'group';
|
row[opts.groupField] = group;
|
}
|
data.push(row);
|
}
|
};
|
|
$.fn.combobox.defaults = $.extend({}, $.fn.combo.defaults, {
|
valueField: 'value',
|
textField: 'text',
|
groupField: null,
|
groupFormatter: function(group){return group;},
|
mode: 'local', // or 'remote'
|
method: 'post',
|
url: null,
|
data: null,
|
|
keyHandler: {
|
up: function(e){nav(this,'prev');e.preventDefault()},
|
down: function(e){nav(this,'next');e.preventDefault()},
|
left: function(e){},
|
right: function(e){},
|
enter: function(e){doEnter(this)},
|
query: function(q,e){doQuery(this, q)}
|
},
|
filter: function(q, row){
|
var opts = $(this).combobox('options');
|
return row[opts.textField].toLowerCase().indexOf(q.toLowerCase()) == 0;
|
},
|
formatter: function(row){
|
var opts = $(this).combobox('options');
|
return row[opts.textField];
|
},
|
loader: function(param, success, error){
|
var opts = $(this).combobox('options');
|
if (!opts.url) return false;
|
$.ajax({
|
type: opts.method,
|
url: opts.url,
|
data: param,
|
dataType: 'json',
|
success: function(data){
|
success(data);
|
},
|
error: function(){
|
error.apply(this, arguments);
|
}
|
});
|
},
|
loadFilter: function(data){
|
return data;
|
},
|
|
onBeforeLoad: function(param){},
|
onLoadSuccess: function(){},
|
onLoadError: function(){},
|
onSelect: function(record){},
|
onUnselect: function(record){}
|
});
|
})(jQuery);
|