UNPKG

json-editor

Version:
356 lines (320 loc) 11.3 kB
JSONEditor.defaults.editors.select = JSONEditor.AbstractEditor.extend({ setValue: function(value,initial) { value = this.typecast(value||''); // Sanitize value before setting it var sanitized = value; if(this.enum_values.indexOf(sanitized) < 0) { sanitized = this.enum_values[0]; } if(this.value === sanitized) { return; } this.input.value = this.enum_options[this.enum_values.indexOf(sanitized)]; if(this.select2) this.select2.select2('val',this.input.value); this.value = sanitized; this.onChange(); }, register: function() { this._super(); if(!this.input) return; this.input.setAttribute('name',this.formname); }, unregister: function() { this._super(); if(!this.input) return; this.input.removeAttribute('name'); }, getNumColumns: function() { if(!this.enum_options) return 3; var longest_text = this.getTitle().length; for(var i=0; i<this.enum_options.length; i++) { longest_text = Math.max(longest_text,this.enum_options[i].length+4); } return Math.min(12,Math.max(longest_text/7,2)); }, typecast: function(value) { if(this.schema.type === "boolean") { return !!value; } else if(this.schema.type === "number") { return 1*value; } else if(this.schema.type === "integer") { return Math.floor(value*1); } else { return ""+value; } }, getValue: function() { return this.value; }, preBuild: function() { var self = this; this.input_type = 'select'; this.enum_options = []; this.enum_values = []; this.enum_display = []; var i; // Enum options enumerated if(this.schema["enum"]) { var display = this.schema.options && this.schema.options.enum_titles || []; $each(this.schema["enum"],function(i,option) { self.enum_options[i] = ""+option; self.enum_display[i] = ""+(display[i] || option); self.enum_values[i] = self.typecast(option); }); if(!this.isRequired()){ self.enum_display.unshift(' '); self.enum_options.unshift('undefined'); self.enum_values.unshift(undefined); } } // Boolean else if(this.schema.type === "boolean") { self.enum_display = this.schema.options && this.schema.options.enum_titles || ['true','false']; self.enum_options = ['1','']; self.enum_values = [true,false]; if(!this.isRequired()){ self.enum_display.unshift(' '); self.enum_options.unshift('undefined'); self.enum_values.unshift(undefined); } } // Dynamic Enum else if(this.schema.enumSource) { this.enumSource = []; this.enum_display = []; this.enum_options = []; this.enum_values = []; // Shortcut declaration for using a single array if(!(Array.isArray(this.schema.enumSource))) { if(this.schema.enumValue) { this.enumSource = [ { source: this.schema.enumSource, value: this.schema.enumValue } ]; } else { this.enumSource = [ { source: this.schema.enumSource } ]; } } else { for(i=0; i<this.schema.enumSource.length; i++) { // Shorthand for watched variable if(typeof this.schema.enumSource[i] === "string") { this.enumSource[i] = { source: this.schema.enumSource[i] }; } // Make a copy of the schema else if(!(Array.isArray(this.schema.enumSource[i]))) { this.enumSource[i] = $extend({},this.schema.enumSource[i]); } else { this.enumSource[i] = this.schema.enumSource[i]; } } } // Now, enumSource is an array of sources // Walk through this array and fix up the values for(i=0; i<this.enumSource.length; i++) { if(this.enumSource[i].value) { this.enumSource[i].value = this.jsoneditor.compileTemplate(this.enumSource[i].value, this.template_engine); } if(this.enumSource[i].title) { this.enumSource[i].title = this.jsoneditor.compileTemplate(this.enumSource[i].title, this.template_engine); } if(this.enumSource[i].filter) { this.enumSource[i].filter = this.jsoneditor.compileTemplate(this.enumSource[i].filter, this.template_engine); } } } // Other, not supported else { throw "'select' editor requires the enum property to be set."; } }, build: function() { var self = this; if(!this.options.compact) this.header = this.label = this.theme.getFormInputLabel(this.getTitle()); if(this.schema.description) this.description = this.theme.getFormInputDescription(this.schema.description); if(this.options.compact) this.container.className += ' compact'; this.input = this.theme.getSelectInput(this.enum_options); this.theme.setSelectOptions(this.input,this.enum_options,this.enum_display); if(this.schema.readOnly || this.schema.readonly) { this.always_disabled = true; this.input.disabled = true; } this.input.addEventListener('change',function(e) { e.preventDefault(); e.stopPropagation(); self.onInputChange(); }); this.control = this.theme.getFormControl(this.label, this.input, this.description); this.container.appendChild(this.control); this.value = this.enum_values[0]; }, onInputChange: function() { var val = this.input.value; var new_val; // Invalid option, use first option instead if(this.enum_options.indexOf(val) === -1) { new_val = this.enum_values[0]; } else { new_val = this.enum_values[this.enum_options.indexOf(val)]; } // If valid hasn't changed if(new_val === this.value) return; // Store new value and propogate change event this.value = new_val; this.onChange(true); }, setupSelect2: function() { // If the Select2 library is loaded use it when we have lots of items if(window.jQuery && window.jQuery.fn && window.jQuery.fn.select2 && (this.enum_options.length > 2 || (this.enum_options.length && this.enumSource))) { var options = $extend({},JSONEditor.plugins.select2); if(this.schema.options && this.schema.options.select2_options) options = $extend(options,this.schema.options.select2_options); this.select2 = window.jQuery(this.input).select2(options); var self = this; this.select2.on('select2-blur',function() { self.input.value = self.select2.select2('val'); self.onInputChange(); }); this.select2.on('change',function() { self.input.value = self.select2.select2('val'); self.onInputChange(); }); } else { this.select2 = null; } }, postBuild: function() { this._super(); this.theme.afterInputReady(this.input); this.setupSelect2(); }, onWatchedFieldChange: function() { var self = this, vars, j; // If this editor uses a dynamic select box if(this.enumSource) { vars = this.getWatchedFieldValues(); var select_options = []; var select_titles = []; for(var i=0; i<this.enumSource.length; i++) { // Constant values if(Array.isArray(this.enumSource[i])) { select_options = select_options.concat(this.enumSource[i]); select_titles = select_titles.concat(this.enumSource[i]); } else { var items = []; // Static list of items if(Array.isArray(this.enumSource[i].source)) { items = this.enumSource[i].source; // A watched field } else { items = vars[this.enumSource[i].source]; } if(items) { // Only use a predefined part of the array if(this.enumSource[i].slice) { items = Array.prototype.slice.apply(items,this.enumSource[i].slice); } // Filter the items if(this.enumSource[i].filter) { var new_items = []; for(j=0; j<items.length; j++) { if(this.enumSource[i].filter({i:j,item:items[j],watched:vars})) new_items.push(items[j]); } items = new_items; } var item_titles = []; var item_values = []; for(j=0; j<items.length; j++) { var item = items[j]; // Rendered value if(this.enumSource[i].value) { item_values[j] = this.enumSource[i].value({ i: j, item: item }); } // Use value directly else { item_values[j] = items[j]; } // Rendered title if(this.enumSource[i].title) { item_titles[j] = this.enumSource[i].title({ i: j, item: item }); } // Use value as the title also else { item_titles[j] = item_values[j]; } } // TODO: sort select_options = select_options.concat(item_values); select_titles = select_titles.concat(item_titles); } } } var prev_value = this.value; this.theme.setSelectOptions(this.input, select_options, select_titles); this.enum_options = select_options; this.enum_display = select_titles; this.enum_values = select_options; if(this.select2) { this.select2.select2('destroy'); } // If the previous value is still in the new select options, stick with it if(select_options.indexOf(prev_value) !== -1) { this.input.value = prev_value; this.value = prev_value; } // Otherwise, set the value to the first select option else { this.input.value = select_options[0]; this.value = select_options[0] || ""; if(this.parent) this.parent.onChildEditorChange(this); else this.jsoneditor.onChange(); this.jsoneditor.notifyWatchers(this.path); } this.setupSelect2(); } this._super(); }, enable: function() { if(!this.always_disabled) { this.input.disabled = false; if(this.select2) this.select2.select2("enable",true); } this._super(); }, disable: function() { this.input.disabled = true; if(this.select2) this.select2.select2("enable",false); this._super(); }, destroy: function() { if(this.label && this.label.parentNode) this.label.parentNode.removeChild(this.label); if(this.description && this.description.parentNode) this.description.parentNode.removeChild(this.description); if(this.input && this.input.parentNode) this.input.parentNode.removeChild(this.input); if(this.select2) { this.select2.select2('destroy'); this.select2 = null; } this._super(); } });