-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Home
This wiki is intended for people who want to understand JSON Editor's code structure in order to hack, contribute to, or customize the code. If you simply want to use JSON Editor as is, the README should suffice.
This document assumes basic knowledge of JSON Schema.
This document is a work in progress. More will be added soon.
JSON Editor is built to be extremely modular. This section will go over each of the modular components and how they work together.
These files wrap everything in a closure to keep things self contained.
In addition, intro.js
has licence information in a comment at the top along with the current version number and date. JSON Editor uses Semantic Versioning and is in the pre-1.0 phase. This version number is incremented whenever code is pushed to github. The minor version is incremented when major new features or backwards compatibility breaks are added. Otherwise, the patch version is incremented.
JSON Editor uses John Resig's Simple Javascript Inheritance model (http://ejohn.org/blog/simple-javascript-inheritance/). I don't recommend using this for complicated inheritance structures, but it fits JSON Editor's use case perfectly.
var MyParentClass = Class.extend({
method1: function() {},
method2: function() {}
});
var MyChildClass = MyParentClass.extend({
method1: function() {
this._super();
},
method3: function() {}
});
Every part of JSON Editor is a class. This makes it easy to extend parts as needed without modifying the core code directly.
JSON Editor was originally built as a jQuery plugin. When the jQuery dependency was removed, a couple utility functions were added in its place.
-
$extend - Just like
jQuery.extend
, except it is recursive by default. -
$each - Identical behavior to
jQuery.each
- $trigger - Trigger a native JavaScript event
- $triggerc - Trigger a custom JavaScript event
This file contains polyfills for old browsers. Currently, there are only 3 polyfills:
- requestAnimationFrame
- CustomEvent constructor
- Array.isArray
The validator is responsible for validating JSON against a JSON Schema and returning a list of errors. The validator is run automatically every time the editor's value changes.
Validation results are used a number of different places. The obvious ones are for displaying errors inline in the rendered form and powering the validate
api call. Another not-so-obvious use of the validation results is to determine which oneOf
schema to use when rendering part of the form. Consider the following JSON Schema:
{
"type": "object",
"oneOf": [
{
"properties": {
"name": {"type": "string"}
},
"required": ["name"],
"additionalProperties": false
},
{
"properties": {
"id": {"type": "integer"}
},
"required": ["id"],
"additionalProperties": false
}
]
}
When the value of the form is set programatically, JSON Editor validates the value against each of the schemas and uses the first one that passes to render the form. A similar thing is done for compound types (e.g. { "type": ["integer","string"] }
).
The Validator code itself is very complex. It starts with the outermost schema and recursively descends to child schemas, validating along the way. All of the JSON Schema Draft 3 and Draft 4 keywords are supported.
If there is a validation error, a simple error object is added to an array. At the end of validation, this array of errors is returned. An empty array is returned if there are no validation errors. Each error object in the array has 3 properties, path
, property
, and message
.
{
"path": "root.person.first_name",
"property": "minLength",
"message": "Value must be at least 2 characters long"
}
At each step in the recursive descent, JSON Editor will also call any custom validation functions defined in JSONEditor.defaults.custom_validators
.
JSON Editor supports multiple icon libraries. These are used to add icons to buttons.
All icon libraries extend JSONEditor.AbstractIconLib
. AbstractIconLib is set up to make it really easy to add new icon library support. Here's the code for FontAwesome4 support (src/iconlibs/fontawesome4.js):
JSONEditor.defaults.iconlibs.fontawesome4 = JSONEditor.AbstractIconLib.extend({
mapping: {
collapse: 'caret-square-o-down',
expand: 'caret-square-o-right',
delete: 'times',
edit: 'pencil',
add: 'plus',
cancel: 'ban',
save: 'save',
moveup: 'arrow-up',
movedown: 'arrow-down'
},
icon_prefix: 'fa fa-'
});
Calling getIcon("cancel")
will return the DOM element <i class="fa fa-ban"></i>
. If you want to add an icon library that doesn't conform to this style, you can override the getIcon
method and handle the DOM creation yourself.
Themes handle DOM creation, layout, and styling of JSON Editor forms. All themes extend the JSONEditor.AbstractTheme
class.
There are a handful of themes provided by default and it's fairly easy to create your own. The methods in the abstract class return sensible default DOM node structures, so in most cases you can just do something like this:
JSONEditor.defaults.themes.mytheme = JSONEditor.AbstractTheme.extend({
getTable: function() {
// Base function creates an empty <table> DOM element
var el = this._super();
// Modify this base element
el.style.fontSize = '50px';
return el;
}
});
A "template" in JSON Editor refers to javascript template engines like Mustache or Handlebars. Templates are objects with a compile
method that returns a compiled template function. This function takes 2 a single view
parameter containing variables and returns a string. Here is a barebones example:
var mytemplate = {
compile: function(template_string) {
return function(view) {
return template_string + ' (' + JSON.stringify(view) + ')';
}
}
};
Templates are used in a number of different places:
- The
template
keyword for schemas of typestring
- The
headerTemplate
schema keyword - The
enumSource.filter
,enumSource.title
, andenumSource.value
schema keywords
This file defines the base class for all editors - JSONEditor.AbstractEditor
. An editor
is a class that provides an editing interface for a schema. For example, a boolean editor may render a checkbox and label. Some editors, like those for objects and arrays, contain child editors. This recursive structure allows JSON Editor to support arbitrary levels of nesting in a JSON Schema.
JSONEditor.defaults.resolvers
contains an array or resolver functions for determining which editor to use for a particular schema. If a resolver function matches, it returns the name of the editor, otherwise it returns null and the next resolver function is checked. For example, there is a resolver function that checks for {"type":"boolean"}
and returns the boolean editor if it matches.
The AbstractEditor class defines many methods which can be extended by child classes. These are explained below.
This is called right after instantiating the editor. You can put any setup code here, but do not create any DOM elements. For example, you can parse the schema options, setup your data structures, instantiate and pre-build child editors, etc.
This function has access to the following object properties:
-
this.schema
- A copy of the JSON Schema for this editor -
this.options
- Editor options (from the schema or set globally) -
this.jsoneditor
- A reference to the root JSONEditor instance. -
this.parent
- A reference to the parent editor ornull
in the case of the root. -
this.key
- The key of this field. For example, in{"properties": { "name": {"type": "string"}}}
, the key for the string editor would bename
. The key is "root" for the root editor. -
this.path
- A dot separated path to the current editor (e.g. "root.person.name"). The last segment is the same asthis.key
. -
this.formname
- The editor path in a form-friendly format (e.g.root[person][name]
).
This is where you create DOM elements and render them to the screen. This function has access to all the properties in preBuild
plus:
-
this.container
- The containing DOM element for the editor. -
this.theme
- An instance of a theme class (i.e. one extendingJSONEditor.AbstractTheme
). Use this to create DOM structures.
When the user changes the value of the editor (e.g. by checking a checkbox), it needs to alert JSON Editor by calling this.onChange(true);
. You also probably want to store this value by calling this.refreshValue()
.
This is called immediately after build
and is usually used to setup event listeners and do any last minute cleanup.
The abstract postBuild
function has some default functionality, so make sure to call this._super()
if you decide to override it.
This is called when the editor's value is changed programatically. It should update the UI to reflect the new value. For example, calling setValue(false)
on a boolean editor should uncheck the checkbox.
The initial
parameter is set to true
when setting the initial (or default) value of the editor.
This function should call this.refreshValue()
when done.
This function should build the JSON value for the editor and store it in this.value
. For example, a simple string editor could do this.value = this.input.value;
*note - this.value
is what editor.getValue()
returns
This should destroy all DOM elements and event listeners, delete all variables, and clean up any memory used. The abstract function handles some of the common destroy
tasks, so you should call this._super()
at the end if you decide to extend this method.
Documentation for the other methods is coming soon:
- setupWatchListeners()
- onWatchedFieldChange()
- showValidationErrors(errors)
- enable()
- disable()
- getNumColumns()
- register()
- unregister()
- addLinks()
- updateHeaderText()
The core JSON Editor code provides some utility functions and glues all the other modular components together.
The JSONEditor.expandSchema
utility function resolves any $ref
, allOf
, and extends
keywords. These keywords are flattened by merging the referenced schema into the parent one.
This:
{
"type": "string",
"allOf": [
{ "minLength": 3 },
{ "maxLength": 10 }
]
}
is flattened to this:
{
"type": "string",
"minLength": 3,
"maxLength": 10
}
This pre-processing step greatly reduces the complexity of the rest of the code.
Expanding schemas is the only asynchronous part of JSON Editor. This is to allow for loading external $ref
URLs via ajax.
More documentation for core.js
coming soon.
This file sets default options and makes it possible to use JSON Editor without any configuration if desired. Any of the defaults can be overridden after JSON Editor is loaded on the page.
JSON Editor can also be used as a jQuery plugin. This feature is deprecated and may be removed in the future. This file creates a small jQuery plugin and dispatches calls to the real JSONEditor library. If jQuery is not loaded on the page, this file does nothing.