Skip to content

Latest commit

 

History

History
1387 lines (1229 loc) · 31.5 KB

README.md

File metadata and controls

1387 lines (1229 loc) · 31.5 KB

Tests

Jedi - JSON Editing and Data Integrity

Generates forms from JSON schemas. Can be used in backend to validate JSON data too. Check Out the Playground

Table of Contents

Key Features

  • Dependency free
  • JSON Schema Validation: Easily validate your JSON data using JSON schemas.
  • JSON Editing: Generate user-friendly forms for smooth JSON editing in the browser.
  • Dereferences JSON Schema '$ref' pointers.
  • CSS libraries Integration:
    • Bootstrap 3
    • Bootstrap 4
    • Bootstrap 5
  • Icon libraries Integration:
    • Glyphicons
    • Bootstrap icons
    • FontAwesome 3
    • FontAwesome 4
    • FontAwesome 5
    • FontAwesome 6
  • Plugin Editors:
    • Quill - powerful rich text editor
    • Flatpickr - lightweight and powerful datetime picker
    • Awesomplete - Ultra lightweight, customizable, simple autocomplete widget with zero dependencies
    • Jodit - WYSIWYG Editor
    • Raty - star Rating Plugin

Getting Started

As a Validator

const refParser = new Jedi.RefParser()

const init = async () => {
  await refParser.dereference(schema)

  const jedi = new Jedi.Create({
    refParser: refParser,
    schema: {
      "type": "string"
    }
  })
}

init()

As an Editor

<div id="jedi-container"></div>
const refParser = new Jedi.RefParser()

const init = async () => {
  await refParser.dereference(schema)

  const jedi = new Jedi.Create({
    container: document.querySelector('#jedi-container'),
    theme: new Jedi.ThemeBootstrap3(),
    refParser: refParser,
    schema: {
      "type": "string"
    }
  })
}

init()

Instance Options

Option Type Default Description
container HTMLElement null The HTML element that will contain the generated form.
iconLib string null Specifies the icon library to use for UI components. Valid options include:
  • 'glyphicons'
  • 'bootstrapIcons'
  • 'fontAwesome3'
  • 'fontAwesome4'
  • 'fontAwesome5'
  • 'fontAwesome6'
theme Theme null An instance of Theme to apply to the UI. Valid options include:
  • new Jedi.Theme()
  • new Jedi.ThemeBootstrap3()
  • new Jedi.ThemeBootstrap4()
  • new Jedi.ThemeBootstrap5()
refParser new Jedi.RefParser null An instance of RefParser to handle '$ref' keywords.
enablePropertiesToggle boolean false Enables a toggle to show/hide properties in the UI.
enableCollapseToggle boolean false Allows sections to be collapsible in the UI.
deactivateNonRequired boolean false Deactivates non-required properties.
schema object {} A JSON schema for the form.
showErrors string 'change' Determines when to display validation errors. Options include:
  • 'never'
  • 'change'
  • 'always'
data object undefined Initial data to populate the form.
assertFormat boolean false Treats 'format' as a validator rather than just an annotation.
enforceConst boolean false Enforces the const keyword value in editors.
customEditors array [] An array of custom editor classes.
hiddenInputAttributes object {} Attributes for hidden inputs in the form.
enforceEnumDefault boolean true When true uses the first item in the enum as the default value
id string '' Used to prefix id and for attributes
laguage string 'en' Set default language for error messages and UI texts
translations object '{}' Used to add new translations or override the default ones.
translations: {
  en: {
    errorEnum: 'LOL'
  }
}

Schema options

The x-options custom annotation can be used in JSON Schemas to changes how instances and editors behave. When setting the same option as Jedi options and as x-options, the x-options one will be applied. x-options must be of type object.

{
  "title": "Message",
  "type": "string",
  "x-options": {
    "format": "textarea"
  }
}

Some options depend on other options to be set. In the example the option "enumTitles" depends on the option "enum".

{
  "title": "Type",
  "type": "string",
  "enum": [
    "#000000",
    "#ffffff"
  ],
  "x-options": {
    "enumTitles": [
      "Black",
      "White"
    ]
  }
}

