Implemented method `setSchema`
This commit is contained in:
parent
a2b84b2dd8
commit
1d9d9c2594
|
@ -6,6 +6,8 @@ https://github.com/josdejong/jsoneditor
|
|||
## not yet released, version 5.1.0
|
||||
|
||||
- Implemented support for JSON schema validation, powered by `ajv`.
|
||||
A JSON schema can be configured via the option `schema` or the method
|
||||
`setSchema`.
|
||||
- Added a minimalist bundle to the `dist` folder, excluding `ace` and `ajv`.
|
||||
- Fixed an error throw when switching to mode "code" via the menu.
|
||||
|
||||
|
|
41
docs/api.md
41
docs/api.md
|
@ -10,7 +10,7 @@ Constructs a new JSONEditor.
|
|||
|
||||
*Parameters:*
|
||||
|
||||
- `{Element} container`
|
||||
- `{Element} container`
|
||||
|
||||
An HTML DIV element. The JSONEditor will be created inside this container element.
|
||||
|
||||
|
@ -20,11 +20,13 @@ Constructs a new JSONEditor.
|
|||
[Configuration options](#configuration-options).
|
||||
|
||||
- `{JSON} json`
|
||||
|
||||
Initial JSON data to be loaded into the JSONEditor. Alternatively, the method `JSONEditor.set(json)` can be used to load JSON data into the editor.
|
||||
|
||||
*Returns:*
|
||||
|
||||
- `{JSONEditor} editor`
|
||||
|
||||
New instance of a JSONEditor.
|
||||
|
||||
### Configuration options
|
||||
|
@ -33,7 +35,7 @@ Constructs a new JSONEditor.
|
|||
|
||||
Provide a custom version of the [Ace editor](http://ace.c9.io/) and use this instead of the version that comes embedded with JSONEditor. Only applicable when `mode` is `code`.
|
||||
|
||||
- `{function} ajv`
|
||||
- `{Object} ajv`
|
||||
|
||||
Provide a custom instance of [ajv](https://github.com/epoberezkin/ajv), the
|
||||
library used for JSON schema validation. Example:
|
||||
|
@ -124,6 +126,7 @@ Set JSON data.
|
|||
*Parameters:*
|
||||
|
||||
- `{JSON} json`
|
||||
|
||||
JSON data to be displayed in the JSONEditor.
|
||||
|
||||
#### `JSONEditor.setMode(mode)`
|
||||
|
@ -132,7 +135,8 @@ Switch mode. Mode `code` requires the [Ace editor](http://ace.ajax.org/).
|
|||
|
||||
*Parameters:*
|
||||
|
||||
- `{String} mode`
|
||||
- `{String} mode`
|
||||
|
||||
Available values: `tree`, `view`, `form`, `code`, `text`.
|
||||
|
||||
#### `JSONEditor.setName(name)`
|
||||
|
@ -141,19 +145,32 @@ Set a field name for the root node.
|
|||
|
||||
*Parameters:*
|
||||
|
||||
- `{String | undefined} name`
|
||||
- `{String | undefined} name`
|
||||
|
||||
Field name of the root node. If undefined, the current name will be removed.
|
||||
|
||||
#### `JSONEditor.setSchema(schema)`
|
||||
|
||||
Set a JSON schema for validation of the JSON object. See also option `schema`.
|
||||
See [http://json-schema.org/](http://json-schema.org/) for more information on the JSON schema definition.
|
||||
|
||||
*Parameters:*
|
||||
|
||||
- `{Object} schema`
|
||||
|
||||
A JSON schema.
|
||||
|
||||
#### `JSONEditor.setText(jsonString)`
|
||||
|
||||
Set text data in the editor.
|
||||
|
||||
This method throws an exception when the provided jsonString does not contain
|
||||
This method throws an exception when the provided jsonString does not contain
|
||||
valid JSON and the editor is in mode `tree`, `view`, or `form`.
|
||||
|
||||
*Parameters:*
|
||||
|
||||
- `{String} jsonString`
|
||||
- `{String} jsonString`
|
||||
|
||||
Contents of the editor as string.
|
||||
|
||||
#### `JSONEditor.get()`
|
||||
|
@ -165,7 +182,8 @@ which can be the case when the editor is in mode `code` or `text`.
|
|||
|
||||
*Returns:*
|
||||
|
||||
- `{JSON} json`
|
||||
- `{JSON} json`
|
||||
|
||||
JSON data from the JSONEditor.
|
||||
|
||||
#### `JSONEditor.getMode()`
|
||||
|
@ -174,7 +192,8 @@ Retrieve the current mode of the editor.
|
|||
|
||||
*Returns:*
|
||||
|
||||
- `{String} mode`
|
||||
- `{String} mode`
|
||||
|
||||
Current mode of the editor for example `tree` or `code`.
|
||||
|
||||
#### `JSONEditor.getName()`
|
||||
|
@ -183,7 +202,8 @@ Retrieve the current field name of the root node.
|
|||
|
||||
*Returns:*
|
||||
|
||||
- `{String | undefined} name`
|
||||
- `{String | undefined} name`
|
||||
|
||||
Current field name of the root node, or undefined if not set.
|
||||
|
||||
#### `JSONEditor.getText()`
|
||||
|
@ -192,7 +212,8 @@ Get JSON data as string.
|
|||
|
||||
*Returns:*
|
||||
|
||||
- `{String} jsonString`
|
||||
- `{String} jsonString`
|
||||
|
||||
Contents of the editor as string. When the editor is in code `text` or `code`,
|
||||
the returned text is returned as-is. For the other modes, the returned text
|
||||
is a compacted string. In order to get the JSON formatted with a certain
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
var Ajv;
|
||||
try {
|
||||
Ajv = require('ajv/dist/ajv.bundle.js');
|
||||
}
|
||||
catch (err) {
|
||||
// no problem... when we need Ajv we will throw a neat exception
|
||||
}
|
||||
|
||||
var treemode = require('./treemode');
|
||||
var textmode = require('./textmode');
|
||||
var util = require('./util');
|
||||
|
@ -254,6 +262,51 @@ JSONEditor.prototype._onError = function(err) {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set a JSON schema for validation of the JSON object.
|
||||
* To remove the schema, call JSONEditor.setSchema(null)
|
||||
* @param {Object | null} schema
|
||||
*/
|
||||
JSONEditor.prototype.setSchema = function (schema) {
|
||||
// compile a JSON schema validator if a JSON schema is provided
|
||||
if (schema) {
|
||||
var ajv;
|
||||
try {
|
||||
// grab ajv from options if provided, else create a new instance
|
||||
ajv = this.options.ajv || Ajv({ allErrors: true });
|
||||
|
||||
}
|
||||
catch (err) {
|
||||
console.warn('Failed to create an instance of Ajv, JSON Schema validation is not available. Please use a JSONEditor bundle including Ajv, or pass an instance of Ajv as via the configuration option `ajv`.');
|
||||
}
|
||||
|
||||
if (ajv) {
|
||||
this.validateSchema = ajv.compile(schema);
|
||||
|
||||
// add schema to the options, so that when switching to an other mode,
|
||||
// the set schema is not lost
|
||||
this.options.schema = schema;
|
||||
|
||||
// validate now
|
||||
this.validate();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// remove current schema
|
||||
this.validateSchema = null;
|
||||
this.options.schema = null;
|
||||
this.validate(); // to clear current error messages
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate current JSON object against the configured JSON schema
|
||||
* Throws an exception when no JSON schema is configured
|
||||
*/
|
||||
JSONEditor.prototype.validate = function () {
|
||||
// must be implemented by treemode and textmode
|
||||
};
|
||||
|
||||
/**
|
||||
* Register a plugin with one ore multiple modes for the JSON Editor.
|
||||
*
|
||||
|
|
|
@ -342,6 +342,14 @@ textmode.setText = function(jsonText) {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate current JSON object against the configured JSON schema
|
||||
* Throws an exception when no JSON schema is configured
|
||||
*/
|
||||
textmode.validate = function () {
|
||||
// TODO: implement validate for textmode
|
||||
};
|
||||
|
||||
// define modes
|
||||
module.exports = [
|
||||
{
|
||||
|
|
|
@ -1,10 +1,3 @@
|
|||
var Ajv;
|
||||
try {
|
||||
Ajv = require('ajv/dist/ajv.bundle.js');
|
||||
}
|
||||
catch (err) {
|
||||
// no problem... when we need Ajv we will throw a neat exception
|
||||
}
|
||||
var Highlighter = require('./Highlighter');
|
||||
var History = require('./History');
|
||||
var SearchBox = require('./SearchBox');
|
||||
|
@ -47,6 +40,7 @@ treemode.create = function (container, options) {
|
|||
this.multiselection = {
|
||||
nodes: []
|
||||
};
|
||||
this.validateSchema = null; // will be set in .setSchema(schema)
|
||||
this.errorNodes = [];
|
||||
|
||||
|
||||
|
@ -95,20 +89,7 @@ treemode._setOptions = function (options) {
|
|||
}
|
||||
|
||||
// compile a JSON schema validator if a JSON schema is provided
|
||||
this._validate = null;
|
||||
if (this.options.schema) {
|
||||
var ajv;
|
||||
try {
|
||||
// grab ajv from options if provided, else create a new instance
|
||||
ajv = options.ajv || Ajv({ allErrors: true });
|
||||
}
|
||||
catch (err) {
|
||||
console.warn('Failed to create an instance of Ajv, JSON Schema validation is not available. Please use a JSONEditor bundle including Ajv, or pass an instance of Ajv as via the configuration option `ajv`.');
|
||||
}
|
||||
if (ajv) {
|
||||
this._validate = ajv.compile(this.options.schema);
|
||||
}
|
||||
}
|
||||
this.setSchema(this.options.schema);
|
||||
|
||||
// create a debounced validate function
|
||||
var wait = this.options.debounceInterval;
|
||||
|
@ -372,56 +353,62 @@ treemode._onChange = function () {
|
|||
* Throws an exception when no JSON schema is configured
|
||||
*/
|
||||
treemode.validate = function () {
|
||||
if (!this._validate) {
|
||||
// clear all current errors
|
||||
if (this.errorNodes) {
|
||||
this.errorNodes.forEach(function (node) {
|
||||
node.setError(null);
|
||||
});
|
||||
}
|
||||
|
||||
if (!this.validateSchema) {
|
||||
// if no schema is configured or ajv was not loaded, skip validation
|
||||
return;
|
||||
}
|
||||
|
||||
var root = this.node;
|
||||
if (!root) { // TODO: this should be redundant but is needed on mode switch
|
||||
return;
|
||||
}
|
||||
|
||||
//console.time('validate'); // TODO: clean up time measurement
|
||||
var valid = this._validate(this.node.getValue());
|
||||
var valid = this.validateSchema(root.getValue());
|
||||
//console.timeEnd('validate');
|
||||
|
||||
// clear all current errors
|
||||
this.errorNodes.forEach(function (node) {
|
||||
node.setError(null);
|
||||
});
|
||||
|
||||
// apply all new errors
|
||||
var root = this.node;
|
||||
if (!valid) {
|
||||
this.errorNodes = this._validate.errors
|
||||
.map(function findNode (error) {
|
||||
return {
|
||||
node: root.findNode(error.dataPath),
|
||||
error: error
|
||||
}
|
||||
})
|
||||
.filter(function hasNode (entry) {
|
||||
return entry.node != null
|
||||
})
|
||||
.reduce(function expandParents (all, entry) {
|
||||
// expand parents, then merge such that parents come first and
|
||||
// original entries last
|
||||
return entry.node
|
||||
.findParents()
|
||||
.map(function (parent) {
|
||||
return {
|
||||
node: parent,
|
||||
child: entry.node,
|
||||
error: {
|
||||
message: parent.type === 'object'
|
||||
? 'Contains invalid properties' // object
|
||||
: 'Contains invalid items' // array
|
||||
}
|
||||
};
|
||||
})
|
||||
.concat(all, [entry]);
|
||||
}, [])
|
||||
// TODO: dedupe the parent nodes
|
||||
.map(function setError (entry) {
|
||||
entry.node.setError(entry.error, entry.child);
|
||||
return entry.node;
|
||||
});
|
||||
this.errorNodes = this.validateSchema.errors
|
||||
.map(function findNode (error) {
|
||||
return {
|
||||
node: root.findNode(error.dataPath),
|
||||
error: error
|
||||
}
|
||||
})
|
||||
.filter(function hasNode (entry) {
|
||||
return entry.node != null
|
||||
})
|
||||
.reduce(function expandParents (all, entry) {
|
||||
// expand parents, then merge such that parents come first and
|
||||
// original entries last
|
||||
return entry.node
|
||||
.findParents()
|
||||
.map(function (parent) {
|
||||
return {
|
||||
node: parent,
|
||||
child: entry.node,
|
||||
error: {
|
||||
message: parent.type === 'object'
|
||||
? 'Contains invalid properties' // object
|
||||
: 'Contains invalid items' // array
|
||||
}
|
||||
};
|
||||
})
|
||||
.concat(all, [entry]);
|
||||
}, [])
|
||||
// TODO: dedupe the parent nodes
|
||||
.map(function setError (entry) {
|
||||
entry.node.setError(entry.error, entry.child);
|
||||
return entry.node;
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.errorNodes = [];
|
||||
|
|
|
@ -42,7 +42,7 @@
|
|||
options = {
|
||||
mode: 'tree',
|
||||
modes: ['code', 'form', 'text', 'tree', 'view'], // allowed modes
|
||||
error: function (err) {
|
||||
onError: function (err) {
|
||||
alert(err.toString());
|
||||
}
|
||||
};
|
||||
|
|
|
@ -65,7 +65,7 @@
|
|||
|
||||
var options = {
|
||||
mode: 'text',
|
||||
modes: ['text', 'form', 'tree', 'view'], // allowed modes
|
||||
modes: ['code', 'form', 'text', 'tree', 'view'], // allowed modes
|
||||
onError: function (err) {
|
||||
console.error(err);
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue