Files
AVEF/imports/util/selectize/selectize.js
Wynne Crisman 94000458e4 Copied starter Meteor App files.
Cut and paste of the BasicMeteorApp.
2018-07-30 14:15:39 -07:00

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);
}
});