titleHidden

  • Type: boolean
  • Default: false
  • Description: Hides the editor title.
  • Examples:

Hide editor title.

{
  "title": "Message",
  "type": "string",
  "x-options": {
    "titleHidden": true
  }
}

titleIconClass

  • Type: string
  • Description: Icon class to use in titles if using any.
  • Examples:

Show a fontawesome envelope icon in the title.

{
  "title": "Message",
  "type": "string",
  "x-options": {
    "titleIconClass": "fas fa-envelope"
  }
}

showErrors

  • Type: string
  • Default: "change"
  • Options: "never", "change", "always"
  • Description: Determines when to display validation errors.
  • Examples:

Always show errors for this editor even if the value didn't change.

{
  "title": "Message",
  "type": "string",
  "x-options": {
    "showErrors": "always"
  }
}

assertFormat

  • Type: boolean
  • Default: "false"
  • Options: "never", "change", "always"
  • Description: Treats "format" as a validator rather than just an annotation.
  • Examples:

Treat "format": "email" as a constraint keyword instead of an annotation.

{
  "title": "Message",
  "type": "string",
  "format": "email",
  "x-options": {
    "assertFormat": true
  }
}

messages

  • Type: string[]
  • Description: Used to define custom error messages.
  • Examples:

If editor has any error, displays 2 custom error messages.

{
  "title": "Message",
  "type": "string",
  "minLength": "10",
  "maxLength": "100",
  "x-options": {
    "messages": [
      "Must be at least 10 characters long",
      "Must be at most 100 characters long"
    ]
  }
}

info

  • Type: object
  • Description: Used to display extra information. If HTML will be rendered only DOMPurify is available, otherwise only the textContent will be displayed without any HTML tags.
  • Options:
    • variant: "modal"
    • title: Plain text or HTML.
    • content: Plain text or HTML.
  • Examples:

Displays an info button right after the title, that opens a modal with title and content.

{
  "title": "Message",
  "type": "string",
  "x-options": {
    "info": {
      "variant": "modal",
      "title": "<h4>Info Button title</h4>",
      "content": "<p>Info button content</p>"
    }
  }
}

inputAttributes

  • Type: object
  • Description: Used to set attributes for the editor input.
  • Examples:

Add placeholder attribute to textarea.

{
  "title": "Message",
  "type": "string",
  "x-options": {
    "format": "textarea",
    "inputAttributes": {
      "placeholder": "Your message here..."
    }
  }
}

enumTitles

  • Type: string[]
  • Depends on: "enum"
  • Description: Used to display user-friendly labels in the editor instead of those listen in "enum".
  • Examples:

Display color names instead of hex codes.

{
  "title": "Color",
  "type": "string",
  "enum": [
    "ff0000",
    "00ff00",
    "0000ff"
  ],
  "x-options": {
    "enumTitles": [
      "Red",
      "Green",
      "Blue"
    ]
  }
}

enforceEnumDefault

  • Type: boolean
  • Default: false
  • Depends on: "enum"
  • Description: Whether the editor initial value will be the first item in the "enum".
  • Examples:

Default value for this editor will be "".

{
  "title": "Color",
  "type": "string",
  "enum": [
    "ff0000",
    "00ff00",
    "0000ff"
  ],
  "x-options": {
    "enforceEnumDefault": false
  }
}

Default value for this editor will be "ff0000".

{
  "title": "Color",
  "type": "string",
  "enum": [
    "ff0000",
    "00ff00",
    "0000ff"
  ],
  "x-options": {
    "enforceEnumDefault": true
  }
}

enforceConst

  • Type: boolean
  • Default: false
  • Depends on: "const"
  • Description: Value will remain whatever is defined in schema "const".
  • Examples:

Default value for this editor will be "ff0000".

{
  "title": "Color",
  "type": "string",
  "const": "ff0000",
  "x-options": {
    "enforceConst": true
  }
}

switcherTitle

  • Type: string
  • Default: "undefined". The property name or the title will be used instead.
  • Depends on: "oneOf", "anyOf"
  • Description: The text displayed in the multiple editor switcher to select this sub-schema editor.
  • Examples:

