/** * @uses jQuery * @class */ var Qs_Form_Element_MultiDraggableSelect = (function () { var _namespace = 'multiDraggableSelect'; var _module = function() { this.initialize.apply(this, arguments); }; _module.defaultOptions = { elementId: undefined, filterDelay: 200 }; _module.prototype = { initialize: function (options) { this.cache = { availableItemTexts: [] }; this.options = $.extend({}, _module.defaultOptions, options); this.element = $('#' + this.options.elementId); this.availableList = this.element.find('.availableList'); this.selectedList = this.element.find('.selectedList'); this.countField = this.element.find('.selectedCount'); this.filterField = this.element.find('input.filter'); if (this.element.size() && this.availableList.size() && this.selectedList.size()) { this.initToolbars(); this.initLists(); } else { alert('Can not initialize element ' + _namespace); } return this; }, initToolbars: function () { this.updateSelectedCount(); this.bindLinksEvents(); this.bindFilterEvents(); return this; }, updateSelectedCount: function () { var count = this.selectedList.children('li.item').size(); this.countField.text(count); return this; }, bindLinksEvents: function () { var that = this; this.element.find('.availableToolbar a.addAll').bind('click.' + _namespace, function () { that.onAddAllClick.apply(that, arguments); }); this.element.find('.selectedToolbar a.removeAll').bind('click.' + _namespace, function () { that.onRemoveAllClick.apply(that, arguments); }); return this; }, bindFilterEvents: function() { var that = this, filterTimer; this.filterField.bind('focus.' + _namespace, function() { $(this).addClass('active'); }); this.filterField.bind('blur.' + _namespace, function() { $(this).removeClass('active'); }); this.filterField.bind('keypress.' + _namespace, function(e) { if (e.keyCode == 13) { return false; } }); this.filterField.bind('keyup.' + _namespace, function() { clearTimeout(filterTimer); filterTimer = setTimeout(function () { that.filterAvailableItems(); }, that.options.filterDelay); }); }, /** * @param {String} [query] */ filterAvailableItems: function(query) { query = (undefined === query) ? $.trim(this.filterField.val().toLowerCase()) : query; var cache, items = this.availableList.children('li.item'); if (query) { if ((cache = this.getAvailableItemsCache()) && items.length === cache.length) { var visibleItems = []; for (var i = 0, l = cache.length; i < l; ++i) { if (-1 !== cache[i].indexOf(query)) { visibleItems.push(items[i]); } } items.hide(); $(visibleItems).show(); } else { this.cleanAvailableItemsCache(); } } else { items.show(); } }, cleanAvailableItemsCache: function () { this.cache.availableItemTexts = []; return this; }, getAvailableItemsCache: function () { var that = this; if (!this.cache.availableItemTexts || !this.cache.availableItemTexts.length) { var cache = []; this.availableList.children('li.item').each(function (i, node) { cache.push($.trim(('' + that.getNodeText(node)).toLowerCase())); }); this.cache.availableItemTexts = cache; } return this.cache.availableItemTexts; }, getNodeText: function (target) { var text, node = (target instanceof jQuery) ? target.get(0) : target; if (node && node.childNodes) { for (var i = node.childNodes.length - 1; i >= 0; --i) { if (3 === node.childNodes[i].nodeType) { text = node.childNodes[i].nodeValue; break; } } } return text; }, initLists: function () { var that = this; this.updateInputsState(this.availableList, false); this.availableList.children('li.item').bind('dblclick.' + _namespace, function () { that.onItemDblClick.apply(that, arguments); }); this.selectedList.children('li.item').bind('dblclick.' + _namespace, function () { that.onItemDblClick.apply(that, arguments); }); this.availableList.sortable({ connectWith: '#' + this.options.elementId + ' .selectedList', containment: this.element, placeholder: 'ui-state-highlight', distance: 5, items: '> li.item', update: function () { that.onSortableUpdate.apply(that, arguments); } }).disableSelection(); this.selectedList.sortable({ connectWith: '#' + this.options.elementId + ' .availableList', containment: this.element, placeholder: 'ui-state-highlight', distance: 5, items: '> li.item', update: function () { that.onSortableUpdate.apply(that, arguments); } }).disableSelection(); return this; }, /** * @param {jQuery|HTMLElement} context * @param {Boolean} enable * @return {*} */ updateInputsState: function (context, enable) { if (enable) { $('input[disabled]', context).removeAttr('disabled'); } else { $('input:not([disabled])', context).attr('disabled', 'disabled'); } return this; }, onSortableUpdate: function (e, ui) { this.cleanAvailableItemsCache(); if (ui.sender) { var enable = (ui.sender.get(0) !== this.selectedList.get(0)); this.updateInputsState(ui.item, enable); this.updateSelectedCount(); } return this; }, onAddAllClick: function (e) { e.preventDefault(); var items = this.availableList.children('li.item').detach().show(); this.updateInputsState(items, true); this.selectedList.append(items); this.cleanAvailableItemsCache(); this.updateSelectedCount(); return this; }, onRemoveAllClick: function (e) { e.preventDefault(); var items = this.selectedList.children('li.item').detach(); this.updateInputsState(items, false); this.availableList.append(items); this.cleanAvailableItemsCache(); this.filterAvailableItems(); this.updateSelectedCount(); return this; }, onItemDblClick: function (e) { e.preventDefault(); var item = $(e.currentTarget), toSelected = (item.parent().get(0) === this.availableList.get(0)); item.detach(); this.updateInputsState(item, toSelected); item.appendTo(toSelected ? this.selectedList : this.availableList); this.cleanAvailableItemsCache(); this.filterAvailableItems(); this.updateSelectedCount(); return this; } }; return _module; })();