json-editor
Version:
JSON Schema based editor
288 lines (250 loc) • 8.47 kB
JavaScript
// Multiple Editor (for when `type` is an array)
JSONEditor.defaults.editors.multiple = JSONEditor.AbstractEditor.extend({
register: function() {
if(this.editors) {
for(var i=0; i<this.editors.length; i++) {
if(!this.editors[i]) continue;
this.editors[i].unregister();
}
if(this.editors[this.type]) this.editors[this.type].register();
}
this._super();
},
unregister: function() {
this._super();
if(this.editors) {
for(var i=0; i<this.editors.length; i++) {
if(!this.editors[i]) continue;
this.editors[i].unregister();
}
}
},
getNumColumns: function() {
if(!this.editors[this.type]) return 4;
return Math.max(this.editors[this.type].getNumColumns(),4);
},
enable: function() {
if(this.editors) {
for(var i=0; i<this.editors.length; i++) {
if(!this.editors[i]) continue;
this.editors[i].enable();
}
}
this.switcher.disabled = false;
this._super();
},
disable: function() {
if(this.editors) {
for(var i=0; i<this.editors.length; i++) {
if(!this.editors[i]) continue;
this.editors[i].disable();
}
}
this.switcher.disabled = true;
this._super();
},
switchEditor: function(i) {
var self = this;
if(!this.editors[i]) {
this.buildChildEditor(i);
}
var current_value = self.getValue();
self.type = i;
self.register();
$each(self.editors,function(type,editor) {
if(!editor) return;
if(self.type === type) {
if(self.keep_values) editor.setValue(current_value,true);
editor.container.style.display = '';
}
else editor.container.style.display = 'none';
});
self.refreshValue();
self.refreshHeaderText();
},
buildChildEditor: function(i) {
var self = this;
var type = this.types[i];
var holder = self.theme.getChildEditorHolder();
self.editor_holder.appendChild(holder);
var schema;
if(typeof type === "string") {
schema = $extend({},self.schema);
schema.type = type;
}
else {
schema = $extend({},self.schema,type);
schema = self.jsoneditor.expandRefs(schema);
// If we need to merge `required` arrays
if(type.required && Array.isArray(type.required) && self.schema.required && Array.isArray(self.schema.required)) {
schema.required = self.schema.required.concat(type.required);
}
}
var editor = self.jsoneditor.getEditorClass(schema);
self.editors[i] = self.jsoneditor.createEditor(editor,{
jsoneditor: self.jsoneditor,
schema: schema,
container: holder,
path: self.path,
parent: self,
required: true
});
self.editors[i].preBuild();
self.editors[i].build();
self.editors[i].postBuild();
if(self.editors[i].header) self.editors[i].header.style.display = 'none';
self.editors[i].option = self.switcher_options[i];
holder.addEventListener('change_header_text',function() {
self.refreshHeaderText();
});
if(i !== self.type) holder.style.display = 'none';
},
preBuild: function() {
var self = this;
this.types = [];
this.type = 0;
this.editors = [];
this.validators = [];
this.keep_values = true;
if(typeof this.jsoneditor.options.keep_oneof_values !== "undefined") this.keep_values = this.jsoneditor.options.keep_oneof_values;
if(typeof this.options.keep_oneof_values !== "undefined") this.keep_values = this.options.keep_oneof_values;
if(this.schema.oneOf) {
this.oneOf = true;
this.types = this.schema.oneOf;
delete this.schema.oneOf;
}
else if(this.schema.anyOf) {
this.anyOf = true;
this.types = this.schema.anyOf;
delete this.schema.anyOf;
}
else {
if(!this.schema.type || this.schema.type === "any") {
this.types = ['string','number','integer','boolean','object','array','null'];
// If any of these primitive types are disallowed
if(this.schema.disallow) {
var disallow = this.schema.disallow;
if(typeof disallow !== 'object' || !(Array.isArray(disallow))) {
disallow = [disallow];
}
var allowed_types = [];
$each(this.types,function(i,type) {
if(disallow.indexOf(type) === -1) allowed_types.push(type);
});
this.types = allowed_types;
}
}
else if(Array.isArray(this.schema.type)) {
this.types = this.schema.type;
}
else {
this.types = [this.schema.type];
}
delete this.schema.type;
}
this.display_text = this.getDisplayText(this.types);
},
build: function() {
var self = this;
var container = this.container;
this.header = this.label = this.theme.getFormInputLabel(this.getTitle());
this.container.appendChild(this.header);
this.switcher = this.theme.getSwitcher(this.display_text);
container.appendChild(this.switcher);
this.switcher.addEventListener('change',function(e) {
e.preventDefault();
e.stopPropagation();
self.switchEditor(self.display_text.indexOf(this.value));
self.onChange(true);
});
this.editor_holder = document.createElement('div');
container.appendChild(this.editor_holder);
var validator_options = {};
if(self.jsoneditor.options.custom_validators) {
validator_options.custom_validators = self.jsoneditor.options.custom_validators;
}
this.switcher_options = this.theme.getSwitcherOptions(this.switcher);
$each(this.types,function(i,type) {
self.editors[i] = false;
var schema;
if(typeof type === "string") {
schema = $extend({},self.schema);
schema.type = type;
}
else {
schema = $extend({},self.schema,type);
// If we need to merge `required` arrays
if(type.required && Array.isArray(type.required) && self.schema.required && Array.isArray(self.schema.required)) {
schema.required = self.schema.required.concat(type.required);
}
}
self.validators[i] = new JSONEditor.Validator(self.jsoneditor,schema,validator_options);
});
this.switchEditor(0);
},
onChildEditorChange: function(editor) {
if(this.editors[this.type]) {
this.refreshValue();
this.refreshHeaderText();
}
this._super();
},
refreshHeaderText: function() {
var display_text = this.getDisplayText(this.types);
$each(this.switcher_options, function(i,option) {
option.textContent = display_text[i];
});
},
refreshValue: function() {
this.value = this.editors[this.type].getValue();
},
setValue: function(val,initial) {
// Determine type by getting the first one that validates
var self = this;
$each(this.validators, function(i,validator) {
if(!validator.validate(val).length) {
self.type = i;
self.switcher.value = self.display_text[i];
return false;
}
});
this.switchEditor(this.type);
this.editors[this.type].setValue(val,initial);
this.refreshValue();
self.onChange();
},
destroy: function() {
$each(this.editors, function(type,editor) {
if(editor) editor.destroy();
});
if(this.editor_holder && this.editor_holder.parentNode) this.editor_holder.parentNode.removeChild(this.editor_holder);
if(this.switcher && this.switcher.parentNode) this.switcher.parentNode.removeChild(this.switcher);
this._super();
},
showValidationErrors: function(errors) {
var self = this;
// oneOf and anyOf error paths need to remove the oneOf[i] part before passing to child editors
if(this.oneOf || this.anyOf) {
var check_part = this.oneOf? 'oneOf' : 'anyOf';
$each(this.editors,function(i,editor) {
if(!editor) return;
var check = self.path+'.'+check_part+'['+i+']';
var new_errors = [];
$each(errors, function(j,error) {
if(error.path.substr(0,check.length)===check) {
var new_error = $extend({},error);
new_error.path = self.path+new_error.path.substr(check.length);
new_errors.push(new_error);
}
});
editor.showValidationErrors(new_errors);
});
}
else {
$each(this.editors,function(type,editor) {
if(!editor) return;
editor.showValidationErrors(errors);
});
}
}
});