Switcher options displayed are:

  • "I want to pay with Credit Card"
  • "I want to pay with PayPal"

But in the sub-editors the titles remain:

  • "Card Number"
  • "Email"
{
  "anyOf": [
    {
      "title": "Card Number",
      "type": "string",
      "x-options": {
        "switcherTitle": "I want to pay with Credit Card"
      }
    },
    {
      "title": "Email",
      "type": "string",
      "x-options": {
        "switcherTitle": "I want to pay with PayPal"
      }
    }
  ]
}

format

  • Type: string
  • Description: Determines editor UI and behaviours. The effect of "format" depends on the schema "type" keyword.
  • Options:
    • Boolean:
      • "select" (default)
      • "radios"
      • "radios-inline"
      • "checkbox"
    • String:
      • "text" (default)
      • "hidden"
      • "color"
      • "date"
      • "datetime-local"
      • "email"
      • "number"
      • "month"
      • "password"
      • "search"
      • "time"
      • "tel"
      • "url"
      • "week"
      • "textarea"
    • Number:
      • "number" (default)
      • "select"
      • "radios"
      • "radios-inline"
    • integer:
      • "number" (default)
      • "select"
      • "radios"
      • "radios-inline"
    • Array:
      • "list" (default)
      • "nav-vertical"
      • "nav-horizontal"
      • "table"
    • Object:
      • "list" (default)
      • "nav-vertical"
      • "nav-horizontal"
      • "grid"
  • Examples:

Use radios to display color names instead of hex codes.

{
  "title": "Color",
  "type": "string",
  "enum": [
    "Red",
    "Green",
    "Blue"
  ],
  "x-options": {
    "format": "radios"
  }
}

grid

  • Type: object
  • Description: A configuration object to determine the position of the property editor in the parent's grid.
  • Options:
    • columns: How many columns should the editor occupy.
    • offset: How many columns should the editor be offseted.
    • newRow: Whether the editor should be put in a new row.
  • Examples:

enableCollapseToggle

  • Type: boolean
  • Description: Display a collapse button used to collapse or expand editors that support collapse like object and arrays
  • Examples:

startCollapsed

  • Type: boolean
  • Description: Whether the editor should start expanded or collapsed. Works on editors that support collapse like object and arrays
  • Examples:
{
  "title": "Person",
  "type": "object",
  "x-options": {
    "startCollapsed": true
  },
  "properties": {
    "name": {
      "type": "string",
      "title": "Name"
    }
  }
}

deactivateNonRequired

  • Type: boolean
  • Description: Whether the editor should deactivate (hide) or activate (show) non required properties. Works on only with object type editors.
  • Examples:
{
  "title": "Person",
  "type": "object",
  "x-options": {
    "deactivateNonRequired": true
  },
  "required": [
    "name"
  ],
  "properties": {
    "name": {
      "type": "string",
      "title": "Name"
    },
    "age": {
      "type": "integer",
      "title": "Age"
    }
  }
}

sortable

  • Type: boolean
  • Description: Allows drag and drop if Sortable.js is installed. Works only with array type editors.
  • Examples:
{
  "type": "object",
  "properties": {
    "items": {
      "type": "array",
      "title": "items",
      "items": {
        "title": "This is a number editor",
        "type": "number"
      },
      "x-options": {
        "sortable": true
      }
    }
  }
}

titleTemplate

Language and Translations

The default language for UI and error messages is en (english). The language can be set to any of the supported languages in the instance options.

This will set german as the default language:

  const jedi = new Jedi.Create({
    language: 'de'
  })

Currently, the supported languages are en (english), de (german), it (italian) and es (spanish). New languages can be added to the translations option. To use them the language options should be set to the language specified.

