696 lines
17 KiB
JavaScript
696 lines
17 KiB
JavaScript
|
|
import './selectize.html';
|
|
|
|
/* Meteor need globals */
|
|
/* eslint strict: 0 */
|
|
/* jshint strict: false */
|
|
|
|
UniSelectize = function (options, template) {
|
|
this.items = new ReactiveVar([]);
|
|
this.itemsSelected = new ReactiveVar([]);
|
|
this.itemsUnselected = new ReactiveVar([]);
|
|
|
|
this.open = new ReactiveVar(false);
|
|
this.loading = new ReactiveVar(false);
|
|
this.searchText = new ReactiveVar();
|
|
this.activeOption = new ReactiveVar(-1);
|
|
this.inputPosition = new ReactiveVar(-1);
|
|
this.optionsMethodParams = new ReactiveVar();
|
|
|
|
this.create = options.create;
|
|
this.template = template;
|
|
this.multiple = options.multiple;
|
|
this.sortMethod = _.isUndefined(options.sortMethod) ? 'label' : options.sortMethod;
|
|
this.placeholder = options.placeholder;
|
|
this.removeButton = options.removeButton !== false;
|
|
this.createMethod = options.createMethod;
|
|
this.optionsMethod = options.optionsMethod;
|
|
this.optionsPlaceholder = options.optionsPlaceholder;
|
|
|
|
};
|
|
|
|
UniSelectize.prototype.triggerChangeEvent = function() {
|
|
var self = this;
|
|
Meteor.defer(function () {
|
|
$(self.template.find('select')).change();
|
|
});
|
|
};
|
|
|
|
|
|
UniSelectize.prototype.setItems = function (items, value) {
|
|
if (!_.isArray(items)) {
|
|
console.warn('invalid options format');
|
|
}
|
|
|
|
var values = value && (_.isArray(value) ? value : [value]);
|
|
|
|
items = _.filter(items, function (item) {
|
|
if (!item.value || !item.label) {
|
|
console.info('invalid option', item);
|
|
return false;
|
|
}
|
|
return true;
|
|
});
|
|
|
|
var itemValues = items.map(function (item) {
|
|
return item.value;
|
|
});
|
|
|
|
_.each(values, function (val) {
|
|
if (!_.contains(itemValues, val) && val) {
|
|
items.push({
|
|
value: val,
|
|
label: val
|
|
});
|
|
}
|
|
});
|
|
|
|
_.each(items, function (item) {
|
|
if (_.contains(values, item.value)) {
|
|
item.selected = true;
|
|
}
|
|
});
|
|
this.items.set(items);
|
|
};
|
|
|
|
UniSelectize.prototype.addItems = function (newItems, value) {
|
|
if (!_.isArray(newItems)) {
|
|
console.warn('invalid options format');
|
|
}
|
|
|
|
var values = value && (_.isArray(value) ? value : [value]);
|
|
var items = this.items.get();
|
|
var itemsValues = items.map(function (item) {
|
|
return item.value;
|
|
});
|
|
|
|
_.each(newItems, function (newItem) {
|
|
if (!newItem.value || !newItem.label) {
|
|
console.info('invalid option', newItem);
|
|
return;
|
|
}
|
|
|
|
if (!_.contains(itemsValues, newItem.value)) {
|
|
var item = {
|
|
value: newItem.value,
|
|
label: newItem.label,
|
|
selected: newItem.selected
|
|
};
|
|
|
|
if (_.contains(values, newItem.value)) {
|
|
item.selected = true;
|
|
}
|
|
|
|
items.push(item);
|
|
} else if (typeof newItem.selected !== 'undefined') {
|
|
var item = _.find(items, function (item) {
|
|
return item.value === newItem.value;
|
|
});
|
|
item.selected = newItem.selected;
|
|
}
|
|
});
|
|
|
|
this.items.set(items);
|
|
};
|
|
|
|
|
|
UniSelectize.prototype.removeUnusedItems = function (newItems) {
|
|
if (!_.isArray(newItems)) {
|
|
console.warn('invalid options format');
|
|
}
|
|
|
|
var items = this.items.get();
|
|
var newItemsValues = newItems.map(function (item) {
|
|
return item.value;
|
|
});
|
|
|
|
items = _.filter(items, function (item) {
|
|
return _.contains(newItemsValues, item.value) || item.selected;
|
|
});
|
|
|
|
this.items.set(items);
|
|
};
|
|
|
|
UniSelectize.prototype.itemsAutorun = function () {
|
|
var items = this.items.get();
|
|
var itemsSelected = [];
|
|
var itemsUnselected = [];
|
|
|
|
_.each(items, function (item) {
|
|
if (item.selected) {
|
|
itemsSelected.push(item);
|
|
} else {
|
|
itemsUnselected.push(item);
|
|
}
|
|
});
|
|
|
|
if (this.sortMethod) {
|
|
itemsSelected = _.sortBy(itemsSelected, this.sortMethod);
|
|
itemsUnselected = _.sortBy(itemsUnselected, this.sortMethod);
|
|
}
|
|
|
|
var itemsSelectedPrev = this.itemsSelected.get();
|
|
if (!_.isEqual(itemsSelectedPrev, itemsSelected)) {
|
|
this.itemsSelected.set(itemsSelected);
|
|
}
|
|
|
|
if (this.placeholder && this.optionsPlaceholder) {
|
|
itemsUnselected.unshift({
|
|
value: '',
|
|
label: _.isString(this.optionsPlaceholder) ? this.optionsPlaceholder: this.placeholder
|
|
});
|
|
}
|
|
|
|
this.itemsUnselected.set(itemsUnselected);
|
|
};
|
|
|
|
UniSelectize.prototype.itemsSelectedAutorun = function () {
|
|
var itemsSelected = this.template.uniSelectize.itemsSelected.get();
|
|
this.template.uniSelectize.inputPosition.set(itemsSelected.length - 1);
|
|
};
|
|
|
|
UniSelectize.prototype.inputFocus = function () {
|
|
var self = this;
|
|
Meteor.defer(function () {
|
|
var $input = $(self.template.find('input'));
|
|
$input.focus();
|
|
});
|
|
};
|
|
|
|
UniSelectize.prototype.selectItem = function (value) {
|
|
var items = this.items.get();
|
|
var multiple = this.multiple;
|
|
|
|
_.each(items, function (item) {
|
|
if (value === '') {
|
|
item.selected = false;
|
|
} else if (item.value === value) {
|
|
item.selected = true;
|
|
} else if (!multiple) {
|
|
item.selected = false;
|
|
}
|
|
});
|
|
|
|
this.setItems(items);
|
|
this.triggerChangeEvent();
|
|
};
|
|
|
|
UniSelectize.prototype.unselectItem = function (value, reset) {
|
|
var items = this.items.get();
|
|
|
|
_.each(items, function (item) {
|
|
if (item.value === value || reset) {
|
|
item.selected = false;
|
|
}
|
|
});
|
|
|
|
this.setItems(items);
|
|
this.triggerChangeEvent()
|
|
};
|
|
|
|
UniSelectize.prototype.removeItemBeforeInput = function () {
|
|
var items = this.itemsSelected.get();
|
|
var inputPosition = this.inputPosition.get();
|
|
var itemToRemove;
|
|
|
|
_.each(items, function (item, index) {
|
|
if (index === inputPosition) {
|
|
itemToRemove = item;
|
|
}
|
|
});
|
|
|
|
if (itemToRemove) {
|
|
this.unselectItem(itemToRemove.value, false);
|
|
}
|
|
};
|
|
|
|
UniSelectize.prototype.removeItemAfterInput = function () {
|
|
var items = this.itemsSelected.get();
|
|
var inputPosition = this.inputPosition.get();
|
|
var itemToRemove;
|
|
|
|
_.each(items, function (item, index) {
|
|
if (index === inputPosition + 1) {
|
|
itemToRemove = item;
|
|
}
|
|
});
|
|
|
|
if (itemToRemove) {
|
|
this.unselectItem(itemToRemove.value, false);
|
|
}
|
|
};
|
|
|
|
UniSelectize.prototype.selectActiveItem = function () {
|
|
var itemsUnselected = this.getItemsUnselectedFiltered();
|
|
var activeOption = this.activeOption.get();
|
|
var itemToSelect = itemsUnselected && itemsUnselected[activeOption];
|
|
|
|
if (activeOption === itemsUnselected.length && this.create) {
|
|
this.createItem();
|
|
return;
|
|
}
|
|
|
|
itemToSelect && this.selectItem(itemToSelect.value);
|
|
|
|
if (this.multiple) {
|
|
this.open.set(true);
|
|
this.inputFocus();
|
|
} else {
|
|
this.open.set(false);
|
|
}
|
|
};
|
|
|
|
UniSelectize.prototype.insertItem = function (item) {
|
|
var items = this.items.get();
|
|
|
|
if (!_.find(items, function (obj) {
|
|
if (obj.value === item.value) {
|
|
obj.selected = item.selected;
|
|
return true;
|
|
}
|
|
return false;
|
|
})) {
|
|
items.push(item);
|
|
}
|
|
|
|
this.setItems(items);
|
|
this.triggerChangeEvent();
|
|
};
|
|
|
|
UniSelectize.prototype.createItem = function () {
|
|
var self = this;
|
|
var template = this.template;
|
|
var searchText = this.searchText.get();
|
|
|
|
if (!searchText) {
|
|
return false;
|
|
}
|
|
|
|
var item = {
|
|
label: searchText,
|
|
value: searchText,
|
|
selected: true
|
|
};
|
|
|
|
if (template.uniSelectize.createMethod) {
|
|
Meteor.call(template.uniSelectize.createMethod, searchText, searchText, function (error, value) {
|
|
if (error) {
|
|
console.error('universe selectize create method error:', error);
|
|
return;
|
|
}
|
|
|
|
Meteor.defer(function () {
|
|
item.value = value || item.value;
|
|
self.insertItem(item);
|
|
});
|
|
});
|
|
} else {
|
|
this.insertItem(item);
|
|
}
|
|
|
|
if (this.multiple) {
|
|
this.inputFocus();
|
|
} else {
|
|
this.open.set(false);
|
|
}
|
|
};
|
|
|
|
UniSelectize.prototype.getItemsUnselectedFiltered = function () {
|
|
var items = this.itemsUnselected.get();
|
|
var searchText = this.searchText.get();
|
|
|
|
return _.filter(items, function (item) {
|
|
if (item.label && item.label.search(new RegExp(searchText, 'i')) !== -1) {
|
|
return true;
|
|
}
|
|
return false;
|
|
});
|
|
};
|
|
|
|
|
|
UniSelectize.prototype.checkDisabled = function () {
|
|
if (this.template.data.disabled) {
|
|
throw new Meteor.Error('This field is disabled');
|
|
}
|
|
};
|
|
|
|
UniSelectize.prototype.measureString = function (str, $parent) {
|
|
if (!str) {
|
|
return 0;
|
|
}
|
|
|
|
var $test = $('<test>').css({
|
|
position: 'absolute',
|
|
top: -99999,
|
|
left: -99999,
|
|
width: 'auto',
|
|
padding: 0,
|
|
whiteSpace: 'pre'
|
|
}).text(str).appendTo('body');
|
|
|
|
this.transferStyles($parent, $test, [
|
|
'letterSpacing',
|
|
'fontSize',
|
|
'fontFamily',
|
|
'fontWeight',
|
|
'textTransform'
|
|
]);
|
|
|
|
var width = $test.width();
|
|
$test.remove();
|
|
|
|
return width;
|
|
};
|
|
|
|
UniSelectize.prototype.transferStyles = function ($from, $to, properties) {
|
|
var i, n, styles = {};
|
|
|
|
if (properties) {
|
|
for (i = 0, n = properties.length; i < n; i++) {
|
|
styles[properties[i]] = $from.css(properties[i]);
|
|
}
|
|
} else {
|
|
styles = $from.css();
|
|
}
|
|
|
|
$to.css(styles);
|
|
};
|
|
|
|
UniSelectize.prototype.getOptionsFromMethod = function (values) {
|
|
var self = this;
|
|
var methodName = this.optionsMethod;
|
|
var searchText = this.searchText.get();
|
|
var params = this.optionsMethodParams.get();
|
|
|
|
if (!methodName) {
|
|
return false;
|
|
}
|
|
|
|
var searchVal = {
|
|
searchText: searchText,
|
|
values: values || [],
|
|
params: params || null
|
|
};
|
|
|
|
self.loading.set(true);
|
|
Meteor.call(methodName, searchVal, function (err, options) {
|
|
self.loading.set(false);
|
|
if (params) {
|
|
self.removeUnusedItems(options);
|
|
}
|
|
self.addItems(options, values);
|
|
});
|
|
};
|
|
|
|
Template.Selectize.onCreated(function () {
|
|
var template = this;
|
|
template.uniSelectize = new UniSelectize(template.data, template);
|
|
});
|
|
|
|
Template.Selectize.onRendered(function () {
|
|
var template = this;
|
|
|
|
template.autorun(function () {
|
|
var data = Template.currentData();
|
|
var value = data.value;
|
|
|
|
if (template.uniSelectize.optionsMethod) {
|
|
template.uniSelectize.getOptionsFromMethod(value);
|
|
} else {
|
|
var options = data.options;
|
|
template.uniSelectize.setItems(options, value);
|
|
}
|
|
});
|
|
|
|
template.autorun(function () {
|
|
template.uniSelectize.itemsAutorun();
|
|
});
|
|
|
|
template.autorun(function () {
|
|
template.uniSelectize.itemsSelectedAutorun();
|
|
});
|
|
|
|
template.autorun(function () {
|
|
var data = Template.currentData();
|
|
var methodParams = data.optionsMethodParams;
|
|
var params = _.isFunction(methodParams) ? methodParams() : methodParams;
|
|
|
|
template.uniSelectize.optionsMethodParams.set(params);
|
|
});
|
|
|
|
this.form = $(template.find('select')).parents('form');
|
|
this.form.bind('reset', function () {
|
|
template.uniSelectize.unselectItem(null, true);
|
|
});
|
|
});
|
|
|
|
Template.Selectize.onDestroyed(function () {
|
|
if (this.form) {
|
|
this.form.unbind('reset');
|
|
}
|
|
});
|
|
|
|
Template.Selectize.helpers({
|
|
multiple: function () {
|
|
var template = Template.instance();
|
|
return template.uniSelectize.multiple;
|
|
},
|
|
removeButton: function () {
|
|
var template = Template.instance();
|
|
return template.uniSelectize.multiple && template.uniSelectize.removeButton;
|
|
},
|
|
getItems: function () {
|
|
var template = Template.instance();
|
|
return template.uniSelectize.items.get();
|
|
},
|
|
getItemsSelected: function () {
|
|
var template = Template.instance();
|
|
return template.uniSelectize.itemsSelected.get();
|
|
},
|
|
getItemsUnselected: function () {
|
|
var template = Template.instance();
|
|
return template.uniSelectize.getItemsUnselectedFiltered();
|
|
},
|
|
getSearchText: function () {
|
|
var template = Template.instance();
|
|
return template.uniSelectize.searchText.get();
|
|
},
|
|
open: function () {
|
|
var template = Template.instance();
|
|
return template.uniSelectize.open.get();
|
|
},
|
|
loading: function () {
|
|
var template = Template.instance();
|
|
return template.uniSelectize.loading.get();
|
|
},
|
|
inputPosition: function (position) {
|
|
var template = Template.instance();
|
|
var inputPosition = template.uniSelectize.inputPosition.get();
|
|
return position === inputPosition;
|
|
},
|
|
activeOption: function (position) {
|
|
var template = Template.instance();
|
|
var activeOption = template.uniSelectize.activeOption.get();
|
|
var itemsUnselected = template.uniSelectize.getItemsUnselectedFiltered();
|
|
var createOption = template.uniSelectize.create;
|
|
|
|
if (activeOption === itemsUnselected.length && createOption) {
|
|
return position === 'create';
|
|
}
|
|
|
|
return position === activeOption;
|
|
},
|
|
getPlaceholder: function () {
|
|
var template = Template.instance();
|
|
var itemsSelected = template.uniSelectize.itemsSelected.get();
|
|
|
|
if (itemsSelected.length) {
|
|
return false;
|
|
}
|
|
|
|
return template.uniSelectize.placeholder;
|
|
},
|
|
isPlaceholder: function () {
|
|
return this.value === '' ? 'uniPlaceholder' : '';
|
|
}
|
|
});
|
|
|
|
|
|
Template.Selectize.events({
|
|
'click .selectize-input': function (e, template) {
|
|
template.uniSelectize.checkDisabled();
|
|
template.uniSelectize.inputFocus(template);
|
|
|
|
template.uniSelectize.getOptionsFromMethod();
|
|
},
|
|
'keydown input.js-selectizeInput': function (e, template) {
|
|
var uniSelectize = template.uniSelectize;
|
|
var itemsSelected = uniSelectize.itemsSelected.get();
|
|
var itemsUnselected = uniSelectize.getItemsUnselectedFiltered();
|
|
var inputPosition = uniSelectize.inputPosition.get();
|
|
var activeOption = uniSelectize.activeOption.get();
|
|
|
|
template.uniSelectize.checkDisabled();
|
|
|
|
var $input = $(e.target);
|
|
var width = template.uniSelectize.measureString($input.val(), $input) + 10;
|
|
|
|
$input.width(width);
|
|
|
|
switch (e.keyCode) {
|
|
case 8: // backspace
|
|
if ($input.val() === '') {
|
|
e.preventDefault();
|
|
uniSelectize.removeItemBeforeInput();
|
|
}
|
|
uniSelectize.open.set(true);
|
|
uniSelectize.inputFocus();
|
|
|
|
break;
|
|
|
|
case 46: // delete
|
|
if ($input.val() === '') {
|
|
uniSelectize.removeItemAfterInput();
|
|
}
|
|
uniSelectize.open.set(true);
|
|
uniSelectize.inputFocus();
|
|
|
|
break;
|
|
|
|
case 27: // escape
|
|
$input.blur();
|
|
break;
|
|
|
|
case 13: // enter
|
|
e.preventDefault();
|
|
|
|
if (activeOption === -1 && $input.val() === '') {
|
|
break;
|
|
}
|
|
|
|
if (itemsUnselected && itemsUnselected.length > 0) {
|
|
uniSelectize.selectActiveItem(template);
|
|
uniSelectize.searchText.set('');
|
|
$input.val('');
|
|
} else if (uniSelectize.create /*&& createOnBlur*/) {
|
|
uniSelectize.createItem();
|
|
uniSelectize.searchText.set('');
|
|
$input.val('');
|
|
}
|
|
|
|
break;
|
|
case 37: // left
|
|
if (!uniSelectize.multiple) {
|
|
break;
|
|
}
|
|
if (inputPosition > -1) {
|
|
uniSelectize.inputPosition.set(inputPosition - 1);
|
|
uniSelectize.inputFocus();
|
|
}
|
|
break;
|
|
case 39: // right
|
|
if (!uniSelectize.multiple) {
|
|
break;
|
|
}
|
|
if (inputPosition < itemsSelected.length - 1) {
|
|
uniSelectize.inputPosition.set(inputPosition + 1);
|
|
uniSelectize.inputFocus();
|
|
}
|
|
break;
|
|
case 38: // up
|
|
if (activeOption > -1) {
|
|
uniSelectize.activeOption.set(activeOption - 1);
|
|
}
|
|
break;
|
|
case 40: // down
|
|
if (activeOption < itemsUnselected.length - 1 ||
|
|
(activeOption < itemsUnselected.length && uniSelectize.create)) {
|
|
uniSelectize.activeOption.set(activeOption + 1);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!template.uniSelectize.multiple && itemsSelected.length) {
|
|
return false;
|
|
}
|
|
},
|
|
'keyup input.js-selectizeInput': function (e, template) {
|
|
template.uniSelectize.checkDisabled();
|
|
|
|
var $el = $(e.target);
|
|
var value = $el.val();
|
|
template.uniSelectize.searchText.set(value);
|
|
template.uniSelectize.getOptionsFromMethod();
|
|
},
|
|
'focus input.js-selectizeInput': function (e, template) {
|
|
template.uniSelectize.checkDisabled();
|
|
template.uniSelectize.open.set(true);
|
|
|
|
Meteor.clearTimeout(template.uniSelectize.timeoutId);
|
|
},
|
|
'change input.js-selectizeInput': function(e, template) {
|
|
template.uniSelectize.checkDisabled();
|
|
|
|
// prevent non-autoform fields changes from submitting the form when autosave is enabled
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
},
|
|
'blur input.js-selectizeInput': function (e, template) {
|
|
template.uniSelectize.checkDisabled();
|
|
|
|
template.uniSelectize.timeoutId = Meteor.setTimeout(function () {
|
|
template.uniSelectize.open.set(false);
|
|
}, 500);
|
|
},
|
|
'scroll .selectize-dropdown-content': function (e, template) {
|
|
Meteor.clearTimeout(template.uniSelectize.timeoutId);
|
|
template.uniSelectize.timeoutId = Meteor.setTimeout(function () {
|
|
template.uniSelectize.open.set(false);
|
|
}, 5000);
|
|
},
|
|
'click .selectize-dropdown-content > div:not(.create)': function (e, template) {
|
|
e.preventDefault();
|
|
template.uniSelectize.checkDisabled();
|
|
var $input = $(template.find('input'));
|
|
var itemsUnselected = template.uniSelectize.getItemsUnselectedFiltered();
|
|
var itemsUnselectedLength = itemsUnselected && itemsUnselected.length;
|
|
|
|
template.uniSelectize.selectItem(this.value);
|
|
template.uniSelectize.searchText.set('');
|
|
$input.val('');
|
|
|
|
if (template.uniSelectize.multiple && itemsUnselectedLength && this.value) {
|
|
template.uniSelectize.inputFocus();
|
|
} else {
|
|
template.uniSelectize.open.set(false);
|
|
}
|
|
},
|
|
'mouseenter .selectize-dropdown-content > div': function (e, template) {
|
|
var $el = $(e.target);
|
|
var elIndex = $el.attr('data-index');
|
|
var itemsUnselected = template.uniSelectize.getItemsUnselectedFiltered();
|
|
|
|
if (elIndex === 'create') {
|
|
elIndex = itemsUnselected.length;
|
|
} else {
|
|
elIndex = parseInt(elIndex);
|
|
}
|
|
|
|
template.uniSelectize.activeOption.set(elIndex);
|
|
},
|
|
'click .create': function (e, template) {
|
|
e.preventDefault();
|
|
template.uniSelectize.checkDisabled();
|
|
var $input = $(template.find('input'));
|
|
|
|
template.uniSelectize.createItem();
|
|
template.uniSelectize.searchText.set('');
|
|
$input.val('');
|
|
},
|
|
'click .remove': function (e, template) {
|
|
e.preventDefault();
|
|
template.uniSelectize.checkDisabled();
|
|
|
|
template.uniSelectize.unselectItem(this.value, false);
|
|
}
|
|
}); |