/** * jQuery Selective v0.3.5 * https://github.com/amazingSurge/jquery-selective * * Copyright (c) amazingSurge * Released under the LGPL-3.0 license */ import $$1 from 'jquery'; /*eslint no-empty-function: "off"*/ var DEFAULTS = { namespace: 'selective', buildFromHtml: true, closeOnSelect: false, local: null, selected: null, withSearch: false, searchType: null, //'change' or 'keyup' ajax: { work: false, url: null, quietMills: null, loadMore: false, pageSize: null }, query: function() {}, //function(api, search_text, page) {}, tpl: { frame: function() { return `
${this.options.tpl.triggerButton.call(this)}
${this.options.tpl.list.call(this)}
${this.options.tpl.items.call(this)}
`; }, search: function() { return ``; }, select: function() { return ``; }, optionValue: function(data) { if('name' in data) { return data.name; } return data; }, option: function(content) { return ``; }, items: function() { return ``; }, item: function(content) { return `
  • ${content}${this.options.tpl.itemRemove.call(this)}
  • `; }, itemRemove: function() { return `x`; }, triggerButton: function() { return `
    Add
    `; }, list: function() { return ``; }, listItem: function(content) { return `
  • ${content}
  • `; } }, onBeforeShow: null, onAfterShow: null, onBeforeHide: null, onAfterHide: null, onBeforeSearch: null, onAfterSearch: null, onBeforeSelected: null, onAfterSelected: null, onBeforeUnselect: null, onAfterUnselect: null, onBeforeItemRemove: null, onAfterItemRemove: null, onBeforeItemAdd: null, onAfterItemAdd: null }; class Options { constructor(instance) { this.instance = instance; } getOptions() { this.instance.$options = this.instance.$select.find('option'); return this.instance.$options; } select(opt) { $(opt).prop('selected', true); return this.instance; } unselect(opt) { $(opt).prop('selected', false); return this.instance; } add(data) { /*eslint consistent-return: "off"*/ if (this.instance.options.buildFromHtml === false && this.instance.getItem('option', this.instance.$select, this.instance.options.tpl.optionValue(data)) === undefined) { const $option = $(this.instance.options.tpl.option.call(this.instance, data)); this.instance.setIndex($option, data); this.instance.$select.append($option); return $option; } } remove(opt) { $(opt).remove(); return this.instance; } } class List { constructor(instance) { this.instance = instance; } build(data) { const $list = $(''); const $options = this.instance._options.getOptions(); if (this.instance.options.buildFromHtml === true) { if ($options.length !== 0) { $.each($options, (i, n) => { const $li = $(this.instance.options.tpl.listItem.call(this.instance, n.text)); const $n = $(n); this.instance.setIndex($li, $n); if ($n.attr('selected') !== undefined) { this.instance.select($li); } $list.append($li); }); } } else if (data !== null) { $.each(data, i => { const $li = $(this.instance.options.tpl.listItem.call(this.instance, data[i])); this.instance.setIndex($li, data[i]); $list.append($li); }); if ($options.length !== 0) { $.each($options, (i, n) => { const $n = $(n); const li = this.instance.getItem('li', $list, this.instance.options.tpl.optionValue($n.data('selective_index'))); if (li !== undefined) { this.instance._list.select(li); } }); } } this.instance.$list.append($list.children('li')); return this.instance; } buildSearch() { if (this.instance.options.withSearch === true) { this.instance.$triggerDropdown.prepend(this.instance.options.tpl.search.call(this.instance)); this.instance.$search = this.instance.$triggerDropdown.find(`.${this.instance.namespace}-search`); } return this.instance; } select(obj) { this.instance._trigger("beforeSelected"); $(obj).addClass(`${this.instance.namespace}-selected`); this.instance._trigger("afterSelected"); return this.instance; } unselect(obj) { this.instance._trigger("beforeUnselected"); $(obj).removeClass(`${this.instance.namespace}-selected`); this.instance._trigger("afterUnselected"); return this.instance; } click() { const that = this; this.instance.$list.on('click', 'li', function() { const $this = $(this); if (!$this.hasClass(`${that.instance.namespace}-selected`)) { that.instance.select($this); } }); } filter(val) { $.expr[':'].Contains = (a, i, m) => jQuery(a).text().toUpperCase().includes(m[3].toUpperCase()); if (val) { this.instance.$list.find(`li:not(:Contains(${val}))`).slideUp(); this.instance.$list.find(`li:Contains(${val})`).slideDown(); } else { this.instance.$list.children('li').slideDown(); } return this.instance; } loadMore() { const pageMax = this.instance.options.ajax.pageSize || 9999; this.instance.$listWrap.on('scroll.selective', () => { if (pageMax > this.instance.page) { const listHeight = this.instance.$list.outerHeight(true); const wrapHeight = this.instance.$listWrap.outerHeight(); const wrapScrollTop = this.instance.$listWrap.scrollTop(); const below = listHeight - wrapHeight - wrapScrollTop; if (below === 0) { this.instance.options.query(this.instance, this.instance.$search.val(), ++this.instance.page); } } }); return this.instance; } loadMoreRemove() { this.instance.$listWrap.off('scroll.selective'); return this.instance; } } class Search { constructor(instance) { this.instance = instance; } change() { this.instance.$search.change(() => { this.instance._trigger("beforeSearch"); if (this.instance.options.buildFromHtml === true) { this.instance._list.filter(this.instance.$search.val()); } else if (this.instance.$search.val() !== '') { this.instance.page = 1; this.instance.options.query(this.instance, this.instance.$search.val(), this.instance.page); } else { this.instance.update(this.instance.options.local); } this.instance._trigger("afterSearch"); }); } keyup() { const quietMills = this.instance.options.ajax.quietMills || 1000; let oldValue = ''; let currentValue = ''; let timeout; this.instance.$search.on('keyup', e => { this.instance._trigger("beforeSearch"); currentValue = this.instance.$search.val(); if (this.instance.options.buildFromHtml === true) { if (currentValue !== oldValue) { this.instance._list.filter(currentValue); } } else if (currentValue !== oldValue || e.keyCode === 13) { window.clearTimeout(timeout); timeout = window.setTimeout(() => { if (currentValue !== '') { this.instance.page = 1; this.instance.options.query(this.instance, currentValue, this.instance.page); } else { this.instance.update(this.instance.options.local); } }, quietMills); } oldValue = currentValue; this.instance._trigger("afterSearch"); }); } bind(type) { if (type === 'change') { this.change(); } else if (type === 'keyup') { this.keyup(); } } } class Items { constructor(instance) { this.instance = instance; } withDefaults(data) { if (data !== null) { $.each(data, i => { this.instance._options.add(data[i]); this.instance._options.select(this.instance.getItem('option', this.instance.$select, this.instance.options.tpl.optionValue(data[i]))); this.instance._items.add(data[i]); }); } } add(data, content) { let $item; let fill; if (this.instance.options.buildFromHtml === true) { fill = content; } else { fill = data; } $item = $(this.instance.options.tpl.item.call(this.instance, fill)); this.instance.setIndex($item, data); this.instance.$items.append($item); } remove(obj) { obj = $(obj); let $li; let $option; if (this.instance.options.buildFromHtml === true) { this.instance._list.unselect(obj.data('selective_index')); this.instance._options.unselect(obj.data('selective_index').data('selective_index')); } else { $li = this.instance.getItem('li', this.instance.$list, this.instance.options.tpl.optionValue(obj.data('selective_index'))); if ($li !== undefined) { this.instance._list.unselect($li); } $option = this.instance.getItem('option', this.instance.$select, this.instance.options.tpl.optionValue(obj.data('selective_index'))); this.instance._options.unselect($option)._options.remove($option); } obj.remove(); return this.instance; } click() { const that = this; this.instance.$items.on('click', `.${this.instance.namespace}-remove`, function() { const $this = $(this); const $item = $this.parents('li'); that.instance.itemRemove($item); }); } } const NAMESPACE$1 = 'selective'; /** * Plugin constructor **/ class Selective { constructor(element, options = {}) { this.element = element; this.$element = $$1(element).hide() || $$1(''); this.options = $$1.extend(true, {}, DEFAULTS, options); this.namespace = this.options.namespace; const $frame = $$1(this.options.tpl.frame.call(this)); //get the select const _build = () => { this.$element.html(this.options.tpl.select.call(this)); return this.$element.children('select'); }; this.$select = this.$element.is('select') === true ? this.$element : _build(); this.$element.after($frame); this.init(); this.opened = false; } init() { this.$selective = this.$element.next(`.${this.namespace}`); this.$items = this.$selective.find(`.${this.namespace}-items`); this.$trigger = this.$selective.find(`.${this.namespace}-trigger`); this.$triggerButton = this.$selective.find(`.${this.namespace}-trigger-button`); this.$triggerDropdown = this.$selective.find(`.${this.namespace}-trigger-dropdown`); this.$listWrap = this.$selective.find(`.${this.namespace}-list-wrap`); this.$list = this.$selective.find(`.${this.namespace}-list`); this._list = new List(this); this._options = new Options(this); this._search = new Search(this); this._items = new Items(this); this._items.withDefaults(this.options.selected); this.update(this.options.local)._list.buildSearch(); this.$triggerButton.on('click', () => { if (this.opened === false) { this.show(); } else { this.hide(); } }); this._list.click(this); this._items.click(this); if (this.options.withSearch === true) { this._search.bind(this.options.searchType); } this._trigger('ready'); } _trigger(eventType, ...params) { let data = [this].concat(params); // event this.$element.trigger(`${NAMESPACE$1}::${eventType}`, data); // callback eventType = eventType.replace(/\b\w+\b/g, (word) => { return word.substring(0, 1).toUpperCase() + word.substring(1); }); let onFunction = `on${eventType}`; if (typeof this.options[onFunction] === 'function') { this.options[onFunction].apply(this, params); } } _show() { $$1(document).on('click.selective', e => { if (this.options.closeOnSelect === true) { if ($$1(e.target).closest(this.$triggerButton).length === 0 && $$1(e.target).closest(this.$search).length === 0) { this._hide(); } } else if ($$1(e.target).closest(this.$trigger).length === 0) { this._hide(); } }); this.$trigger.addClass(`${this.namespace}-active`); this.opened = true; if (this.options.ajax.loadMore === true) { this._list.loadMore(); } return this; } _hide() { $$1(document).off('click.selective'); this.$trigger.removeClass(`${this.namespace}-active`); this.opened = false; if (this.options.ajax.loadMore === true) { this._list.loadMoreRemove(); } return this; } show() { this._trigger("beforeShow"); this._show(); this._trigger("afterShow"); return this; } hide() { this._trigger("beforeHide"); this._hide(); this._trigger("afterHide"); return this; } select($li) { this._list.select($li); const data = $li.data('selective_index'); if (this.options.buildFromHtml === true) { this._options.select(data); this.itemAdd($li, data.text()); } else { this._options.add(data); this._options.select(this.getItem('option', this.$select, this.options.tpl.optionValue(data))); this.itemAdd(data); } return this; } unselect($li) { this._list.unselect($li); return this; } setIndex(obj, index) { obj.data('selective_index', index); return this; } getItem(type, $list, index) { const $items = $list.children(type); let position = ''; for (let i = 0; i < $items.length; i++) { if (this.options.tpl.optionValue($items.eq(i).data('selective_index')) === index) { position = i; } } return position === '' ? undefined : $items.eq(position); } itemAdd(data, content) { this._trigger("beforeItemAdd"); this._items.add(data, content); this._trigger("afterItemAdd"); return this; } itemRemove($li) { this._trigger("beforeItemRemove"); this._items.remove($li); this._trigger("afterItemRemove"); return this; } optionAdd(data) { this._options.add(data); return this; } optionRemove(opt) { this._options.remove(opt); return this; } update(data) { this.$list.empty(); this.page = 1; if (data !== null) { this._list.build(data); } else { this._list.build(); } return this; } destroy() { this.$selective.remove(); this.$element.show(); $$1(document).off('click.selective'); this._trigger('destroy'); } static setDefaults(options) { $$1.extend(true, DEFAULTS, $$1.isPlainObject(options) && options); } } var info = { version:'0.3.5' }; const NAMESPACE = 'selective'; const OtherSelective = $$1.fn.selective; const jQuerySelective = function(options, ...args) { if (typeof options === 'string') { const method = options; if (/^_/.test(method)) { return false; } else if ((/^(get)/.test(method))) { const instance = this.first().data(NAMESPACE); if (instance && typeof instance[method] === 'function') { return instance[method](...args); } } else { return this.each(function() { const instance = $$1.data(this, NAMESPACE); if (instance && typeof instance[method] === 'function') { instance[method](...args); } }); } } return this.each(function() { if (!$$1(this).data(NAMESPACE)) { $$1(this).data(NAMESPACE, new Selective(this, options)); } }); }; $$1.fn.selective = jQuerySelective; $$1.selective = $$1.extend({ setDefaults: Selective.setDefaults, noConflict: function() { $$1.fn.selective = OtherSelective; return jQuerySelective; } }, info);