The default translation can be overridden in the instance options as well.

  const jedi = new Jedi.Create({
    language: 'de',
    translations: {
      de: {
        errorAdditionalProperties: 'Hat die zusätzliche Eigenschaft "{{ property }}", aber keine zusätzlichen Eigenschaften sind erlaubt.',
        errorAnyOf: 'Muss mindestens einem der bereitgestellten Schemata entsprechen.',
        errorConst: 'Muss den Wert {{ const }} haben.',
        errorContains: 'Muss mindestens ein Element enthalten, das dem bereitgestellten Schema entspricht.',
        errorDependentRequired: 'Muss die erforderlichen Eigenschaften haben: {{ dependentRequired }}.',
        errorEnum: 'Muss einer der aufgeführten Werte sein: {{ enum }}.',
        errorExclusiveMaximum: 'Muss kleiner als {{ exclusiveMaximum }} sein.',
        errorExclusiveMinimum: 'Muss größer als {{ exclusiveMinimum }} sein.',
        errorFormat: 'Muss ein gültiges {{ format }} sein.',
        errorItems: 'Muss Elemente enthalten, die dem bereitgestellten Schema entsprechen.',
        errorMaximum: 'Muss höchstens {{ maximum }} sein.',
        errorMaxItems: 'Darf höchstens {{ maxItems }} Elemente enthalten.',
        errorMaxLength: 'Darf höchstens {{ maxLength }} Zeichen lang sein.',
        errorMaxProperties: 'Darf höchstens {{ maxProperties }} Eigenschaften haben.',
        errorMaxContains: 'Darf höchstens {{ maxContains }} Elemente enthalten, die dem bereitgestellten Schema entsprechen. Aktuell enthält es {{ counter }}.',
        errorMinContains: 'Muss mindestens {{ minContains }} Elemente enthalten, die dem bereitgestellten Schema entsprechen. Aktuell enthält es {{ counter }}.',
        errorMinimum: 'Muss mindestens {{ minimum }} sein.',
        errorMinItems: 'Muss mindestens {{ minItems }} Elemente enthalten.',
        errorMinLength: 'Muss mindestens {{ minLength }} Zeichen lang sein.',
        errorMinProperties: 'Muss mindestens {{ minProperties }} Eigenschaften haben.',
        errorMultipleOf: 'Muss ein Vielfaches von {{ multipleOf }} sein.',
        errorNot: 'Darf nicht dem bereitgestellten Schema entsprechen.',
        errorOneOf: 'Muss genau einem der bereitgestellten Schemata entsprechen. Derzeit entspricht es {{ counter }} der Schemata.',
        errorPattern: 'Muss dem Muster "{{ pattern }}" entsprechen.',
        errorPrefixItems: 'Element {{ index }} entspricht nicht der Validierung.',
        errorPropertyNames: 'Der Eigenschaftsname "{{ propertyName }}" entspricht nicht der Validierung.',
        errorProperties: 'Die folgenden Eigenschaften entsprechen nicht ihren Schemata: {{ properties }}',
        errorRequired: 'Muss die erforderlichen Eigenschaften haben: {{ required }}.',
        errorType: 'Muss vom Typ {{ type }} sein.',
        errorUnevaluatedProperties: 'Hat eine ungültige nicht bewertete Eigenschaft "{{ property }}"',
        errorUniqueItems: 'Muss eindeutige Elemente haben.'
      }
    }
  })

The text between brackets like {{ minimum }} or {{ minLength }} are templates. This templates will be replaced dynamically with values specified in constrains.

The error message for the following schema will be "Muss mindestens 3 Zeichen lang sein." because of the minLength: 3.

{
  "title": "Email",
  "format": "email",
  "type": "string",
  "minLength": 3
}

Editors

An editor is a UI that allows users to input data and finally edit the relative json instance. Editors can be as simple as a checkbox input filed for a boolean, or as complex as a wysiwyg rich text editor for a string representing html. The type of editor greatly depends on the type of json data that it's connected to and the keywords present in it's json schema.

Virtually all editors can have the following features:

  • title: text for labels or legends
  • description: text for descriptions
  • info: x-options to configure extra info about the editor.
  • inputAttributes: x-options to add or override input attributes if the editor has an input.
{
  "type": "string",
  "title": "label text for this editor",
  "description": "description text for this editor",
  "x-options": {
    "info": {
      "variant": "modal",
      "title": "<h4>Info Button title</h4>",
      "content": "<p>Info button content</p>"
    },
    "inputAttributes": {
      "placeholder": "placeholder text"
    }
  }
}

