gdoo/public/assets/js/aggrid/celleditor/dropdown.js

454 lines
10 KiB
JavaScript

(function ($, undefined) {
var pluginName = 'agDropdownCellEditor',
dataKey = 'ag.dropdown.celleditor';
var defaults = {
maxHeight: 200
};
// Utility functions
var keys = {
ESC: 27,
TAB: 9,
RETURN: 13,
LEFT: 37,
UP: 38,
RIGHT: 39,
DOWN: 40,
ENTER: 13,
SHIFT: 16
}
/**
* Constructor
* @param {[Node]} element [Select element]
* @param {[Object]} options [Option object]
*/
var Plugin = function (input, options) {
this.grid = options.grid;
this.config = options.config;
this.items = options.data.items;
this.selected = options.data.selected;
this.hook = options.hook;
this.arrow = options.arrow || 'icon-search';
this.name = options.name;
this.onSelect = options.select || function() {};
this.$input = $(input);
// Settings
this.settings = $.extend({}, defaults, options);
// Initialize
this.init();
$.fn[pluginName].instances.push(this);
};
$.extend(Plugin.prototype, {
init: function () {
// Construct the comboselect
this._construct();
// Add event bindings
this._events();
},
_construct: function () {
var me = this;
// Wrap the Select
this.$container = $('<div class="combo-select combo-open combo-'+ me.name +'" />');
// Append dropdown arrow
this.$arrow = $('<div class="combo-arrow"><i class="fa '+ this.arrow + '"></i></div>');
// Append dropdown
this.$dropdown = $('<ul class="combo-dropdown" />').appendTo(this.$container);
// Create dropdown options
this._build();
this.$input.after(this.$arrow);
$('body').append(this.$container);
var height = this.$input.outerHeight();
var width = this.$input.outerWidth();
var offset = this.$input.offset();
this.$container.css({width: width + 2, left: offset.left - 1, top: offset.top + height + 1});
},
_build: function () {
var me = this;
var o = '', k = 0;
o += '<li class="option-item-empty">无匹配选项</li>';
$.each(this.items, function (i, e) {
if (e == 'optgroup') {
return o += '<li class="option-group">' + this.label + '</li>';
}
o += '<li class="' + (this.disabled ? 'option-disabled' : "option-item") + ' ' + (this.id == me.selected ? 'option-selected' : '') + '" data-index="' + (k) + '" data-value="' + this.id + '">' + (this.name) + '<i>' + this.code + '</i></li>';
k++;
})
this.$dropdown.html(o)
// Items
this.$items = this.$dropdown.children();
},
_events: function () {
var me = this;
this.$arrow.off();
this.$container.off();
this.$input.off();
// Dropdown Arrow: click
this.$arrow.on('click.arrow', $.proxy(this._toggle, this));
// Dropdown: close
this.$container.on('dropdown:close', $.proxy(this._close, this));
// Dropdown: open
this.$container.on('dropdown:open', $.proxy(this._open, this));
// Dropdown: update
this.$container.on('dropdown:update', $.proxy(this._update, this));
// Input: keydown
this.$input.on('keydown', $.proxy(this._keydown, this));
// Input: keyup
this.$input.on('keyup', $.proxy(this._keyup, this));
// Dropdown item: click
this.$container.on('click.item', '.option-item', $.proxy(this._select, this));
},
_keydown: function (event) {
switch (event.which) {
case keys.ESC:
this.$container.trigger('dropdown:close');
break;
case keys.UP:
this._move('up', event);
event.stopPropagation();
break;
case keys.DOWN:
this._move('down', event);
event.stopPropagation();
break;
case keys.TAB:
this._enter(event);
break;
case keys.RIGHT:
//this._autofill(event);
break;
case keys.ENTER:
this._enter(event);
break;
default:
break;
}
},
_keyup: function (event) {
switch (event.which) {
case keys.ESC:
case keys.ENTER:
case keys.UP:
case keys.DOWN:
case keys.LEFT:
case keys.RIGHT:
case keys.TAB:
case keys.SHIFT:
break;
default:
this._filter(event.target.value);
break;
}
},
_enter: function (event) {
var item = this._getHovered();
this._select(item);
},
_move: function (dir, event) {
var items = this._getVisible(),
current = this._getHovered(),
index = current.prevAll('.option-item').filter(':visible').length,
total = items.length;
switch (dir) {
case 'up':
index--;
(index < 0) && (index = (total - 1));
break;
case 'down':
index++;
(index >= total) && (index = 0);
break;
}
items.removeClass('option-hover')
.eq(index)
.addClass('option-hover');
if (!this.opened) this.$container.trigger('dropdown:open');
this._fixScroll();
},
_select: function (event) {
var item = event.currentTarget ? $(event.currentTarget) : $(event);
//if (!item.length) return;
var index = item.data('index');
this._selectByIndex(index);
this.$container.trigger('dropdown:close');
},
/**
* Set selected index and trigger change
* @type {[type]}
*/
_selectByIndex: function (index) {
if (typeof index == 'undefined') {
// 为空设置不选中
index = -1;
}
this._getAll()
.removeClass('option-selected')
.filter(function() {
return $(this).data('index') == index
}).addClass('option-selected')
this._change();
},
_autofill: function () {
var item = this._getHovered();
if (item.length) {
var index = item.data('index');
this._selectByIndex(index);
}
},
_filter: function (search) {
var self = this,
items = this._getAll(),
needle = $.trim(search).toLowerCase(),
reEscape = new RegExp('(\\' + ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\'].join('|\\') + ')', 'g'),
pattern = '(' + search.replace(reEscape, '\\$1') + ')';
// Unwrap all markers
$('.combo-marker', items).contents().unwrap();
// Search
if (needle) {
// Hide Disabled and optgroups
this.$items.filter('.option-group, .option-disabled').hide();
items
.hide()
.filter(function () {
var $this = $(this),
text = $.trim($this.text()).toLowerCase();
// Found
if (text.toString().indexOf(needle) != -1) {
// Wrap the selection
$this
.html(function (index, oldhtml) {
return oldhtml.replace(new RegExp(pattern, 'gi'), '<span class="combo-marker">$1</span>');
});
return true;
}
})
.show();
} else {
items.show();
}
// Open the dropdown
this.$container.trigger('dropdown:open');
// 搜索结果为不存在时候显示
if(this._getVisible().length == 0) {
this.$items.filter('.option-item-empty').show();
} else {
this.$items.filter('.option-item-empty').hide();
}
},
_highlight: function() {
/*
1. Check if there is a selected item
2. Add hover class to it
3. If not add hover class to first item
*/
var visible = this._getVisible().removeClass('option-hover'),
$selected = visible.filter('.option-selected');
if ($selected.length) {
$selected.addClass('option-hover');
} else {
visible.removeClass('option-hover')
.first()
.addClass('option-hover');
}
},
_updateInput: function() {
var item = this._getAll().filter('.option-selected');
var index = item.data('index');
this.onSelect.call(this, this.items[index]);
/*
if (index) {
this.onSelect.call(this, this.items[index]);
} else {
this.onSelect.call(this, this.items[index]);
}*/
},
_focus: function (event) {
// Toggle focus class
this.$container.toggleClass('combo-focus', !this.opened);
// Open combo
if (!this.opened) this.$container.trigger('dropdown:open');
},
_change: function () {
this._updateInput();
},
_getAll: function () {
return this.$items.filter('.option-item');
},
_getVisible: function () {
return this.$items.filter('.option-item').filter(':visible')
},
_getHovered: function () {
return this._getVisible().filter('.option-hover');
},
_open: function () {
var self = this
this.$container.addClass('combo-open');
this.$arrow.addClass('combo-arrow-open');
this.opened = true;
// Highligh the items
this._highlight();
// Fix scroll
this._fixScroll();
// Close all others
$.each($.fn[pluginName].instances, function(i, plugin) {
if (plugin != self && plugin.opened) plugin.$container.trigger('dropdown:close');
})
},
_toggle: function(e) {
this.opened ? this._close.call(this) : this._open.call(this);
this.$input.focus();
e.stopPropagation();
},
_close: function() {
this.$container.removeClass('combo-open combo-focus');
this.$arrow.removeClass('combo-arrow-open');
this.$container.trigger('dropdown:closed');
this.opened = false;
// Show all items
this.$items.filter('.option-item').show();
},
_fixScroll: function() {
// If dropdown is hidden
if (this.$dropdown.is(':hidden')) return;
// Else
var item = this._getHovered();
if (!item.length) return;
// Scroll
var offsetTop,
upperBound,
lowerBound,
heightDelta = item.outerHeight();
offsetTop = item[0].offsetTop;
upperBound = this.$dropdown.scrollTop();
lowerBound = upperBound + this.settings.maxHeight - heightDelta;
if (offsetTop < upperBound) {
this.$dropdown.scrollTop(offsetTop);
} else if (offsetTop > lowerBound) {
this.$dropdown.scrollTop(offsetTop - this.settings.maxHeight + heightDelta);
}
},
/**
* 更新
*/
_update: function() {
this.$dropdown.empty();
this._build();
},
/**
* 销毁
*/
dispose: function() {
// 删除dom
this.$arrow.remove();
this.$input.remove();
this.$dropdown.remove();
}
});
$.fn[pluginName] = function(options, args) {
this.each(function() {
var $e = $(this),
instance = $e.data('plugin_' + dataKey);
if (typeof options === 'string') {
if (instance && typeof instance[options] === 'function') {
instance[options](args);
}
} else {
if (instance && instance.dispose) {
instance.dispose();
}
$.data(this, "plugin_" + dataKey, new Plugin(this, options));
}
});
return this;
};
$.fn[pluginName].instances = [];
})(jQuery);