Json edit

JSON editor dialog (intended as a library for userscripts)

Этот скрипт недоступен для установки пользователем. Он является библиотекой, которая подключается к другим скриптам мета-ключом // @require https://update.greasyfork.org/scripts/441035/1250389/Json%20edit.js

Автор
agreg
Версия
0.0.1
Создан
07.03.2022
Обновлён
07.03.2022
Лицензия
MIT

Multiline JSON/plain text editor dialog with support for syntax highlighting, pretty-formatting and JSON validation. Can be used both in userscripts and in webpages (source – slightly modified to support loading the script from a Gist where it's served as a text file).

It uses Prism for syntax highlighting (and a custom theme, but it can be overridden).

Usage

Simply include the script in your code: either as @require dependency (in userscripts) or as src attribute of a <script> tag.

If you want to enable syntax highlighting, also include the following links (listed as @requres in the code):

https://cdnjs.cloudflare.com/ajax/libs/prism/1.27.0/prism.min.js
https://cdnjs.cloudflare.com/ajax/libs/prism/1.27.0/components/prism-json.min.js
https://cdnjs.cloudflare.com/ajax/libs/prism/1.27.0/plugins/match-braces/prism-match-braces.min.js

The first two are needed for highlighting JSON syntax, the last one is needed for matching braces colouring.

After including the dependencies, refer to the API docs below to use the editor dialog and exposed utilities. Here's the minimum usage example:

var data = {}, modal = $jsonEdit.createEditorModal('JSON-EDITOR', {maxWidth: '1024px'}); // default is 90%
document.body.append(modal);
editButton.onclick = () => modal.editAsJson(data).then(value => {data = value});

Default looks can be altered by supplying your own CSS. (Refer to [Prism][Prism] documentation for details.)

Editor dialog contains title, error line, editing area (with highlighting overlay), and dialog action buttons. Additionally, in JSON mode it contains a reformat/validation toolbar, with parameter inputs (see pformat) and a Check / Reformat button (this action is used automatically when ever toolbar inputs state changes). If validation fails (whether upon using the toolbar or upon clicking OK), the error text will be displayed above the JSON editor, and the text cursor will be moved to the position of error.
The state of toolbar is retained between openings of the dialog.

API

The library exposes a single global value: $jsonEdit. It contains following functions:

  • pformat(value, {indent="", width=80, sparse=false, compact=false}?) – pretty-formatter for JSON (based on Python pprint module).
    indent is the shared string prefix (initial indent);
    width is the width limit of compact lists (see compact);
    sparse enables vertical sparseness (produced output will be similar to conventional JSON formatting);
    compact enables inlining long lists for compact views (if used with sparse, only applies to arrays).

    console.log( $jsonEdit.pformat(data) );
    
  • parseJson(string) – non-throwing JSON parser that returns either the parsed value or an error object.

    let o = $jsonEdit.parseJson(input);
    if (o instanceof Error)
      throw Error;
    else
      return o;
    
    • ParseError is the class of error produced by parseJson; it has an additional position field containing error position in the input string (or 0 if could not be detected).
  • theme(selector) produces CSS used to highlight JSON in editor (with the same colours).
    selector is a CSS rule selector which should refer to a parent element of <pre> tag containing the code to be highlighted. (Note that for highlighting to work correctly, the code must be wrapped in <pre><code> tags.)

    document.head.querySelector('style').innerHTML += $jsonEdit.theme("#parent-element");
    
  • createEditorModal(id, {maxWidth='90%'}?) generates and returns a modal object, which is a DOM element (to be appended to document body) containing several additional methods.
    id is the id attribute of the returned DOM element (required for working styling);
    maxWidth defines width limit of the dialog frame (might be a good idea to use a fixed value).

    var modal = $jsonEdit.createEditorModal('JSON-EDITOR', {maxWidth: '1024px'});
    

Modal object

The dialog can be opened in either json or text mode; this affects highlighting, validation/reformatting (along with the toolbar visibility), and resulting value of editing.

  • mode is the field containing latest mode the dialog was opened in.

  • toggle(visibility?) opens/closes the dialog; new state is defined by visibility value (it changes to the opposite when no value is passed).

    confirm("Cancel editing?") && modal.toggle(false);
    
  • editText(value?, {title="Enter text"}?) opens the dialog in text mode; it's not highlighted, not validated and not reformatted. The returned value is a promise, resolving to the string produced after clicking "OK". (If an edit-method used again, previous promises won't get resolved on "OK" click.)
    value is the new text to be edited (if not present, most recent editor content is used);
    title is the dialog title.

    modal.editText("foo", {title: "Edit the ID"}).then(processText);
    
  • editJson(value?, {validator?, title="Enter json"}?) opens the dialog in json mode; in this mode the text is highlighted and validated as JSON (reformatting only happens manually). The returned value is the parsed JSON object.
    validator is an alternative validation function; if it's provided, an invalid JSON text is validated against it before displaying an error when OK check fails (if validation passes, the promise will resolve to a text value). Validator throwing an error is treated as

    modal.editJson(`{"foo": "bar"}`).then(processData);
    modal.editJson("", {validator: s => !s}).then(value => (value === "" ? processEmpty() : processData(value));
    
  • editAsJson(value, {validator?, title="Enter json"}?) opens the dialog in json mode; the only difference from editJson is the input value.
    value is a JSON (plain JS) object; it's converted into a JSON string and pretty-formatted before editing begins. (Note that in editAsJson, the value isn't optional.)

    modal.editAsJson({foo: "bar"}).then(processData);
    
  • render(node, text, mode?) renders and optionally highlights (depending on the mode) provided text within the node.
    node is the <code> DOM element containing the text to display (note that it should be wrapped in <pre>);
    mode is rendering mode ('json' enables highlighting); by default, the latest editing mode is used.

    modal.render(preview.querySelector('pre > code'), `{"foo": "bar"}`, 'json');