Array

A fieldset that can contain list of child editors. Each child editor correspond to an items in the array. Child editors are placed from top to bottom and occupy the whole with available.

  • Has buttons to add, delete and sort items.
  • Can be collapsed and expanded.
  • Items can be sort via drag and drop if Sortable.js is present and "soratble": true is set in x-options
{
  "type": "array",
  "title": "Array",
  "description": "Arrays are used for ordered elements. In JSON, each element in an array may be of a different type.",
  "items": {
    "title": "I am an array item editor",
    "type": "string"
  },
  "x-options": {
    "sortable": true
  }
}

Array checkboxes

A fieldset to containing a list of enumerated editors. Each editor is represented by a checkboxes. Works only if the items are of type string, number or integer.

{
  "title": "Array",
  "description": "Array of unique values wich item types can be string, number or integer",
  "type": "array",
  "uniqueItems": true,
  "items": {
    "enum": [
      "value1",
      "value2"
    ]
  }
}

Array nav

A fieldset to containing a list of enumerated editors. Each editor is represented by a checkboxes. Works only if the items are of type string, number or integer.

options:

  • titleTemplate is used to dynamically generate the nav items text. The parameters available are:
    • {{ i0 }} is the index of the item starting by 0.
    • {{ i1 }} is the index of the item starting by 1. More useful for end users.
    • {{ value }} The value of the items.

With vertical nav

{
  "type": "array",
  "title": "People",
  "x-options": {
    "format": "nav-vertical",
    "titleTemplate": "{{ i1 }} {{ value.name }}"
  },
  "items": {
    "type": "object",
    "title": "Person",
    "properties": {
      "name": {
        "title": "Name",
        "type": "string"
      }
    }
  },
  "default": [
    {
      "name": "Albert"
    }
  ]
}

With horizontal nav

{
  "type": "array",
  "title": "People",
  "x-options": {
    "format": "nav-horizontal",
    "titleTemplate": "{{ i1 }} {{ value.name }}"
  },
  "items": {
    "type": "object",
    "title": "Person",
    "properties": {
      "name": {
        "title": "Name",
        "type": "string"
      }
    }
  },
  "default": [
    {
      "name": "Albert"
    }
  ]
}

Array table

A table where each item editor is rendered in a new table row. Useful for array of objects.

{
  "title": "users",
  "type": "array",
  "x-options": {
    "sortable": true,
    "format": "table"
  },
  "items": {
    "type": "object",
    "title": "Person",
    "description": "User",
    "properties": {
      "name": {
        "type": "string",
        "title": "Name"
      }
    }
  },
  "default": [
    { "name": "Albert" },
    { "name": "Betti" }
  ]
}

Boolean checkbox

Renders a type checkbox input

{
  "type": "boolean",
  "title": "Boolean",
  "x-options": {
    "format": "checkbox"
  }
}

Boolean radios

Renders two type radio inputs. The radio labels can be customized with the enumTitles option.

{
  "type": "boolean",
  "title": "Boolean",
  "x-options": {
    "format": "radios",
    "enumTitles": [
      "Yes",
      "No"
    ]
  }
}

Inline variant

{
  "type": "boolean",
  "title": "Boolean",
  "x-options": {
    "format": "radios-inline",
    "enumTitles": [
      "Yes",
      "No"
    ]
  }
}

Boolean select

Renders type select input with 2 options. The options labels can be customized with the enumTitles option.

{
  "type": "boolean",
  "title": "Boolean",
  "x-options": {
    "format": "select",
    "enumTitles": [
      "Yes",
      "No"
    ]
  }
}

Number input

Renders type number input. Handles numberand integer types.

{
  "type": "number",
  "title": "Number"
}

Number radios

Renders as many radio type inputs as values in the enum constraint. The radio labels can be customized with the enumTitles option. Handles numberand integer types.

