Implement validation in mode `"preview"`
This commit is contained in:
parent
3ed0318624
commit
745a4f3665
|
@ -125,7 +125,7 @@
|
|||
schema: schema,
|
||||
schemaRefs: {"job": job},
|
||||
mode: 'tree',
|
||||
modes: ['code', 'text', 'tree']
|
||||
modes: ['code', 'text', 'tree', 'preview']
|
||||
};
|
||||
|
||||
// create the editor
|
||||
|
|
|
@ -46,7 +46,7 @@
|
|||
|
||||
var options = {
|
||||
mode: 'tree',
|
||||
modes: ['code', 'text', 'tree'],
|
||||
modes: ['code', 'text', 'tree', 'preview'],
|
||||
onValidate: function (json) {
|
||||
// rules:
|
||||
// - team, names, and ages must be filled in and be of correct type
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
|
||||
var options = {
|
||||
mode: 'tree',
|
||||
modes: ['code', 'text', 'tree'],
|
||||
modes: ['code', 'text', 'tree', 'preview'],
|
||||
onValidate: function (json) {
|
||||
// in this validation function we fake sending a request to a server
|
||||
// to validate the existence of customers
|
||||
|
|
|
@ -549,6 +549,11 @@ div.jsoneditor-tree .jsoneditor-button.jsoneditor-schema-error {
|
|||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.jsoneditor .jsoneditor-validation-errors {
|
||||
width: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.jsoneditor .jsoneditor-additional-errors {
|
||||
position: absolute;
|
||||
margin: auto;
|
||||
|
@ -585,6 +590,7 @@ div.jsoneditor-tree .jsoneditor-button.jsoneditor-schema-error {
|
|||
|
||||
.jsoneditor .jsoneditor-text-errors td pre {
|
||||
margin: 0;
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.jsoneditor .jsoneditor-text-errors tr {
|
||||
|
|
|
@ -3,14 +3,14 @@
|
|||
* @param {Object} config
|
||||
* @property {boolean} errorTableVisible
|
||||
* @property {function (boolean) : void} onToggleVisibility
|
||||
* @property {function (number) } onFocusLine
|
||||
* @property {function (number) } onChangeHeight
|
||||
* @property {function (number)} [onFocusLine]
|
||||
* @property {function (number)} onChangeHeight
|
||||
* @constructor
|
||||
*/
|
||||
function ErrorTable (config) {
|
||||
this.errorTableVisible = config.errorTableVisible;
|
||||
this.onToggleVisibility = config.onToggleVisibility;
|
||||
this.onFocusLine = config.onFocusLine;
|
||||
this.onFocusLine = config.onFocusLine || function () {};
|
||||
this.onChangeHeight = config.onChangeHeight;
|
||||
|
||||
this.dom = {};
|
||||
|
@ -76,6 +76,7 @@ ErrorTable.prototype.setErrors = function (errors, errorLocations) {
|
|||
// keep default behavior for parse errors
|
||||
if (this.errorTableVisible && errors.length > 0) {
|
||||
var validationErrors = document.createElement('div');
|
||||
validationErrors.className = 'jsoneditor-validation-errors';
|
||||
validationErrors.innerHTML = '<table class="jsoneditor-text-errors"><tbody></tbody></table>';
|
||||
var tbody = validationErrors.getElementsByTagName('tbody')[0];
|
||||
|
||||
|
@ -140,9 +141,9 @@ ErrorTable.prototype.setErrors = function (errors, errorLocations) {
|
|||
}
|
||||
|
||||
// update the status bar
|
||||
var validationErrorsCount = errors.reduce(function (acc, curr) {
|
||||
return (curr.type === 'validation' ? ++acc: acc)
|
||||
}, 0);
|
||||
var validationErrorsCount = errors.filter(function (error) {
|
||||
return error.type !== 'error'
|
||||
}).length;
|
||||
if (validationErrorsCount > 0) {
|
||||
this.dom.validationErrorCount.style.display = 'inline';
|
||||
this.dom.validationErrorCount.innerText = validationErrorsCount;
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
var jmespath = require('jmespath');
|
||||
var translate = require('./i18n').translate;
|
||||
var ModeSwitcher = require('./ModeSwitcher');
|
||||
var ErrorTable = require('./ErrorTable');
|
||||
var textmode = require('./textmode')[0].mixin;
|
||||
var showSortModal = require('./showSortModal');
|
||||
var showTransformModal = require('./showTransformModal');
|
||||
var MAX_PREVIEW_CHARACTERS = require('./constants').MAX_PREVIEW_CHARACTERS;
|
||||
|
@ -225,7 +227,22 @@ previewmode.create = function (container, options) {
|
|||
}
|
||||
}
|
||||
|
||||
this.errorTable = new ErrorTable({
|
||||
errorTableVisible: true,
|
||||
onToggleVisibility: function () {
|
||||
me.validate();
|
||||
},
|
||||
onFocusLine: null,
|
||||
onChangeHeight: function (height) {
|
||||
// TODO: change CSS to using flex box, remove setting height using JavaScript
|
||||
var totalHeight = height + me.dom.statusBar.clientHeight + 1;
|
||||
me.content.style.marginBottom = (-totalHeight) + 'px';
|
||||
me.content.style.paddingBottom = totalHeight + 'px';
|
||||
}
|
||||
});
|
||||
|
||||
this.frame.appendChild(this.content);
|
||||
this.frame.appendChild(this.errorTable.getErrorTable());
|
||||
this.container.appendChild(this.frame);
|
||||
|
||||
if (options.statusBar) {
|
||||
|
@ -245,6 +262,10 @@ previewmode.create = function (container, options) {
|
|||
this.dom.arrayInfo.className = 'jsoneditor-size-info';
|
||||
this.dom.arrayInfo.innerText = '';
|
||||
statusBar.appendChild(this.dom.arrayInfo);
|
||||
|
||||
statusBar.appendChild(this.errorTable.getErrorCounter());
|
||||
statusBar.appendChild(this.errorTable.getWarningIcon());
|
||||
statusBar.appendChild(this.errorTable.getErrorIcon());
|
||||
}
|
||||
|
||||
this._renderPreview();
|
||||
|
@ -656,13 +677,9 @@ previewmode.executeWithBusyMessage = function (fn, message) {
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Validate current JSON object against the configured JSON schema
|
||||
* Throws an exception when no JSON schema is configured
|
||||
*/
|
||||
previewmode.validate = function () {
|
||||
// FIXME: implement validate (also support custom validation)
|
||||
};
|
||||
// TODO: refactor into composable functions instead of this shaky mixin-like structure
|
||||
previewmode.validate = textmode.validate
|
||||
previewmode._renderErrors = textmode._renderErrors
|
||||
|
||||
// define modes
|
||||
module.exports = [
|
||||
|
|
|
@ -80,7 +80,6 @@ textmode.create = function (container, options) {
|
|||
this.aceEditor = undefined; // ace code editor
|
||||
this.textarea = undefined; // plain text editor (fallback when Ace is not available)
|
||||
this.validateSchema = null;
|
||||
this.validationSequence = 0;
|
||||
this.annotations = [];
|
||||
|
||||
// create a debounced validate function
|
||||
|
@ -287,7 +286,6 @@ textmode.create = function (container, options) {
|
|||
this.errorTable = new ErrorTable({
|
||||
errorTableVisible: this.mode === 'text',
|
||||
onToggleVisibility: function () {
|
||||
console.log('toggle')
|
||||
me.validate();
|
||||
},
|
||||
onFocusLine: function (line) {
|
||||
|
@ -787,32 +785,12 @@ textmode.updateText = function(jsonText) {
|
|||
* Throws an exception when no JSON schema is configured
|
||||
*/
|
||||
textmode.validate = function () {
|
||||
var doValidate = false;
|
||||
var schemaErrors = [];
|
||||
var parseErrors = [];
|
||||
var json;
|
||||
try {
|
||||
json = this.get(); // this can fail when there is no valid json
|
||||
doValidate = true;
|
||||
}
|
||||
catch (err) {
|
||||
if (this.getText()) {
|
||||
// try to extract the line number from the jsonlint error message
|
||||
var match = /\w*line\s*(\d+)\w*/g.exec(err.message);
|
||||
var line;
|
||||
if (match) {
|
||||
line = +match[1];
|
||||
}
|
||||
parseErrors.push({
|
||||
type: 'error',
|
||||
message: err.message.replace(/\n/g, '<br>'),
|
||||
line: line
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// only validate the JSON when parsing the JSON succeeded
|
||||
if (doValidate) {
|
||||
// execute JSON schema validation (ajv)
|
||||
if (this.validateSchema) {
|
||||
var valid = this.validateSchema(json);
|
||||
|
@ -826,7 +804,7 @@ textmode.validate = function () {
|
|||
|
||||
// execute custom validation and after than merge and render all errors
|
||||
// TODO: implement a better mechanism for only using the last validation action
|
||||
this.validationSequence++;
|
||||
this.validationSequence = (this.validationSequence || 0) + 1;
|
||||
var me = this;
|
||||
var seq = this.validationSequence;
|
||||
validateCustom(json, this.options.onValidate)
|
||||
|
@ -841,8 +819,22 @@ textmode.validate = function () {
|
|||
console.error('Custom validation function did throw an error', err);
|
||||
});
|
||||
}
|
||||
else {
|
||||
this._renderErrors([]);
|
||||
catch (err) {
|
||||
if (this.getText()) {
|
||||
// try to extract the line number from the jsonlint error message
|
||||
var match = /\w*line\s*(\d+)\w*/g.exec(err.message);
|
||||
var line;
|
||||
if (match) {
|
||||
line = +match[1];
|
||||
}
|
||||
parseErrors = [{
|
||||
type: 'error',
|
||||
message: err.message.replace(/\n/g, '<br>'),
|
||||
line: line
|
||||
}];
|
||||
}
|
||||
|
||||
this._renderErrors(parseErrors);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
var isPromise = require('./util').isPromise;
|
||||
var isValidValidationError = require('./util').isValidValidationError;
|
||||
var stringifyPath = require('./util').stringifyPath;
|
||||
|
||||
/**
|
||||
* Execute custom validation if configured.
|
||||
|
@ -21,7 +23,7 @@ function validateCustom (json, onValidate) {
|
|||
if (Array.isArray(customValidationPathErrors)) {
|
||||
return customValidationPathErrors
|
||||
.filter(function (error) {
|
||||
var valid = util.isValidValidationError(error);
|
||||
var valid = isValidValidationError(error);
|
||||
|
||||
if (!valid) {
|
||||
console.warn('Ignoring a custom validation error with invalid structure. ' +
|
||||
|
@ -34,7 +36,7 @@ function validateCustom (json, onValidate) {
|
|||
.map(function (error) {
|
||||
// change data structure into the structure matching the JSON schema errors
|
||||
return {
|
||||
dataPath: util.stringifyPath(error.path),
|
||||
dataPath: stringifyPath(error.path),
|
||||
message: error.message
|
||||
}
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue