/*! JSON Editor v0.7.28 - JSON Schema -> HTML Editor * By Jeremy Dorn - https://github.com/jdorn/json-editor/ * Released under the MIT license * * Date: 2016-08-07 */ /** * See README.md for requirements and usage info */ (function() { /*jshint loopfunc: true */ /* Simple JavaScript Inheritance * By John Resig http://ejohn.org/ * MIT Licensed. */ // Inspired by base2 and Prototype var Class; (function(){ var initializing = false, fnTest = /xyz/.test(function(){window.postMessage("xyz");}) ? /\b_super\b/ : /.*/; // The base Class implementation (does nothing) Class = function(){}; // Create a new Class that inherits from this class Class.extend = function extend(prop) { var _super = this.prototype; // Instantiate a base class (but only create the instance, // don't run the init constructor) initializing = true; var prototype = new this(); initializing = false; // Copy the properties over onto the new prototype for (var name in prop) { // Check if we're overwriting an existing function prototype[name] = typeof prop[name] == "function" && typeof _super[name] == "function" && fnTest.test(prop[name]) ? (function(name, fn){ return function() { var tmp = this._super; // Add a new ._super() method that is the same method // but on the super-class this._super = _super[name]; // The method only need to be bound temporarily, so we // remove it when we're done executing var ret = fn.apply(this, arguments); this._super = tmp; return ret; }; })(name, prop[name]) : prop[name]; } // The dummy class constructor function Class() { // All construction is actually done in the init method if ( !initializing && this.init ) this.init.apply(this, arguments); } // Populate our constructed prototype object Class.prototype = prototype; // Enforce the constructor to be what we expect Class.prototype.constructor = Class; // And make this class extendable Class.extend = extend; return Class; }; return Class; })(); // CustomEvent constructor polyfill // From MDN (function () { function CustomEvent ( event, params ) { params = params || { bubbles: false, cancelable: false, detail: undefined }; var evt = document.createEvent( 'CustomEvent' ); evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail ); return evt; } CustomEvent.prototype = window.Event.prototype; window.CustomEvent = CustomEvent; })(); // requestAnimationFrame polyfill by Erik Möller. fixes from Paul Irish and Tino Zijdel // MIT license (function() { var lastTime = 0; var vendors = ['ms', 'moz', 'webkit', 'o']; for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) { window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame']; window.cancelAnimationFrame = window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame']; } if (!window.requestAnimationFrame) window.requestAnimationFrame = function(callback, element) { var currTime = new Date().getTime(); var timeToCall = Math.max(0, 16 - (currTime - lastTime)); var id = window.setTimeout(function() { callback(currTime + timeToCall); }, timeToCall); lastTime = currTime + timeToCall; return id; }; if (!window.cancelAnimationFrame) window.cancelAnimationFrame = function(id) { clearTimeout(id); }; }()); // Array.isArray polyfill // From MDN (function() { if(!Array.isArray) { Array.isArray = function(arg) { return Object.prototype.toString.call(arg) === '[object Array]'; }; } }()); /** * Taken from jQuery 2.1.3 * * @param obj * @returns {boolean} */ var $isplainobject = function( obj ) { // Not plain objects: // - Any object or value whose internal [[Class]] property is not "[object Object]" // - DOM nodes // - window if (typeof obj !== "object" || obj.nodeType || (obj !== null && obj === obj.window)) { return false; } if (obj.constructor && !Object.prototype.hasOwnProperty.call(obj.constructor.prototype, "isPrototypeOf")) { return false; } // If the function hasn't returned already, we're confident that // |obj| is a plain object, created by {} or constructed with new Object return true; }; var $extend = function(destination) { var source, i,property; for(i=1; i 0 && (obj.length - 1) in obj)) { for(i=0; i= waiting && !callback_fired) { callback_fired = true; callback(); } }); } // Request failed else { window.console.log(r); throw "Failed to fetch ref via ajax- "+url; } }; r.send(); }); if(!waiting) { callback(); } }, expandRefs: function(schema) { schema = $extend({},schema); while (schema.$ref) { var ref = schema.$ref; delete schema.$ref; if(!this.refs[ref]) ref = decodeURIComponent(ref); schema = this.extendSchemas(schema,this.refs[ref]); } return schema; }, expandSchema: function(schema) { var self = this; var extended = $extend({},schema); var i; // Version 3 `type` if(typeof schema.type === 'object') { // Array of types if(Array.isArray(schema.type)) { $each(schema.type, function(key,value) { // Schema if(typeof value === 'object') { schema.type[key] = self.expandSchema(value); } }); } // Schema else { schema.type = self.expandSchema(schema.type); } } // Version 3 `disallow` if(typeof schema.disallow === 'object') { // Array of types if(Array.isArray(schema.disallow)) { $each(schema.disallow, function(key,value) { // Schema if(typeof value === 'object') { schema.disallow[key] = self.expandSchema(value); } }); } // Schema else { schema.disallow = self.expandSchema(schema.disallow); } } // Version 4 `anyOf` if(schema.anyOf) { $each(schema.anyOf, function(key,value) { schema.anyOf[key] = self.expandSchema(value); }); } // Version 4 `dependencies` (schema dependencies) if(schema.dependencies) { $each(schema.dependencies,function(key,value) { if(typeof value === "object" && !(Array.isArray(value))) { schema.dependencies[key] = self.expandSchema(value); } }); } // Version 4 `not` if(schema.not) { schema.not = this.expandSchema(schema.not); } // allOf schemas should be merged into the parent if(schema.allOf) { for(i=0; i schema.minimum) : (value >= schema.minimum); // Use math.js is available if(window.math) { valid = window.math[schema.exclusiveMinimum?'larger':'largerEq']( window.math.bignumber(value), window.math.bignumber(schema.minimum) ); } // Use Decimal.js if available else if(window.Decimal) { valid = (new window.Decimal(value))[schema.exclusiveMinimum?'gt':'gte'](new window.Decimal(schema.minimum)); } if(!valid) { errors.push({ path: path, property: 'minimum', message: this.translate( (schema.exclusiveMinimum?'edt_msg_error_minimum_excl':'edt_msg_error_minimum_incl'), [schema.minimum] ) }); } } } // String specific validation else if(typeof value === "string") { // `maxLength` if(schema.maxLength) { if((value+"").length > schema.maxLength) { errors.push({ path: path, property: 'maxLength', message: this.translate('edt_msg_error_maxLength', [schema.maxLength]) }); } } // `minLength` if(schema.minLength) { if((value+"").length < schema.minLength) { errors.push({ path: path, property: 'minLength', message: this.translate((schema.minLength===1?'edt_msg_error_notempty':'edt_msg_error_minLength'), [schema.minLength]) }); } } // `pattern` if(schema.pattern) { if(!(new RegExp(schema.pattern)).test(value)) { errors.push({ path: path, property: 'pattern', message: this.translate('edt_msg_error_pattern', [schema.pattern]) }); } } } // Array specific validation else if(typeof value === "object" && value !== null && Array.isArray(value)) { // `items` and `additionalItems` if(schema.items) { // `items` is an array if(Array.isArray(schema.items)) { for(i=0; i schema.maxItems) { errors.push({ path: path, property: 'maxItems', message: this.translate('edt_msg_error_maxItems', [schema.maxItems]) }); } } // `minItems` if(schema.minItems) { if(value.length < schema.minItems) { errors.push({ path: path, property: 'minItems', message: this.translate('edt_msg_error_minItems', [schema.minItems]) }); } } // `uniqueItems` if(schema.uniqueItems) { var seen = {}; for(i=0; i schema.maxProperties) { errors.push({ path: path, property: 'maxProperties', message: this.translate('edt_msg_error_maxProperties', [schema.maxProperties]) }); } } // `minProperties` if(schema.minProperties) { valid = 0; for(i in value) { if(!value.hasOwnProperty(i)) continue; valid++; } if(valid < schema.minProperties) { errors.push({ path: path, property: 'minProperties', message: this.translate('edt_msg_error_minProperties', [schema.minProperties]) }); } } // Version 4 `required` if(schema.required && Array.isArray(schema.required)) { for(i=0; i=0) { holder = this.theme.getBlockLinkHolder(); link = this.theme.getBlockLink(); link.setAttribute('target','_blank'); var media = document.createElement(type); media.setAttribute('controls','controls'); this.theme.createMediaLink(holder,link,media); // When a watched field changes, update the url this.link_watchers.push(function(vars) { var url = href(vars); link.setAttribute('href',url); link.textContent = data.rel || url; media.setAttribute('src',url); }); } // Text links else { link = holder = this.theme.getBlockLink(); holder.setAttribute('target','_blank'); holder.textContent = data.rel; // When a watched field changes, update the url this.link_watchers.push(function(vars) { var url = href(vars); holder.setAttribute('href',url); holder.textContent = data.rel || url; }); } if(download && link) { if(download === true) { link.setAttribute('download',''); } else { this.link_watchers.push(function(vars) { link.setAttribute('download',download(vars)); }); } } if(data.class) link.className = link.className + ' ' + data.class; return holder; }, refreshWatchedFieldValues: function() { if(!this.watched_values) return; var watched = {}; var changed = false; var self = this; if(this.watched) { var val,editor; for(var name in this.watched) { if(!this.watched.hasOwnProperty(name)) continue; editor = self.jsoneditor.getEditor(this.watched[name]); val = editor? editor.getValue() : null; if(self.watched_values[name] !== val) changed = true; watched[name] = val; } } watched.self = this.getValue(); if(this.watched_values.self !== watched.self) changed = true; this.watched_values = watched; return changed; }, getWatchedFieldValues: function() { return this.watched_values; }, updateHeaderText: function() { if(this.header) { // If the header has children, only update the text node's value if(this.header.children.length) { for(var i=0; i -1; else if(this.jsoneditor.options.required_by_default) return true; else return true; }, getDisplayText: function(arr) { var disp = []; var used = {}; // Determine how many times each attribute name is used. // This helps us pick the most distinct display text for the schemas. $each(arr,function(i,el) { if(el.title) { used[el.title] = used[el.title] || 0; used[el.title]++; } if(el.description) { used[el.description] = used[el.description] || 0; used[el.description]++; } if(el.format) { used[el.format] = used[el.format] || 0; used[el.format]++; } if(el.type) { used[el.type] = used[el.type] || 0; used[el.type]++; } }); // Determine display text for each element of the array $each(arr,function(i,el) { var name; // If it's a simple string if(typeof el === "string") name = el; // Object else if(el.title && used[el.title]<=1) name = el.title; else if(el.format && used[el.format]<=1) name = el.format; else if(el.type && used[el.type]<=1) name = el.type; else if(el.description && used[el.description]<=1) name = el.descripton; else if(el.title) name = el.title; else if(el.format) name = el.format; else if(el.type) name = el.type; else if(el.description) name = el.description; else if(JSON.stringify(el).length < 50) name = JSON.stringify(el); else name = "type"; disp.push(name); }); // Replace identical display text with "text 1", "text 2", etc. var inc = {}; $each(disp,function(i,name) { inc[name] = inc[name] || 0; inc[name]++; if(used[name] > 1) disp[i] = name + " " + inc[name]; }); return disp; }, getOption: function(key) { try { throw "getOption is deprecated"; } catch(e) { window.console.error(e); } return this.options[key]; }, showValidationErrors: function(errors) { } }); JSONEditor.defaults.editors["null"] = JSONEditor.AbstractEditor.extend({ getValue: function() { return null; }, setValue: function() { this.onChange(); }, getNumColumns: function() { return 2; } }); JSONEditor.defaults.editors.string = JSONEditor.AbstractEditor.extend({ 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'); }, setValue: function(value,initial,from_template) { var self = this; if(this.template && !from_template) { return; } if(value === null || typeof value === 'undefined') value = ""; else if(typeof value === "object") value = JSON.stringify(value); else if(typeof value !== "string") value = ""+value; if(value === this.serialized) return; // Sanitize value before setting it var sanitized = this.sanitize(value); if(this.input.value === sanitized) { return; } this.input.value = sanitized; // If using SCEditor, update the WYSIWYG if(this.sceditor_instance) { this.sceditor_instance.val(sanitized); } else if(this.epiceditor) { this.epiceditor.importFile(null,sanitized); } else if(this.ace_editor) { this.ace_editor.setValue(sanitized); } var changed = from_template || this.getValue() !== value; this.refreshValue(); if(initial) this.is_dirty = false; else if(this.jsoneditor.options.show_errors === "change") this.is_dirty = true; if(this.adjust_height) this.adjust_height(this.input); // Bubble this setValue to parents if the value changed this.onChange(changed); }, getNumColumns: function() { var min = Math.ceil(Math.max(this.getTitle().length,this.schema.maxLength||0,this.schema.minLength||0)/5); var num; if(this.input_type === 'textarea') num = 6; else if(['text','email'].indexOf(this.input_type) >= 0) num = 4; else num = 2; return Math.min(12,Math.max(min,num)); }, build: function() { var self = this, i; 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.schema.append) this.append = this.theme.getFormInputAppend(this.getAppend()); this.format = this.schema.format; if(!this.format && this.schema.media && this.schema.media.type) { this.format = this.schema.media.type.replace(/(^(application|text)\/(x-)?(script\.)?)|(-source$)/g,''); } if(!this.format && this.options.default_format) { this.format = this.options.default_format; } if(this.options.format) { this.format = this.options.format; } // Specific format if(this.format) { // Text Area if(this.format === 'textarea') { this.input_type = 'textarea'; this.input = this.theme.getTextareaInput(); } // Range Input else if(this.format === 'range') { this.input_type = 'range'; var min = this.schema.minimum || 0; var max = this.schema.maximum || Math.max(100,min+1); var step = 1; if(this.schema.multipleOf) { if(min%this.schema.multipleOf) min = Math.ceil(min/this.schema.multipleOf)*this.schema.multipleOf; if(max%this.schema.multipleOf) max = Math.floor(max/this.schema.multipleOf)*this.schema.multipleOf; step = this.schema.multipleOf; } this.input = this.theme.getRangeInput(min,max,step); } // Source Code else if([ 'actionscript', 'batchfile', 'bbcode', 'c', 'c++', 'cpp', 'coffee', 'csharp', 'css', 'dart', 'django', 'ejs', 'erlang', 'golang', 'groovy', 'handlebars', 'haskell', 'haxe', 'html', 'ini', 'jade', 'java', 'javascript', 'json', 'less', 'lisp', 'lua', 'makefile', 'markdown', 'matlab', 'mysql', 'objectivec', 'pascal', 'perl', 'pgsql', 'php', 'python', 'r', 'ruby', 'sass', 'scala', 'scss', 'smarty', 'sql', 'stylus', 'svg', 'twig', 'vbscript', 'xml', 'yaml' ].indexOf(this.format) >= 0 ) { this.input_type = this.format; this.source_code = true; this.input = this.theme.getTextareaInput(); } // HTML5 Input type else { this.input_type = this.format; this.input = this.theme.getFormInputField(this.input_type); } } // Number or integer adds html5 tag 'number' else if (this.schema.type == "number" || this.schema.type == "integer"){ var min = this.schema.minimum var max = this.schema.maximum var step = this.schema.step this.input = this.theme.getRangeInput(min,max,step); } // Normal text input else { this.input_type = 'text'; this.input = this.theme.getFormInputField(this.input_type); } // minLength, maxLength, and pattern if(typeof this.schema.maxLength !== "undefined") this.input.setAttribute('maxlength',this.schema.maxLength); if(typeof this.schema.pattern !== "undefined") this.input.setAttribute('pattern',this.schema.pattern); else if(typeof this.schema.minLength !== "undefined") this.input.setAttribute('pattern','.{'+this.schema.minLength+',}'); if(this.options.compact) { this.container.className += ' compact'; } else { if(this.options.input_width) this.input.style.width = this.options.input_width; } if(this.schema.readOnly || this.schema.readonly || this.schema.template) { this.always_disabled = true; this.input.disabled = true; } this.input .addEventListener('change',function(e) { e.preventDefault(); e.stopPropagation(); // Don't allow changing if this field is a template if(self.schema.template) { this.value = self.value; return; } var val = this.value; // sanitize value var sanitized = self.sanitize(val); if(val !== sanitized) { this.value = sanitized; } self.is_dirty = true; self.refreshValue(); self.onChange(true); }); if(this.options.input_height) this.input.style.height = this.options.input_height; if(this.options.expand_height) { this.adjust_height = function(el) { if(!el) return; var i, ch=el.offsetHeight; // Input too short if(el.offsetHeight < el.scrollHeight) { i=0; while(el.offsetHeight < el.scrollHeight+3) { if(i>100) break; i++; ch++; el.style.height = ch+'px'; } } else { i=0; while(el.offsetHeight >= el.scrollHeight+3) { if(i>100) break; i++; ch--; el.style.height = ch+'px'; } el.style.height = (ch+1)+'px'; } }; this.input.addEventListener('keyup',function(e) { self.adjust_height(this); }); this.input.addEventListener('change',function(e) { self.adjust_height(this); }); this.adjust_height(); } if(this.format) this.input.setAttribute('data-schemaformat',this.format); this.control = this.theme.getFormControl(this.label, this.input, this.description, this.append); this.container.appendChild(this.control); // Any special formatting that needs to happen after the input is added to the dom window.requestAnimationFrame(function() { // Skip in case the input is only a temporary editor, // otherwise, in the case of an ace_editor creation, // it will generate an error trying to append it to the missing parentNode if(self.input.parentNode) self.afterInputReady(); if(self.adjust_height) self.adjust_height(self.input); }); // Compile and store the template if(this.schema.template) { this.template = this.jsoneditor.compileTemplate(this.schema.template, this.template_engine); this.refreshValue(); } else { this.refreshValue(); } }, enable: function() { if(!this.always_disabled) { this.input.disabled = false; // TODO: WYSIWYG and Markdown editors } this._super(); }, disable: function() { this.input.disabled = true; // TODO: WYSIWYG and Markdown editors this._super(); }, afterInputReady: function() { var self = this, options; // Code editor if(this.source_code) { // WYSIWYG html and bbcode editor if(this.options.wysiwyg && ['html','bbcode'].indexOf(this.input_type) >= 0 && window.jQuery && window.jQuery.fn && window.jQuery.fn.sceditor ) { options = $extend({},{ plugins: self.input_type==='html'? 'xhtml' : 'bbcode', emoticonsEnabled: false, width: '100%', height: 300 },JSONEditor.plugins.sceditor,self.options.sceditor_options||{}); window.jQuery(self.input).sceditor(options); self.sceditor_instance = window.jQuery(self.input).sceditor('instance'); self.sceditor_instance.blur(function() { // Get editor's value var val = window.jQuery("
"+self.sceditor_instance.val()+"
"); // Remove sceditor spans/divs window.jQuery('#sceditor-start-marker,#sceditor-end-marker,.sceditor-nlf',val).remove(); // Set the value and update self.input.value = val.html(); self.value = self.input.value; self.is_dirty = true; self.onChange(true); }); } // EpicEditor for markdown (if it's loaded) else if (this.input_type === 'markdown' && window.EpicEditor) { this.epiceditor_container = document.createElement('div'); this.input.parentNode.insertBefore(this.epiceditor_container,this.input); this.input.style.display = 'none'; options = $extend({},JSONEditor.plugins.epiceditor,{ container: this.epiceditor_container, clientSideStorage: false }); this.epiceditor = new window.EpicEditor(options).load(); this.epiceditor.importFile(null,this.getValue()); this.epiceditor.on('update',function() { var val = self.epiceditor.exportFile(); self.input.value = val; self.value = val; self.is_dirty = true; self.onChange(true); }); } // ACE editor for everything else else if(window.ace) { var mode = this.input_type; // aliases for c/cpp if(mode === 'cpp' || mode === 'c++' || mode === 'c') { mode = 'c_cpp'; } this.ace_container = document.createElement('div'); this.ace_container.style.width = '100%'; this.ace_container.style.position = 'relative'; this.ace_container.style.height = '400px'; this.input.parentNode.insertBefore(this.ace_container,this.input); this.input.style.display = 'none'; this.ace_editor = window.ace.edit(this.ace_container); this.ace_editor.setValue(this.getValue()); // The theme if(JSONEditor.plugins.ace.theme) this.ace_editor.setTheme('ace/theme/'+JSONEditor.plugins.ace.theme); // The mode mode = window.ace.require("ace/mode/"+mode); if(mode) this.ace_editor.getSession().setMode(new mode.Mode()); // Listen for changes this.ace_editor.on('change',function() { var val = self.ace_editor.getValue(); self.input.value = val; self.refreshValue(); self.is_dirty = true; self.onChange(true); }); } } self.theme.afterInputReady(self.input); }, refreshValue: function() { this.value = this.input.value; if(typeof this.value !== "string") this.value = ''; this.serialized = this.value; }, destroy: function() { // If using SCEditor, destroy the editor instance if(this.sceditor_instance) { this.sceditor_instance.destroy(); } else if(this.epiceditor) { this.epiceditor.unload(); } else if(this.ace_editor) { this.ace_editor.destroy(); } this.template = null; if(this.input && this.input.parentNode) this.input.parentNode.removeChild(this.input); if(this.label && this.label.parentNode) this.label.parentNode.removeChild(this.label); if(this.description && this.description.parentNode) this.description.parentNode.removeChild(this.description); this._super(); }, /** * This is overridden in derivative editors */ sanitize: function(value) { return value; }, /** * Re-calculates the value if needed */ onWatchedFieldChange: function() { var self = this, vars, j; // If this editor needs to be rendered by a macro template if(this.template) { vars = this.getWatchedFieldValues(); this.setValue(this.template(vars),false,true); } this._super(); }, showValidationErrors: function(errors) { var self = this; if(this.jsoneditor.options.show_errors === "always") {} else if(!this.is_dirty && this.previous_error_setting===this.jsoneditor.options.show_errors) return; this.previous_error_setting = this.jsoneditor.options.show_errors; var messages = []; $each(errors,function(i,error) { if(error.path === self.path) { messages.push(error.message); } }); if(messages.length) { this.theme.addInputError(this.input, messages.join('. ')+'.'); } else { this.theme.removeInputError(this.input); } } }); JSONEditor.defaults.editors.number = JSONEditor.defaults.editors.string.extend({ sanitize: function(value) { return (value+"").replace(/[^0-9\.\-eE]/g,''); }, getNumColumns: function() { return 2; }, getValue: function() { return this.value*1; } }); JSONEditor.defaults.editors.integer = JSONEditor.defaults.editors.number.extend({ sanitize: function(value) { value = value + ""; return value.replace(/[^0-9\-]/g,''); }, getNumColumns: function() { return 2; } }); JSONEditor.defaults.editors.object = JSONEditor.AbstractEditor.extend({ getDefault: function() { return $extend({},this.schema["default"] || {}); }, getChildEditors: function() { return this.editors; }, register: function() { this._super(); if(this.editors) { for(var i in this.editors) { if(!this.editors.hasOwnProperty(i)) continue; this.editors[i].register(); } } }, unregister: function() { this._super(); if(this.editors) { for(var i in this.editors) { if(!this.editors.hasOwnProperty(i)) continue; this.editors[i].unregister(); } } }, getNumColumns: function() { return Math.max(Math.min(12,this.maxwidth),3); }, enable: function() { if(this.editjson_button) this.editjson_button.disabled = false; if(this.addproperty_button) this.addproperty_button.disabled = false; this._super(); if(this.editors) { for(var i in this.editors) { if(!this.editors.hasOwnProperty(i)) continue; this.editors[i].enable(); } } }, disable: function() { if(this.editjson_button) this.editjson_button.disabled = true; if(this.addproperty_button) this.addproperty_button.disabled = true; this.hideEditJSON(); this._super(); if(this.editors) { for(var i in this.editors) { if(!this.editors.hasOwnProperty(i)) continue; this.editors[i].disable(); } } }, layoutEditors: function() { var self = this, i, j; if(!this.row_container) return; // Sort editors by propertyOrder this.property_order = Object.keys(this.editors); this.property_order = this.property_order.sort(function(a,b) { var ordera = self.editors[a].schema.propertyOrder; var orderb = self.editors[b].schema.propertyOrder; if(typeof ordera !== "number") ordera = 1000; if(typeof orderb !== "number") orderb = 1000; return ordera - orderb; }); var container; if(this.format === 'grid') { var rows = []; $each(this.property_order, function(j,key) { var editor = self.editors[key]; if(editor.property_removed) return; var found = false; var width = editor.options.hidden? 0 : (editor.options.grid_columns || editor.getNumColumns()); var height = editor.options.hidden? 0 : editor.container.offsetHeight; // See if the editor will fit in any of the existing rows first for(var i=0; i height)) { found = i; } } } // If there isn't a spot in any of the existing rows, start a new row if(found === false) { rows.push({ width: 0, minh: 999999, maxh: 0, editors: [] }); found = rows.length-1; } rows[found].editors.push({ key: key, //editor: editor, width: width, height: height }); rows[found].width += width; rows[found].minh = Math.min(rows[found].minh,height); rows[found].maxh = Math.max(rows[found].maxh,height); }); // Make almost full rows width 12 // Do this by increasing all editors' sizes proprotionately // Any left over space goes to the biggest editor // Don't touch rows with a width of 6 or less for(i=0; i rows[i].editors[biggest].width) biggest = j; rows[i].editors[j].width *= 12/rows[i].width; rows[i].editors[j].width = Math.floor(rows[i].editors[j].width); new_width += rows[i].editors[j].width; } if(new_width < 12) rows[i].editors[biggest].width += 12-new_width; rows[i].width = 12; } } // layout hasn't changed if(this.layout === JSON.stringify(rows)) return false; this.layout = JSON.stringify(rows); // Layout the form container = document.createElement('div'); for(i=0; i= this.schema.maxProperties); if(this.addproperty_checkboxes) { this.addproperty_list.innerHTML = ''; } this.addproperty_checkboxes = {}; // Check for which editors can't be removed or added back for(i in this.cached_editors) { if(!this.cached_editors.hasOwnProperty(i)) continue; this.addPropertyCheckbox(i); if(this.isRequired(this.cached_editors[i]) && i in this.editors) { this.addproperty_checkboxes[i].disabled = true; } if(typeof this.schema.minProperties !== "undefined" && num_props <= this.schema.minProperties) { this.addproperty_checkboxes[i].disabled = this.addproperty_checkboxes[i].checked; if(!this.addproperty_checkboxes[i].checked) show_modal = true; } else if(!(i in this.editors)) { if(!can_add && !this.schema.properties.hasOwnProperty(i)) { this.addproperty_checkboxes[i].disabled = true; } else { this.addproperty_checkboxes[i].disabled = false; show_modal = true; } } else { show_modal = true; can_remove = true; } } if(this.canHaveAdditionalProperties()) { show_modal = true; } // Additional addproperty checkboxes not tied to a current editor for(i in this.schema.properties) { if(!this.schema.properties.hasOwnProperty(i)) continue; if(this.cached_editors[i]) continue; show_modal = true; this.addPropertyCheckbox(i); } // If no editors can be added or removed, hide the modal button if(!show_modal) { this.hideAddProperty(); this.addproperty_controls.style.display = 'none'; } // If additional properties are disabled else if(!this.canHaveAdditionalProperties()) { this.addproperty_add.style.display = 'none'; this.addproperty_input.style.display = 'none'; } // If no new properties can be added else if(!can_add) { this.addproperty_add.disabled = true; } // If new properties can be added else { this.addproperty_add.disabled = false; } }, isRequired: function(editor) { if(typeof editor.schema.required === "boolean") return editor.schema.required; else if(Array.isArray(this.schema.required)) return this.schema.required.indexOf(editor.key) > -1; else if(this.jsoneditor.options.required_by_default) return true; else return false; }, setValue: function(value, initial) { var self = this; value = value || {}; if(typeof value !== "object" || Array.isArray(value)) value = {}; // First, set the values for all of the defined properties $each(this.cached_editors, function(i,editor) { // Value explicitly set if(typeof value[i] !== "undefined") { self.addObjectProperty(i); editor.setValue(value[i],initial); } // Otherwise, remove value unless this is the initial set or it's required else if(!initial && !self.isRequired(editor)) { self.removeObjectProperty(i); } // Otherwise, set the value to the default else { editor.setValue(editor.getDefault(),initial); } }); $each(value, function(i,val) { if(!self.cached_editors[i]) { self.addObjectProperty(i); if(self.editors[i]) self.editors[i].setValue(val,initial); } }); this.refreshValue(); this.layoutEditors(); this.onChange(); }, showValidationErrors: function(errors) { var self = this; // Get all the errors that pertain to this editor var my_errors = []; var other_errors = []; $each(errors, function(i,error) { if(error.path === self.path) { my_errors.push(error); } else { other_errors.push(error); } }); // Show errors for this editor if(this.error_holder) { if(my_errors.length) { var message = []; this.error_holder.innerHTML = ''; this.error_holder.style.display = ''; $each(my_errors, function(i,error) { self.error_holder.appendChild(self.theme.getErrorMessage(error.message)); }); } // Hide error area else { this.error_holder.style.display = 'none'; } } // Show error for the table row if this is inside a table if(this.options.table_row) { if(my_errors.length) { this.theme.addTableRowError(this.container); } else { this.theme.removeTableRowError(this.container); } } // Show errors for child editors $each(this.editors, function(i,editor) { editor.showValidationErrors(other_errors); }); } }); JSONEditor.defaults.editors.array = JSONEditor.AbstractEditor.extend({ getDefault: function() { return this.schema["default"] || []; }, register: function() { this._super(); if(this.rows) { for(var i=0; i= this.schema.items.length) { if(this.schema.additionalItems===true) { return {}; } else if(this.schema.additionalItems) { return $extend({},this.schema.additionalItems); } } else { return $extend({},this.schema.items[i]); } } else if(this.schema.items) { return $extend({},this.schema.items); } else { return {}; } }, getItemInfo: function(i) { var schema = this.getItemSchema(i); // Check if it's cached this.item_info = this.item_info || {}; var stringified = JSON.stringify(schema); if(typeof this.item_info[stringified] !== "undefined") return this.item_info[stringified]; // Get the schema for this item schema = this.jsoneditor.expandRefs(schema); this.item_info[stringified] = { title: schema.title || "item", 'default': schema["default"], width: 12, child_editors: schema.properties || schema.items }; return this.item_info[stringified]; }, getElementEditor: function(i) { var item_info = this.getItemInfo(i); var schema = this.getItemSchema(i); schema = this.jsoneditor.expandRefs(schema); schema.title = $.i18n(item_info.title)+' '+(i+1); var editor = this.jsoneditor.getEditorClass(schema); var holder; if(this.tabs_holder) { holder = this.theme.getTabContent(); } else if(item_info.child_editors) { holder = this.theme.getChildEditorHolder(); } else { holder = this.theme.getIndentedPanel(); } this.row_holder.appendChild(holder); var ret = this.jsoneditor.createEditor(editor,{ jsoneditor: this.jsoneditor, schema: schema, container: holder, path: this.path+'.'+i, parent: this, required: true }); ret.preBuild(); ret.build(); ret.postBuild(); if(!ret.title_controls) { ret.array_controls = this.theme.getButtonHolder(); holder.appendChild(ret.array_controls); } return ret; }, destroy: function() { this.empty(true); if(this.title && this.title.parentNode) this.title.parentNode.removeChild(this.title); if(this.description && this.description.parentNode) this.description.parentNode.removeChild(this.description); if(this.row_holder && this.row_holder.parentNode) this.row_holder.parentNode.removeChild(this.row_holder); if(this.controls && this.controls.parentNode) this.controls.parentNode.removeChild(this.controls); if(this.panel && this.panel.parentNode) this.panel.parentNode.removeChild(this.panel); this.rows = this.row_cache = this.title = this.description = this.row_holder = this.panel = this.controls = null; this._super(); }, empty: function(hard) { if(!this.rows) return; var self = this; $each(this.rows,function(i,row) { if(hard) { if(row.tab && row.tab.parentNode) row.tab.parentNode.removeChild(row.tab); self.destroyRow(row,true); self.row_cache[i] = null; } self.rows[i] = null; }); self.rows = []; if(hard) self.row_cache = []; }, destroyRow: function(row,hard) { var holder = row.container; if(hard) { row.destroy(); if(holder.parentNode) holder.parentNode.removeChild(holder); if(row.tab && row.tab.parentNode) row.tab.parentNode.removeChild(row.tab); } else { if(row.tab) row.tab.style.display = 'none'; holder.style.display = 'none'; row.unregister(); } }, getMax: function() { if((Array.isArray(this.schema.items)) && this.schema.additionalItems === false) { return Math.min(this.schema.items.length,this.schema.maxItems || Infinity); } else { return this.schema.maxItems || Infinity; } }, refreshTabs: function(refresh_headers) { var self = this; $each(this.rows, function(i,row) { if(!row.tab) return; if(refresh_headers) { row.tab_text.textContent = row.getHeaderText(); } else { if(row.tab === self.active_tab) { self.theme.markTabActive(row.tab); row.container.style.display = ''; } else { self.theme.markTabInactive(row.tab); row.container.style.display = 'none'; } } }); }, setValue: function(value, initial) { // Update the array's value, adding/removing rows when necessary value = value || []; if(!(Array.isArray(value))) value = [value]; var serialized = JSON.stringify(value); if(serialized === this.serialized) return; // Make sure value has between minItems and maxItems items in it if(this.schema.minItems) { while(value.length < this.schema.minItems) { value.push(this.getItemInfo(value.length)["default"]); } } if(this.getMax() && value.length > this.getMax()) { value = value.slice(0,this.getMax()); } var self = this; $each(value,function(i,val) { if(self.rows[i]) { // TODO: don't set the row's value if it hasn't changed self.rows[i].setValue(val,initial); } else if(self.row_cache[i]) { self.rows[i] = self.row_cache[i]; self.rows[i].setValue(val,initial); self.rows[i].container.style.display = ''; if(self.rows[i].tab) self.rows[i].tab.style.display = ''; self.rows[i].register(); } else { self.addRow(val,initial); } }); for(var j=value.length; j= this.rows.length; $each(this.rows,function(i,editor) { // Hide the move down button for the last row if(editor.movedown_button) { if(i === self.rows.length - 1) { editor.movedown_button.style.display = 'none'; } else { editor.movedown_button.style.display = ''; } } // Hide the delete button if we have minItems items if(editor.delete_button) { if(minItems) { editor.delete_button.style.display = 'none'; } else { editor.delete_button.style.display = ''; } } // Get the value for this editor self.value[i] = editor.getValue(); }); var controls_needed = false; if(!this.value.length) { this.delete_last_row_button.style.display = 'none'; this.remove_all_rows_button.style.display = 'none'; } else if(this.value.length === 1) { this.remove_all_rows_button.style.display = 'none'; // If there are minItems items in the array, or configured to hide the delete_last_row button, hide the delete button beneath the rows if(minItems || this.hide_delete_last_row_buttons) { this.delete_last_row_button.style.display = 'none'; } else { this.delete_last_row_button.style.display = ''; controls_needed = true; } } else { if(minItems || this.hide_delete_last_row_buttons) { this.delete_last_row_button.style.display = 'none'; } else { this.delete_last_row_button.style.display = ''; controls_needed = true; } if(minItems || this.hide_delete_all_rows_buttons) { this.remove_all_rows_button.style.display = 'none'; } else { this.remove_all_rows_button.style.display = ''; controls_needed = true; } } // If there are maxItems in the array, hide the add button beneath the rows if((this.getMax() && this.getMax() <= this.rows.length) || this.hide_add_button){ this.add_row_button.style.display = 'none'; } else { this.add_row_button.style.display = ''; controls_needed = true; } if(!this.collapsed && controls_needed) { this.controls.style.display = 'inline-block'; } else { this.controls.style.display = 'none'; } } }, addRow: function(value, initial) { var self = this; var i = this.rows.length; self.rows[i] = this.getElementEditor(i); self.row_cache[i] = self.rows[i]; if(self.tabs_holder) { self.rows[i].tab_text = document.createElement('span'); self.rows[i].tab_text.textContent = self.rows[i].getHeaderText(); self.rows[i].tab = self.theme.getTab(self.rows[i].tab_text); self.rows[i].tab.addEventListener('click', function(e) { self.active_tab = self.rows[i].tab; self.refreshTabs(); e.preventDefault(); e.stopPropagation(); }); self.theme.addTab(self.tabs_holder, self.rows[i].tab); } var controls_holder = self.rows[i].title_controls || self.rows[i].array_controls; // Buttons to delete row, move row up, and move row down if(!self.hide_delete_buttons) { self.rows[i].delete_button = this.getButton(self.getItemTitle(),'delete',this.translate('edt_msg_button_delete_row_title',[self.getItemTitle()])); self.rows[i].delete_button.className += ' delete'; self.rows[i].delete_button.setAttribute('data-i',i); self.rows[i].delete_button.addEventListener('click',function(e) { e.preventDefault(); e.stopPropagation(); var i = this.getAttribute('data-i')*1; var value = self.getValue(); var newval = []; var new_active_tab = null; $each(value,function(j,row) { if(j===i) { // If the one we're deleting is the active tab if(self.rows[j].tab === self.active_tab) { // Make the next tab active if there is one // Note: the next tab is going to be the current tab after deletion if(self.rows[j+1]) new_active_tab = self.rows[j].tab; // Otherwise, make the previous tab active if there is one else if(j) new_active_tab = self.rows[j-1].tab; } return; // If this is the one we're deleting } newval.push(row); }); self.setValue(newval); if(new_active_tab) { self.active_tab = new_active_tab; self.refreshTabs(); } self.onChange(true); }); if(controls_holder) { controls_holder.appendChild(self.rows[i].delete_button); } } if(i && !self.hide_move_buttons) { self.rows[i].moveup_button = this.getButton('','moveup',this.translate('edt_msg_button_move_up_title')); self.rows[i].moveup_button.className += ' moveup'; self.rows[i].moveup_button.setAttribute('data-i',i); self.rows[i].moveup_button.addEventListener('click',function(e) { e.preventDefault(); e.stopPropagation(); var i = this.getAttribute('data-i')*1; if(i<=0) return; var rows = self.getValue(); var tmp = rows[i-1]; rows[i-1] = rows[i]; rows[i] = tmp; self.setValue(rows); self.active_tab = self.rows[i-1].tab; self.refreshTabs(); self.onChange(true); }); if(controls_holder) { controls_holder.appendChild(self.rows[i].moveup_button); } } if(!self.hide_move_buttons) { self.rows[i].movedown_button = this.getButton('','movedown',this.translate('edt_msg_button_move_down_title')); self.rows[i].movedown_button.className += ' movedown'; self.rows[i].movedown_button.setAttribute('data-i',i); self.rows[i].movedown_button.addEventListener('click',function(e) { e.preventDefault(); e.stopPropagation(); var i = this.getAttribute('data-i')*1; var rows = self.getValue(); if(i>=rows.length-1) return; var tmp = rows[i+1]; rows[i+1] = rows[i]; rows[i] = tmp; self.setValue(rows); self.active_tab = self.rows[i+1].tab; self.refreshTabs(); self.onChange(true); }); if(controls_holder) { controls_holder.appendChild(self.rows[i].movedown_button); } } if(value) self.rows[i].setValue(value, initial); self.refreshTabs(); }, addControls: function() { var self = this; this.collapsed = false; this.toggle_button = this.getButton('','collapse',this.translate('edt_msg_button_collapse')); this.title_controls.appendChild(this.toggle_button); var row_holder_display = self.row_holder.style.display; var controls_display = self.controls.style.display; this.toggle_button.addEventListener('click',function(e) { e.preventDefault(); e.stopPropagation(); if(self.collapsed) { self.collapsed = false; if(self.panel) self.panel.style.display = ''; self.row_holder.style.display = row_holder_display; if(self.tabs_holder) self.tabs_holder.style.display = ''; self.controls.style.display = controls_display; self.setButtonText(this,'','collapse',self.translate('edt_msg_button_collapse')); } else { self.collapsed = true; self.row_holder.style.display = 'none'; if(self.tabs_holder) self.tabs_holder.style.display = 'none'; self.controls.style.display = 'none'; if(self.panel) self.panel.style.display = 'none'; self.setButtonText(this,'','expand',self.translate('edt_msg_button_expand')); } }); // If it should start collapsed if(this.options.collapsed) { $trigger(this.toggle_button,'click'); } // Collapse button disabled if(this.schema.options && typeof this.schema.options.disable_collapse !== "undefined") { if(this.schema.options.disable_collapse) this.toggle_button.style.display = 'none'; } else if(this.jsoneditor.options.disable_collapse) { this.toggle_button.style.display = 'none'; } // Add "new row" and "delete last" buttons below editor this.add_row_button = this.getButton(this.getItemTitle(),'add',this.translate('edt_msg_button_add_row_title',[this.getItemTitle()])); this.add_row_button.addEventListener('click',function(e) { e.preventDefault(); e.stopPropagation(); var i = self.rows.length; if(self.row_cache[i]) { self.rows[i] = self.row_cache[i]; self.rows[i].setValue(self.rows[i].getDefault(), true); self.rows[i].container.style.display = ''; if(self.rows[i].tab) self.rows[i].tab.style.display = ''; self.rows[i].register(); } else { self.addRow(); } self.active_tab = self.rows[i].tab; self.refreshTabs(); self.refreshValue(); self.onChange(true); }); self.controls.appendChild(this.add_row_button); this.delete_last_row_button = this.getButton(this.translate('edt_msg_button_delete_last',[this.getItemTitle()]),'delete',this.translate('edt_msg_button_delete_last_title',[this.getItemTitle()])); this.delete_last_row_button.addEventListener('click',function(e) { e.preventDefault(); e.stopPropagation(); var rows = self.getValue(); var new_active_tab = null; if(self.rows.length > 1 && self.rows[self.rows.length-1].tab === self.active_tab) new_active_tab = self.rows[self.rows.length-2].tab; rows.pop(); self.setValue(rows); if(new_active_tab) { self.active_tab = new_active_tab; self.refreshTabs(); } self.onChange(true); }); self.controls.appendChild(this.delete_last_row_button); this.remove_all_rows_button = this.getButton(this.translate('edt_msg_button_delete_all'),'delete',this.translate('edt_msg_button_delete_all_title')); this.remove_all_rows_button.addEventListener('click',function(e) { e.preventDefault(); e.stopPropagation(); self.setValue([]); self.onChange(true); }); self.controls.appendChild(this.remove_all_rows_button); if(self.tabs) { this.add_row_button.style.width = '100%'; this.add_row_button.style.textAlign = 'left'; this.add_row_button.style.marginBottom = '3px'; this.delete_last_row_button.style.width = '100%'; this.delete_last_row_button.style.textAlign = 'left'; this.delete_last_row_button.style.marginBottom = '3px'; this.remove_all_rows_button.style.width = '100%'; this.remove_all_rows_button.style.textAlign = 'left'; this.remove_all_rows_button.style.marginBottom = '3px'; } }, showValidationErrors: function(errors) { var self = this; // Get all the errors that pertain to this editor var my_errors = []; var other_errors = []; $each(errors, function(i,error) { if(error.path === self.path) { my_errors.push(error); } else { other_errors.push(error); } }); // Show errors for this editor if(this.error_holder) { if(my_errors.length) { var message = []; this.error_holder.innerHTML = ''; this.error_holder.style.display = ''; $each(my_errors, function(i,error) { self.error_holder.appendChild(self.theme.getErrorMessage(error.message)); }); } // Hide error area else { this.error_holder.style.display = 'none'; } } // Show errors for child editors $each(this.rows, function(i,row) { row.showValidationErrors(other_errors); }); } }); JSONEditor.defaults.editors.table = JSONEditor.defaults.editors.array.extend({ register: function() { this._super(); if(this.rows) { for(var i=0; i this.schema.maxItems) { value = value.slice(0,this.schema.maxItems); } var serialized = JSON.stringify(value); if(serialized === this.serialized) return; var numrows_changed = false; var self = this; $each(value,function(i,val) { if(self.rows[i]) { // TODO: don't set the row's value if it hasn't changed self.rows[i].setValue(val); } else { self.addRow(val); numrows_changed = true; } }); for(var j=value.length; j= this.rows.length; var need_row_buttons = false; $each(this.rows,function(i,editor) { // Hide the move down button for the last row if(editor.movedown_button) { if(i === self.rows.length - 1) { editor.movedown_button.style.display = 'none'; } else { need_row_buttons = true; editor.movedown_button.style.display = ''; } } // Hide the delete button if we have minItems items if(editor.delete_button) { if(minItems) { editor.delete_button.style.display = 'none'; } else { need_row_buttons = true; editor.delete_button.style.display = ''; } } if(editor.moveup_button) { need_row_buttons = true; } }); // Show/hide controls column in table $each(this.rows,function(i,editor) { if(need_row_buttons) { editor.controls_cell.style.display = ''; } else { editor.controls_cell.style.display = 'none'; } }); if(need_row_buttons) { this.controls_header_cell.style.display = ''; } else { this.controls_header_cell.style.display = 'none'; } var controls_needed = false; if(!this.value.length) { this.delete_last_row_button.style.display = 'none'; this.remove_all_rows_button.style.display = 'none'; this.table.style.display = 'none'; } else if(this.value.length === 1) { this.table.style.display = ''; this.remove_all_rows_button.style.display = 'none'; // If there are minItems items in the array, or configured to hide the delete_last_row button, hide the delete button beneath the rows if(minItems || this.hide_delete_last_row_buttons) { this.delete_last_row_button.style.display = 'none'; } else { this.delete_last_row_button.style.display = ''; controls_needed = true; } } else { this.table.style.display = ''; if(minItems || this.hide_delete_last_row_buttons) { this.delete_last_row_button.style.display = 'none'; } else { this.delete_last_row_button.style.display = ''; controls_needed = true; } if(minItems || this.hide_delete_all_rows_buttons) { this.remove_all_rows_button.style.display = 'none'; } else { this.remove_all_rows_button.style.display = ''; controls_needed = true; } } // If there are maxItems in the array, hide the add button beneath the rows if((this.schema.maxItems && this.schema.maxItems <= this.rows.length) || this.hide_add_button) { this.add_row_button.style.display = 'none'; } else { this.add_row_button.style.display = ''; controls_needed = true; } if(!controls_needed) { this.controls.style.display = 'none'; } else { this.controls.style.display = ''; } }, refreshValue: function() { var self = this; this.value = []; $each(this.rows,function(i,editor) { // Get the value for this editor self.value[i] = editor.getValue(); }); this.serialized = JSON.stringify(this.value); }, addRow: function(value) { var self = this; var i = this.rows.length; self.rows[i] = this.getElementEditor(i); var controls_holder = self.rows[i].table_controls; // Buttons to delete row, move row up, and move row down if(!this.hide_delete_buttons) { self.rows[i].delete_button = this.getButton('','delete',this.translate('edt_msg_button_delete_row_title_short')); self.rows[i].delete_button.className += ' delete'; self.rows[i].delete_button.setAttribute('data-i',i); self.rows[i].delete_button.addEventListener('click',function(e) { e.preventDefault(); e.stopPropagation(); var i = this.getAttribute('data-i')*1; var value = self.getValue(); var newval = []; $each(value,function(j,row) { if(j===i) return; // If this is the one we're deleting newval.push(row); }); self.setValue(newval); self.onChange(true); }); controls_holder.appendChild(self.rows[i].delete_button); } if(i && !this.hide_move_buttons) { self.rows[i].moveup_button = this.getButton('','moveup',this.translate('edt_msg_button_move_up_title')); self.rows[i].moveup_button.className += ' moveup'; self.rows[i].moveup_button.setAttribute('data-i',i); self.rows[i].moveup_button.addEventListener('click',function(e) { e.preventDefault(); e.stopPropagation(); var i = this.getAttribute('data-i')*1; if(i<=0) return; var rows = self.getValue(); var tmp = rows[i-1]; rows[i-1] = rows[i]; rows[i] = tmp; self.setValue(rows); self.onChange(true); }); controls_holder.appendChild(self.rows[i].moveup_button); } if(!this.hide_move_buttons) { self.rows[i].movedown_button = this.getButton('','movedown',this.translate('edt_msg_button_move_down_title')); self.rows[i].movedown_button.className += ' movedown'; self.rows[i].movedown_button.setAttribute('data-i',i); self.rows[i].movedown_button.addEventListener('click',function(e) { e.preventDefault(); e.stopPropagation(); var i = this.getAttribute('data-i')*1; var rows = self.getValue(); if(i>=rows.length-1) return; var tmp = rows[i+1]; rows[i+1] = rows[i]; rows[i] = tmp; self.setValue(rows); self.onChange(true); }); controls_holder.appendChild(self.rows[i].movedown_button); } if(value) self.rows[i].setValue(value); }, addControls: function() { var self = this; this.collapsed = false; this.toggle_button = this.getButton('','collapse',this.translate('edt_msg_button_collapse')); if(this.title_controls) { this.title_controls.appendChild(this.toggle_button); this.toggle_button.addEventListener('click',function(e) { e.preventDefault(); e.stopPropagation(); if(self.collapsed) { self.collapsed = false; self.panel.style.display = ''; self.setButtonText(this,'','collapse',self.translate('edt_msg_button_collapse')); } else { self.collapsed = true; self.panel.style.display = 'none'; self.setButtonText(this,'','expand',self.translate('edt_msg_button_expand')); } }); // If it should start collapsed if(this.options.collapsed) { $trigger(this.toggle_button,'click'); } // Collapse button disabled if(this.schema.options && typeof this.schema.options.disable_collapse !== "undefined") { if(this.schema.options.disable_collapse) this.toggle_button.style.display = 'none'; } else if(this.jsoneditor.options.disable_collapse) { this.toggle_button.style.display = 'none'; } } // Add "new row" and "delete last" buttons below editor this.add_row_button = this.getButton(this.getItemTitle(),'add',this.translate('edt_msg_button_add_row_title',[this.getItemTitle()])); this.add_row_button.addEventListener('click',function(e) { e.preventDefault(); e.stopPropagation(); self.addRow(); self.refreshValue(); self.refreshRowButtons(); self.onChange(true); }); self.controls.appendChild(this.add_row_button); this.delete_last_row_button = this.getButton(this.translate('edt_msg_button_delete_last',[this.getItemTitle()]),'delete',this.translate('edt_msg_button_delete_last_title',[this.getItemTitle()])); this.delete_last_row_button.addEventListener('click',function(e) { e.preventDefault(); e.stopPropagation(); var rows = self.getValue(); rows.pop(); self.setValue(rows); self.onChange(true); }); self.controls.appendChild(this.delete_last_row_button); this.remove_all_rows_button = this.getButton(this.translate('edt_msg_button_delete_all'),'delete',this.translate('edt_msg_button_delete_all_title')); this.remove_all_rows_button.addEventListener('click',function(e) { e.preventDefault(); e.stopPropagation(); self.setValue([]); self.onChange(true); }); self.controls.appendChild(this.remove_all_rows_button); } }); // Multiple Editor (for when `type` is an array) JSONEditor.defaults.editors.multiple = JSONEditor.AbstractEditor.extend({ register: function() { if(this.editors) { for(var i=0; inull'; } // Array or Object else if(typeof el === "object") { // TODO: use theme var ret = ''; $each(el,function(i,child) { var html = self.getHTML(child); // Add the keys to object children if(!(Array.isArray(el))) { // TODO: use theme html = '
'+i+': '+html+'
'; } // TODO: use theme ret += '
  • '+html+'
  • '; }); if(Array.isArray(el)) ret = '
      '+ret+'
    '; else ret = "
      "+ret+'
    '; return ret; } // Boolean else if(typeof el === "boolean") { return el? 'true' : 'false'; } // String else if(typeof el === "string") { return el.replace(/&/g,'&').replace(//g,'>'); } // Number else { return el; } }, setValue: function(val) { if(this.value !== val) { this.value = val; this.refreshValue(); this.onChange(); } }, destroy: function() { if(this.display_area && this.display_area.parentNode) this.display_area.parentNode.removeChild(this.display_area); if(this.title && this.title.parentNode) this.title.parentNode.removeChild(this.title); if(this.switcher && this.switcher.parentNode) this.switcher.parentNode.removeChild(this.switcher); this._super(); } }); 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 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= 2 || (this.enum_options.length && this.enumSource))) { var options = $extend({},JSONEditor.plugins.selectize); if(this.schema.options && this.schema.options.selectize_options) options = $extend(options,this.schema.options.selectize_options); this.selectize = window.jQuery(this.input).selectize($extend(options, { create: true, onChange : function() { self.onInputChange(); } })); } else { this.selectize = null; } }, postBuild: function() { this._super(); this.theme.afterInputReady(this.input); this.setupSelectize(); }, 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; iSize: '+Math.floor((this.value.length-this.value.split(',')[0].length-1)/1.33333)+' bytes'; if(mime.substr(0,5)==="image") { this.preview.innerHTML += '
    '; var img = document.createElement('img'); img.style.maxWidth = '100%'; img.style.maxHeight = '100px'; img.src = this.value; this.preview.appendChild(img); } } }, enable: function() { if(this.uploader) this.uploader.disabled = false; this._super(); }, disable: function() { if(this.uploader) this.uploader.disabled = true; this._super(); }, setValue: function(val) { if(this.value !== val) { this.value = val; this.input.value = this.value; this.refreshPreview(); this.onChange(); } }, destroy: function() { if(this.preview && this.preview.parentNode) this.preview.parentNode.removeChild(this.preview); if(this.title && this.title.parentNode) this.title.parentNode.removeChild(this.title); if(this.input && this.input.parentNode) this.input.parentNode.removeChild(this.input); if(this.uploader && this.uploader.parentNode) this.uploader.parentNode.removeChild(this.uploader); this._super(); } }); JSONEditor.defaults.editors.upload = JSONEditor.AbstractEditor.extend({ getNumColumns: function() { return 4; }, build: function() { var self = this; this.title = this.header = this.label = this.theme.getFormInputLabel(this.getTitle()); // Input that holds the base64 string this.input = this.theme.getFormInputField('hidden'); this.container.appendChild(this.input); // Don't show uploader if this is readonly if(!this.schema.readOnly && !this.schema.readonly) { if(!this.jsoneditor.options.upload) throw "Upload handler required for upload editor"; // File uploader this.uploader = this.theme.getFormInputField('file'); this.uploader.addEventListener('change',function(e) { e.preventDefault(); e.stopPropagation(); if(this.files && this.files.length) { var fr = new FileReader(); fr.onload = function(evt) { self.preview_value = evt.target.result; self.refreshPreview(); self.onChange(true); fr = null; }; fr.readAsDataURL(this.files[0]); } }); } var description = this.schema.description; if (!description) description = ''; this.preview = this.theme.getFormInputDescription(description); this.container.appendChild(this.preview); this.control = this.theme.getFormControl(this.label, this.uploader||this.input, this.preview); this.container.appendChild(this.control); }, refreshPreview: function() { if(this.last_preview === this.preview_value) return; this.last_preview = this.preview_value; this.preview.innerHTML = ''; if(!this.preview_value) return; var self = this; var mime = this.preview_value.match(/^data:([^;,]+)[;,]/); if(mime) mime = mime[1]; if(!mime) mime = 'unknown'; var file = this.uploader.files[0]; this.preview.innerHTML = 'Type: '+mime+', Size: '+file.size+' bytes'; if(mime.substr(0,5)==="image") { this.preview.innerHTML += '
    '; var img = document.createElement('img'); img.style.maxWidth = '100%'; img.style.maxHeight = '100px'; img.src = this.preview_value; this.preview.appendChild(img); } this.preview.innerHTML += '
    '; var uploadButton = this.getButton('Upload', 'upload', 'Upload'); this.preview.appendChild(uploadButton); uploadButton.addEventListener('click',function(event) { event.preventDefault(); uploadButton.setAttribute("disabled", "disabled"); self.theme.removeInputError(self.uploader); if (self.theme.getProgressBar) { self.progressBar = self.theme.getProgressBar(); self.preview.appendChild(self.progressBar); } self.jsoneditor.options.upload(self.path, file, { success: function(url) { self.setValue(url); if(self.parent) self.parent.onChildEditorChange(self); else self.jsoneditor.onChange(); if (self.progressBar) self.preview.removeChild(self.progressBar); uploadButton.removeAttribute("disabled"); }, failure: function(error) { self.theme.addInputError(self.uploader, error); if (self.progressBar) self.preview.removeChild(self.progressBar); uploadButton.removeAttribute("disabled"); }, updateProgress: function(progress) { if (self.progressBar) { if (progress) self.theme.updateProgressBar(self.progressBar, progress); else self.theme.updateProgressBarUnknown(self.progressBar); } } }); }); }, enable: function() { if(this.uploader) this.uploader.disabled = false; this._super(); }, disable: function() { if(this.uploader) this.uploader.disabled = true; this._super(); }, setValue: function(val) { if(this.value !== val) { this.value = val; this.input.value = this.value; this.onChange(); } }, destroy: function() { if(this.preview && this.preview.parentNode) this.preview.parentNode.removeChild(this.preview); if(this.title && this.title.parentNode) this.title.parentNode.removeChild(this.title); if(this.input && this.input.parentNode) this.input.parentNode.removeChild(this.input); if(this.uploader && this.uploader.parentNode) this.uploader.parentNode.removeChild(this.uploader); this._super(); } }); JSONEditor.defaults.editors.checkbox = JSONEditor.AbstractEditor.extend({ setValue: function(value,initial) { this.value = !!value; this.input.checked = this.value; 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() { return Math.min(12,Math.max(this.getTitle().length/7,2)); }, build: function() { var self = this; if(!this.options.compact) { this.label = this.header = this.theme.getCheckboxLabel(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.getCheckbox(); this.control = this.theme.getFormControl(this.label, this.input, this.description); 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.value = this.checked; self.onChange(true); }); this.container.appendChild(this.control); }, enable: function() { if(!this.always_disabled) { this.input.disabled = false; } this._super(); }, disable: function() { this.input.disabled = true; 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); this._super(); } }); JSONEditor.defaults.editors.arraySelectize = JSONEditor.AbstractEditor.extend({ build: function() { this.title = this.theme.getFormInputLabel(this.getTitle()); this.title_controls = this.theme.getHeaderButtonHolder(); this.title.appendChild(this.title_controls); this.error_holder = document.createElement('div'); if(this.schema.description) { this.description = this.theme.getDescription(this.schema.description); } if(this.schema.append) { this.append = this.theme.getAppend(this.getAppend()); } this.input = document.createElement('select'); this.input.setAttribute('multiple', 'multiple'); var group = this.theme.getFormControl(this.title, this.input, this.description); this.container.appendChild(group); this.container.appendChild(this.error_holder); window.jQuery(this.input).selectize({ delimiter: false, createOnBlur: true, create: true }); }, postBuild: function() { var self = this; this.input.selectize.on('change', function(event) { self.refreshValue(); self.onChange(true); }); }, destroy: function() { this.empty(true); if(this.title && this.title.parentNode) this.title.parentNode.removeChild(this.title); if(this.description && this.description.parentNode) this.description.parentNode.removeChild(this.description); if(this.input && this.input.parentNode) this.input.parentNode.removeChild(this.input); this._super(); }, empty: function(hard) {}, setValue: function(value, initial) { var self = this; // Update the array's value, adding/removing rows when necessary value = value || []; if(!(Array.isArray(value))) value = [value]; this.input.selectize.clearOptions(); this.input.selectize.clear(true); value.forEach(function(item) { self.input.selectize.addOption({text: item, value: item}); }); this.input.selectize.setValue(value); this.refreshValue(initial); }, refreshValue: function(force) { this.value = this.input.selectize.getValue(); }, showValidationErrors: function(errors) { var self = this; // Get all the errors that pertain to this editor var my_errors = []; var other_errors = []; $each(errors, function(i,error) { if(error.path === self.path) { my_errors.push(error); } else { other_errors.push(error); } }); // Show errors for this editor if(this.error_holder) { if(my_errors.length) { var message = []; this.error_holder.innerHTML = ''; this.error_holder.style.display = ''; $each(my_errors, function(i,error) { self.error_holder.appendChild(self.theme.getErrorMessage(error.message)); }); } // Hide error area else { this.error_holder.style.display = 'none'; } } } }); var matchKey = (function () { var elem = document.documentElement; if (elem.matches) return 'matches'; else if (elem.webkitMatchesSelector) return 'webkitMatchesSelector'; else if (elem.mozMatchesSelector) return 'mozMatchesSelector'; else if (elem.msMatchesSelector) return 'msMatchesSelector'; else if (elem.oMatchesSelector) return 'oMatchesSelector'; })(); JSONEditor.AbstractTheme = Class.extend({ getContainer: function() { return document.createElement('div'); }, getFloatRightLinkHolder: function() { var el = document.createElement('div'); el.style = el.style || {}; el.style.cssFloat = 'right'; el.style.marginLeft = '10px'; return el; }, getModal: function() { var el = document.createElement('div'); el.style.backgroundColor = 'white'; el.style.border = '1px solid black'; el.style.boxShadow = '3px 3px black'; el.style.position = 'absolute'; el.style.zIndex = '10'; el.style.display = 'none'; return el; }, getGridContainer: function() { var el = document.createElement('div'); return el; }, getGridRow: function() { var el = document.createElement('div'); el.className = 'row'; return el; }, getGridColumn: function() { var el = document.createElement('div'); return el; }, setGridColumnSize: function(el,size) { }, getLink: function(text) { var el = document.createElement('a'); el.setAttribute('href','#'); el.appendChild(document.createTextNode(text)); return el; }, disableHeader: function(header) { header.style.color = '#ccc'; }, disableLabel: function(label) { label.style.color = '#ccc'; }, enableHeader: function(header) { header.style.color = ''; }, enableLabel: function(label) { label.style.color = ''; }, getFormInputLabel: function(text) { var el = document.createElement('label'); el.appendChild(document.createTextNode(text)); return el; }, getCheckboxLabel: function(text) { var el = this.getFormInputLabel(text); el.style.fontWeight = 'normal'; return el; }, getHeader: function(text) { var el = document.createElement('h3'); if(typeof text === "string") { el.textContent = text; } else { el.appendChild(text); } return el; }, getCheckbox: function() { var el = this.getFormInputField('checkbox'); el.style.display = 'inline-block'; el.style.width = 'auto'; return el; }, getMultiCheckboxHolder: function(controls,label,description) { var el = document.createElement('div'); if(label) { label.style.display = 'block'; el.appendChild(label); } for(var i in controls) { if(!controls.hasOwnProperty(i)) continue; controls[i].style.display = 'inline-block'; controls[i].style.marginRight = '20px'; el.appendChild(controls[i]); } if(description) el.appendChild(description); return el; }, getSelectInput: function(options) { var select = document.createElement('select'); if(options) this.setSelectOptions(select, options); return select; }, getSwitcher: function(options) { var switcher = this.getSelectInput(options); switcher.style.backgroundColor = 'transparent'; switcher.style.display = 'inline-block'; switcher.style.fontStyle = 'italic'; switcher.style.fontWeight = 'normal'; switcher.style.height = 'auto'; switcher.style.marginBottom = 0; switcher.style.marginLeft = '5px'; switcher.style.padding = '0 0 0 3px'; switcher.style.width = 'auto'; return switcher; }, getSwitcherOptions: function(switcher) { return switcher.getElementsByTagName('option'); }, setSwitcherOptions: function(switcher, options, titles) { this.setSelectOptions(switcher, options, titles); }, setSelectOptions: function(select, options, titles) { titles = titles || []; select.innerHTML = ''; for(var i=0; i 1) { var cur; func = function(vars) { cur = vars; for(i=0; i= 0) { // For enumerated strings, number, or integers if(schema.items.enum) { return 'multiselect'; } // For non-enumerated strings (tag editor) else if(JSONEditor.plugins.selectize.enable && schema.items.type === "string") { return 'arraySelectize'; } } }); // Use the multiple editor for schemas with `oneOf` set JSONEditor.defaults.resolvers.unshift(function(schema) { // If this schema uses `oneOf` or `anyOf` if(schema.oneOf || schema.anyOf) return "multiple"; }); /** * This is a small wrapper for using JSON Editor like a typical jQuery plugin. */ (function() { if(window.jQuery || window.Zepto) { var $ = window.jQuery || window.Zepto; $.jsoneditor = JSONEditor.defaults; $.fn.jsoneditor = function(options) { var self = this; var editor = this.data('jsoneditor'); if(options === 'value') { if(!editor) throw "Must initialize jsoneditor before getting/setting the value"; // Set value if(arguments.length > 1) { editor.setValue(arguments[1]); } // Get value else { return editor.getValue(); } } else if(options === 'validate') { if(!editor) throw "Must initialize jsoneditor before validating"; // Validate a specific value if(arguments.length > 1) { return editor.validate(arguments[1]); } // Validate current value else { return editor.validate(); } } else if(options === 'destroy') { if(editor) { editor.destroy(); this.data('jsoneditor',null); } } else { // Destroy first if(editor) { editor.destroy(); } // Create editor editor = new JSONEditor(this.get(0),options); this.data('jsoneditor',editor); // Setup event listeners editor.on('change',function() { self.trigger('change'); }); editor.on('ready',function() { self.trigger('ready'); }); } return this; }; } })(); window.JSONEditor = JSONEditor; })(); //# sourceMappingURL=jsoneditor.js.map