{
  "type": "number",
  "title": "Quantity",
  "enum": [
    0,
    1,
    2
  ],
  "x-options": {
    "format": "radios",
    "enumTitles": [
      "None",
      "One",
      "A pair"
    ]
  }
}

Inline variant

{
  "type": "number",
  "title": "Quantity",
  "enum": [
    0,
    1,
    2
  ],
  "x-options": {
    "format": "radios-inline",
    "enumTitles": [
      "None",
      "One",
      "A pair"
    ]
  }
}

Number select

Renders as many radio type inputs as values in the enum constraint. The options labels can be customized with the enumTitles option. Handles numberand integer types.

{
  "type": "number",
  "title": "Quantity",
  "enum": [
    0,
    1,
    2
  ],
  "x-options": {
    "enumTitles": [
      "None",
      "One",
      "A pair"
    ]
  }
}

Object

Renders a fieldset that will contain it properties editors. The fieldset can be collapsed or expanded.

{
  "type": "object",
  "title": "Login",
  "properties": {
    "email": {
      "title": "E-Mail",
      "type": "string",
      "format": "email"
    },
    "password": {
      "title": "Password",
      "type": "string",
      "minLength": 8
    }
  }
}

Object grid

Renders a fieldset that will contain it properties editors and use a grid system to position its property editors. The fieldset can be collapsed or expanded.

{
  "type": "object",
  "title": "Login",
  "x-options": {
    "format": "grid"
  },
  "properties": {
    "email": {
      "title": "E-Mail",
      "type": "string",
      "format": "email",
      "x-options": {
        "grid": {
          "columns": 6
        }
      }
    },
    "password": {
      "title": "Password",
      "type": "string",
      "minLength": 8,
      "x-options": {
        "grid": {
          "columns": 6
        }
      }
    }
  }
}

Object nav

Renders a fieldset that will contain it properties editors. The fieldset can be collapsed or expanded.

With vertical nav

{
  "x-options": {
    "format": "nav-vertical"
  },
  "type": "object",
  "title": "All Editors",
  "properties": {
    "personA": {
      "title": "Person A",
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "age": {
          "type": "integer",
          "minimum": 0
        }
      }
    },
    "personB": {
      "title": "Person B",
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "age": {
          "type": "integer",
          "minimum": 0
        }
      }
    }
  }
}

With horizontal nav

{
  "x-options": {
    "format": "nav-horizontal"
  },
  "type": "object",
  "title": "All Editors",
  "properties": {
    "personA": {
      "title": "Person A",
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "age": {
          "type": "integer",
          "minimum": 0
        }
      }
    },
    "personB": {
      "title": "Person B",
      "type": "object",
      "properties": {
        "name": {
          "type": "string"
        },
        "age": {
          "type": "integer",
          "minimum": 0
        }
      }
    }
  }
}

String input

Renders type text input.

{
  "type": "string",
  "title": "String"
}

String radios

Renders as many radio type inputs as values in the enum constraint. The radio labels can be customized with the enumTitles option.

{
  "type": "string",
  "title": "String radios",
  "enum": [
    "albert",
    "betti",
    "carl"
  ],
  "x-options": {
    "format": "radios",
    "enumTitles": [
      "Albert",
      "Betti",
      "Carl"
    ]
  }
}

Inline variant

{
  "type": "string",
  "title": "String radios",
  "enum": [
    "albert",
    "betti",
    "carl"
  ],
  "x-options": {
    "format": "radios-inline",
    "enumTitles": [
      "Albert",
      "Betti",
      "Carl"
    ]
  }
}

String select

Renders as many radio type inputs as values in the enum constraint. The options labels can be customized with the enumTitles option.

{
  "type": "string",
  "title": "String select",
  "enum": [
    "albert",
    "betti",
    "carl"
  ],
  "x-options": {
    "enumTitles": [
      "Albert",
      "Betti",
      "Carl"
    ]
  }
}

String textarea

Renders a textarea.

{
  "type": "string",
  "title": "String",
  "x-options": {
    "format": "textarea"
  }
}

License

Jedi is released under the MIT License, making it free for commercial and non-commercial use.

Resources