Compare commits

..

330 Commits

Author SHA1 Message Date
josdejong 52b6e94e39 Update dependencies 2020-06-03 15:50:57 +02:00
jos 38007b715d Update dependencies 2020-02-26 14:42:37 +01:00
jos 92297c0d2c Remove unused variable 2018-10-17 13:19:10 +02:00
jos ae1e39ba3f Implemented caret selection 2018-10-17 13:17:19 +02:00
jos 76e4bf5e16 Fix objects/arrays not copied correctly to clipboard 2018-10-03 18:05:21 +02:00
jos a869fa0f3a Cleanup old selection stuff 2018-10-03 15:18:12 +02:00
jos 17df475c11 Move some logic to `TreeModeMenu` and some small tweaks and fixes 2018-10-03 15:06:55 +02:00
jos 21d8db13d0 Update search results on patch/undo/redo 2018-10-03 12:32:48 +02:00
jos 7012de59d6 Select patched contents 2018-10-03 12:14:34 +02:00
jos ce37b88296 Cut/copy/paste/insert/duplicate/remove mostly working for selections (WIP) 2018-10-03 11:33:03 +02:00
jos f1ddc03c6d Create `before-childs` and `after-childs` 2018-09-26 21:40:33 +02:00
jos f33342b54b Rename selection areas to before, on, after 2018-09-26 17:54:04 +02:00
jos 0f24a9204f Implemented `findSelectionPointerFromEvent` (WIP) 2018-09-26 17:40:44 +02:00
jos 9a2c4f1e6a Use caret down instead of chevron down for dropdowns 2018-09-26 11:56:39 +02:00
jos aaa498b4ec Implemented `findSelectionPointerFromEvent` 2018-09-26 11:32:40 +02:00
jos 6c17d6256c Add custom svg logos to source code 2018-09-26 08:41:30 +02:00
jos a0de92b919 Move custom icons in a separate file 2018-09-19 21:39:06 +02:00
jos 3d2f9ce8df Created custom icons for format/compact 2018-09-19 21:33:46 +02:00
jos 4f86135050 Fixed broken unit tests 2018-09-19 15:16:45 +02:00
jos 3e795b3275 Order search results 2018-09-19 14:50:53 +02:00
jos e298d63311 Implemented result count in search box 2018-09-19 14:28:12 +02:00
jos 263f38f45c Search focus and quick keys working 2018-09-19 14:12:56 +02:00
jos b4a0dd6a3d Created insert dropdown 2018-09-19 13:27:36 +02:00
jos 2999fbc380 Refactor into a generic `DropDown` component 2018-09-19 13:05:15 +02:00
jos 2c560264c0 Refactor ModeDropDown 2018-09-19 11:43:40 +02:00
jos 0349f94ead Remove floating menu 2018-09-19 11:01:12 +02:00
jos 4c539cb4f5 Implement most menu functionality 2018-09-19 10:39:46 +02:00
jos 702dc5ed20 Use chevron icons in search and mode button 2018-09-19 10:04:51 +02:00
jos 37e22908c7 Fix react error on switching modes. Add more keys 2018-09-19 09:44:12 +02:00
jos 3865a1d365 Fix expand button losing focus when clicking it. Add missing `key` here and there 2018-09-19 09:23:40 +02:00
jos fdd44a276c Floating search box 2018-09-12 21:47:04 +02:00
jos 081cde4489 Replace svg sprite with fontawesome icons. Extend menu (WIP) 2018-09-12 17:54:20 +02:00
jos 0fb816d074 Moved tree mode menu in a separate component 2018-09-12 11:16:04 +02:00
jos 3028617ff7 Ignore css files 2018-09-12 10:18:29 +02:00
jos b6aea6df9d Remove css files from repo (only keep scss) 2018-09-12 10:17:14 +02:00
jos 088bee74cb Fix bundle not working due to undefined initial JSON 2018-09-05 17:59:15 +02:00
jos 80f45f39ec Refactored `findSelectionIndices` 2018-09-05 12:14:52 +02:00
jos 9b2b8233af Fix add in array reusing existing element as oldValue 2018-09-05 12:10:49 +02:00
jos e2ffd04e6e Fixed unit tests 2018-09-05 11:33:18 +02:00
jos 41a7069398 Fixing unit tests 2018-09-05 11:06:15 +02:00
jos a62b1e1c94 Fixed path not being updated in nodes 2018-09-05 09:30:00 +02:00
jos ec987385c8 Fix a bug in syncing an eson value. Cleanup old ESON types 2018-09-05 09:12:44 +02:00
jos 410353c86f Extended immutableJSONPatch with options fromJSON, toJSON, clone 2018-08-29 22:23:30 +02:00
jos dc814a3aa5 Rename terminology of JSONPatch 2018-08-29 12:27:33 +02:00
jos 56124cf17f Flatten `META` symbol, remove ordering of object keys from ESON model, simplify patch actions (WIP) 2018-08-19 20:36:57 +02:00
jos d6ad4c87d0 Revert react_demo (WIP, still broken) 2018-08-15 15:19:46 +02:00
jos fc1f73c4a6 Upgraded dependencies 2018-08-15 15:06:00 +02:00
jos b1f51b04a0 Update package-lock.json 2018-08-15 14:53:38 +02:00
jos cc3e441361 Update react example 2018-08-15 14:52:49 +02:00
jos 65df3428ac Position floating menu below for insert actions 2018-03-07 12:17:52 +01:00
jos 1b2bcd6dd9 Updated font-family 2018-01-18 20:32:01 +01:00
jos 950463f3a9 Oops fixed broken css of Mode Menu 2018-01-10 22:30:33 +01:00
jos 0ba51276f4 Fixed broken unit tests 2018-01-10 22:18:39 +01:00
jos 1127c15ea2 All floating menus working now 2018-01-10 22:11:23 +01:00
jos 7cdfb44345 Created insert buttons 2018-01-10 12:47:49 +01:00
jos 14e6315159 Highlight selected content only instead of whole width of editor 2018-01-03 12:06:54 +01:00
jos 2466b6d4da Minor css tweaks 2018-01-03 10:43:57 +01:00
jos 9eb944d926 Rendering more like JSON 2018-01-01 19:32:30 +01:00
jos d53e5360a3 In between menu large on the right side 2017-12-30 17:33:07 +01:00
jos 5d4a551526 Fixed ActionMenu not visible in arrays 2017-12-30 15:55:53 +01:00
jos d73b79cb4e Implemented top/bottom positioning of ActionMenu 2017-12-30 15:47:07 +01:00
jos ccf89162b7 Implement apply eson state with jsonpatch replace 2017-12-29 21:40:23 +01:00
jos 419bdc6307 Keep expanded state with copy/paste 2017-12-29 21:36:55 +01:00
jos 9a37fe0451 Moved webpack files under ./config 2017-12-29 20:41:37 +01:00
jos 8b2541e3d8 Improved expand function, fixed expand/collapse of TreeMode 2017-12-27 18:18:23 +01:00
jos e5c6459f73 Fixed search matching array indexes 2017-12-27 17:54:21 +01:00
jos 8bb9cb10cc Some refactoring 2017-12-27 17:33:40 +01:00
jos 46661177db Some refactoring 2017-12-27 17:16:40 +01:00
jos 1d4a5af82e Use event emitter. Cleanup old action menu 2017-12-27 16:58:52 +01:00
jos 9e0249f550 Fixed TreeMode rendering everything again when any options changed 2017-12-27 15:34:30 +01:00
jos 6385e4b193 Added index files 2017-12-26 21:21:39 +01:00
jos 29fe32da40 Fixes in .gitignore 2017-12-26 21:16:26 +01:00
jos 99790c0fac Updated readme 2017-12-26 21:14:33 +01:00
jos abfcca84d6 Update react demo (it works now :) ) 2017-12-26 21:09:23 +01:00
jos 8ffb7702ba update .babelrc, .gitignore, and others 2017-12-26 20:46:38 +01:00
jos 29fed7099f Changed to new build system, removed flow 2017-12-26 20:40:31 +01:00
jos b011b196e1 Some fixes and refactoring in sorting objects 2017-12-20 09:00:27 +01:00
jos 346517b947 Fixed some unit tests 2017-12-20 08:44:10 +01:00
jos 0e22497467 Implemented sort action that keeps state 2017-12-20 08:36:55 +01:00
jos 34ca56aee0 Cleanup 2017-12-17 21:52:21 +01:00
jos aee48b75db Removed a TODO 2017-12-17 21:38:23 +01:00
jos e69d962ada Some refactoring in applying META data 2017-12-17 21:33:45 +01:00
jos 9db7fdf0e5 Fixed keeping id's intact when replacing a value 2017-12-17 21:10:07 +01:00
jos dd22b97eb0 Renamed field 'jsoneditor' to 'meta' in extended JSON Patch 2017-12-17 13:53:06 +01:00
jos 1f5f85a4e0 Refactor patchEson to pass Path instead of String internally 2017-12-17 13:44:13 +01:00
jos e979e0f016 Fix many small issues in the UI 2017-12-16 14:13:52 +01:00
jos 7064578b31 Renamed keys to props in ESON model 2017-12-15 21:02:17 +01:00
jos 1a6661fbb5 Many patch action working again in UI 2017-12-15 20:34:07 +01:00
jos 156f330e4e Refactored ESON to use Symbols, refactored patchEson 2017-12-15 19:57:21 +01:00
jos 53b20e2f59 Refactored model to use Symbol 2017-12-15 14:02:42 +01:00
jos a059eb844e Implemented spliceEsonArray 2017-12-15 12:59:45 +01:00
jos f491a00575 Selection working again 2017-12-14 16:40:55 +01:00
jos 378c8ef250 Fixed expand/collapse all 2017-12-14 14:37:25 +01:00
jos 338d19b5a9 JSON Schema errors working again 2017-12-14 14:30:02 +01:00
jos 040fe12d75 Fix clearing search result 2017-12-13 17:03:26 +01:00
jos 5fb69ffcc5 Search working in the editor again 2017-12-13 16:53:08 +01:00
jos e30674a971 Refactor search, previousSearchResult, nextSearchResult 2017-12-13 16:48:22 +01:00
jos 49cc7eb288 Implemented transform and expand for new ESON model 2017-12-13 11:47:12 +01:00
jos c19334894c New ESON model (WIP) 2017-11-29 21:52:18 +01:00
jos a9174edf16 Fixed performance issue 2017-11-29 11:04:19 +01:00
jos 745b77725b Fixed removing multiple items from an array 2017-11-22 13:38:18 +01:00
jos 0a7df1dad9 Remove old comment 2017-11-22 13:06:06 +01:00
jos b3c41bce03 Remove `simplifyPatch`, it doesn't always work correctly 2017-11-22 13:05:53 +01:00
jos b71afda45a Fixed enter key in search field 2017-11-22 12:02:27 +01:00
jos 157f63d11a Fixed insert menu missing before arrays and objects 2017-11-22 11:36:47 +01:00
jos e69868da85 Some refactoring: created `getInEson`, `setInEson`, `updateInEson`, `deleteInEson` 2017-11-22 10:45:00 +01:00
jos 56528dc054 Fixed unit tests 2017-11-22 10:12:59 +01:00
jos bac12dcc5a Replace/insert working. Insert before instead of after 2017-11-22 10:09:53 +01:00
jos 2e75e5a9cf Initialize selection as null 2017-11-08 16:12:00 +01:00
jos 8cded5496c Fixed not removing selection before duplication 2017-11-08 16:10:39 +01:00
jos cb354f2331 Implemented duplicate for multiple nodes 2017-11-08 15:41:40 +01:00
jos dd989f9a64 Cut/Copy/Paste selection starting to work (WIP) 2017-11-08 13:13:01 +01:00
jos 8425579718 Floating menu starting to work (WIP) 2017-11-03 14:23:04 +01:00
jos a2f7f61389 Show floating menu on selection 2017-10-14 21:57:59 +02:00
jos cea4e2c101 Floating menu (WIP) 2017-10-13 13:27:33 +02:00
jos 0910aa5a63 Move favicon to root 2017-10-06 10:55:31 +02:00
jos 26fa339c35 Implemented cut/copy/paste (via quickkeys) 2017-09-29 21:52:17 +02:00
jos 375ea56316 Some refactoring in `applySelection` 2017-09-29 11:08:44 +02:00
jos 52ec02e3e1 Implemented selecting nodes 2017-09-29 10:06:14 +02:00
jos eee0b55636 Refactored unit tests (moved json objects into separate files) 2017-09-22 12:24:13 +02:00
jos 943d721d84 Implemented support for selection in eson 2017-09-22 11:38:23 +02:00
jos f3313158db Fixed issue with escaping spaces 2017-09-18 21:05:26 +02:00
jos 6f9776a07a Fixed broken JSONSchema errors 2017-09-17 21:03:33 +02:00
jos 432e169f32 Renamed 'jsonData' to 'ESON' 2017-09-08 13:36:15 +02:00
jos 2ee11399ec Fixed optional types of flow 2017-09-08 11:30:33 +02:00
jos 86f8aa56d0 Moved all JSON Patch methods into a separate file 2017-09-08 11:14:41 +02:00
jos 12f1543ef9 Add package-lock.json 2017-09-08 10:29:39 +02:00
jos 598fe63d80 Don't expand search result itself when focusing it 2017-09-08 10:29:09 +02:00
jos 99cc07577d Move react to devDependencies 2017-09-03 17:07:17 +02:00
jos 8462bcda2c Implemented custom key bindings 2017-07-24 15:50:18 +02:00
jos 239b702040 Implemented key bindings in the mode menu 2017-07-24 14:35:27 +02:00
jos 91c1fd823f Updated package-lock.json 2017-07-24 14:09:46 +02:00
jos 7380be631c Updated docs on key bindings 2017-07-24 14:09:37 +02:00
jos 1c37b303b9 Created key bindings for `text` mode 2017-07-24 14:09:10 +02:00
jos e069d3f0b3 Implemented key bindings `Alt+Home` and `Alt+End` 2017-07-24 13:39:34 +02:00
jos 633daf6c95 Implemented key bindings in Menu 2017-07-19 20:50:05 +02:00
jos 3ca23568cf Fixed `Ctrl+E` not working anymore 2017-07-19 14:36:04 +02:00
jos a03d962daa Some refactoring 2017-07-19 14:31:26 +02:00
jos c5ce6525a5 Implemented key bindings for undo/redo 2017-07-19 13:56:14 +02:00
jos 52977b009c Updated package-lock.json 2017-07-19 13:52:50 +02:00
jos b162f5ed13 Implemented key bindings for search 2017-07-19 13:52:28 +02:00
jos 5b1426eb7c Remove not yet used ref 2017-07-13 19:49:45 +02:00
jos f786940d8d Some refactoring 2017-07-13 12:20:48 +02:00
jos 94b7be90d3 Refactored action menus, added quick keys Ctrl+M, Ctrl+E 2017-07-13 12:10:42 +02:00
jos bb8734707e Set focus to correct input fields after insert/append/duplicate/remove 2017-07-12 17:09:03 +02:00
jos bb6565f3b3 Implemented quickkeys to move up/down/left/right 2017-07-12 15:01:19 +02:00
jos 111b85a4cb Fixed invalid dependency version number 2017-07-12 09:47:42 +02:00
jos fb71b61ba5 Implemented basic support for key bindings 2017-06-11 17:14:46 +02:00
jos 82ff880c27 Added missing dependencies 2017-06-11 15:06:25 +02:00
jos 82ddb965fb Updated dependencies 2017-06-11 13:44:22 +02:00
jos 7eb9464474 Upgraded dependencies 2017-06-09 09:42:03 +02:00
Jos de Jong 1c09829622 Fixed version number for gulp-multi-process 2017-01-18 09:37:54 +01:00
jos 1cd6d71dda Upgrade to `gulp-multi-process v0.4.0` which fixes a windows issue (see #352) 2017-01-17 20:05:43 +01:00
jos b730cb29bf Fixed broken ModeMenu mouse click 2017-01-10 20:14:26 +01:00
jos 07f92467e7 Try get react bundle working (js is ok, css still broken) 2017-01-10 20:03:09 +01:00
jos ba1eb2a837 A bit of refactoring 2017-01-08 20:51:08 +01:00
jos 6f1fbac9ac Fixed ModeMenu broken after using it when bundled with `preact-compat` 2017-01-08 15:34:01 +01:00
jos 675432c52d Fixed broken modes `form` and `view` 2017-01-08 15:23:17 +01:00
jos ce484c670a Use react for development for the great error messages, preact for bundling for production 2017-01-07 19:48:17 +01:00
jos 984c8bac3d Upgraded dependencies 2017-01-06 23:18:05 +01:00
jos ea01e581cd Switched to `preact-compat` 2017-01-06 23:17:09 +01:00
jos 840e5f41a7 Fixed broken undo 2017-01-06 23:00:36 +01:00
jos 85ae6d3b5e Replaced `getPath()` and `props.parent` with `props.path` 2017-01-06 20:33:01 +01:00
jos 1cce254e9c Fixed losing focus when editing property 2017-01-06 20:17:31 +01:00
jos ab8d4b4be6 Changed data model to items and props having an id 2017-01-06 13:57:16 +01:00
jos 0f7c601635 Fixed broken unit test 2017-01-05 15:15:53 +01:00
jos b256e1c8ce Better scrollTo offset 2017-01-05 15:04:39 +01:00
jos a9a453f51f Fixed expanding root node too when expanding path 2017-01-05 15:00:05 +01:00
jos d5500bef89 Implemented scrolling to active search result 2017-01-05 14:47:20 +01:00
jos 65e868b1c3 Upgraded dependencies 2017-01-05 11:39:01 +01:00
jos afcf19bac5 A bit more refactoring 2017-01-05 11:18:38 +01:00
jos 9f81dfb2f6 Refactoring ul/li 2017-01-05 10:48:32 +01:00
jos 0e490fdeee expand the active search result if not expanded 2017-01-01 21:13:14 +01:00
jos bef37648b7 Go to next search result on enter 2017-01-01 20:20:17 +01:00
jos d2e1bed9d6 Created gulp task `compile-es5-lib` (WIP, not yet compiling less into css) 2017-01-01 20:08:10 +01:00
jos 349e6015a3 Some preparations for moveTo active search result (WIP) 2016-12-31 12:32:24 +01:00
jos fec1bb8f23 Implemented highlighting prev/next search result 2016-12-30 14:41:37 +01:00
jos 6ba53f7364 Implemented functions `nextSearchResult` and `previousSearchResult` 2016-12-30 14:05:11 +01:00
jos 100efb35ae Restructured search data model 2016-12-30 13:45:43 +01:00
jos 198e8edf85 Fixed ordering of search results 2016-12-30 10:52:48 +01:00
jos aa4b963592 Changed the structure of SearchResult. Highlight active search result 2016-12-30 10:44:57 +01:00
jos 95f0a31731 Added search icon, added prev/next button (not yet doing anything) 2016-12-26 14:37:52 +01:00
jos d1f35c6214 Show search result count 2016-12-26 11:21:52 +01:00
jos c7418807d8 Updated examples 2016-12-26 10:41:07 +01:00
jos f209df27a9 Updated readme 2016-12-26 10:26:33 +01:00
jos 2e434f49f9 Worked out react bundle (not yet working though) 2016-12-26 10:18:26 +01:00
jos 785ab5205c React API mostly working (WIP) 2016-12-22 12:08:32 +01:00
jos 98f56efc47 Finished switch to React 2016-12-04 22:14:21 +01:00
jos 4208dff7b9 Merge branch 'next_react' into next
# Conflicts:
#	package.json
#	src/components/CodeMode.js
#	src/components/JSONNode.js
#	src/components/TextMode.js
#	src/components/TreeMode.js
#	src/index.js
2016-12-02 11:46:46 +01:00
jos 8824cd10f8 Start with being able to set focus (WIP) 2016-12-02 11:38:54 +01:00
jos 37f2f77124 Refactored `search` to return an array with results, implemented `addSearchResults` 2016-11-27 21:16:17 +01:00
jos 939ad792d6 First basic implementation of search (WIP) 2016-11-27 15:41:10 +01:00
jos e5e61b71e3 Implemented function search 2016-11-19 21:21:09 +01:00
jos 96186b836a Replace `expandRecursive` with `transform` 2016-11-19 20:49:01 +01:00
jos e6cb225514 Implemented function `transform` 2016-11-19 20:44:58 +01:00
jos 70810655b8 Implemented JSON schema support for tree/form/view mode 2016-11-12 15:22:55 +01:00
jos fe3bc56d53 Implemented addErrors and removeErrors 2016-11-12 14:10:10 +01:00
jos 8da5ece3b8 Some styling improvements for errors 2016-11-12 13:23:53 +01:00
jos e45aa82b4b Cleanup reference of aceEditor 2016-11-12 11:36:48 +01:00
jos 6120949acf Some refactoring 2016-11-12 10:58:06 +01:00
jos 2bc4cf7dfe Fixed mode code not reckoning with option escapeUnicode 2016-11-12 10:38:04 +01:00
jos f01f52094e Add utf-8 meta tag in examples 2016-11-11 20:26:32 +01:00
jos 68a5b1476f Implemented JSON Schema support for mode `text` and `code` 2016-11-11 20:18:31 +01:00
jos 18d63fcd9a Updated dependencies 2016-11-11 09:34:17 +01:00
jos 116d5fe620 Added css for drag button 2016-11-11 09:32:02 +01:00
jos a70ba17bc7 Little refactoring 2016-10-30 17:38:21 +01:00
jos f882756dda Keep expanded state when patching data 2016-10-30 17:31:16 +01:00
jos a06f7ac5d1 No react warnings in bundles 2016-10-28 23:06:49 +02:00
jos a7c77ff9d1 Try react 2016-10-28 22:21:44 +02:00
jos 3f3fef9b40 Updated explanation in example 08 2016-10-28 21:30:01 +02:00
jos a5145ca004 Fixed minimalist bundle not excluding ace 2016-10-28 21:28:15 +02:00
jos b179318dc6 Upgraded dependencies 2016-10-28 21:21:59 +02:00
jos b73ff81e19 Implemented option `history` 2016-10-28 21:14:22 +02:00
jos 9cbb7574c0 Implemented option `escapeUnicode` 2016-10-28 14:00:44 +02:00
jos 8a3fffcd24 Fixed broken imports 2016-10-28 13:44:41 +02:00
jos 076853bf04 Moved all components in a folder components 2016-10-28 13:33:52 +02:00
jos f2f1636ef0 Added some headers in examples 2016-10-28 13:31:13 +02:00
jos 8f6ddf91bc Implemented `isValueEditable` and `isPropertyEditable` 2016-10-28 13:24:51 +02:00
jos 4a12eed14f Updated dark theme example 2016-10-28 12:14:47 +02:00
jos 9722414728 Remove semicolons from examples 2016-10-28 11:46:46 +02:00
jos 099c5ee8ba Fixed insert not working 2016-10-28 11:04:06 +02:00
jos 9d05195aec Moved large json from develop.html in a separate file 2016-10-28 09:39:47 +02:00
jos 25ecb2dfab Added example synchronizing two editors 2016-10-28 09:36:05 +02:00
jos a399aef0ea Updated dependencies 2016-10-22 10:28:50 +02:00
jos f6dfe874db Fixed action menu of root node not working 2016-10-17 20:38:35 +02:00
jos dc8bb9349c Ignore `dist` folder 2016-10-14 17:47:27 +02:00
jos 30aa73d3a3 Dropped support for bower (don't commit bundles anymore) 2016-10-14 17:46:00 +02:00
jos 3b1a5c2d24 Hide undo/redo menu items when in mode 'view'. Updated some examples 2016-10-14 17:30:16 +02:00
jos 6cf85d2ce9 Implemented mode form 2016-10-14 17:10:09 +02:00
jos 482720b28c Implemented mode `view` 2016-10-14 16:05:52 +02:00
jos bb62795b6b Add graceful-fs (else yarn doesn't work) 2016-10-14 15:06:52 +02:00
jos bde1c9c4d1 Fixed broken build script 2016-10-14 14:59:46 +02:00
jos 1cad4fc8ea Implemented `onChangeText` 2016-10-14 13:46:15 +02:00
jos 5ff41f2d9d Implemented mode `code` (using ace editor) 2016-10-14 12:28:33 +02:00
jos a607d2c2f4 Improved watch script 2016-10-14 09:54:37 +02:00
jos ceea59b30d Aways package jsonlint, it's essential. Also some small fixes. 2016-09-30 17:05:23 +02:00
jos ae90077ed6 Removed semi colons 2016-09-30 16:51:43 +02:00
jos b5ce5cb2ae Removed a redundant variable in the gulp file 2016-09-30 16:43:09 +02:00
jos adb3c6bdd9 Integrated jsonlint 2016-09-30 16:42:04 +02:00
jos 5fc5e302dc Refactored ActionMenu and AppendActionMenu 2016-09-30 13:40:14 +02:00
jos 1bcc6382aa Handle error when switching mode 2016-09-29 14:26:20 +02:00
jos 873d5f8ae2 Implemented switch mode menu 2016-09-29 14:19:01 +02:00
jos 88aed193c6 Refactored menus 2016-09-29 10:33:32 +02:00
jos 339b73fe51 Added jsonlint asset (not yet used) 2016-09-24 19:15:35 +02:00
jos d755ca9d03 Implemented patch for TextMode 2016-09-23 20:09:49 +02:00
jos 0c3faa03ea Implemented option onError 2016-09-23 19:53:57 +02:00
jos 804c68010f Implemented setMode, setText, getText 2016-09-23 19:46:04 +02:00
jos b44a465207 Implemented mode `text` 2016-09-23 14:46:59 +02:00
jos 84031dc3ef Define keys 2016-09-23 14:02:08 +02:00
jos 10e9f16b75 Removed a todo 2016-09-23 12:07:44 +02:00
jos 6db127739c Some refactoring 2016-09-23 12:01:39 +02:00
jos 75c1497de1 Minor refactoring 2016-09-23 11:53:25 +02:00
jos 54788aa593 Created immutability function `insertAt` 2016-09-23 11:41:00 +02:00
jos 2a1fabc6ac Fixed the need for try/catch around oldValue 2016-09-23 11:17:53 +02:00
jos 291cfbfa22 Improved errors. Fixed move before 2016-09-23 11:15:56 +02:00
jos 515e7a6bf2 Fixed undo move losing position 2016-09-23 09:33:27 +02:00
jos 7f979b97dd Changed the signature of `jsonToData` to pass the json value first and make the other args optional 2016-09-18 21:54:39 +02:00
jos 0a857aaad6 Simplify patch 2016-09-18 15:40:40 +02:00
jos ad36723618 Fixed `move` 2016-09-18 15:30:57 +02:00
jos c8b3bd2d7a Extra info in JSONPatch mostly working 2016-09-17 16:46:58 +02:00
jos 7b6a3747d2 Refactored 'object' and 'array' to 'Object' and 'Array' respectively 2016-09-17 15:40:17 +02:00
jos fb758d3135 Turn on uglify again 2016-09-17 15:25:26 +02:00
jos 83ae2bab07 Fixed duplicate variables 2016-09-17 15:23:31 +02:00
jos d235425f36 Some refactoring 2016-09-17 15:12:25 +02:00
jos ff7f683b11 Fixed some issues with history 2016-09-17 14:18:54 +02:00
jos de6d7c9551 Reordered functions 2016-09-16 20:39:42 +02:00
jos 611db9c431 Removed `name` from global options 2016-09-16 20:37:07 +02:00
jos 3d467e65e1 History starts to work with JSONPatch 2016-09-16 15:09:31 +02:00
jos 678db6bced Use JSONPatch actions internally 2016-09-16 14:41:51 +02:00
jos 44183e01bd More refactoring 2016-09-09 15:19:57 +02:00
jos 7adc760b33 Refactored API of `remove` and `replace` 2016-09-09 14:43:58 +02:00
jos ec63a9a759 Make `add` standalone 2016-09-09 14:30:07 +02:00
jos bb8850fb91 immutabilityHelpers don't accept non-existing paths 2016-09-09 11:43:36 +02:00
jos fe0f98dfe0 Implemented jsonpatch operations 2016-09-09 11:01:06 +02:00
jos 94671507b5 Prevent duplicate property names 2016-08-26 13:25:34 +02:00
jos 9350debba2 Fixed property names not being escaped when rendering 2016-08-26 12:25:51 +02:00
jos 7280239771 Fixed losing caret position whilst typing 2016-08-26 12:16:43 +02:00
jos ea6b00b67d Fixed build script not outputting errors 2016-08-26 09:19:15 +02:00
jos 71c38f07af Created helper function to find a unique name (not yet used) 2016-08-26 08:57:27 +02:00
jos 123b0c7cb4 Implemented simple undo/redo support 2016-08-21 14:15:30 +02:00
jos 56fc3164ec Implemented menu with expand all / collapse all buttons 2016-08-21 13:43:28 +02:00
jos 737963b908 Remove console outputs 2016-08-21 13:14:18 +02:00
jos b6d622e0d0 Fixed array/object not being rendered empty when removing the last item 2016-08-21 13:12:47 +02:00
jos c5a68b1da3 Implemented expand/collapse methods and ctrl+expand/ctrl+collapse 2016-08-21 12:45:25 +02:00
jos d8a0079032 Show placeholders when a `prop` or `value` is empty 2016-08-20 11:34:37 +02:00
jos 069d35ace4 Moved the logic for manipulating JSONData object into a separate file 2016-08-20 11:14:28 +02:00
jos c8a5614511 Renamed `watch` script to `start` 2016-08-20 10:06:18 +02:00
jos 41821ef825 The factory function now creates a neat wrapper object instead of returning a TreeMode object 2016-08-19 21:14:09 +02:00
jos 422315dba2 Some refactoring 2016-08-14 14:00:14 +02:00
jos ebca411384 Moved functions from objectUtils.js to immutabilityHelpers.js 2016-08-13 21:45:09 +02:00
jos 24ab2899dc Some early refactoring of docs and examples 2016-08-13 21:38:32 +02:00
jos a12505b017 Updated license information on some other places too 2016-08-13 21:23:43 +02:00
jos 25dfa2c0e1 Put new build script into place, update unit testing, changed license to MIT, merged css and image into the bundled js file 2016-08-13 21:15:52 +02:00
jos d014146956 Added some todo's 2016-08-12 13:47:35 +02:00
jos 1099e3859f Set up a structure for JSONEditor base class (instead of Main) 2016-08-07 13:50:46 +02:00
jos 608f45c8e7 Changed singnature of `handleInsert`, `handleDuplicate`, and `handleRemove` 2016-08-06 14:18:15 +02:00
jos a065fbb09e Create a function `getPath` instead of passing path via props 2016-08-06 14:08:57 +02:00
jos ab37f5ba9a Handle state of context menus in the JSONNodes. Append context menu working now 2016-08-05 20:23:23 +02:00
jos 9d61ce001a Halfway implementing AppendContextMenu. Upgraded to preact v5.6.0 2016-08-05 14:17:24 +02:00
jos 7f6e7459df Fixed preact errors regarding `contentEditable` 2016-08-05 11:21:16 +02:00
jos 4baa98c961 Some refactoring. Pass options `name` and `expand` via `.set` 2016-07-31 22:02:51 +02:00
jos 274a99ddef Removed helper functions in Main 2016-07-31 21:42:24 +02:00
jos 525a41a7d5 Implemented data conversion when switching type 2016-07-31 15:25:49 +02:00
jos 49f0ed3e4f Implemented support for type 'string' 2016-07-31 14:41:28 +02:00
jos 38250a38ba Refactored the internal data structure 2016-07-31 14:27:20 +02:00
jos 224e436828 Sort objects by property instead of value 2016-07-30 20:37:00 +02:00
jos 5416676735 Changed internal path to Array again 2016-07-30 20:30:08 +02:00
jos 667d3f32aa Implemented actions for ContextMenu (not all fully working yet) 2016-07-30 14:40:58 +02:00
jos c3c836fa89 Fixes in life cycle of ContextMenu. Adjust top/bottom orientation 2016-07-24 22:14:45 +02:00
jos a9f0fe07c1 Completed displaying of context menu 2016-07-24 15:31:16 +02:00
jos a1859a9aff Fixed showing multiple context menus 2016-07-16 14:31:01 +02:00
jos cd08e16789 Refactored path to be a JSON pointer 2016-07-16 14:24:28 +02:00
jos 37ae2111ee Created context menu button. Some refactoring 2016-07-16 13:48:20 +02:00
jos fda4f94655 Implemented a data model, fixed ordering of object properties, implemented options `name` and `expand` 2016-07-15 22:43:59 +02:00
jos fd631cd34c Keep state of value in JSONNode whilst typing (for live updating of colors) 2016-07-14 15:35:37 +02:00
jos d0abc3124a Fixed array index not being rendered when an array item is an object or array 2016-07-14 15:23:16 +02:00
jos b796de2128 Implemented expand/collapse 2016-07-14 15:15:50 +02:00
jos 5adf72dcc1 Some refactoring in the build scripts 2016-07-13 15:09:56 +02:00
jos 32853ea0d8 Some refactoring 2016-07-13 14:50:31 +02:00
jos 7fb5ca6517 Some refactoring 2016-07-13 14:32:43 +02:00
jos c0f075a9e6 Largely fixed jumping of fields when renaming. Some refactoring. 2016-07-13 14:26:11 +02:00
jos 8723855bdf Added `react-dev-server` dependency 2016-07-12 21:45:38 +02:00
jos 22785614af Created temporary scripts 2016-07-12 21:43:32 +02:00
jos c46f27334c Css fixes and improvements 2016-07-12 21:35:43 +02:00
jos 1c3a323387 Refactored `escape` utils 2016-07-12 21:20:11 +02:00
jos f011e3f107 coloring fields, urls, and a refactoring 2016-07-12 21:07:50 +02:00
jos 89657a539f escape/unescape fields and values 2016-07-12 16:19:57 +02:00
jos 4e0aa5659c Apply changes in fields 2016-07-12 15:43:42 +02:00
jos 0d250cbdcd Basic editor using preact 2016-07-12 13:56:40 +02:00
jos b4cf47b06f Moved old source code to `src_old` 2016-07-12 13:56:04 +02:00
221 changed files with 62392 additions and 44648 deletions

View File

@ -1,5 +1,20 @@
{
"plugins": [
"transform-class-properties",
"transform-object-rest-spread",
"transform-react-jsx",
["transform-runtime", {
"polyfill": false,
"regenerator": true
}]
],
"presets": [
["@babel/preset-env"]
["env", {
"targets": {
"browsers": ["last 2 versions", "ie >= 9", "safari >= 7"]
},
"modules": "commonjs",
"loose": true
}]
]
}

1
.github/FUNDING.yml vendored
View File

@ -1 +0,0 @@
github: josdejong

37
.gitignore vendored
View File

@ -1,10 +1,31 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# Ignore css files generated from scss
/src/**/*.css
# dependencies
/node_modules
# testing
/coverage
# production
/lib
/dist
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
# webstorm
.idea
*.iml
# visual studio code
.vscode
build
dist
downloads
node_modules
*.zip
npm-debug.log
/.vs
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View File

@ -1,5 +1,4 @@
bower.json
CONTRIBUTING.md
downloads
misc
node_modules
@ -10,4 +9,4 @@ component.json
.npmignore
.gitignore
*.zip
npm-debug.log
npm-debug.log

View File

@ -1,5 +0,0 @@
language: node_js
node_js:
- "lts/*"
script: npm test && npm run lint

View File

@ -6,18 +6,10 @@ up with ideas and suggestions, and contribute to the code.
There are a few preferences regarding code contributions:
- Send pull requests to the `develop` branch, not the `master` branch.
- You can use modern JavaScript features, the code is transpiled using Babel.
- `jsoneditor` follows the https://standardjs.com/ code style. To test:
```
npm run lint
```
- If possible, create a unit test for any new functionality. To run tests:
```
npm test
```
- `jsoneditor` follows the node.js code style as described
[here](http://nodeguide.com/style.html).
- Send pull requests to the `develop` branch, not the `master` branch.
- Only commit changes done in the source files under `./src`, do not
commit builds located in the `./lib` and `./dist` folders.
Thanks!

View File

@ -3,916 +3,7 @@
https://github.com/josdejong/jsoneditor
## not yet published, version 9.1.2
- Log a clear error in the console when the returned value of `onEditable` is
invalid. See #1112.
## 2020-09-23, version 9.1.1
- Fix #1111: Enum dropdown not showing when using patternProperties for schema.
Thanks @ziga-miklic.
- Fixed JSONEditor not working when opened in a new window, see #1098.
Thanks @joshkel.
- Fix quick-key `Ctrl+D` (duplicate) not working.
- Define "charset: utf-8" in all HTML examples.
## 2020-09-15, version 9.1.0
- Implemented German translation (`de`). Thanks @s-a.
- Fix quick-keys `Ctrl-\` (format) and `Ctrl-Shift-\` (compact) not working
in `code` mode.
- Updated dependencies to `ajv@6.12.5`.
## 2020-09-09, version 9.0.5
- Fix #1090: autocomplete firing on dragging or clicking a node.
- Fix #1096: editor crashing when passing an empty string as `name`.
- Updated dependencies to `ajv@6.12.4`.
## 2020-08-15, version 9.0.4
- Updated dependencies to `ace-builds@1.4.12`, `ajv@6.12.3`.
- Fix #1077: change the `main` field in `package.json` to point to the actual
bundled and minified file instead of a node.js index file.
## 2020-07-02, version 9.0.3
- Fix regression introduced in `v9.0.2` in the select boxes in the
Transform model not lighlighting the matches correctly.
## 2020-07-01, version 9.0.2
- Fix #1029: XSS vulnerabilities. Thanks @onemoreflag for reporting.
- Fix #1017: unable to style the color of a value containing a color.
Thanks @p3x-robot.
## 2020-06-24, version 9.0.1
- Fixed broken link to the Ace editor website (https://ace.c9.io/).
Thanks @p3x-robot.
- Fix #1027: create IE11 Array polyfills `find` and `findIndex` in such a way
that they are not iterable.
## 2020-05-24, version 9.0.0
- Implemented option `limitDragging`, see #962. This is a breaking change when
using a JSON schema: dragging is more restrictive by default in that case.
Set `limitDragging: false` to keep the old, non-restricted behavior.
## 2020-05-13, version 8.6.8
- Fix #936: too many return characters inserted when pasting formatted text
from OpenOffice.
## 2020-05-10, version 8.6.7
- Fix #858: the `dist/jsoneditor.js` bundle containing a link to a
non-existing source map.
- Fix #978: in some special cases the caret was jumping to the beginning of the
line whilst typing.
- Update dependencies to `ajv@6.12.2`.
## 2020-04-21, version 8.6.6
- Fix #969: adding a new property to an empty object or array is broken.
Regression introduced in `v8.6.5`.
## 2020-04-19, version 8.6.5
- Fix #964: translation of titles of some context menu items not working.
- Update dependencies to `ace-builds@1.4.11`, `ajv@6.12.1`.
## 2020-03-29, version 8.6.4
- Fix #921: `sortObjectKeys` emits `onChange` events.
- Fix #946: `language` not working in modes `text`, `code`, and `preview`.
- Revert reckoning with the order of object properties when updating an
object (introduced in `v8.6.2`). See #917.
- Implement support for repairing line separate JSON.
## 2020-03-18, version 8.6.3
- Fix #932: `JSONEditor.update` broken, did not always recognize when the
input changed. Regression introduced in `v8.6.2`.
## 2020-03-18, version 8.6.2
- Fixed #917, #926: Keep order of properties when updating an object.
- Fixed #928: Custom root name not reflected in path of navigation bar.
- Upgraded to `ajv@6.12.0`
## 2020-02-17, version 8.6.1
- Fixed #908: editor throwing an exception when switching from `'preview'`
to `'code'` mode.
## 2020-02-16, version 8.6.0
- Fixed #906: Implemented turning Python objects containing `True`, `False`
and `None` into valid JSON using repair.
## 2020-02-06, version 8.5.3
- Fix #892: the undo/redo buttons in mode `code` being broken when custom
loading an old version of Ace Editor.
## 2020-02-05, version 8.5.2
- Fix undo/redo buttons in mode `code` not always updating.
## 2020-02-05, version 8.5.1
- Fix broken build.
## 2020-02-05, version 8.5.0
- Implemented support for customizing the query language used in the
Transform modal. New options `createQuery`, `executeQuery`, and
`queryDescription` are available for this now. An example is available
in `examples/23_custom_query_language.html`. See #857, #871.
- Implement undo/redo buttons in `code` mode.
- Fix history (undo/redo) being cleared in mode `code` and `text` after
transforming or sorting.
## 2020-01-25, version 8.4.1
- Fix `console.log` in production code. Oopsie.
## 2020-01-25, version 8.4.0
- Added CSS classes `jsoneditor-expanded` and `jsoneditor-collapsed` on array
and object nodes reflecting there state.
## 2020-01-18, version 8.3.0
- Update dependency `ajv` to `v6.11.0`.
- Fix #790: editor breaking when missing a translation containing a
placeholder.
## 2020-01-16, version 8.2.0
- Make it easy to create custom styling by overriding default SASS variable
values, see #881. Thanks @petermanders89.
- Update `ace` to `v1.4.8`.
## 2020-01-06, version 8.1.2
- Fix #873: buttons Format, Compact, and Repair not supporting
internationalization.
- Fix #877: Some CSS styling issues when used in combination with Materialize.
- Updated dependency `vanilla-picker` to `v2.10.1`.
## 2019-12-28, version 8.1.1
- Fixed the file size reported in `preview` mode show `KB` and `MB` instead
of `KiB` and `MiB` in order to match the size reported by filesystems.
## 2019-12-18, version 8.1.0
- Implemented `popupAnchor` allowing to select a custom anchor element.
See #869 and #870.
- Fixed #502: CSS rule `* { font-family: ... }` resulting in Ace editor (`code`
mode) not having a mono-space font anymore.
## 2019-12-11, version 8.0.0
- Implemented option `timestampFormat` which allows customizing the formatting
of timestamp tags. See also option `timestampTag`. Thanks @smallp.
- Changed the behavior of `timestampTag` to fallback on the built-in rules when
the function does not return a boolean. See #856.
- Reverted the heuristics introduced in `v7.3.0` to check whether some field
contains a timestamp based on the field name, because they can give wrong
timestamps in case of values in seconds instead of the assumed milliseconds
(see #847, #856).
## 2019-12-08, version 7.5.0
- Extended the callback `onValidationError` to also report parse errors,
and distinguish between JSON schema validation errors and custom errors.
See #861 and #612. Thanks @meirotstein.
## 2019-12-01, version 7.4.0
- Implemented callback function `onValidationError`, see #612, #854.
Thanks @meirotstein.
- Fixed #850: make autocomplete options robust against non-string inputs
like `null`, `123`, `true`, `false`.
## 2019-12-01, version 7.3.1
- Fixed #855: `onFocus` and `onBlur` not working in modes `text` and `code`
when editor was created without main menu bar, and `editor.destroy()`
throwing an exception.
## 2019-11-27, version 7.3.0
- Implemented callbacks `onFocus` and `onBlur` (PR #809, issue #727).
Thanks @123survesh.
- Fixed #847: allow customizing the in rules determining whether a value
is a timestamp or not by passing a callback function to `timestampTag`.
## 2019-10-27, version 7.2.1
- Fixed #826: editor not allowing indentation `0`.
- Fixed #828: do not expand/collapse when clicking the text of a node
in modes `view` or `form`.
- Fixed #829: z-index issue of context-menu button and conflicting css names.
## 2019-10-23, version 7.2.0
- Implemented Japanese translation (`ja`). Thanks @yutakiyama.
- Implemented French translation (`fr-FR`), and some improvements in the
translation. Thanks @yannickyvin.
- Upgraded to the latest version of Ace editor, 1.4.7.
- Fixed #824: Parse errors not displayed with bottom right error icon in modes
`code` and `text`.
## 2019-10-13, version 7.1.0
- Upgraded to the latest version of Ace editor 1.4.6. Changed implementation
to use `ace-builds` directly instead of `brace` (still using Ace 1.2.9).
- Improved Portuguese translation. Thanks @victorananias.
## 2019-10-06, version 7.0.5
- Upgraded dependencies: `vanilla-picker@2.10.0`.
- Minor documentation improvements. Thanks @slash-arun.
- Minor styling fixes.
## 2019-09-11, version 7.0.4
- Fixed #723: schema error popup and color picker not always fully visible.
- Fixed wrong text color in search box when using JSONEditor in combination
with bootstrap. See #791. Thanks @dmitry-kulikov.
- Fixed react examples not working out of the box when cloning or downloading
the git repository of JSONEditor. See #787, #788. Thanks @vishwasnavadak.
## 2019-09-04, version 7.0.3
- Fixed `index.js` pointing to non-transpiled code. See #783.
- Fixed absolute url of images in SASS. Thanks @moonbreezee.
## 2019-09-02, version 7.0.2
- Fix #781: race condition when destroying the editor right after setting data.
## 2019-09-01, version 7.0.1
- Fix npm package missing `dist` folder.
## 2019-09-01, version 7.0.0
- Converted the code largely to ES6, put Babel transpiler in place.
- Dropped support for bower, removed the `dist` folder from the git repository.
- Fixed #586: caret position lost when switching browser tabs.
## 2019-08-28, version 6.4.1
- Fix styling of autocompletion dropdown broken. Regression since `v6.4.0`.
## 2019-08-28, version 6.4.0
- Replaces CSS with SASS internally, improvements in styling. Thanks @ppetkow.
- Fixed #761: JSON schema errors not rendered in the gutter for mode `code`
when the path contained a property with a forward slash, and errors not
clickable in the error table.
- Fixed #777: option `sortObjectKeys` broken.
## 2019-08-15, version 6.3.0
- Fixed #755: JSONEditor throwing an exception in mode `code`, `text`, and
`preview` when `statusBar: false`.
- When duplicating an object property, move focus to the field and do not
immediately add the ` (copy)` suffix. See #766.
- Fixed #769: option `name` not working anymore. Regression since `v6.1.0`.
- Fixed #763: `autocomplete.trigger: 'focus'` throws an error when opening the
context menu. Thanks @Thaina.
- Updated dependencies `json-source-map@0.6.1`
## 2019-08-01, version 6.2.1
- Updated Chinese translation. Thanks @SargerasWang.
## 2019-07-28, version 6.2.0
- Implemented new mode `preview`, capable of working with large JSON documents
up to 500 MiB.
- Repair button is now capable of turning MongoDB documents into valid JSON.
- Fixed #730: in `code` mode, there was an initial undo action which clears
the content.
- Upgraded dependencies `vanilla-picker@2.9.2`, `mobius1-selectr@2.4.13`,
`ajv@6.10.2`.
## 2019-06-22, version 6.1.0
- Implemented menu options `sort` and `transform` for modes `code` and `text`.
- Implemented new context menu item `extract`.
- Minor tweaks in the way paths are displayed in the sort and transform modals.
## 2019-06-12, version 6.0.0
- Breaking change: upgraded dependency `ajv@6.10.0`, supporting JSON schema
draft-07 alongside draft-06 and draft-04.
- Upgraded dependency `vanilla-picker@2.8.1`.
- Use JSON schema title as name for the root object if defined (see #635).
## 2019-06-08, version 5.34.0
- Extended the autocomplete feature with new options `filter` and `trigger`.
Thanks @Gcaufy.
- Removed :hover style on disabled buttons. Thanks @Gcaufy.
- Upgraded dependency `mobius1-selectr@2.4.12`.
## 2019-05-29, version 5.33.0
- Fixed #697: JSON Schema enum dropdown not working inside an array.
- Fixed #698: When using `onCreateMenu`, `node.path` is null when clicking
on an append node or when multiple nodes are selected.
- Upgraded dependencies to `mobius1-selectr@2.4.10`, `vanilla-picker@2.8.0`.
- Remove :hover style on disabled buttons. Thanks @Gcaufy.
## 2019-04-27, version 5.32.5
- Fixed a bug in the JMESPath query wizard which didn't correctly handle
selecting multiple fields.
- Fixed context menu not working when multiple nodes are selected.
## 2019-04-10, version 5.32.4
- Fixed #682 and #687: JSONEditor not being able to handle JSON schema
validation errors when the root of the document is an Array. Thanks @DusuWen.
## 2019-04-04, version 5.32.3
- Fixed #684: `const` used in bundled library.
## 2019-04-03, version 5.32.2
- Fixed #416: Clipped action menu for append nodes.
- Improve detection of value type in transform modal.
- Styling improvements in the transform modal.
- Fix CSS class for default/non-default schema values not applied to enums,
see (#666).
- Fixed #671: Improved handling of duplicate property names, which could cause
values to be cleared when used as a controlled component in for example React.
## 2019-03-28, version 5.32.1
- Fixed a regression in parsing JSON paths: numbers where parsed as strings
instead of a numeric value. See #679. Thanks @AdamVig.
- Fixed using hyphens in the path of custom validation errors (see #665).
Thanks @tobiasfriden.
## 2019-03-20, version 5.32.0
- Implemented support for reckoning with JSON schema default values: custom
styling can be applied for default and non-default values. Thanks @AdamVig.
- Fixed #667: resolving JSON Schema examples and descriptions did not always
work for referenced schemas. Thanks @AdamVig.
- Fixed #676: JSON Paths containing array properties with a `]` not parsed
correctly.
## 2019-03-14, version 5.31.1
- Fix IE11 issue.
- Some fixes in the Simplified Chinese translation.
Thanks @@adf0001 and @yuxizhe.
## 2019-03-10, version 5.31.0
- Display JSON schema examples in tooltip (#664). Thanks @AdamVig.
## 2019-03-02, version 5.30.0
- Implemented a new option `onCreateMenu` to customize the action menu.
Thanks @RobAley.
## 2019-02-20, version 5.29.1
- Fixed #661: JSONEditor broken on IE11 caused by duplicate JSON entries
in a translation.
## 2019-02-16, version 5.29.0
- Added Simplified Chinese localization. Thanks @long2ice.
- Added Turkish localization. Thanks @beratpostalci.
- Improved JSON schema titles on fields. Fixes #321. Thanks @AdamVig.
- Fixes in resolving JSON schemas, see #651. Thanks @AdamVig.
- Fix #657: `onClassName` throwing an error when a node is removed.
## 2019-01-23, version 5.28.2
- Fix #639: Occurrence of non-ES5 `const` declaration in published code.
Regression introduced in `v5.28.0`.
## 2019-01-22, version 5.28.1
- Fix #637: Vertical white border left/right from the main menu in some
specific circumstances.
- Fix #638: Cannot expand after collapse. Regression introduced in v5.28.0.
## 2019-01-21, version 5.28.0
- Implemented new option `maxVisibleChilds` to customize the maximum number
childs that is rendered by default. Thanks @20goto10.
- Implemented new option `onClassName`, allowing customized and dynamic
styling of nodes. See 20_custom_css_style_for_nodes.html for a demo.
Thanks @maestr0.
- Make the method `refresh()` public.
## 2019-01-16, version 5.27.1
- Improved navigating deeply nested paths via the navigation bar, see #619.
Thanks @meirotstein.
- Sdd title from schema description to show the tips for user input.
Thanks @tylerchen.
- Fix JSON Schema not resolving refs `$ref`, and not creating enum dropdowns.
Thanks @tylerchen.
## 2019-01-05, version 5.27.0
- Implemented customizing object and array names via a new option
`onNodeName`. Thanks @bnanchen.
- Visibility of schema validation errors at the bottom of mode code and text
are now toggleable. Thanks @meirotstein.
- Fixed text of the mode switcher not being translated. Thanks @antfu.
## 2018-12-06, version 5.26.3
- Fixed #610: JSON Repair now removes trailing commas.
- Upgraded devDependency `gulp` to v4. Thanks @maestr0.
## 2018-11-13, version 5.26.2
- Fixed dragging and selecting multiple nodes not working
(regression introduced in `v5.26.1`).
## 2018-11-13, version 5.26.1
- Fixed `.update()` throwing an exception when replacing a JSON object
with `null`. Thanks @DullReferenceException.
- Fixed #598: Search field can't be focused in object view.
## 2018-11-12, version 5.26.0
- Implemented option `mainMenuBar` to enable/disable the main menu bar.
Thanks @tanmayrajani.
## 2018-10-29, version 5.25.0
- Implemented options `enableSort` and `enableTransform` so you can turn off
these features. Thanks @tanmayrajani.
- Fixed #590: validation failing in code and text mode when status
bar is disabled.
- Fixed #589: the path in the navigation bar is not updated
when duplicating or removing a node, and neither after an undo/redo action.
- Fixed duplicate and remove of the action menu of multiple selected
nodes not working.
- Fixed not preventing default selection of text when selecting nodes.
- Fixed #595: navigation bar path link not working.
## 2018-10-08, version 5.24.7
- Fix #582: parse error annotations not always up to date in
code editor. Thanks @meirotstein.
## 2018-09-12, version 5.24.6
- Fix #548: `import JSONEditor from 'jsoneditor'` not working in
TypeScript projects (gave a constructor is undefined error).
## 2018-09-06, version 5.24.5
- Fixed a bug in textmode on IE 11, not loading the editor when
`Promise` is undefined.
## 2018-09-06, version 5.24.4
- Fixed #576: Visualization in mode `view` when an array
with more than 100 items is rendered.
- Fixed JSONEditor not working on IE11: continue and throw console
errors when `Promise` is undefined. Regression since `v5.23.0`.
- Fixed `onClose` of color picker not being fired when clicking outside
the picker to close it.
- Upgraded dependencies `brace`, `mobius1-selectr`, `vanilla-picker`.
- Upgraded devDependency `mocha`.
## 2018-08-29, version 5.24.3
- Fixed color picker not working in ES6 projects.
- Fixed color picker closing immediately after the first `onChange`
event, and `onChange` events are now debounced like all text inputs.
## 2018-08-27, version 5.24.2
- Improved error and validation messaging in `text` mode.
Thanks @meirotstein.
- Clicking a message now selects the line where the error occurs.
- Icon bottom right showing when there are warnings or errors.
- Fixed field still editable after moving a node from an object
to an array, changing the field from a property into an index.
## 2018-08-26, version 5.24.1
- Context menu and color picker are now absolutely positioned, and
can overflow the borders of the editor.
- Fixed #568: mode switcher disappearing when selecting the current
mode again.
- Fixed `transform` not creating/removing expand button when the type
of a node changed.
## 2018-08-22, version 5.24.0
- Implemented a color picker, and allow hooking in a custom color
picker. new options are `colorPicker` and `onColorPicker`.
- Implemented a timestamp tag displayed right from timestamps,
with corresponding option `timestampTag`.
## 2018-08-17, version 5.23.1
- Fixed #566: transform function broken, regression since `v5.20.0`.
## 2018-08-15, version 5.23.0
- Implemented support for custom validation using a new `onValidate` callback.
- In tree mode, nodes containing a validation error now have a className
`jsoneditor-validation-error` which can be used for custom styling.
## 2018-08-13, version 5.22.0
- Implemented `onEvent` callback triggered when an event occurs in a JSON
field or value. Thanks @cristinabarrantes.
## 2018-08-12, version 5.21.0
- Show validation errors inline instead of at the bottom when in code
mode. Thanks @meirotstein.
- Fix #562: allow `$` character in property names of of a JSON schema.
## 2018-08-10, version 5.20.0
_Good news: JSONEditor is finally framework friendly and can now be easily
integrated in React, Vue, and Angular!_
- Implemented new methods `update` and `updateText`, which maintain the state
of the editor (expanded nodes, search, selection). This makes it easy to
integrate in frameworks like React.
- Implemented options `onChangeJSON(json)` and `onChangeText(jsonString)`.
- Added two React examples to the `examples` folder.
- Fixed menu buttons "Sort" and "Transform" being available in modes `view`
and `form`.
## 2018-08-02, version 5.19.2
- Fixed #558: scrolling to search results and automatically scrolling up/down
when dragging an item broken (regression since v5.19.1).
## 2018-07-28, version 5.19.1
- Fixed #557: inner contents of the scrollable area being displayed outside of
the editor (on Chrome only).
## 2018-07-11, version 5.19.0
- No more grayed out icons of the context menu, see #532.
- Added Sort and Transform buttons to the main menu.
- Fixes and improvements in the Transform dialog.
## 2018-06-27, version 5.18.0
- Implemented JMESPath support for advanced filtering, sorting, and
transforming of JSON documents.
- Implemented a new option `modalAnchor` to control at which part of the
screen the modals are displayed.
- Fixed #544: JSON Schema errors sometimes not being displayed in the
editor.
## 2018-06-03, version 5.17.1
- Fixed a bug in a translation text.
## 2018-06-03, version 5.17.0
- Implemented advanced sorting for arrays.
## 2018-05-23, version 5.16.0
- Better handling of JSON documents containing large arrays:
- Only displays the first 100 items of large arrays,
with buttons "show more" and "show all" to render more items.
- Search results are now limited to max 1000 matches,
and search does no longer expand the paths to all matches
but only expands the path of the current search result.
- Fixed index numbers of Array items not being updated after sorting.
## 2018-05-02, version 5.15.0
- Implemented selection API: `onSelectionChanged`, `onTextSelectionChanged`,
`getSelection`, `getTextSelection`, `setSelection`, `setTextSelection`,
and `getNodesByRange`. Thanks @meirotstein.
## 2018-03-21, version 5.14.1
- Fixed absolute path of css image `jsoneditor-icons.svg`, which could.
give issues with webpack plugin "file-loader". Thanks @landru29.
## 2018-02-25, version 5.14.0
- Implemented support for translations. Thanks @mariohmol.
- Fixed a bug sometimes occurring when dragging items from array to
object, see #509. Thanks @43081j.
- Fixed autocomplete not accepting returned `null` values, see #512.
Thanks @43081j.
- Fixed memory inefficiency when working with large JSON Schema's
generating many errors. Thanks @43081j.
## 2018-02-07, version 5.13.3
- Fixed a positioning issue with JSON Schema errors in text/code mode.
## 2018-01-18, version 5.13.2
- Fixed view mode opening links in a new tab instead of current tab
when Ctrl key is not down. Thanks @LEW21.
- Fixed #502: code editor not showing a monospaced font some cases.
## 2017-12-28, version 5.13.1
- Fixed another occurrence of #494: properties not escaped in the
navigation bar.
## 2017-12-28, version 5.13.0
- Implemented cursor position in text mode. Thanks @meirotstein.
- Fixed #494: properties not escaped in the navigation bar.
Thanks @meirotstein.
## 2017-12-18, version 5.12.0
- Implemented #482: Include `caseSensitive` option for autocomplete.
Thanks @israelito3000.
- Upgraded dependencies
- `ajv@5.5.2`
## 2017-11-22, version 5.11.0
- Upgraded dependencies
- `ajv@5.4.0`
- `brace@0.11.0`
- Fixed dropdown for JSON Schema enums when defined inside pattern
properties. Thanks @alquist.
- Fixed code containing a non UTF-8 character. Thanks @alshakero.
## 2017-11-15, version 5.10.1
- Some styling tweaks in the navigation bar and status bar.
- Don't display status bar in `text` mode (which doesn't yet support
row and col counts).
## 2017-11-15, version 5.10.0
- Implemented a navigation bar showing the path. Thanks @meirotstein.
- Implemented a status bar showing cursor location.
Thanks @meirotstein.
- Implemented repairing JSON objects containing left and right single
and double quotes (which you get when typing a JSON object in Word)
in `text` and `code` mode.
- Implemented repairing JSON objects containing special white space
characters like non-breaking space.
- Upgraded dependency `ajv` to version `5.3.0`.
- Fixed #481: A polyfill required `DocumentType` which is not defined
in all environments.
## 2017-09-16, version 5.9.6
- Fixed displaying a dropdown for enums inside composite schemas.
Thanks @hachichaud.
- Fixed #461: Urls opening twice on Firefox and Safari.
## 2017-08-26, version 5.9.5
- Fixed a regression introduced in `v5.9.4`: after using the context
menu once, it was not possible to set focus to an other input field
anymore.
## 2017-08-20, version 5.9.4
- Fixed #447: context menus not working in Shadow DOM. Thanks @tomalec.
## 2017-07-24, version 5.9.3
- Fixed broken multi-selection (regression).
## 2017-07-13, version 5.9.2
- Fixed a bug in the JSON sanitizer.
## 2017-07-13, version 5.9.1
- `setText` method of tree mode now automatically sanitizes JSON input
when needed.
- Fixed #430: automatically fix unescaped control characters in
JSON input.
## 2017-07-10, version 5.9.0
- Implemented support for JSON schema references `$ref`, see #302.
Thanks @meirotstein.
- Fixed #429: JSONEditor no longer accepting an empty array for option
`modes`. Thanks @trystan2k.
- Fixed JSONEditor picking the first entry of `modes` as initial mode
instead of option `mode`.
## 2017-07-08, version 5.8.2
- Select first option from `modes` instead of `tree` when `mode` is not
configured. Thanks @bag-man.
- Some fixes and improvements in the API of autocompletion.
Thanks @israelito3000.
## 2017-07-03, version 5.8.1
- Fixed broken minified bundles in folder `dist` (again...).
## 2017-07-02, version 5.8.0
- Implemented support for autocompletion. Thanks @israelito3000.
## 2017-06-27, version 5.7.2
- Fixed broken minified bundles in folder `dist`
(reverted to `uglify-js@2.8.22` for now).
## 2017-06-25, version 5.7.1
- Upgraded dependency `ajv` to version `5.2.0`. Resolves warnings in
Webpack build processes.
## 2017-05-26, version 5.7.0
- Implemented support for template items. Thanks @israelito3000.
- Upgraded dependencies to the latest versions. Thanks @andreykaipov.
## 2017-04-15, version 5.6.0
- Implemented readonly option for modes `text` and `code.`
Thanks @walkerrandolphsmith.
- Upgraded dependencies (`brance` and `ajv`) to the latest versions.
- Fixed not being able to move focus to enum select box when clicking
a JSON Schema warning.
- Fixed #309: already loaded version of Ace being overwritten by the
embedded version of JSONEditor.
- Fixed #368: Mode selection drop down not fully visible on small screen.
- Fixed #253: Optimize the input experience of Chinese IME.
Thanks @chinesedfan.
## 2017-01-06, version 5.5.11
- Fixed embedded version of jsoneditor ace theme not being loaded in
minimalist version (see #55).
- Fixed a styling issue in the SearchBox of Ace editor (mode `code`).
- Fixed #347: CSS more robust against global settings of div position.
- Added docs and example on how to use a custom version of Ace editor.
## 2016-11-02, version 5.5.10
- Fixed #85: pressing enter in an input in a form containing a JSONEditor too
breaks submitting the form.
## 2016-10-17, version 5.5.9
- Fixed #329: Editor showing duplicate key warnings for keys defined on the
Object prototype, like `toString` and `watch`.
## 2016-09-27, version 5.5.8
- Fixed #314: JSON schema validation throwing an error "Unexpected token ' in
JSON at position 0" in specific cases. Thanks @apostrophest
## 2016-08-17, version 5.5.7
## not yet released, version 5.5.7
- Fixed #308: wrong positioning of label "empty array" when `onEditable`
returns false.
@ -1364,7 +455,7 @@ integrated in React, Vue, and Angular!_
## 2012-08-12, version 1.2.0
- New: Added search functionality. Search results are expanded and highlighted.
- New: Added search functionality. Search results are expanded and highlighed.
Quickkeys in the search box: Enter (next), Shift+Enter (previous), Ctrl+Enter
(search again).
- New: The position of the vertical separator between left and right panel is
@ -1411,7 +502,7 @@ integrated in React, Vue, and Angular!_
## 2012-03-01, version 0.9.10
- Nicer looking select box for the field types, with icons.
- Improved drag and drop: better visualized, and now working in all browsers.
- Improved drag and drop: better visualized, and now working in all browers.
- Previous values will be restored after changing the type of a field. When
changing the type back, the previous value or childs will be restored.
- When hovering buttons (fieldtype, duplicate, delete, add) or when dragging
@ -1444,7 +535,7 @@ integrated in React, Vue, and Angular!_
## 2012-01-09, version 0.9.7
- Added functionality to expand/collapse a node and all its childs. Click
- Added functionallity to expand/collapse a node and all its childs. Click
the expand button of a node while holding Ctrl down.
- Small interface improvements

177
LICENSE
View File

@ -1,176 +1,7 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
Copyright 2015-2017 Jos de Jong
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
1. Definitions.
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

17
NOTICE
View File

@ -1,17 +0,0 @@
JSON Editor
https://github.com/josdejong/jsoneditor
Copyright (C) 2011-2020 Jos de Jong
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

142
README.md
View File

@ -1,11 +1,5 @@
# JSON Editor
[![Version](https://img.shields.io/npm/v/jsoneditor.svg)](https://www.npmjs.com/package/jsoneditor)
[![Downloads](https://img.shields.io/npm/dm/jsoneditor.svg)](https://www.npmjs.com/package/jsoneditor)
![Maintenance](https://img.shields.io/maintenance/yes/2020.svg)
[![License](https://img.shields.io/github/license/josdejong/jsoneditor.svg)](https://github.com/josdejong/jsoneditor/blob/master/LICENSE)
[![FOSSA Status](https://app.fossa.io/api/projects/git%2Bgithub.com%2Fjosdejong%2Fjsoneditor.svg?type=shield)](https://app.fossa.io/projects/git%2Bgithub.com%2Fjosdejong%2Fjsoneditor?ref=badge_shield)
JSON Editor is a web-based tool to view, edit, format, and validate JSON.
It has various modes such as a tree editor, a code editor, and a plain text
editor.
@ -13,50 +7,32 @@ editor.
The editor can be used as a component in your own web application. The library
can be loaded as CommonJS module, AMD module, or as a regular javascript file.
Supported browsers: Chrome, Firefox, Safari, Opera, Edge, Internet Explorer 11.
Supported browsers: Chrome, Firefox, Safari, Opera, Internet Explorer 9+.
<img alt="json editor" src="https://raw.github.com/josdejong/jsoneditor/master/misc/jsoneditor.png"> &nbsp; <img alt="code editor" src="https://raw.github.com/josdejong/jsoneditor/master/misc/codeeditor.png">
Cross browser testing for JSONEditor is generously provided by <a href="https://www.browserstack.com" target="_blank">BrowserStack</a>
<a href="https://www.browserstack.com" target="_blank"><img alt="BrowserStack" src="https://raw.github.com/josdejong/jsoneditor/master/misc/browserstack.png"></a>
## Features
JSONEditor has various modes, with the following features.
### Tree mode
- Change, add, move, remove, and duplicate fields and values.
### Tree editor
- Edit, add, move, remove, and duplicate fields and values.
- Change type of values.
- Sort arrays and objects.
- Transform JSON using [JMESPath](http://jmespath.org/) queries.
- Colorized code.
- Color picker.
- Search & highlight text in the tree view.
- Undo and redo all actions.
- JSON schema validation (powered by [ajv](https://github.com/epoberezkin/ajv)).
### Code mode
### Code editor
- Colorized code (powered by [Ace](https://ace.c9.io)).
- Inspect JSON (powered by [Ace](https://ace.c9.io)).
- Format and compact JSON.
- Repair JSON.
- JSON schema validation (powered by [ajv](https://github.com/epoberezkin/ajv)).
### Text mode
### Text editor
- Format and compact JSON.
- Repair JSON.
- JSON schema validation (powered by [ajv](https://github.com/epoberezkin/ajv)).
### Preview mode
- Handle large JSON documents up to 500 MiB.
- Transform JSON using [JMESPath](http://jmespath.org/) queries.
- Format and compact JSON.
- Repair JSON.
- JSON schema validation (powered by [ajv](https://github.com/epoberezkin/ajv)).
## Documentation
@ -71,48 +47,76 @@ JSONEditor has various modes, with the following features.
## Install
with npm (recommended):
Install via npm:
npm install jsoneditor
> Note that to use JSONEditor in Internet Explorer 11, it is necessary
> to load a polyfill for `Promise` in your application.
### Versions
There are two versions of jsoneditor available: a full version and
a minimalist version.
#### Full version
If you're not sure which version to use, use the full version: jsoneditor.js.
#### Minimalist version
The minimalist version, jsoneditor-minimalist.js, has excluded the following libraries:
- `ace` (via `brace`), used for the code editor.
- `ajv`, used for JSON schema validation.
This reduces the the size of the minified and gzipped JavaScript considerably.
When to use the minimalist version?
- If you don't need the mode "code" and don't need JSON schema validation.
- Or if you want to provide `ace` and/or `ajv` yourself via the configuration
options, for example when you already use Ace in other parts of your
web application too and don't want to bundle the library twice.
### More
There is a directive available for using `jsoneditor` in Angular.js:
[https://github.com/angular-tools/ng-jsoneditor](https://github.com/angular-tools/ng-jsoneditor)
## Use
```html
<!DOCTYPE HTML>
<html lang="en">
<html>
<head>
<!-- when using the mode "code", it's important to specify charset utf-8 -->
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<link href="jsoneditor/dist/jsoneditor.min.css" rel="stylesheet" type="text/css">
<script src="jsoneditor/dist/jsoneditor.min.js"></script>
<script src="jsoneditor/dist/jsoneditor.js"></script>
</head>
<body>
<div id="jsoneditor" style="width: 400px; height: 400px;"></div>
<script>
// create the editor
const container = document.getElementById("jsoneditor")
const options = {}
const editor = new JSONEditor(container, options)
var container = document.getElementById('jsoneditor');
var options = {};
var editor = jsoneditor(container, options);
// set json
const initialJson = {
var json = {
"Array": [1, 2, 3],
"Boolean": true,
"Null": null,
"Number": 123,
"Object": {"a": "b", "c": "d"},
"String": "Hello World"
}
editor.set(initialJson)
};
editor.set(json);
// get json
const updatedJson = editor.get()
var json = editor.get();
</script>
</body>
</html>
@ -136,51 +140,23 @@ jsoneditor:
npm run build
```
This will generate the files `./jsoneditor.js`, `./jsoneditor.css`, and
minified versions in the dist of the project.
This will generate the file `./dist/jsoneditor.js` and
`./dist/jsoneditor-minimalist.js` and corresponding source maps.
- To automatically build when a source file has changed:
- For development, start a develop server which automatically reloads
when a source file has changed:
```
npm start
```
This will update `./jsoneditor.js` and `./jsoneditor.css` in the dist folder
on every change, but it will **NOT** update the minified versions as that's
an expensive operation.
- Run unit tests (Jest):
```
npm test
```
## Test
Run unit tests:
```
npm test
```
Run code linting ([JavaScript Standard Style](https://standardjs.com/)):
```
npm run lint
```
## Custom builds
The source code of JSONEditor consists of CommonJS modules. JSONEditor can be bundled in a customized way using a module bundler like [browserify](http://browserify.org/) or [webpack](http://webpack.github.io/). First, install all dependencies of jsoneditor:
npm install
To create a custom bundle of the source code using browserify:
browserify ./index.js -o ./jsoneditor.custom.js -s JSONEditor
The Ace editor, used in mode `code`, accounts for about one third of the total
size of the library. To exclude the Ace editor from the bundle:
browserify ./index.js -o ./jsoneditor.custom.js -s JSONEditor -x brace -x brace/mode/json -x brace/ext/searchbox
To minify the generated bundle, use [uglifyjs](https://github.com/mishoo/UglifyJS2):
uglifyjs ./jsoneditor.custom.js -o ./jsoneditor.custom.min.js -m -c
## License
MIT

53
config/webpack.config.js Normal file
View File

@ -0,0 +1,53 @@
const webpack = require('webpack')
const minifyPlugin = new webpack.optimize.UglifyJsPlugin({ sourceMap: true })
const productionEnvPlugin = new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')
}
})
module.exports = {
entry: './src/jsoneditor/index.vanilla.js',
devtool: 'source-map',
cache: true,
bail: true,
output: {
library: 'jsoneditor',
libraryTarget: 'umd',
filename: 'dist/jsoneditor.js'
},
plugins: [
// bannerPlugin,
productionEnvPlugin,
minifyPlugin
],
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: { loader: 'babel-loader'}
},
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
},
{
test: /\.svg/,
use: {
loader: 'svg-url-loader',
options: {}
}
}
]
},
// using preact saves in the order of 25 kB
resolve: {
'alias': {
'react': 'preact-compat',
'react-dom': 'preact-compat'
}
}
}

View File

@ -0,0 +1,19 @@
const webpack = require('webpack')
const config = require('./webpack.config')
const emptyFile = __dirname + '/../src/jsoneditor/utils/empty.js'
const excludeAcePlugin = new webpack.NormalModuleReplacementPlugin(new RegExp('assets\/ace'), emptyFile)
const excludeAjvPlugin = new webpack.NormalModuleReplacementPlugin(new RegExp('^ajv$'), emptyFile)
const configMinimalist = Object.assign({}, config, {
output: Object.assign({}, config.output, {
filename: 'dist/jsoneditor-minimalist.js'
}),
plugins: [
excludeAcePlugin,
excludeAjvPlugin
].concat(config.plugins)
})
module.exports = configMinimalist

File diff suppressed because it is too large Load Diff

35
docs/key_bindings.md Normal file
View File

@ -0,0 +1,35 @@
# Key bindings
## Tree Editor
Name | Windows key combination | Mac key combination | Description
----------------------------- | ----------------------- | -------------------------- | ------------------------------------------------
`up`, `down`, `left`, `right` | Alt+Arrows | Option+Arrows | Move the caret up/down/left/right between fields
`duplicate` | Ctrl+D | Command+D | Duplicate field
`remove` | Ctrl+Del | Command+Del | Remove field
`openUrl` | Ctrl+Enter | Command+Enter | Open link when on a field containing an url
`insert` | Ctrl+Ins | Command+Ins | Insert a new field with type auto
`expand` | Ctrl+E | Command+E | Expand or collapse field
`end` | Alt+End | Option+End | Move the caret to the last field
`find` | Ctrl+F | Command+F | Find
`findNext` | F3, Ctrl+G | F3, Command+G | Find next
`findPrevious` | Shift+F3, Ctrl+Shift+G | Shift+F3, Command+Shift+G | Find previous
`home` | Alt+Home | Option+Home | Move the caret to the first field
`actionMenu` | Ctrl+M | Command+M | Show actions menu
`undo` | Ctrl+Z | Command+Z | Undo last action
`redo` | Ctrl+Shift+Z | Command+Shift+Z | Redo
## Code Editor
The code editor is powered by [Ace Editor](http://ace.c9.io/). This editor's
shortcut keys are described here:
https://github.com/ajaxorg/ace/wiki/Default-Keyboard-Shortcuts
Additionally, there are shortcut keys to format/compact the code:
Name | Windows key combination | Mac key combination | Description
--------- | ----------------------- | ------------------- | ------------------------------------------------
`format` | Ctrl+\ | Command+\ | Format JSON data, set proper indentation
`compact` | Ctrl+Shift+\ | Command+Shift+\ | Compact JSON data, remove all whitespace

View File

@ -1,38 +1,3 @@
# Shortcut keys
## Tree Editor
Key | Description
----------------------- | ------------------------------------------------
Alt+Arrows | Move the caret up/down/left/right between fields
Ctrl+Shift+Arrow Up/Down| Select multiple fields
Shift+Alt+Arrows | Move current field or selected fields up/down/left/right
Ctrl+D | Duplicate field
Ctrl+Del | Remove field
Ctrl+Enter | Open link when on a field containing an url
Ctrl+Ins | Insert a new field with type auto
Ctrl+Shift+Ins | Append a new field with type auto
Ctrl+E | Expand or collapse field
Alt+End | Move the caret to the last field
Ctrl+F | Find
F3, Ctrl+G | Find next
Shift+F3, Ctrl+Shift+G | Find previous
Alt+Home | Move the caret to the first field
Ctrl+M | Show actions menu
Ctrl+Z | Undo last action
Ctrl+Shift+Z | Redo
## Code Editor
The code editor is powered by [Ace Editor](http://ace.c9.io/). This editor's
shortcut keys are described here:
https://github.com/ajaxorg/ace/wiki/Default-Keyboard-Shortcuts
Additionally, there are shortcut keys to format/compact the code:
Key | Description
----------------------- | ------------------------------------------------
Ctrl+\ | Format JSON data, set proper indentation
Ctrl+Shift+\ | Compact JSON data, remove all whitespace
This page has been renamed to [Key Bindings](#key_bindings.md).

View File

@ -1,25 +0,0 @@
# Styling Reference
Documentation for writing custom JSON Editor styles.
## Node
Node is the fundamental unit that makes up the hierarchical JSON display in the Form, Tree, and View modes. It can be
customized with several classes that reflect its type and state.
- `jsoneditor-field`: the property name
- `jsoneditor-value`: the value of the property
- The value element will have one of the following classes depending on its type:
- `jsoneditor-null`
- `jsoneditor-undefined`
- `jsoneditor-number`
- `jsoneditor-string`
- `jsoneditor-string jsoneditor-color-value`
- `jsoneditor-boolean`
- `jsoneditor-regexp`
- `jsoneditor-array`
- `jsoneditor-object`
- `jsoneditor-url`
- `jsoneditor-is-default`: applied to the value element when the value matches the default from the schema
- `jsoneditor-is-not-default`: applied to the value element when the value does not match the default from the schema
- `jsoneditor-schema-error`: the warning icon that appears when the Node has a schema validation error
- `jsoneditor-popover`: the popover that appears when hovering over the schema validation error warning icon

View File

@ -2,23 +2,22 @@
### Install
Install via npm:
using npm:
npm install jsoneditor
## Load
To implement JSONEditor in a web application, load the javascript and css file
To implement JSONEditor in a web application, load the javascript file
in the head of the HTML page:
```html
<link href="jsoneditor/dist/jsoneditor.min.css" rel="stylesheet" type="text/css">
<script src="jsoneditor/dist/jsoneditor.min.js"></script>
```html\
<script src="jsoneditor/dist/jsoneditor.js"></script>
```
## Use
In the body, create a div element with an id and a size:
In the body, create an div element with an id and a size:
```html
<div id="jsoneditor" style="width: 400px; height: 400px;"></div>
@ -27,11 +26,11 @@ In the body, create a div element with an id and a size:
After the page is loaded, load the editor with javascript:
```js
var container = document.getElementById("jsoneditor");
var container = document.getElementById("jsoneditor")
var options = {
mode: 'tree'
};
var editor = new JSONEditor(container, options);
}
var editor = jsoneditor(container, options)
```
To set JSON data in the editor:
@ -44,14 +43,14 @@ var json = {
"Number": 123,
"Object": {"a": "b", "c": "d"},
"String": "Hello World"
};
editor.set(json);
}
editor.set(json)
```
To get JSON data from the editor:
```js
var json = editor.get();
var json = editor.get()
```
@ -59,25 +58,24 @@ var json = editor.get();
```html
<!DOCTYPE HTML>
<html lang="en">
<html>
<head>
<!-- when using the mode "code", it's important to specify charset utf-8 -->
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<link href="jsoneditor/dist/jsoneditor.min.css" rel="stylesheet" type="text/css">
<script src="jsoneditor/dist/jsoneditor.min.js"></script>
<script src="jsoneditor/dist/jsoneditor.js"></script>
</head>
<body>
<p>
<button onclick="setJSON();">Set JSON</button>
<button onclick="getJSON();">Get JSON</button>
<button onclick="setJSON()">Set JSON</button>
<button onclick="getJSON()">Get JSON</button>
</p>
<div id="jsoneditor" style="width: 400px; height: 400px;"></div>
<script>
// create the editor
var container = document.getElementById("jsoneditor");
var editor = new JSONEditor(container);
var container = document.getElementById('jsoneditor')
var editor = jsoneditor(container)
// set json
function setJSON () {
@ -88,14 +86,14 @@ var json = editor.get();
"Number": 123,
"Object": {"a": "b", "c": "d"},
"String": "Hello World"
};
editor.set(json);
}
editor.set(json)
}
// get json
function getJSON() {
var json = editor.get();
alert(JSON.stringify(json, null, 2));
var json = editor.get()
alert(JSON.stringify(json, null, 2))
}
</script>
</body>

View File

@ -1,11 +1,9 @@
<!DOCTYPE HTML>
<html lang="en">
<html>
<head>
<meta charset="utf-8">
<meta charset="UTF-8">
<title>Basic usage | JSONEditor</title>
<title>JSONEditor | Basic usage</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
@ -24,29 +22,26 @@
<script>
// create the editor
const container = document.getElementById('jsoneditor')
const options = {}
const editor = new JSONEditor(container, options)
var container = document.getElementById('jsoneditor')
var options = {}
var editor = jsoneditor(container, options)
// set json
document.getElementById('setJSON').onclick = function () {
const json = {
var json = {
'array': [1, 2, 3],
'boolean': true,
'color': '#82b92c',
'null': null,
'number': 123,
'object': {'a': 'b', 'c': 'd'},
'time': 1575599819000,
'string': 'Hello World',
'onlineDemo': 'https://jsoneditoronline.org/'
'string': 'Hello World'
}
editor.set(json)
}
// get json
document.getElementById('getJSON').onclick = function () {
const json = editor.get()
var json = editor.get()
alert(JSON.stringify(json, null, 2))
}
</script>

View File

@ -1,11 +1,9 @@
<!DOCTYPE HTML>
<html lang="en">
<html>
<head>
<meta charset="utf-8">
<meta charset="UTF-8">
<title>Viewer | JSONEditor</title>
<title>JSONEditor | Viewer</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
@ -20,18 +18,20 @@
</head>
<body>
<p>
This editor is read-only (mode='viewer').
This editor is read-only (mode='view').
</p>
<div id="jsoneditor"></div>
<script>
const container = document.getElementById('jsoneditor')
var container = document.getElementById('jsoneditor')
const options = {
var options = {
mode: 'view'
}
const json = {
var editor = jsoneditor(container, options)
var json = {
'array': [1, 2, 3],
'boolean': true,
'null': null,
@ -39,8 +39,8 @@
'object': {'a': 'b', 'c': 'd'},
'string': 'Hello World'
}
editor.set(json)
const editor = new JSONEditor(container, options, json)
</script>
</body>
</html>

View File

@ -1,12 +1,11 @@
<!DOCTYPE HTML>
<html lang="en">
<html>
<head>
<title>Switch mode | JSONEditor</title>
<!-- when using the mode "code", it's important to specify charset utf-8 -->
<meta charset="utf-8">
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<title>JSONEditor | Switch mode</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
@ -29,6 +28,7 @@
</head>
<body>
<h1>Switch mode</h1>
<p>
Switch editor mode using the mode box.
Note that the mode can be changed programmatically as well using the method
@ -38,20 +38,22 @@
<div id="jsoneditor"></div>
<script>
const container = document.getElementById('jsoneditor')
var container = document.getElementById('jsoneditor')
const options = {
var options = {
mode: 'tree',
modes: ['code', 'form', 'text', 'tree', 'view', 'preview'], // allowed modes
modes: ['text', 'code', 'tree', 'form', 'view'], // allowed modes
onError: function (err) {
alert(err.toString())
},
onModeChange: function (newMode, oldMode) {
console.log('Mode switched from', oldMode, 'to', newMode)
onChangeMode: function (mode, prevMode) {
console.log('Mode switched from', prevMode, 'to', mode)
}
}
const json = {
var editor = jsoneditor(container, options)
var json = {
"array": [1, 2, 3],
"boolean": true,
"null": null,
@ -60,7 +62,7 @@
"string": "Hello World"
}
const editor = new JSONEditor(container, options, json)
editor.set(json)
</script>
</body>
</html>

View File

@ -1,11 +1,9 @@
<!DOCTYPE HTML>
<html lang="en">
<html>
<head>
<meta charset="utf-8">
<meta charset="UTF-8">
<title>Load and save | JSONEditor</title>
<title>JSONEditor | Load and save</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<script src="https://bgrins.github.io/filereader.js/filereader.js"></script>
@ -40,7 +38,7 @@
<script>
// create the editor
const editor = new JSONEditor(document.getElementById('jsoneditor'))
var editor = jsoneditor(document.getElementById('jsoneditor'))
// Load a JSON document
FileReaderJS.setupInput(document.getElementById('loadDocument'), {
@ -55,19 +53,19 @@
// Save a JSON document
document.getElementById('saveDocument').onclick = function () {
// Save Dialog
let fname = window.prompt("Save as...")
fname = window.prompt('Save as...')
// Check json extension in file name
if (fname.indexOf(".") === -1) {
fname = fname + ".json"
if (fname.indexOf('.') == -1) {
fname = fname + '.json'
} else {
if (fname.split('.').pop().toLowerCase() === "json") {
if (fname.split('.').pop().toLowerCase() == 'json'){
// Nothing to do
} else {
fname = fname.split('.')[0] + ".json"
fname = fname.split('.')[0] + '.json'
}
}
const blob = new Blob([editor.getText()], {type: 'application/json;charset=utf-8'})
}
var blob = new Blob([editor.getText()], {type: 'application/json;charset=utf-8'})
saveAs(blob, fname)
}
</script>

View File

@ -1,65 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSONEditor | Custom editable fields</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
#jsoneditor {
width: 500px;
}
</style>
</head>
<body>
<p>
In this example:
</p>
<ul>
<li>the field <code>_id</code> and its value are read-only</li>
<li>the field <code>name</code> is read-only but has an editable value</li>
<li>the field <code>age</code> and its value are editable</li>
</ul>
<div id="jsoneditor"></div>
<script>
const container = document.getElementById('jsoneditor')
const options = {
onEditable: function (node) {
// node is an object like:
// {
// field: 'FIELD',
// value: 'VALUE',
// path: ['PATH', 'TO', 'NODE']
// }
switch (node.field) {
case '_id':
return false
case 'name':
return {
field: false,
value: true
}
default:
return true
}
}
}
const json = {
_id: 123456,
name: 'John',
age: 32
}
const editor = new JSONEditor(container, options, json)
</script>
</body>
</html>

View File

@ -0,0 +1,61 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Read-only properties and values | JSONEditor</title>
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
#jsoneditor {
width: 300px;
}
</style>
</head>
<body>
<h1>Read-only properties and values</h1>
<p>
In this example:
</p>
<ul>
<li>the field <code>_id</code> and its value are read-only</li>
<li>the field <code>name</code> is read-only but has an editable value</li>
<li>the field <code>age</code> and its value are editable</li>
</ul>
<div id="jsoneditor"></div>
<script>
var container = document.getElementById('jsoneditor');
var options = {
// all properties are editable except '_id' and 'name'
isPropertyEditable: function (path) {
if (path.length === 1 && path[0] === '_id' || path[0] === 'name') {
return false
}
return true
},
// all values are editable except '_id'
isValueEditable: function (path) {
if (path.length === 1 && path[0] === '_id') {
return false
}
return true
}
}
var json = {
_id: 123456,
name: 'John',
age: 32
}
var editor = jsoneditor(container, options)
editor.set(json)
</script>
</body>
</html>

View File

@ -1,45 +1,46 @@
<!DOCTYPE HTML>
<html lang="en">
<html>
<head>
<meta charset="utf-8">
<meta charset="UTF-8">
<title>Custom styling | JSONEditor</title>
<title>JSONEditor | Custom styling</title>
<script src="../dist/jsoneditor.js"></script>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
#jsoneditor {
width: 500px;
height: 500px;
}
<style type="text/css">
#jsoneditor {
width: 500px;
height: 500px;
}
p {
width: 500px;
font-family: "DejaVu Sans", sans-serif;
}
</style>
p {
width: 500px;
font-family: "DejaVu Sans", sans-serif;
}
</style>
<link href="./css/darktheme.css" rel="stylesheet" type="text/css">
<link href="./css/darktheme.css" rel="stylesheet" type="text/css">
</head>
<body>
<h1>Custom styling</h1>
<p>
This example demonstrates how to customize the look of JSONEditor,
the editor below has a dark theme. Note that the example isn't worked
out for the mode <code>code</code>. To do that, you can load and configure
a custom theme for the Ace editor.
This example demonstrates how to customize the look of JSONEditor,
the editor below has a dark theme. Note that the example isn't worked
out for the mode <code>code</code>. To do that, you can load and configure
a custom theme for the Ace editor.
</p>
<div id="jsoneditor"></div>
<script>
// create the editor
const container = document.getElementById('jsoneditor')
const options = {
modes: ['tree', 'text']
}
const json = {
var editor = jsoneditor(document.getElementById('jsoneditor'), {
modes: ['text', 'tree']
})
// load json
var json = {
'array': [1, 2, 3],
'boolean': true,
'null': null,
@ -47,7 +48,7 @@
'object': {'a': 'b', 'c': 'd'},
'string': 'Hello World'
}
const editor = new JSONEditor(container, options, json)
editor.set(json)
</script>
</body>
</html>

View File

@ -1,11 +1,9 @@
<!DOCTYPE HTML>
<html lang="en">
<html>
<head>
<meta charset="utf-8">
<meta charset="UTF-8">
<title>JSON schema validation | JSONEditor</title>
<title>JSONEditor | JSON schema validation</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
@ -18,16 +16,12 @@
height: 500px;
}
/* custom bold styling for non-default JSON schema values */
.jsoneditor-is-not-default {
font-weight: bold;
}
</style>
</head>
<body>
<h1>JSON schema validation</h1>
<p>
This example demonstrates JSON schema validation. The JSON object in this example must contain properties like <code>firstName</code> and <code>lastName</code>, can can optionally have a property <code>age</code> which must be a positive integer.
This example demonstrates JSON schema validation. The JSON object in this example must contain properties <code>firstName</code> and <code>lastName</code>, can can optionally have a property <code>age</code> which must be a positive integer.
</p>
<p>
See <a href="http://json-schema.org/" target="_blank">http://json-schema.org/</a> for more information.
@ -36,103 +30,44 @@
<div id="jsoneditor"></div>
<script>
const schema = {
"title": "Employee",
"description": "Object containing employee details",
var schema = {
"title": "Example Schema",
"type": "object",
"properties": {
"firstName": {
"title": "First Name",
"description": "The given name.",
"examples": [
"John"
],
"type": "string"
},
"lastName": {
"title": "Last Name",
"description": "The family name.",
"examples": [
"Smith"
],
"type": "string"
},
"gender": {
"title": "Gender",
"enum": ["male", "female"]
},
"availableToHire": {
"type": "boolean",
"default": false
},
"age": {
"description": "Age in years",
"type": "integer",
"minimum": 0,
"examples": [28, 32]
},
"job": {
"$ref": "job"
"minimum": 0
}
},
"required": ["firstName", "lastName"]
}
const job = {
"title": "Job description",
"type": "object",
"required": ["address"],
"properties": {
"company": {
"type": "string",
"examples": [
"ACME",
"Dexter Industries"
]
},
"role": {
"description": "Job title.",
"type": "string",
"examples": [
"Human Resources Coordinator",
"Software Developer"
],
"default": "Software Developer"
},
"address": {
"type": "string"
},
"salary": {
"type": "number",
"minimum": 120,
"examples": [100, 110, 120]
}
}
}
const json = {
var json = {
firstName: 'John',
lastName: 'Doe',
gender: null,
age: "28",
availableToHire: true,
job: {
company: 'freelance',
role: 'developer',
salary: 100
}
age: 28
}
const options = {
schema: schema,
schemaRefs: {"job": job},
mode: 'tree',
modes: ['code', 'text', 'tree', 'preview']
var options = {
modes: ['code', 'tree']
}
// create the editor
const container = document.getElementById('jsoneditor')
const editor = new JSONEditor(container, options, json)
var container = document.getElementById('jsoneditor')
var editor = jsoneditor(container, options)
editor.setSchema(schema)
editor.set(json)
</script>
</body>
</html>

View File

@ -1,66 +1,55 @@
<!DOCTYPE HTML>
<html lang="en">
<html>
<head>
<meta charset="utf-8">
<meta charset="UTF-8">
<title>Custom Ace Editor | JSONEditor</title>
<title>JSONEditor | Custom Ace</title>
<!-- load a custom version of Ace editor -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.6/ace.js"></script>
<!-- load the minimalist version of JSONEditor, which doesn't have Ace embedded -->
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<!-- we use the minimalist jsoneditor, which doesn't have Ace Editor included -->
<script src="../dist/jsoneditor-minimalist.js"></script>
<!-- load your own instance of Ace Editor and all plugins that you need -->
<!-- jsoneditor requires ext-searchbox and mode-json -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.5/ace.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.5/ext-searchbox.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.5/mode-json.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/ace/1.2.5/theme-twilight.js"></script>
<style type="text/css">
#jsoneditor {
width: 500px;
height: 500px;
}
body, html {
font-family: "DejaVu Sans", sans-serif;
}
p, li {
width: 500px;
font-size: 10.5pt;
}
code {
background: #f5f5f5;
}
</style>
</head>
<body>
<h1>Custom Ace editor</h1>
<h1>Custom Ace Editor</h1>
<p>
This example demonstrates how to load a custom version of Ace editor into JSONEditor.
</p>
<p>
By default, JSONEditor <code>code</code> mode loads the following Ace plugins:
</p>
<ul>
<li>ace/mode/json</li>
<li>ace/ext/searchbox</li>
<li>ace/theme/jsoneditor</li>
</ul>
<p>
The jsoneditor theme comes embedded with JSONEditor. The other two plugins (json and searchbox) must be available in the folder of the custom Ace editor, or already be loaded via a script tag.
In this example, the we use the minimalist version of jsoneditor and load
and configure Ace editor our selves: we set a different theme and font size.
</p>
<div id="jsoneditor"></div>
<script>
// create the editor
const container = document.getElementById('jsoneditor')
const options = {
modes: ['text', 'code', 'tree', 'form', 'view'],
// create the editor, set mode to 'code' (powered by ace editor)
var container = document.getElementById('jsoneditor')
var options = {
mode: 'code',
ace: ace
onLoadAce: function (aceEditor, container) {
// we can adjust configuration of the ace editor,
// or create a completely new instance of ace editor.
// let's set a custom theme and font size
aceEditor.setTheme('ace/theme/twilight')
aceEditor.setFontSize(16)
return aceEditor
}
}
const json = {
var editor = jsoneditor(container, options)
var json = {
'array': [1, 2, 3],
'boolean': true,
'null': null,
@ -68,7 +57,7 @@
'object': {'a': 'b', 'c': 'd'},
'string': 'Hello World'
}
const editor = new JSONEditor(container, options, json)
editor.set(json)
</script>
</body>
</html>

View File

@ -1,73 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<!-- when using the mode "code", it's important to specify charset utf-8 -->
<meta charset="utf-8">
<title>JSONEditor | Switch mode</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
body {
font: 10.5pt arial;
color: #4d4d4d;
line-height: 150%;
width: 500px;
}
code {
background-color: #f5f5f5;
}
#jsoneditor {
width: 500px;
height: 500px;
}
</style>
</head>
<body>
<p>
Switch editor mode using the mode box.
Note that the mode can be changed programmatically as well using the method
<code>editor.setMode(mode)</code>, try it in the console of your browser.
</p>
<div id="jsoneditor"></div>
<script>
const container = document.getElementById('jsoneditor')
const options = {
mode: 'text',
modes: ['text', 'code'],
onEditable: function (node) {
if (!node.path) {
// In modes code and text, node is empty: no path, field, or value
// returning false makes the text area read-only
return false;
}
},
onError: function (err) {
alert(err.toString())
},
onModeChange: function (newMode, oldMode) {
console.log('Mode switched from', oldMode, 'to', newMode)
}
}
const json = {
"array": [1, 2, 3],
"boolean": true,
"null": null,
"number": 123,
"object": {"a": "b", "c": "d"},
"string": "Hello World"
}
const editor = new JSONEditor(container, options, json)
</script>
</body>
</html>

View File

@ -0,0 +1,64 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Synchronize two editors | JSONEditor</title>
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
body {
font-family: arial, sans-serif;
}
#jsoneditor1,
#jsoneditor2 {
display: inline-block;
width: 350px;
height: 500px;
margin-right: 24px;
}
code {
background: #e5e5e5;
}
</style>
</head>
<body>
<h1>Synchronize two editors</h1>
<p>
This example demonstrates how to keep two editors synchronized by listening for
the <code>onPatch</code> event. Other related events are <code>onChange</code> and <code>onChangeText</code>.
</p>
<div id="jsoneditor1"></div>
<div id="jsoneditor2"></div>
<script>
var json = {
'array': [1, 2, 3],
'boolean': true,
'null': null,
'number': 123,
'object': {'a': 'b', 'c': 'd'},
'string': 'Hello World'
}
var editor1 = jsoneditor(document.getElementById('jsoneditor1'), {
onPatch: function (patch, revert) {
editor2.patch(patch)
}
})
editor1.set(json)
var editor2 = jsoneditor(document.getElementById('jsoneditor2'), {
onPatch: function (patch, revert) {
editor1.patch(patch)
}
})
editor2.set(json)
</script>
</body>
</html>

View File

@ -0,0 +1,56 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="UTF-8">
<title>Custom key bindings | JSONEditor</title>
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
body {
width: 100%;
max-width: 500px;
margin: 0;
padding: 10px;
box-sizing: border-box;
font-family: sans-serif;
}
h1 {
font-size: 120%;
}
</style>
</head>
<body>
<h1>Custom key bindings</h1>
<p>
In this example, the key bindings for <code>format</code> and <code>compact</code> are changed to respectively <code>Ctrl+Alt+1</code> and <code>Ctrl+Alt+2</code> instead of the default <code>Ctrl+\</code> and <code>Ctrl+Shift+\</code>.
</p>
<p>
It's important to define key bindings for both Windows and Mac: <code>Command+Option+1</code> and <code>Command+Option+2</code> in this case.
</p>
<div id="jsoneditor"></div>
<script>
// create the editor
var container = document.getElementById('jsoneditor')
var options = {
modes: ['code', 'text'],
keyBindings: {
compact: ['Ctrl+Alt+1', 'Command+Option+1'],
format: ['Ctrl+Alt+2', 'Command+Option+2']
}
}
var json = {
'array': [1, 2, 3],
'boolean': true,
'null': null,
'number': 123,
'object': {'a': 'b', 'c': 'd'},
'string': 'Hello World'
}
var editor = jsoneditor(container, options)
editor.set(json)
</script>
</body>
</html>

View File

@ -1,73 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSONEditor | Item templates</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
body {
width: 600px;
font: 11pt sans-serif;
}
#jsoneditor {
width: 100%;
height: 500px;
}
</style>
</head>
<body>
<h1>Item templates</h1>
<p>
Using item templates, the options in the context menu under "insert" and "append" can be extended with extra options, containing a domain specific template like a "Person", "Contact", "Order", "Address", etc.
</p>
<div id="jsoneditor"></div>
<script>
const json = [
{
firstName: 'John',
lastName: 'Doe',
age: 28
}
]
const options = {
templates: [
{
text: 'Person',
title: 'Insert a Person Node',
className: 'jsoneditor-type-object',
field: 'PersonTemplate',
value: {
'firstName': 'John',
'lastName': 'Do',
'age': 28
}
},
{
text: 'Address',
title: 'Insert a Address Node',
field: 'AddressTemplate',
value: {
'street': '',
'city': '',
'state': '',
'ZIP code': ''
}
}
]
}
// create the editor
const container = document.getElementById('jsoneditor')
const editor = new JSONEditor(container, options, json)
editor.expandAll()
</script>
</body>
</html>

View File

@ -1,52 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSONEditor | Auto Complete</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
#jsoneditor {
width: 500px;
height: 500px;
}
p {
width: 500px;
font-family: "DejaVu Sans", sans-serif;
}
</style>
</head>
<body>
<p>
This example demonstrates how to autocomplete works, options available are: 'apple','cranberry','raspberry','pie', 'mango', 'mandarine', 'melon', 'appleton'.
</p>
<div id="jsoneditor"></div>
<script>
// create the editor
const container = document.getElementById('jsoneditor')
const options = {
autocomplete: {
getOptions: function () {
return ['apple', 'cranberry', 'raspberry', 'pie', 'mango', 'mandarine', 'melon', 'appleton'];
}
}
}
const json = {
'array': [{'field1':'v1', 'field2':'v2'}, 2, 3],
'boolean': true,
'null': null,
'number': 123,
'object': {'a': 'b', 'c': 'd'},
'string': 'Hello World'
}
const editor = new JSONEditor(container, options, json)
</script>
</body>
</html>

View File

@ -1,73 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSONEditor | Dynamic Auto Complete</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
<style type="text/css">
#jsoneditor {
width: 500px;
height: 500px;
}
p {
width: 500px;
font-family: "DejaVu Sans", sans-serif;
}
</style>
</head>
<body>
<p>
This example demonstrates how to autocomplete works, options available are dynamics and consist in all the strings found in the json
</p>
<div id="jsoneditor"></div>
<script>
// create the editor
const container = document.getElementById('jsoneditor')
const options = {
autocomplete: {
applyTo:['value'],
filter: 'contain',
trigger: 'focus',
getOptions: function (text, path, input, editor) {
return new Promise(function (resolve, reject) {
const options = extractUniqueWords(editor.get())
if (options.length > 0) {
resolve(options)
} else {
reject()
}
})
}
}
}
// helper function to extract all unique words in the keys and values of a JSON object
function extractUniqueWords (json) {
return _.uniq(_.flatMapDeep(json, function (value, key) {
return _.isObject(value)
? [key]
: [key, String(value)]
}))
}
const json = {
'array': [{'field1':'v1', 'field2':'v2'}, 2, 3],
'boolean': true,
'null': null,
'number': 123,
'object': {'a': 'b', 'c': 'd'},
'string': 'Hello World'
}
const editor = new JSONEditor(container, options, json)
</script>
</body>
</html>

View File

@ -1,109 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSONEditor | Advanced Auto Complete</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<script src="https://unpkg.com/jsonpath@0.2.11/jsonpath.min.js"></script>
<style type="text/css">
#jsoneditor {
width: 500px;
height: 500px;
}
p {
width: 500px;
font-family: "DejaVu Sans", sans-serif;
}
</style>
</head>
<body>
<p>
This example demonstrates how to autocomplete works with an ActivationChar option, press "*" in any value and continue with autocompletion.
The autocomplete returns the posible jsonpaths of the existing json document, for example <code>*object.a</code>.
</p>
<div id="jsoneditor"></div>
<script>
// create the editor
const container = document.getElementById('jsoneditor')
const activationChar = '*'
const options = {
autocomplete: {
confirmKeys: [39, 35, 9, 190], // Confirm Autocomplete Keys: [right, end, tab, '.'] // By default are only [right, end, tab]
caseSensitive: false,
getOptions: function (text, path, input, editor) {
if (!text.startsWith(activationChar) || input !== 'value') return []
let data = {}
let startFrom = 0
const lastPoint = text.lastIndexOf('.')
const jsonObj = editor.get()
if ((lastPoint > 0) && (text.length > 1)) {
data = jsonpath.query(jsonObj, '$.' + text.substring(activationChar.length, lastPoint))
if (data.length > 0) {
data = data[0]
} else {
data = {}
}
// Indicate that autocompletion should start after the . (ignoring the first part)
startFrom = text.lastIndexOf('.') + 1
} else {
data = jsonObj
}
const optionsStr = YaskON.stringify(data, null, activationChar)
const options = optionsStr.split('\n')
return { startFrom: startFrom, options: options }
}
}
}
// helper function to auto complete paths of a JSON object
const YaskON = {
// Return first level json paths by the node 'o'
stringify: function (o, prefix, activationChar) {
prefix = prefix || ''
switch (typeof o) {
case 'object':
let output = ''
if (Array.isArray(o)) {
o.forEach(function (e, index) {
output += activationChar + prefix + '[' + index + ']' + '\n'
}.bind(this))
return output
}
output = ''
for (let k in o) {
if (o.hasOwnProperty(k)) {
if (prefix === '') output += this.stringify(o[k], k, activationChar)
}
}
if (prefix !== '') output += activationChar + prefix + '\n'
return output
case 'function':
return ''
default:
return prefix + '\n'
}
}
}
const json = {
'array': [{ 'field1': 'v1', 'field2': 'v2' }, 2, 3],
'boolean': true,
'null': null,
'number': 123,
'object': { 'a': 'b', 'c': 'd' },
'string': 'Hello World'
}
const editor = new JSONEditor(container, options, json)
</script>
</body>
</html>

View File

@ -1,57 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSONEditor | Translate</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
#jsoneditor {
width: 500px;
height: 500px;
}
</style>
</head>
<body>
<p>
JSONEditor has support for multiple languages (i18n), in this case uses <code>pt-BR</code>.
</p>
<div id="jsoneditor"></div>
<script>
// create the editor
const container = document.getElementById('jsoneditor')
const options = {
// switch between pt-BR or en for testing forcing a language
// leave blank to get language
'language': 'pt-BR',
'languages': {
'pt-BR': {
'auto': 'Automático testing'
},
'en': {
'auto': 'Auto testing'
},
'newlang': {
'auto': 'Auto new lang'
}
}
}
const editor = new JSONEditor(container, options)
const json = {
'array': [1, 2, 3],
'boolean': true,
'null': null,
'number': 123,
'object': { 'a': 'b', 'c': 'd' },
'string': 'Hello World'
}
editor.set(json)
</script>
</body>
</html>

View File

@ -1,124 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
body {
font: 10.5pt arial;
color: #4d4d4d;
line-height: 150%;
width: 500px;
padding-left: 40px;
}
code {
background-color: #f5f5f5;
}
code.multiline {
display: block;
white-space: pre-wrap
}
#jsoneditor {
width: 500px;
height: 500px;
}
</style>
</head>
<body>
<p>
Selection indication was done using the <code>on[Text]SelectionChange</code> listeners.<br/>
you can try the following calls in the console of your browser:<br/>
<code class="multiline">
// text and code modes:
editor.getTextSelection()
editor.setTextSelection(startPos, endPos)
// tree mode:
editor.getSelection()
editor.setSelection(startNode, endNode)
</code>
</p>
<form>
<div id="jsoneditor"></div>
<div id="textModeSelection" style="display:none;">
<b>Selection:</b><div id="textRange"></div>
<b>Text:</b><div id="selectedText"></div>
</div>
<div id="treeModeSelection">
<b>Selection:</b>
<div id="selectedNodes"></div>
</div>
</form>
<script>
const container = document.getElementById('jsoneditor')
const options = {
mode: 'tree',
modes: ['code', 'form', 'text', 'tree', 'view', 'preview'], // allowed modes
onError: function (err) {
alert(err.toString())
},
onChange: function () {
console.log('change')
},
onModeChange: function (mode) {
const treeMode = document.getElementById('treeModeSelection')
const textMode = document.getElementById('textModeSelection')
treeMode.style.display = textMode.style.display = 'none'
if (mode === 'code' || mode === 'text') {
textMode.style.display = 'inline'
} else {
treeMode.style.display = 'inline'
}
},
indentation: 4,
escapeUnicode: true,
onTextSelectionChange: function(start, end, text) {
const rangeEl = document.getElementById('textRange')
rangeEl.innerHTML = 'start: ' + JSON.stringify(start) + ', end: ' + JSON.stringify(end)
const textEl = document.getElementById('selectedText')
textEl.innerHTML = text
},
onSelectionChange: function(start, end) {
const nodesEl = document.getElementById('selectedNodes')
nodesEl.innerHTML = ''
if (start) {
nodesEl.innerHTML = ('start: ' + JSON.stringify(start))
if (end) {
nodesEl.innerHTML += ('<br/>end: ' + JSON.stringify(end))
}
}
}
}
const json = {
"array": [1, 2, [3,4,5]],
"boolean": true,
"htmlcode": '&quot;',
"escaped_unicode": '\\u20b9',
"unicode": '\u20b9,\uD83D\uDCA9',
"return": '\n',
"null": null,
"number": 123,
"object": {"a": "b", "c": "d"},
"string": "Hello World",
"url": "http://jsoneditoronline.org"
}
window.editor = new JSONEditor(container, options, json)
console.log('json', json)
console.log('string', JSON.stringify(json))
</script>
</body>
</html>

View File

@ -1,66 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSONEditor | Synchronize two editors</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
body {
font-family: sans-serif;
}
#jsoneditor1,
#jsoneditor2 {
width: 500px;
height: 500px;
margin-right: 10px;
display: inline-block;
}
</style>
</head>
<body>
<p>
Keep two editors synchronized using <code>onChangeText</code> and <code>updateText</code>.
</p>
<p>
This can be done too with <code>onChangeJSON</code> and <code>update</code>, which can only be used in
modes <code>tree</code>, <code>form</code> (and <code>view</code>).
</p>
<div id="jsoneditor1"></div>
<div id="jsoneditor2"></div>
<script>
// create editor 1
const editor1 = new JSONEditor(document.getElementById('jsoneditor1'), {
onChangeText: function (jsonString) {
editor2.updateText(jsonString)
}
})
// create editor 2
const editor2 = new JSONEditor(document.getElementById('jsoneditor2'), {
onChangeText: function (jsonString) {
editor1.updateText(jsonString)
}
})
// set initial data in both editors
const json = {
'array': [1, 2, 3],
'boolean': true,
'null': null,
'number': 123,
'object': {'a': 'b', 'c': 'd'},
'string': 'Hello World'
}
editor1.set(json)
editor2.set(json)
</script>
</body>
</html>

View File

@ -1,96 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
body {
font: 10.5pt arial;
color: #4d4d4d;
line-height: 150%;
width: 500px;
padding-left: 40px;
}
code {
background-color: #f5f5f5;
}
#jsoneditor {
width: 500px;
height: 500px;
}
</style>
</head>
<body>
<p>
When clicking on a JSON field or value, a log message will be shown in
console.
</p>
<form>
<div id="jsoneditor"></div>
</form>
<script>
const container = document.getElementById('jsoneditor')
const options = {
mode: 'tree',
modes: ['code', 'form', 'text', 'tree', 'view', 'preview'], // allowed modes
name: "jsonContent",
onError: function (err) {
alert(err.toString())
},
onEvent: function(node, event) {
if (event.type === 'click') {
let message = 'click on <' + node.field +
'> under path <' + node.path +
'> with pretty path: <' + prettyPrintPath(node.path) + '>'
if (node.value) {
message += ' with value <' + node.value + '>'
}
console.log(message)
}
function prettyPrintPath(path) {
let str = ''
for (let i=0; i<path.length; i++) {
const element = path[i]
if (typeof element === 'number') {
str += '[' + element + ']'
} else {
if (str.length > 0) str += ','
str += element
}
}
return str
}
}
}
const json = {
"array": [1, 2, [3,4,5]],
"boolean": true,
"htmlcode": '&quot;',
"escaped_unicode": '\\u20b9',
"unicode": '\u20b9,\uD83D\uDCA9',
"return": '\n',
"null": null,
"number": 123,
"object": {"a": "b", "c": "d", "e": [1, 2, 3]},
"string": "Hello World",
"url": "http://jsoneditoronline.org",
"[0]": "zero"
}
window.editor = new JSONEditor(container, options, json)
console.log('json', json)
console.log('string', JSON.stringify(json))
</script>
</body>
</html>

View File

@ -1,109 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSONEditor | Custom validation</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
body {
width: 600px;
font: 11pt sans-serif;
}
#jsoneditor {
width: 100%;
height: 500px;
}
</style>
</head>
<body>
<h1>Custom validation</h1>
<p>
This example demonstrates how to run custom validation on a JSON object.
The validation is available in all modes.
</p>
<div id="jsoneditor"></div>
<script>
const json = {
team: [
{
name: 'Joe',
age: 17
},
{
name: 'Sarah',
age: 13
},
{
name: 'Jack'
}
]
}
const options = {
mode: 'tree',
modes: ['code', 'text', 'tree', 'preview'],
onValidate: function (json) {
// rules:
// - team, names, and ages must be filled in and be of correct type
// - a team must have 4 members
// - at lease one member of the team must be adult
const errors = []
if (json && Array.isArray(json.team)) {
// check whether each team member has name and age filled in correctly
json.team.forEach(function (member, index) {
if (typeof member !== 'object') {
errors.push({path: ['team', index], message: 'Member must be an object with properties "name" and "age"'})
}
if ('name' in member) {
if (typeof member.name !== 'string') {
errors.push({path: ['team', index, 'name'], message: 'Name must be a string'})
}
} else {
errors.push({path: ['team', index], message: 'Required property "name"" missing'})
}
if ('age' in member) {
if (typeof member.age !== 'number') {
errors.push({path: ['team', index, 'age'], message: 'Age must be a number'})
}
} else {
errors.push({path: ['team', index], message: 'Required property "age" missing'})
}
})
// check whether the team consists of exactly four members
if (json.team.length !== 4) {
errors.push({path: ['team'], message: 'A team must have 4 members'})
}
// check whether there is at least one adult member in the team
const adults = json.team.filter(function (member) {
return member ? member.age >= 18 : false
})
if (adults.length === 0) {
errors.push({path: ['team'], message: 'A team must have at least one adult person (age >= 18)'})
}
} else {
errors.push({path: [], message: 'Required property "team" missing or not an Array'})
}
return errors
}
}
// create the editor
const container = document.getElementById('jsoneditor')
const editor = new JSONEditor(container, options, json)
editor.expandAll()
</script>
</body>
</html>

View File

@ -1,92 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSONEditor | Custom validation (asynchronous)</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
body {
width: 600px;
font: 11pt sans-serif;
}
#jsoneditor {
width: 100%;
height: 500px;
}
</style>
</head>
<body>
<h1>Asynchronous custom validation</h1>
<p>
This example demonstrates how to run asynchronous custom validation on a JSON object.
The names are checked asynchronously and the results "come in" half a second later.
Known names in this example are 'Joe', 'Harry', 'Megan'. For other names, a validation error will be displayed.
</p>
<div id="jsoneditor"></div>
<script>
const json = {
customers: [
{name: 'Joe'},
{name: 'Sarah'},
{name: 'Harry'},
]
}
const options = {
mode: '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
if (json && Array.isArray(json.customers)) {
return Promise
.all(json.customers.map(function (customer, index) {
return isExistingCustomer(customer && customer.name).then(function (exists) {
if (!exists) {
return {
path: ['customers', index],
message: 'Customer ' + customer.name + ' doesn\'t exist in our database'
}
}
else {
return null
}
})
}))
.then(function (errors) {
return errors.filter(function (error) {
return error != null
})
})
}
else {
return null
}
}
}
// create the editor
const container = document.getElementById('jsoneditor')
const editor = new JSONEditor(container, options, json)
editor.expandAll()
// this function fakes a request (asynchronous) to a server to validate the existence of a customer
function isExistingCustomer (customerName) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
const customers = ['Joe', 'Harry', 'Megan']
const exists = customers.indexOf(customerName) !== -1
resolve(exists)
}, 500)
})
}
</script>
</body>
</html>

View File

@ -1,160 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
body {
font: 10.5pt arial;
color: #4d4d4d;
line-height: 150%;
width: 100%;
padding-left: 10px;
}
code {
background-color: #f5f5f5;
}
#containerLeft {
display: inline-block;
width: 500px;
height: 500px;
margin-right: 10px;
}
#containerRight {
display: inline-block;
width: 500px;
height: 500px;
}
#containerRight .different_element {
background-color: #acee61;
}
#containerRight .different_element div.jsoneditor-field,
#containerRight .different_element div.jsoneditor-value {
color: red;
}
#containerLeft .different_element {
background-color: pink;
}
#containerLeft .different_element div.jsoneditor-field,
#containerLeft .different_element div.jsoneditor-value {
color: red;
}
</style>
</head>
<body>
<h3>JSON Diff</h3>
<p>
This example highlights the differences between two JSON objects using the option <code>onClassName</code>.
Make a change in the left or right editor to see the changes update accordingly.
</p>
<div id="wrapper">
<div id="containerLeft"></div>
<div id="containerRight"></div>
</div>
<script>
const containerLeft = document.getElementById('containerLeft')
const containerRight = document.getElementById('containerRight')
function findNodeInJson(json, path){
if(!json || path.length ===0) {
return {field: undefined, value: undefined}
}
const first = path[0]
const remainingPath = path.slice(1)
if(remainingPath.length === 0) {
return {field: (typeof json[first] !== 'undefined' ? first : undefined), value: json[first]}
} else {
return findNodeInJson(json[first], remainingPath)
}
}
function onClassName({ path, field, value }) {
const thisNode = findNodeInJson(jsonRight, path)
const oppositeNode = findNodeInJson(jsonLeft, path)
let isValueEqual = JSON.stringify(thisNode.value) === JSON.stringify(oppositeNode.value)
if(Array.isArray(thisNode.value) && Array.isArray(oppositeNode.value)) {
isValueEqual = thisNode.value.every(function (e) {
return oppositeNode.value.includes(e)
})
}
if (thisNode.field === oppositeNode.field && isValueEqual) {
return 'the_same_element'
} else {
return 'different_element'
}
}
const optionsLeft = {
mode: 'tree',
onError: function (err) {
alert(err.toString())
},
onClassName: onClassName,
onChangeJSON: function (j) {
jsonLeft = j
window.editorRight.refresh()
}
}
const optionsRight = {
mode: 'tree',
onError: function (err) {
alert(err.toString())
},
onClassName: onClassName,
onChangeJSON: function (j) {
jsonRight = j
window.editorLeft.refresh()
}
}
let jsonLeft = {
"arrayOfArrays": [1, 2, 999, [3,4,5]],
"someField": true,
"boolean": true,
"htmlcode": '&quot;',
"escaped_unicode": '\\u20b9',
"unicode": '\u20b9,\uD83D\uDCA9',
"return": '\n',
"null": null,
"thisObjectDoesntExistOnTheRight" : {key: "value"},
"number": 123,
"object": {"a": "b","new":4, "c": "d", "e": [1, 2, 3]},
"string": "Hello World",
"url": "http://jsoneditoronline.org",
"[0]": "zero"
}
let jsonRight = {
"arrayOfArrays": [1, 2, [3,4,5]],
"boolean": true,
"htmlcode": '&quot;',
"escaped_unicode": '\\u20b9',
"thisFieldDoesntExistOnTheLeft": 'foobar',
"unicode": '\u20b9,\uD83D\uDCA9',
"return": '\n',
"null": null,
"number": 123,
"object": {"a": "b", "c": "d", "e": [1, 2, 3]},
"string": "Hello World",
"url": "http://jsoneditoronline.org",
"[0]": "zero"
}
window.editorLeft = new JSONEditor(containerLeft, optionsLeft, jsonLeft)
window.editorRight = new JSONEditor(containerRight, optionsRight, jsonRight)
</script>
</body>
</html>

View File

@ -1,148 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSONEditor | Basic usage</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
#jsoneditor {
width: 500px;
height: 500px;
}
.submenu-highlight {
background-color: yellow !important;
}
.rainbow {
background: linear-gradient(to right, cyan, yellow, violet, green, orange, blue) !important;
}
.example-class > .jsoneditor-icon {
background-position: -168px -48px; /* warning triangle */
}
.dotty {
border-top : 1px dotted #e5e5e5 !important;
}
</style>
</head>
<body>
<h1>Context Menu Customization</h1>
<p>
This example demonstrates the use of the onCreateMenu callback option, which
allows you to customise context menus after they are created but before they
are shown to the user. You can alter/delete existing items as well as
adding new menu items. See the source code for this example for more
information.
</p>
<div id="jsoneditor"></div>
<script>
// create the editor
const container = document.getElementById('jsoneditor')
const options = {
// onCreateMenu allows us to register a call back function to customise
// the context menu. The callback accpets two parameters, items and path.
// Items is an array containing the current menu items, and path
// (if present) contains the path of the current node (as an array).
// The callback should return the modified (or unmodified) list of menu
// items.
// Every time the user clicks on a context menu button, the menu
// is created from scratch and this callback is called.
onCreateMenu: function (items, node) {
const path = node.path
// log the current items and node for inspection
console.log('items:', items, 'node:', node)
// We are going to add a menu item which returns the current node path
// as a jq path selector ( https://stedolan.github.io/jq/ ). First we
// will create a function, and then We will connect this function to
// the menu item click property in a moment.
function pathTojq() {
let pathString = ''
path.forEach(function (segment, index) { // path is an array, loop through it
if (typeof segment == 'number') { // format the selector for array indexs ...
pathString += '[' + segment + ']'
} else { // ... or object keys
pathString += '."' + segment + '"'
}
})
alert(pathString) // show it to the user.
}
// Create a new menu item. For our example, we only want to do this
// if there is a path (in the case of appendnodes (for new objects)
// path is null until a node is created)
if (path) {
// Each item in the items array represents a menu item,
// and requires the following details :
items.push({
text: 'jq Path', // the text for the menu item
title: 'Show the jq path for this node', // the HTML title attribute
className: 'example-class', // the css class name(s) for the menu item
click: pathTojq // the function to call when the menu item is clicked
})
}
// Now we will iterate through the menu items, which includes the items
// created by jsoneditor, and the new item we added above. In this
// example we will just alter the className property for the items, but
// you can alter any property (e.g. the click callback, text property etc.)
// for any item, or even delete the whole menu item.
items.forEach(function (item, index, items) {
if ("submenu" in item) {
// if the item has a submenu property, it is a submenu heading
// and contains another array of menu items. Let's colour
// that yellow...
items[index].className += ' submenu-highlight'
} else {
// if it's not a submenu heading, let's make it colorful
items[index].className += ' rainbow'
}
})
// note that the above loop isn't recursive, so it only alters the classes
// on the top-level menu items. To also process menu items in submenus
// you should iterate through any "submenu" arrays of items if the item has one.
// next, just for fun, let's remove any menu separators (again just at the
// top level menu). A menu separator is an item with a type : 'separator'
// property
items = items.filter(function (item) {
return item.type !== 'separator'
})
// finally we need to return the items array. If we don't, the menu
// will be empty.
return items
}
}
const json = {
'array': [1, 2, 3],
'boolean': true,
'color': '#82b92c',
'null': null,
'number': 123,
'object': {'a': 'b', 'c': 'd'},
'string': 'Hello World'
}
const editor = new JSONEditor(container, options, json)
</script>
</body>
</html>

View File

@ -1,153 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSONEditor | onValidationError</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
body {
width: 600px;
font: 11pt sans-serif;
}
#jsoneditor {
width: 100%;
height: 500px;
}
#onValidationOutput {
margin: 5px;
}
/* custom bold styling for non-default JSON schema values */
.jsoneditor-is-not-default {
font-weight: bold;
}
</style>
</head>
<body>
<h1>JSON schema validation</h1>
<p>
This example demonstrates onValidationError callback.
</p>
<div id="jsoneditor"></div>
<div id="onValidationOutput"></div>
<script>
var schema = {
"title": "Employee",
"description": "Object containing employee details",
"type": "object",
"properties": {
"firstName": {
"title": "First Name",
"description": "The given name.",
"examples": [
"John"
],
"type": "string"
},
"lastName": {
"title": "Last Name",
"description": "The family name.",
"examples": [
"Smith"
],
"type": "string"
},
"gender": {
"title": "Gender",
"enum": ["male", "female"]
},
"availableToHire": {
"type": "boolean",
"default": false
},
"age": {
"description": "Age in years",
"type": "integer",
"minimum": 0,
"examples": [28, 32]
},
"job": {
"$ref": "job"
}
},
"required": ["firstName", "lastName"]
};
var job = {
"title": "Job description",
"type": "object",
"required": ["address"],
"properties": {
"company": {
"type": "string",
"examples": [
"ACME",
"Dexter Industries"
]
},
"role": {
"description": "Job title.",
"type": "string",
"examples": [
"Human Resources Coordinator",
"Software Developer"
],
"default": "Software Developer"
},
"address": {
"type": "string"
},
"salary": {
"type": "number",
"minimum": 120,
"examples": [100, 110, 120]
}
}
};
var json = {
firstName: 'John',
lastName: 'Doe',
gender: null,
age: "28",
availableToHire: true,
job: {
company: 'freelance',
role: 'developer',
salary: 100
}
};
var options = {
schema: schema,
schemaRefs: {"job": job},
mode: 'code',
modes: ['code', 'text', 'tree', 'preview'],
onValidationError: function(errors) {
console.error('onValidationError', errors);
const outputEL = document.getElementById('onValidationOutput')
outputEL.innerHTML = '<code>onValidationError</code> was called with ' + errors.length + ' error' + (errors.length > 1 ? 's' : '') + ' <br> ' +
'open the browser console to see the error objects';
},
onValidate: function (json) {
var errors = [];
if(!isNaN(json.age) && json.age < 30) {
errors.push({ path: ['age'], message: 'Member age must be 30 or higher' });
}
return errors;
}
};
// create the editor
var container = document.getElementById('jsoneditor');
var editor = new JSONEditor(container, options, json);
</script>
</body>
</html>

View File

@ -1,123 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>JSONEditor | Custom query language</title>
<meta charset="utf-8" />
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<script src="https://unpkg.com/lodash@4.17.15/lodash.min.js"></script>
<style type="text/css">
p {
max-width: 500px;
font-family: sans-serif;
font-size: 11pt;
}
code {
font-size: 11pt;
background: #e5e5e5;
}
#jsoneditor {
width: 500px;
height: 500px;
}
.warning {
color: red;
}
</style>
</head>
<body>
<p>
This demo shows how to configure a custom query language.
Click on the "Transform" button and try it out.
</p>
<p>
This basic example uses lodash functions <code>filter</code>, <code>sort</code>, and <code>pick</code>,
but you can run any JavaScript code.
</p>
<p class="warning">
WARNING: this example uses <code>new Function()</code> which can be dangerous when executed with arbitrary code.
Don't use it in production.
</p>
<div id="jsoneditor"></div>
<script>
const container = document.getElementById('jsoneditor')
const options = {
createQuery: function (json, queryOptions) {
console.log('createQuery', queryOptions)
const { filter, sort, projection } = queryOptions
let query = 'data'
if (filter) {
// Note that the comparisons embrace type coercion,
// so a filter value like '5' (text) will match numbers like 5 too.
const getActualValue = filter.field !== '@'
? `item => _.get(item, '${filter.field}')`
: `item => item`
query = `_.filter(${query}, ${getActualValue} ${filter.relation} '${filter.value}')`
}
if (sort) {
// The '@' field name is a special case,
// which means that the field itself is selected.
// For example when we have an array containing numbers.
query = sort.field !== '@'
? `_.orderBy(${query}, '${sort.field}', '${sort.direction}')`
: `_.sortBy(${query}, '${sort.direction}')`
}
if (projection) {
// It is possible to make a util function "pickFlat"
// and use that when building the query to make it more readable.
if (projection.fields.length > 1) {
const fields = projection.fields.map(field => {
const name = _.last(field.split('.'))
return ` '${name}': _.get(item, '${field}')`
})
query = `_.map(${query}, item => ({\n${fields.join(',\n')}})\n)`
} else {
const field = projection.fields[0]
query = `_.map(${query}, item => _.get(item, '${field}'))`
}
}
return query
},
executeQuery: function (json, query) {
console.log('executeQuery', query)
// WARNING: Using new Function() with arbitrary input can be dangerous! Be careful.
const execute = new Function('data', 'return ' + query)
return execute(json)
},
queryDescription: 'Enter a JavaScript query to filter, sort, or transform the JSON data.<br/>' +
'The <a href="https://lodash.com/" target="_blank">Lodash</a> library is available via <code>_</code> to facilitate this.'
}
const json = []
for (let i = 0; i < 100; i++) {
var longitude = 4 + i / 100
var latitude = 51 + i / 100
json.push({
name: 'Item ' + i,
id: String(i),
index: i,
time: new Date().toISOString(),
location: {
latitude: longitude,
longitude: latitude,
coordinates: [longitude, latitude]
},
random: Math.random()
})
}
const editor = new JSONEditor(container, options, json)
</script>
</body>
</html>

View File

@ -1,89 +0,0 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>JSONEditor | New window</title>
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
<script src="../dist/jsoneditor.js"></script>
<style type="text/css">
#jsoneditor {
width: 500px;
height: 500px;
}
</style>
</head>
<body>
<p>
<button id="openNewEditor">Open Editor in New Window</button>
<button id="setJSON">Set JSON</button>
<button id="getJSON">Get JSON</button>
</p>
<script>
let editor
function openNewEditor() {
const child = window.open("", "_blank", "width=400,height=400")
child.document.title = 'JSONEditor | New window'
child.onunload = function () {
editor = undefined
}
// make the necessary styles available within the child window
// for JSONEditor
const baseUrl = window.location.href.slice(0, window.location.href.lastIndexOf('/'))
const jsonEditorStyles = child.document.createElement("link")
jsonEditorStyles.setAttribute("href", baseUrl + "/../dist/jsoneditor.css")
jsonEditorStyles.setAttribute("rel", "stylesheet")
child.document.head.append(jsonEditorStyles)
// for vanilla-picker
const colorPickerStyles = JSONEditor.VanillaPicker.StyleElement.cloneNode(true)
child.document.head.append(colorPickerStyles)
const container = child.document.createElement("div")
child.document.body.append(container)
// create the editor
const options = {
// Show sort and transform modals in the child window, not the parent.
modalAnchor: child.document.body
}
editor = new JSONEditor(container, options)
}
// create a new window
document.getElementById('openNewEditor').onclick = openNewEditor
// set json
document.getElementById('setJSON').onclick = function () {
if (!editor) {
openNewEditor()
}
const json = {
'array': [1, 2, 3],
'boolean': true,
'color': '#82b92c',
'null': null,
'number': 123,
'object': {'a': 'b', 'c': 'd'},
'time': 1575599819000,
'string': 'Hello World'
}
editor.set(json)
}
// get json
document.getElementById('getJSON').onclick = function () {
if (!editor) {
alert('No editor is open')
} else {
const json = editor.get()
alert(JSON.stringify(json, null, 2))
}
}
</script>
</body>
</html>

View File

@ -6,22 +6,31 @@ div.jsoneditor-menu {
div.jsoneditor-menu {
background-color: #4b4b4b;
}
div.jsoneditor-tree,
div.jsoneditor textarea.jsoneditor-text {
div.jsoneditor-tree-contents,
textarea.jsoneditor-text {
background-color: #666666;
color: #ffffff;
}
div.jsoneditor-field,
.jsoneditor-menu button.jsoneditor-undo:disabled {
background-position: -24px -96px;
}
.jsoneditor-menu button.jsoneditor-redo:disabled {
background-position: -48px -96px;
}
div.jsoneditor-property,
div.jsoneditor-value {
color: #ffffff;
}
table.jsoneditor-search div.jsoneditor-frame {
background: #808080;
.jsoneditor-property:hover,
.jsoneditor-value:hover {
background-color: #808080;
}
tr.jsoneditor-highlight,
tr.jsoneditor-selected {
background-color: #808080;
.jsoneditor-readonly:hover {
background-color: transparent;
}
div.jsoneditor-field[contenteditable=true]:focus,
@ -31,21 +40,17 @@ div.jsoneditor-value[contenteditable=true]:hover,
div.jsoneditor-field.jsoneditor-highlight,
div.jsoneditor-value.jsoneditor-highlight {
background-color: #808080;
border-color: #808080;
}
div.jsoneditor-field.highlight-active,
div.jsoneditor-field.highlight-active:focus,
div.jsoneditor-field.highlight-active:hover,
div.jsoneditor-value.highlight-active,
div.jsoneditor-value.highlight-active:focus,
div.jsoneditor-value.highlight-active:hover {
background-color: #b1b1b1;
border-color: #b1b1b1;
button.jsoneditor-button.jsoneditor-actionmenu {
background-position: -50px -50px;
}
div.jsoneditor-tree button:focus {
background-color: #868686;
button.jsoneditor-button:hover,
button.jsoneditor-button:focus,
button.jsoneditor-button:active {
background-color: #808080;
outline: #808080 solid 1px;
}
/* coloring of JSON in tree mode */
@ -56,7 +61,7 @@ div.jsoneditor td.jsoneditor-separator {
color: #acacac;
}
div.jsoneditor-value.jsoneditor-string {
color: #00ff88;
color: #8bb54b;
}
div.jsoneditor-value.jsoneditor-object,
div.jsoneditor-value.jsoneditor-array {
@ -69,7 +74,7 @@ div.jsoneditor-value.jsoneditor-boolean {
color: #ff8048;
}
div.jsoneditor-value.jsoneditor-null {
color: #49a7fc;
color: #3B8EEA;
}
div.jsoneditor-value.jsoneditor-invalid {
color: white;

View File

@ -1 +0,0 @@
SKIP_PREFLIGHT_CHECK=true

View File

@ -1,21 +0,0 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
/node_modules
# testing
/coverage
# production
/build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*

View File

@ -1,21 +0,0 @@
# JSONEditor React advanced demo
This project was bootstrapped with [Create React App](https://github.com/facebookincubator/create-react-app).
## Install
Install dependencies once:
```
npm install
```
## Run
To run the demo:
```
npm start
```
This will open a development server at http://localhost:3000

View File

@ -1,30 +0,0 @@
{
"name": "react_advanced_demo",
"version": "0.1.0",
"private": true,
"dependencies": {
"jsoneditor": "latest",
"lodash": "4.17.15",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-scripts": "3.4.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

View File

@ -1,13 +0,0 @@
.app .contents {
width: 500px;
height: 400px;
}
.app .contents .mode {
padding: 10px 0;
}
.app .contents .code {
background: #f5f5f5;
overflow: auto;
}

View File

@ -1,90 +0,0 @@
import React, { Component } from 'react';
import JSONEditorReact from './JSONEditorReact';
import './App.css';
const schema = {
title: 'Example Schema',
type: 'object',
properties: {
array: {
type: 'array',
items: {
type: 'number'
}
},
boolean: {
type: 'boolean'
},
number: {
type: 'number'
}
},
required: ['array', 'string', 'boolean']
};
const json = {
'array': [1, 2, 3],
'boolean': true,
'null': null,
'number': 'four',
'object': {'a': 'b', 'c': 'd'},
'string': 'Hello World'
};
const modes = ['tree', 'form', 'view', 'code', 'text'];
class App extends Component {
state = {
schema,
text: JSON.stringify(json, null, 2),
mode: 'tree'
};
render() {
return (
<div className="app">
<h1>JSONEditor React advanced demo</h1>
<div className="contents">
<div className="mode">
mode: <select value={this.state.mode} onChange={this.onModeChangeSelect}>
{
modes.map(mode => <option key={mode} value={mode}>{mode}</option>)
}
</select>
</div>
<JSONEditorReact
schema={this.state.schema}
text={this.state.text}
mode={this.state.mode}
modes={modes}
indentation={4}
onChangeText={this.onChangeText}
onModeChange={this.onModeChange}
/>
<div className="code">
<pre>
<code>
{this.state.text}
</code>
</pre>
</div>
</div>
</div>
);
}
onChangeText = (text) => {
this.setState({ text });
};
onModeChangeSelect = (event) => {
this.setState({ mode: event.target.value });
};
onModeChange = (mode) => {
this.setState({ mode });
};
}
export default App;

View File

@ -1,9 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div);
});

View File

@ -1,4 +0,0 @@
.jsoneditor-react-container {
width: 100%;
height: 100%;
}

View File

@ -1,65 +0,0 @@
import React, {Component} from 'react';
import isEqual from 'lodash/isEqual';
import cloneDeep from 'lodash/cloneDeep';
import JSONEditor from 'jsoneditor';
import 'jsoneditor/dist/jsoneditor.css';
import './JSONEditorReact.css';
export default class JSONEditorReact extends Component {
componentDidMount () {
// copy all properties into options for the editor
// (except the properties for the JSONEditorReact component itself)
const options = Object.assign({}, this.props);
delete options.json;
delete options.text;
this.jsoneditor = new JSONEditor(this.container, options);
if ('json' in this.props) {
this.jsoneditor.set(this.props.json);
}
if ('text' in this.props) {
this.jsoneditor.setText(this.props.text);
}
this.schema = cloneDeep(this.props.schema);
this.schemaRefs = cloneDeep(this.props.schemaRefs);
}
componentDidUpdate() {
if ('json' in this.props) {
this.jsoneditor.update(this.props.json);
}
if ('text' in this.props) {
this.jsoneditor.updateText(this.props.text);
}
if ('mode' in this.props) {
this.jsoneditor.setMode(this.props.mode);
}
// store a clone of the schema to keep track on when it actually changes.
// (When using a PureComponent all of this would be redundant)
const schemaChanged = !isEqual(this.props.schema, this.schema);
const schemaRefsChanged = !isEqual(this.props.schemaRefs, this.schemaRefs);
if (schemaChanged || schemaRefsChanged) {
this.schema = cloneDeep(this.props.schema);
this.schemaRefs = cloneDeep(this.props.schemaRefs);
this.jsoneditor.setSchema(this.props.schema, this.props.schemaRefs);
}
}
componentWillUnmount () {
if (this.jsoneditor) {
this.jsoneditor.destroy();
}
}
render() {
return (
<div className="jsoneditor-react-container" ref={elem => this.container = elem} />
);
}
}

View File

@ -1,3 +0,0 @@
body {
font-family: sans-serif;
}

View File

@ -1,6 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));

View File

@ -1 +0,0 @@
SKIP_PREFLIGHT_CHECK=true

View File

@ -1,21 +1,17 @@
# See https://help.github.com/ignore-files/ for more about ignoring files.
# See http://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
/node_modules
node_modules
# testing
/coverage
coverage
# production
/build
build
# misc
.DS_Store
.env.local
.env.development.local
.env.test.local
.env.production.local
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.env
npm-debug.log
.vscode
.idea

File diff suppressed because it is too large Load Diff

24607
examples/react_demo/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -2,28 +2,18 @@
"name": "react_demo",
"version": "0.1.0",
"private": true,
"devDependencies": {
"react-scripts": "1.1.4"
},
"dependencies": {
"jsoneditor": "latest",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-scripts": "3.4.1"
"jsoneditor": "file:../..",
"react": "16.4.2",
"react-dom": "16.4.2"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

View File

@ -1,34 +1,12 @@
<!DOCTYPE html>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
Only files inside the `public` folder can be referenced from the HTML.
<meta name="viewport" content="width=device-width, initial-scale=1">
Unlike "/favicon.ico" or "favicon.ico", "%PUBLIC_URL%/favicon.ico" will
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>JSONEditor | React demo</title>
<title>React demo | JSONEditor</title>
</head>
<body>
<noscript>
You need to enable JavaScript to run this app.
</noscript>
<div id="root"></div>
<!--
This HTML file is a template.
If you open it directly in the browser, you will see an empty page.
You can add webfonts, meta tags, or analytics to this file.
The build step will place the bundled scripts into the <body> tag.
To begin the development, run `npm start` or `yarn start`.
To create a production bundle, use `npm run build` or `yarn build`.
-->
</body>
</html>

View File

@ -1,12 +1,7 @@
.app .contents {
width: 500px;
height: 400px;
.app {
width: 100%;
max-width: 600px;
}
.app .contents .menu {
padding: 10px 0;
.app h1 {
font-size: 120%;
}
.app .contents .code {
background: #f5f5f5;
}

View File

@ -1,57 +1,47 @@
import React, { Component } from 'react';
import React, { Component } from 'react'
import './App.css'
import JSONEditorDemo from './JSONEditorDemo';
import './App.css';
// Load the react version of JSONEditor
import JSONEditor from 'jsoneditor/react'
const json = {
'array': [1, 2, 3],
'boolean': true,
'null': null,
'number': 123,
'object': {'a': 'b', 'c': 'd'},
'string': 'Hello World'
}
class App extends Component {
state = {
json: {
'array': [1, 2, 3],
'boolean': true,
'null': null,
'number': 123,
'object': {'a': 'b', 'c': 'd'},
'string': 'Hello World'
}
};
json
}
render() {
return (
<div className="app">
<h1>JSONEditor React demo</h1>
<div className="contents">
<div className="menu">
<button onClick={this.updateTime}>
Create/update a field "time"
</button>
</div>
<JSONEditorDemo
<div className="app">
<h1>JSONEditor React demo</h1>
<JSONEditor
mode="tree"
modes={['text', 'code', 'tree', 'form', 'view']}
json={this.state.json}
onChangeJSON={this.onChangeJSON}
onChange={this.onChange}
onChangeText={this.onChangeText}
/>
<div className="code">
<pre>
<code>
{JSON.stringify(this.state.json, null, 2)}
</code>
</pre>
</div>
</div>
</div>
);
)
}
onChangeJSON = (json) => {
this.setState({ json });
};
onChange = (json) => {
console.log('onChange', json)
}
updateTime = () => {
const time = new Date().toISOString();
onChangeText = (text) => {
console.log('onChangeText', text)
this.setState({
json: Object.assign({}, this.state.json, { time })
})
};
this.setState({ text })
}
}
export default App;
export default App

View File

@ -1,9 +0,0 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
it('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<App />, div);
ReactDOM.unmountComponentAtNode(div);
});

View File

@ -1,4 +0,0 @@
.jsoneditor-react-container {
width: 100%;
height: 100%;
}

View File

@ -1,34 +0,0 @@
import React, {Component} from 'react';
import JSONEditor from 'jsoneditor';
import 'jsoneditor/dist/jsoneditor.css';
import './JSONEditorDemo.css';
export default class JSONEditorDemo extends Component {
componentDidMount () {
const options = {
mode: 'tree',
onChangeJSON: this.props.onChangeJSON
};
this.jsoneditor = new JSONEditor(this.container, options);
this.jsoneditor.set(this.props.json);
}
componentWillUnmount () {
if (this.jsoneditor) {
this.jsoneditor.destroy();
}
}
componentDidUpdate() {
this.jsoneditor.update(this.props.json);
}
render() {
return (
<div className="jsoneditor-react-container" ref={elem => this.container = elem} />
);
}
}

View File

@ -1,3 +1,5 @@
body {
margin: 0;
padding: 0;
font-family: sans-serif;
}

View File

@ -1,6 +1,9 @@
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import './index.css'
ReactDOM.render(<App />, document.getElementById('root'));
ReactDOM.render(
<App />,
document.getElementById('root')
)

View File

@ -8,8 +8,7 @@
height: 500px;
}
</style>
<link rel="stylesheet" type="text/css" href="../../dist/jsoneditor.css">
<script data-main="scripts/main" src="https://requirejs.org/docs/release/2.3.6/minified/require.js"></script>
<script data-main="scripts/main" src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.2/require.min.js"></script>
</head>
<body>
<p>

View File

@ -1,25 +1,26 @@
const module = '../../../dist/jsoneditor'
require([module], function (JSONEditor) {
var module = '../../../dist/jsoneditor'
require([module], function (jsoneditor) {
// create the editor
const container = document.getElementById('jsoneditor')
const editor = new JSONEditor(container)
var container = document.getElementById('jsoneditor')
var editor = jsoneditor(container)
// set json
document.getElementById('setJSON').onclick = function () {
const json = {
array: [1, 2, 3],
boolean: true,
null: null,
number: 123,
object: { a: 'b', c: 'd' },
string: 'Hello World'
var json = {
'array': [1, 2, 3],
'boolean': true,
'null': null,
'number': 123,
'object': {'a': 'b', 'c': 'd'},
'string': 'Hello World'
}
editor.set(json)
}
// get json
document.getElementById('getJSON').onclick = function () {
const json = editor.get()
window.alert(JSON.stringify(json, null, 2))
var json = editor.get()
alert(JSON.stringify(json, null, 2))
}
})

View File

@ -1,11 +0,0 @@
{
"groups": {
"default": {
"packages": [
"examples/react_advanced_demo/package.json",
"examples/react_demo/package.json",
"package.json"
]
}
}
}

View File

@ -1,243 +0,0 @@
const fs = require('fs')
const path = require('path')
const gulp = require('gulp')
const log = require('fancy-log')
const format = require('date-format')
const concatCss = require('gulp-concat-css')
const minifyCSS = require('gulp-clean-css')
const sass = require('gulp-sass')
const mkdirp = require('mkdirp')
const webpack = require('webpack')
const uglify = require('uglify-js')
const btoa = require('btoa')
const NAME = 'jsoneditor'
const NAME_MINIMALIST = 'jsoneditor-minimalist'
const ENTRY = './src/js/JSONEditor.js'
const HEADER = './src/js/header.js'
const IMAGE = './src/scss/img/jsoneditor-icons.svg'
const DOCS = './src/docs/*'
const DIST = path.join(__dirname, 'dist')
// generate banner with today's date and correct version
function createBanner () {
const today = format.asString('yyyy-MM-dd', new Date()) // today, formatted as yyyy-MM-dd
const version = require('./package.json').version // math.js version
return String(fs.readFileSync(HEADER))
.replace('@@date', today)
.replace('@@version', version)
}
const bannerPlugin = new webpack.BannerPlugin({
banner: createBanner(),
entryOnly: true,
raw: true
})
const webpackConfigModule = {
rules: [
{
test: /\.m?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.js$/,
use: ['source-map-loader'],
enforce: 'pre'
}
]
}
// create a single instance of the compiler to allow caching
const compiler = webpack({
entry: ENTRY,
output: {
library: 'JSONEditor',
libraryTarget: 'umd',
path: DIST,
filename: NAME + '.js'
},
plugins: [bannerPlugin],
optimization: {
// We no not want to minimize our code.
minimize: false
},
module: webpackConfigModule,
resolve: {
extensions: ['.js'],
mainFields: ['main'] // pick ES5 version of vanilla-picker
},
cache: true
})
// create a single instance of the compiler to allow caching
const compilerMinimalist = webpack({
entry: ENTRY,
output: {
library: 'JSONEditor',
libraryTarget: 'umd',
path: DIST,
filename: NAME_MINIMALIST + '.js'
},
module: webpackConfigModule,
plugins: [
bannerPlugin,
new webpack.IgnorePlugin(new RegExp('^ace-builds')),
new webpack.IgnorePlugin(new RegExp('worker-json-data-url')),
new webpack.IgnorePlugin(new RegExp('^ajv')),
new webpack.IgnorePlugin(new RegExp('^vanilla-picker'))
],
optimization: {
// We no not want to minimize our code.
minimize: false
},
cache: true
})
function minify (name) {
const code = String(fs.readFileSync(DIST + '/' + name + '.js'))
const result = uglify.minify(code, {
sourceMap: {
url: name + '.map'
},
output: {
comments: /@license/,
max_line_len: 64000 // extra large because we have embedded code for workers
}
})
if (result.error) {
throw result.error
}
const fileMin = DIST + '/' + name + '.min.js'
const fileMap = DIST + '/' + name + '.map'
fs.writeFileSync(fileMin, result.code)
fs.writeFileSync(fileMap, result.map)
log('Minified ' + fileMin)
log('Mapped ' + fileMap)
}
// make dist folder structure
gulp.task('mkdir', function (done) {
mkdirp.sync(DIST)
mkdirp.sync(DIST + '/img')
done()
})
// Create an embedded version of the json worker code: a data url
gulp.task('embed-json-worker', function (done) {
const workerBundleFile = './node_modules/ace-builds/src-noconflict/worker-json.js'
const workerEmbeddedFile = './src/js/generated/worker-json-data-url.js'
const workerScript = String(fs.readFileSync(workerBundleFile))
const workerDataUrl = 'data:application/javascript;base64,' + btoa(workerScript)
fs.writeFileSync(workerEmbeddedFile, 'module.exports = \'' + workerDataUrl + '\'\n')
done()
})
// bundle javascript
gulp.task('bundle', function (done) {
// update the banner contents (has a date in it which should stay up to date)
bannerPlugin.banner = createBanner()
compiler.run(function (err, stats) {
if (err) {
log(err)
}
log('bundled ' + NAME + '.js')
done()
})
})
// bundle minimalist version of javascript
gulp.task('bundle-minimalist', function (done) {
// update the banner contents (has a date in it which should stay up to date)
bannerPlugin.banner = createBanner()
compilerMinimalist.run(function (err, stats) {
if (err) {
log(err)
}
log('bundled ' + NAME_MINIMALIST + '.js')
done()
})
})
// bundle css
gulp.task('bundle-css', function (done) {
gulp
.src(['src/scss/jsoneditor.scss'])
.pipe(
sass({
// importer: tildeImporter
})
)
.pipe(concatCss(NAME + '.css'))
.pipe(gulp.dest(DIST))
.pipe(concatCss(NAME + '.min.css'))
.pipe(minifyCSS())
.pipe(gulp.dest(DIST))
done()
})
// create a folder img and copy the icons
gulp.task('copy-img', function (done) {
gulp.src(IMAGE).pipe(gulp.dest(DIST + '/img'))
log('Copied images')
done()
})
// create a folder img and copy the icons
gulp.task('copy-docs', function (done) {
gulp.src(DOCS).pipe(gulp.dest(DIST))
log('Copied doc')
done()
})
gulp.task('minify', function (done) {
minify(NAME)
done()
})
gulp.task('minify-minimalist', function (done) {
minify(NAME_MINIMALIST)
done()
})
// The watch task (to automatically rebuild when the source code changes)
// Does only generate jsoneditor.js and jsoneditor.css, and copy the image
// Does NOT minify the code and does NOT generate the minimalist version
gulp.task('watch', gulp.series('bundle', 'bundle-css', 'copy-img', function () {
gulp.watch(['src/**/*'], gulp.series('bundle', 'bundle-css', 'copy-img'))
}))
// The default task (called when you run `gulp`)
gulp.task('default', gulp.series(
'mkdir',
'embed-json-worker',
gulp.parallel(
'copy-img',
'copy-docs',
'bundle-css',
gulp.series('bundle', 'minify'),
gulp.series('bundle-minimalist', 'minify-minimalist')
)
))

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

File diff suppressed because it is too large Load Diff

Before

Width:  |  Height:  |  Size: 950 KiB

View File

@ -7,10 +7,6 @@ This document describes the steps required to publish a new version of jsonedito
Update the version number in package.json.
Update package-lock.json:
npm install
## Update history
@ -37,8 +33,13 @@ correct date and version number in the header.
## Test
Test whether the npm library is ok by opening some examples, and check whether
the files under `dists` are created and have contents.
Test whether the npm library is ok by installing it locally:
cd ../tmp-folder
npm install ./path/to/jsoneditor
Check whether the examples in the library work ok, and whether the necessary
files are included.
## Commit
@ -59,6 +60,9 @@ Publish to npm:
npm publish
Publish at cdnjs: test after 30 to 60 minutes whether the new version is
published at cdnjs (should auto update).
## Test published library

17291
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,7 +1,7 @@
{
"name": "jsoneditor",
"version": "9.1.1",
"main": "./dist/jsoneditor.min.js",
"version": "6.0.0-BETA",
"main": "./index.js",
"description": "A web-based tool to view, edit, format, and validate JSON",
"tags": [
"json",
@ -10,67 +10,78 @@
"formatter"
],
"author": "Jos de Jong <wjosdejong@gmail.com>",
"license": "Apache-2.0",
"license": "MIT",
"homepage": "https://github.com/josdejong/jsoneditor",
"repository": {
"type": "git",
"url": "https://github.com/josdejong/jsoneditor.git"
},
"bugs": "https://github.com/josdejong/jsoneditor/issues",
"scripts": {
"build": "gulp",
"minify": "gulp minify",
"start": "gulp watch",
"test": "mocha test --require @babel/register",
"lint": "standard --env=mocha",
"prepublishOnly": "npm test && npm run build"
},
"private": false,
"dependencies": {
"ace-builds": "^1.4.12",
"ajv": "^6.12.5",
"javascript-natural-sort": "^0.7.1",
"jmespath": "^0.15.0",
"json-source-map": "^0.6.1",
"mobius1-selectr": "^2.4.13",
"picomodal": "^3.0.0",
"vanilla-picker": "^2.10.1"
"@fortawesome/fontawesome": "1.1.8",
"@fortawesome/fontawesome-free-solid": "5.0.13",
"ajv": "6.12.2",
"brace": "0.11.1",
"javascript-natural-sort": "0.7.1",
"jest": "24.9.0",
"lodash": "4.17.15",
"mitt": "1.2.0",
"prop-types": "15.7.2",
"react-hammerjs": "1.0.1"
},
"peerDependencies": {
"react": "^16.13.1",
"react-dom": "^16.13.1"
},
"devDependencies": {
"@babel/core": "7.11.6",
"@babel/preset-env": "7.11.5",
"@babel/register": "7.11.5",
"babel-loader": "8.1.0",
"btoa": "1.2.1",
"date-format": "3.0.0",
"fancy-log": "1.3.3",
"gulp": "4.0.2",
"gulp-clean-css": "4.3.0",
"gulp-concat-css": "3.1.0",
"gulp-sass": "4.1.0",
"jsdom": "16.4.0",
"json-loader": "0.5.7",
"mkdirp": "1.0.4",
"mocha": "8.1.3",
"source-map-loader": "1.1.0",
"standard": "14.3.4",
"uglify-js": "3.11.1",
"webpack": "4.44.2"
"babel-cli": "6.26.0",
"babel-plugin-external-helpers": "6.22.0",
"babel-plugin-transform-class-properties": "6.24.1",
"babel-plugin-transform-object-rest-spread": "6.26.0",
"babel-plugin-transform-react-jsx": "6.24.1",
"babel-preset-env": "1.7.0",
"console.table": "0.10.0",
"cpy-cli": "3.1.1",
"css-loader": "3.5.3",
"npm-run-all": "4.1.5",
"node-sass-chokidar": "1.4.0",
"preact": "10.4.4",
"preact-compat": "3.19.0",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-scripts": "3.4.1",
"rollup": "2.12.1",
"rollup-plugin-babel": "4.4.0",
"rollup-plugin-commonjs": "10.1.0",
"rollup-plugin-node-resolve": "5.2.0",
"rollup-plugin-postcss": "3.1.1",
"svg-url-loader": "6.0.0"
},
"files": [
"dist",
"docs",
"examples",
"src",
"HISTORY.md",
"index.js",
"LICENSE",
"NOTICE",
"README.md"
],
"standard": {
"ignore": [
"src/js/assets",
"examples/react*"
"scripts": {
"start": "npm-run-all -p watch-css start-js",
"build-css": "node-sass-chokidar src/ -o src/",
"watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive",
"start-js": "react-scripts start",
"build-js": "react-scripts build",
"copy-css-lib": "cpy '**/*.css' '**/*.svg' '../../lib' --cwd='src/jsoneditor' --parents",
"build-js-lib": "babel src/jsoneditor --out-dir lib --ignore spec.js,test.js",
"build-js-bundle": "webpack --config ./config/webpack.config.js",
"build-js-minimalist": "webpack --config ./config/webpack.config.minimalist.js",
"build": "npm-run-all build-css copy-css-lib build-js-lib build-js-bundle build-js-minimalist",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}

BIN
public/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -4,6 +4,12 @@
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="theme-color" content="#000000">
<!--
manifest.json provides metadata used when your web app is added to the
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
-->
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<!--
Notice the use of %PUBLIC_URL% in the tags above.
It will be replaced with the URL of the `public` folder during the build.
@ -13,7 +19,7 @@
work correctly both with client-side routing and a non-root public URL.
Learn how to configure a non-root public URL by running `npm run build`.
-->
<title>JSONEditor | React advanced demo</title>
<title>JSONEditor demo</title>
</head>
<body>
<noscript>

15
public/manifest.json Normal file
View File

@ -0,0 +1,15 @@
{
"short_name": "JSONEditor",
"name": "JSONEditor demo",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": "./index.html",
"display": "standalone",
"theme_color": "#3883fa",
"background_color": "#ffffff"
}

1
react.js vendored Normal file
View File

@ -0,0 +1 @@
module.exports = require('./lib/index.react')

16
src/demo/Demo.css Normal file
View File

@ -0,0 +1,16 @@
body, input, select {
font-family: sans-serif;
font-size: 11pt; }
body {
height: 2000px; }
.demo .menu {
margin: 20px 0; }
.demo .menu button, .demo .menu label {
margin-right: 10px; }
.demo .contents {
height: 400px;
width: 100%;
max-width: 800px; }

197
src/demo/Demo.js Normal file
View File

@ -0,0 +1,197 @@
import React, { Component } from 'react'
import JSONEditor from '../jsoneditor/index.react'
import { setIn } from '../jsoneditor/utils/immutabilityHelpers'
import { largeJson } from './resources/largeJson'
import './Demo.css'
const schema = {
"title": "Example Schema",
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"gender": {
"enum": ["male", "female"]
},
"age": {
"description": "Age in years",
"type": "integer",
"minimum": 0
}
},
"required": ["firstName", "lastName"]
}
const json = {
'array': [1, 2, 3],
'emptyArray': [],
'emptyObject': {},
'firstName': null,
'boolean': true,
'null': null,
'number': 123,
'object': {'a': 'b', 'c': 'd', 'e': [{"first": true}, {"second": true}]},
'string': 'Hello World',
'unicode': 'A unicode character: \u260E',
'url': 'http://jsoneditoronline.org',
'largeArray': [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20],
'structureArray': [
{name: 'Joe', age: 24},
{name: 'Sarah', age: 28},
{name: 'Brett', age: 21},
{name: 'Emma', age: 31},
]
}
function expandAll (path) {
return true
}
class App extends Component {
constructor (props) {
super(props)
this.state = {
logging: false,
editorProps: {
json,
schema: null,
onPatch: this.handlePatch,
onPatchText: this.handlePatchText,
onChange: this.handleChange,
onChangeText: this.handleChangeText,
onChangeMode: this.handleChangeMode,
onError: this.handleError,
name: 'myObject',
mode: 'tree',
modes: ['text', 'code', 'tree', 'form', 'view'],
keyBindings: {
compact: ['Ctrl+\\', 'Command+\\', 'Ctrl+Alt+1', 'Command+Option+1'],
format: ['Ctrl+Shift+\\', 'Command+Shift+\\', 'Ctrl+Alt+2', 'Command+Option+2'],
duplicate: ['Ctrl+D', 'Ctrl+Shift+D', 'Command+D', 'Command+Shift+D']
},
indentation: 4,
escapeUnicode: true,
history: true,
search: true,
expand: expandAll
}
}
}
render() {
return <div className="demo">
<div className="menu">
<button onClick={this.handleSetJson}>Set JSON</button>
<button onClick={this.handleGetJson}>Get JSON</button>
<label>mode:
<select value={this.state.editorProps.mode} onChange={this.handleSetMode}>
<option value="text">text</option>
<option value="code">code</option>
<option value="tree">tree</option>
<option value="form">form</option>
<option value="view">view</option>
</select>
</label>
<label>
<input type="checkbox"
value={this.state.editorProps.schema !== null}
onChange={this.handleToggleJSONSchema} /> JSON Schema
</label>
<label>
<input type="checkbox"
value={this.state.logging}
onChange={this.handleToggleLogging} /> Log events
</label>
</div>
<div className="contents">
<JSONEditor {...this.state.editorProps} />
</div>
</div>
}
handleSetJson = () => {
this.setState({
editorProps: setIn(this.state.editorProps, ['json'], largeJson)
})
}
handleGetJson = () => {
const json = this.state.editorProps.json
alert(JSON.stringify(json, null, 2))
}
handleSetMode = (event) => {
const mode = event.target.value
this.setState({
editorProps: setIn(this.state.editorProps, ['mode'], mode)
})
}
handleToggleLogging = (event) => {
const logging = event.target.checked
this.setState({ logging })
}
handleToggleJSONSchema = (event) => {
const value = event.target.checked ? schema : null
this.setState({
editorProps: setIn(this.state.editorProps, ['schema'], value)
})
}
handleChange = (json) => {
this.log('onChange json=', json)
this.setState({
editorProps: setIn(this.state.editorProps, ['json'], json)
})
}
handleChangeText = (text) => {
this.log('onChangeText', text)
}
handlePatch = (patch, revert) => {
this.log('onPatch patch=', patch, ', revert=', revert)
window.immutableJSONPatch = patch
window.revert = revert
}
handlePatchText = (patch, revert) => {
// FIXME: implement onPatchText
this.log('onPatchText patch=', patch, ', revert=', revert)
}
handleChangeMode = (mode, prevMode) => {
this.log('switched mode from', prevMode, 'to', mode)
this.setState({
editorProps: setIn(this.state.editorProps, ['mode'], mode)
})
}
handleError = (err) => {
console.error(err)
alert(err)
}
log (...args) {
if (this.state.logging) {
console.log(...args)
}
}
}
export default App

26
src/demo/Demo.scss Normal file
View File

@ -0,0 +1,26 @@
body, input, select {
font-family: sans-serif;
font-size: 11pt;
}
body {
height: 2000px;
}
.demo {
.menu {
margin: 20px 0;
button, label {
margin-right: 10px;
}
}
.contents {
height: 400px;
width: 100%;
max-width : 800px;
}
}

10
src/demo/Demo.test.js Normal file
View File

@ -0,0 +1,10 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Demo from './Demo';
test('renders without crashing', () => {
const div = document.createElement('div');
ReactDOM.render(<Demo />, div);
});

179
src/demo/demo.vanilla.html Normal file
View File

@ -0,0 +1,179 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>JSONEditor vanilla demo</title>
<!-- For IE and Edge -->
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.1/es6-shim.min.js"></script>-->
<script src="../../dist/jsoneditor.js"></script>
<script src="./resources/largeJson.js"></script>
<style>
body, input, select {
font-family: sans-serif;
font-size: 11pt;
}
#container {
height: 400px;
width: 100%;
max-width : 800px;
}
</style>
</head>
<body>
<p>
<button id="setJSON">Set JSON</button>
<button id="getJSON">Get JSON</button>
<button id="toggleSchema">Toggle JSON Schema</button>
<label for="mode">mode:
<select id="mode">
<option value="text">text</option>
<option value="code">code</option>
<option value="tree" selected>tree</option>
<option value="form">form</option>
<option value="view">view</option>
</select>
</label>
<label>
<input type="checkbox" id="logEvents" /> Log events
</label>
</p>
<div id="container"></div>
<script>
// prevent contentEditable warnings of React
// https://github.com/facebook/draft-js/issues/53#issuecomment-188280259
console.error = (function() {
const error = console.error
return function(exception) {
if ((exception + '').indexOf('Warning: A component is `contentEditable`') !== 0) {
error.apply(console, arguments)
}
}
})()
// create the editor
const mode = document.getElementById('mode').value
const container = document.getElementById('container')
const options = {
name: 'myObject',
onPatch: function (patch, revert) {
log('onPatch patch=', patch, ', revert=', revert)
window.immutableJSONPatch = patch
window.revert = revert
},
onPatchText: function (patch, revert) {
// FIXME: implement onPatchText
log('onPatchText patch=', patch, ', revert=', revert)
},
onChange: function (json) {
log('onChange json=', json)
},
onChangeText: function (text) {
log('onChangeText', text)
},
onChangeMode: function (mode, prevMode) {
log('switched mode from', prevMode, 'to', mode)
document.getElementById('mode').value = mode
},
onError: function (err) {
console.error(err)
alert(err)
},
mode: mode,
modes: ['text', 'code', 'tree', 'form', 'view'], keyBindings: {
compact: ['Ctrl+\\', 'Command+\\', 'Ctrl+Alt+1', 'Command+Option+1'],
format: ['Ctrl+Shift+\\', 'Command+Shift+\\', 'Ctrl+Alt+2', 'Command+Option+2'],
duplicate: ['Ctrl+D', 'Ctrl+Shift+D', 'Command+D', 'Command+Shift+D']
},
indentation: 4,
escapeUnicode: true,
history: true,
search: true,
expand: function (path) {
return true
}
}
const editor = jsoneditor(container, options)
const json = {
'array': [1, 2, 3],
'emptyArray': [],
'emptyObject': {},
'firstName': null,
'boolean': true,
'null': null,
'number': 123,
'object': {'a': 'b', 'c': 'd', 'e': [{"first": true}, {"second": true}]},
'string': 'Hello World',
'unicode': 'A unicode character: \u260E',
'url': 'http://jsoneditoronline.org'
}
editor.set(json)
const schema = {
"title": "Example Schema",
"type": "object",
"properties": {
"firstName": {
"type": "string"
},
"lastName": {
"type": "string"
},
"gender": {
"enum": ["male", "female"]
},
"age": {
"description": "Age in years",
"type": "integer",
"minimum": 0
}
},
"required": ["firstName", "lastName"]
}
// set json
document.getElementById('setJSON').onclick = async function () {
editor.set(largeJson, {
expand: function (path) {
return true
}
})
}
// set schema
let hasSchema = false
document.getElementById('toggleSchema').onclick = function () {
editor.setSchema(hasSchema ? null : schema)
hasSchema = !hasSchema
}
// get json
document.getElementById('getJSON').onclick = function () {
const json = editor.get()
alert(JSON.stringify(json, null, 2))
}
// change mode
document.getElementById('mode').onchange = function (event) {
const mode = event.target.value
editor.setMode(mode)
}
function log (...args) {
if (document.getElementById('logEvents').checked) {
console.log(...args)
}
}
</script>
</body>
</html>

File diff suppressed because it is too large Load Diff

View File

@ -1,44 +0,0 @@
# Which files do I need?
Ehhh, that's quite some files in this dist folder. Which files do I need?
## Full version
If you're not sure which version to use, use the full version.
Which files are needed when using the full version?
- jsoneditor.min.js
- jsoneditor.map (optional, for debugging purposes only)
- jsoneditor.min.css
- img/jsoneditor-icons.svg
## Minimalist version
The minimalist version has excluded the following libraries:
- `ace` (via `brace`), used for the code editor.
- `ajv`, used for JSON schema validation.
- `vanilla-picker`, used as color picker.
This reduces the the size of the minified and gzipped JavaScript file
from about 210 kB to about 70 kB (one third).
When to use the minimalist version?
- If you don't need the mode "code" and don't need JSON schema validation.
- Or if you want to provide `ace` and/or `ajv` yourself via the configuration
options, for example when you already use Ace in other parts of your
web application too and don't want to bundle the library twice.
- You don't need the color picker, or want to provide your own
color picker using `onColorPicker`.
Which files are needed when using the minimalist version?
- jsoneditor-minimalist.min.js
- jsoneditor-minimalist.map (optional, for debugging purposes only)
- jsoneditor.min.css
- img/jsoneditor-icons.svg

6
src/index.js Normal file
View File

@ -0,0 +1,6 @@
import React from 'react';
import ReactDOM from 'react-dom';
import Demo from './demo/Demo';
ReactDOM.render(<Demo />, document.getElementById('root'));

View File

@ -1,435 +0,0 @@
'use strict'
import { createAbsoluteAnchor } from './createAbsoluteAnchor'
import { addClassName, getSelection, removeClassName, setSelection } from './util'
import { translate } from './i18n'
/**
* A context menu
* @param {Object[]} items Array containing the menu structure
* TODO: describe structure
* @param {Object} [options] Object with options. Available options:
* {function} close Callback called when the
* context menu is being closed.
* @constructor
*/
export class ContextMenu {
constructor (items, options) {
this.dom = {}
const me = this
const dom = this.dom
this.anchor = undefined
this.items = items
this.eventListeners = {}
this.selection = undefined // holds the selection before the menu was opened
this.onClose = options ? options.close : undefined
// create root element
const root = document.createElement('div')
root.className = 'jsoneditor-contextmenu-root'
dom.root = root
// create a container element
const menu = document.createElement('div')
menu.className = 'jsoneditor-contextmenu'
dom.menu = menu
root.appendChild(menu)
// create a list to hold the menu items
const list = document.createElement('ul')
list.className = 'jsoneditor-menu'
menu.appendChild(list)
dom.list = list
dom.items = [] // list with all buttons
// create a (non-visible) button to set the focus to the menu
const focusButton = document.createElement('button')
focusButton.type = 'button'
dom.focusButton = focusButton
const li = document.createElement('li')
li.style.overflow = 'hidden'
li.style.height = '0'
li.appendChild(focusButton)
list.appendChild(li)
function createMenuItems (list, domItems, items) {
items.forEach(item => {
if (item.type === 'separator') {
// create a separator
const separator = document.createElement('div')
separator.className = 'jsoneditor-separator'
const li = document.createElement('li')
li.appendChild(separator)
list.appendChild(li)
} else {
const domItem = {}
// create a menu item
const li = document.createElement('li')
list.appendChild(li)
// create a button in the menu item
const button = document.createElement('button')
button.type = 'button'
button.className = item.className
domItem.button = button
if (item.title) {
button.title = item.title
}
if (item.click) {
button.onclick = event => {
event.preventDefault()
me.hide()
item.click()
}
}
li.appendChild(button)
// create the contents of the button
if (item.submenu) {
// add the icon to the button
const divIcon = document.createElement('div')
divIcon.className = 'jsoneditor-icon'
button.appendChild(divIcon)
const divText = document.createElement('div')
divText.className = 'jsoneditor-text' +
(item.click ? '' : ' jsoneditor-right-margin')
divText.appendChild(document.createTextNode(item.text))
button.appendChild(divText)
let buttonSubmenu
if (item.click) {
// submenu and a button with a click handler
button.className += ' jsoneditor-default'
const buttonExpand = document.createElement('button')
buttonExpand.type = 'button'
domItem.buttonExpand = buttonExpand
buttonExpand.className = 'jsoneditor-expand'
const buttonExpandInner = document.createElement('div')
buttonExpandInner.className = 'jsoneditor-expand'
buttonExpand.appendChild(buttonExpandInner)
li.appendChild(buttonExpand)
if (item.submenuTitle) {
buttonExpand.title = item.submenuTitle
}
buttonSubmenu = buttonExpand
} else {
// submenu and a button without a click handler
const divExpand = document.createElement('div')
divExpand.className = 'jsoneditor-expand'
button.appendChild(divExpand)
buttonSubmenu = button
}
// attach a handler to expand/collapse the submenu
buttonSubmenu.onclick = event => {
event.preventDefault()
me._onExpandItem(domItem)
buttonSubmenu.focus()
}
// create the submenu
const domSubItems = []
domItem.subItems = domSubItems
const ul = document.createElement('ul')
domItem.ul = ul
ul.className = 'jsoneditor-menu'
ul.style.height = '0'
li.appendChild(ul)
createMenuItems(ul, domSubItems, item.submenu)
} else {
// no submenu, just a button with clickhandler
const icon = document.createElement('div')
icon.className = 'jsoneditor-icon'
button.appendChild(icon)
const text = document.createElement('div')
text.className = 'jsoneditor-text'
text.appendChild(document.createTextNode(translate(item.text)))
button.appendChild(text)
}
domItems.push(domItem)
}
})
}
createMenuItems(list, this.dom.items, items)
// TODO: when the editor is small, show the submenu on the right instead of inline?
// calculate the max height of the menu with one submenu expanded
this.maxHeight = 0 // height in pixels
items.forEach(item => {
const height = (items.length + (item.submenu ? item.submenu.length : 0)) * 24
me.maxHeight = Math.max(me.maxHeight, height)
})
}
/**
* Get the currently visible buttons
* @return {Array.<HTMLElement>} buttons
* @private
*/
_getVisibleButtons () {
const buttons = []
const me = this
this.dom.items.forEach(item => {
buttons.push(item.button)
if (item.buttonExpand) {
buttons.push(item.buttonExpand)
}
if (item.subItems && item === me.expandedItem) {
item.subItems.forEach(subItem => {
buttons.push(subItem.button)
if (subItem.buttonExpand) {
buttons.push(subItem.buttonExpand)
}
// TODO: change to fully recursive method
})
}
})
return buttons
}
/**
* Attach the menu to an anchor
* @param {HTMLElement} anchor Anchor where the menu will be attached as sibling.
* @param {HTMLElement} frame The root of the JSONEditor window
* @param {Boolean=} ignoreParent ignore anchor parent in regard to the calculation of the position, needed when the parent position is absolute
*/
show (anchor, frame, ignoreParent) {
this.hide()
// determine whether to display the menu below or above the anchor
let showBelow = true
const parent = anchor.parentNode
const anchorRect = anchor.getBoundingClientRect()
const parentRect = parent.getBoundingClientRect()
const frameRect = frame.getBoundingClientRect()
const me = this
this.dom.absoluteAnchor = createAbsoluteAnchor(anchor, frame, () => {
me.hide()
})
if (anchorRect.bottom + this.maxHeight < frameRect.bottom) {
// fits below -> show below
} else if (anchorRect.top - this.maxHeight > frameRect.top) {
// fits above -> show above
showBelow = false
} else {
// doesn't fit above nor below -> show below
}
const topGap = ignoreParent ? 0 : (anchorRect.top - parentRect.top)
// position the menu
if (showBelow) {
// display the menu below the anchor
const anchorHeight = anchor.offsetHeight
this.dom.menu.style.left = '0'
this.dom.menu.style.top = topGap + anchorHeight + 'px'
this.dom.menu.style.bottom = ''
} else {
// display the menu above the anchor
this.dom.menu.style.left = '0'
this.dom.menu.style.top = ''
this.dom.menu.style.bottom = '0px'
}
// attach the menu to the temporary, absolute anchor
// parent.insertBefore(this.dom.root, anchor);
this.dom.absoluteAnchor.appendChild(this.dom.root)
// move focus to the first button in the context menu
this.selection = getSelection()
this.anchor = anchor
setTimeout(() => {
me.dom.focusButton.focus()
}, 0)
if (ContextMenu.visibleMenu) {
ContextMenu.visibleMenu.hide()
}
ContextMenu.visibleMenu = this
}
/**
* Hide the context menu if visible
*/
hide () {
// remove temporary absolutely positioned anchor
if (this.dom.absoluteAnchor) {
this.dom.absoluteAnchor.destroy()
delete this.dom.absoluteAnchor
}
// remove the menu from the DOM
if (this.dom.root.parentNode) {
this.dom.root.parentNode.removeChild(this.dom.root)
if (this.onClose) {
this.onClose()
}
}
if (ContextMenu.visibleMenu === this) {
ContextMenu.visibleMenu = undefined
}
}
/**
* Expand a submenu
* Any currently expanded submenu will be hided.
* @param {Object} domItem
* @private
*/
_onExpandItem (domItem) {
const me = this
const alreadyVisible = (domItem === this.expandedItem)
// hide the currently visible submenu
const expandedItem = this.expandedItem
if (expandedItem) {
// var ul = expandedItem.ul;
expandedItem.ul.style.height = '0'
expandedItem.ul.style.padding = ''
setTimeout(() => {
if (me.expandedItem !== expandedItem) {
expandedItem.ul.style.display = ''
removeClassName(expandedItem.ul.parentNode, 'jsoneditor-selected')
}
}, 300) // timeout duration must match the css transition duration
this.expandedItem = undefined
}
if (!alreadyVisible) {
const ul = domItem.ul
ul.style.display = 'block'
// eslint-disable-next-line no-unused-expressions
ul.clientHeight // force a reflow in Firefox
setTimeout(() => {
if (me.expandedItem === domItem) {
let childsHeight = 0
for (let i = 0; i < ul.childNodes.length; i++) {
childsHeight += ul.childNodes[i].clientHeight
}
ul.style.height = childsHeight + 'px'
ul.style.padding = '5px 10px'
}
}, 0)
addClassName(ul.parentNode, 'jsoneditor-selected')
this.expandedItem = domItem
}
}
/**
* Handle onkeydown event
* @param {Event} event
* @private
*/
_onKeyDown (event) {
const target = event.target
const keynum = event.which
let handled = false
let buttons, targetIndex, prevButton, nextButton
if (keynum === 27) { // ESC
// hide the menu on ESC key
// restore previous selection and focus
if (this.selection) {
setSelection(this.selection)
}
if (this.anchor) {
this.anchor.focus()
}
this.hide()
handled = true
} else if (keynum === 9) { // Tab
if (!event.shiftKey) { // Tab
buttons = this._getVisibleButtons()
targetIndex = buttons.indexOf(target)
if (targetIndex === buttons.length - 1) {
// move to first button
buttons[0].focus()
handled = true
}
} else { // Shift+Tab
buttons = this._getVisibleButtons()
targetIndex = buttons.indexOf(target)
if (targetIndex === 0) {
// move to last button
buttons[buttons.length - 1].focus()
handled = true
}
}
} else if (keynum === 37) { // Arrow Left
if (target.className === 'jsoneditor-expand') {
buttons = this._getVisibleButtons()
targetIndex = buttons.indexOf(target)
prevButton = buttons[targetIndex - 1]
if (prevButton) {
prevButton.focus()
}
}
handled = true
} else if (keynum === 38) { // Arrow Up
buttons = this._getVisibleButtons()
targetIndex = buttons.indexOf(target)
prevButton = buttons[targetIndex - 1]
if (prevButton && prevButton.className === 'jsoneditor-expand') {
// skip expand button
prevButton = buttons[targetIndex - 2]
}
if (!prevButton) {
// move to last button
prevButton = buttons[buttons.length - 1]
}
if (prevButton) {
prevButton.focus()
}
handled = true
} else if (keynum === 39) { // Arrow Right
buttons = this._getVisibleButtons()
targetIndex = buttons.indexOf(target)
nextButton = buttons[targetIndex + 1]
if (nextButton && nextButton.className === 'jsoneditor-expand') {
nextButton.focus()
}
handled = true
} else if (keynum === 40) { // Arrow Down
buttons = this._getVisibleButtons()
targetIndex = buttons.indexOf(target)
nextButton = buttons[targetIndex + 1]
if (nextButton && nextButton.className === 'jsoneditor-expand') {
// skip expand button
nextButton = buttons[targetIndex + 2]
}
if (!nextButton) {
// move to first button
nextButton = buttons[0]
}
if (nextButton) {
nextButton.focus()
handled = true
}
handled = true
}
// TODO: arrow left and right
if (handled) {
event.stopPropagation()
event.preventDefault()
}
}
}
// currently displayed context menu, a singleton. We may only have one visible context menu
ContextMenu.visibleMenu = undefined

View File

@ -1,194 +0,0 @@
/**
* Show errors and schema warnings in a clickable table view
* @param {Object} config
* @property {boolean} errorTableVisible
* @property {function (boolean) : void} onToggleVisibility
* @property {function (number)} [onFocusLine]
* @property {function (number)} onChangeHeight
* @constructor
*/
export class ErrorTable {
constructor (config) {
this.errorTableVisible = config.errorTableVisible
this.onToggleVisibility = config.onToggleVisibility
this.onFocusLine = config.onFocusLine || (() => {})
this.onChangeHeight = config.onChangeHeight
this.dom = {}
const validationErrorsContainer = document.createElement('div')
validationErrorsContainer.className = 'jsoneditor-validation-errors-container'
this.dom.validationErrorsContainer = validationErrorsContainer
const additionalErrorsIndication = document.createElement('div')
additionalErrorsIndication.style.display = 'none'
additionalErrorsIndication.className = 'jsoneditor-additional-errors fadein'
additionalErrorsIndication.textContent = 'Scroll for more \u25BF'
this.dom.additionalErrorsIndication = additionalErrorsIndication
validationErrorsContainer.appendChild(additionalErrorsIndication)
const validationErrorIcon = document.createElement('span')
validationErrorIcon.className = 'jsoneditor-validation-error-icon'
validationErrorIcon.style.display = 'none'
this.dom.validationErrorIcon = validationErrorIcon
const validationErrorCount = document.createElement('span')
validationErrorCount.className = 'jsoneditor-validation-error-count'
validationErrorCount.style.display = 'none'
this.dom.validationErrorCount = validationErrorCount
this.dom.parseErrorIndication = document.createElement('span')
this.dom.parseErrorIndication.className = 'jsoneditor-parse-error-icon'
this.dom.parseErrorIndication.style.display = 'none'
}
getErrorTable () {
return this.dom.validationErrorsContainer
}
getErrorCounter () {
return this.dom.validationErrorCount
}
getWarningIcon () {
return this.dom.validationErrorIcon
}
getErrorIcon () {
return this.dom.parseErrorIndication
}
toggleTableVisibility () {
this.errorTableVisible = !this.errorTableVisible
this.onToggleVisibility(this.errorTableVisible)
}
setErrors (errors, errorLocations) {
// clear any previous errors
if (this.dom.validationErrors) {
this.dom.validationErrors.parentNode.removeChild(this.dom.validationErrors)
this.dom.validationErrors = null
this.dom.additionalErrorsIndication.style.display = 'none'
}
// create the table with errors
// keep default behavior for parse errors
if (this.errorTableVisible && errors.length > 0) {
const validationErrors = document.createElement('div')
validationErrors.className = 'jsoneditor-validation-errors'
const table = document.createElement('table')
table.className = 'jsoneditor-text-errors'
validationErrors.appendChild(table)
const tbody = document.createElement('tbody')
table.appendChild(tbody)
errors.forEach(error => {
let line
if (!isNaN(error.line)) {
line = error.line
} else if (error.dataPath) {
const errLoc = errorLocations.find(loc => loc.path === error.dataPath)
if (errLoc) {
line = errLoc.line + 1
}
}
const trEl = document.createElement('tr')
trEl.className = !isNaN(line) ? 'jump-to-line' : ''
if (error.type === 'error') {
trEl.className += ' parse-error'
} else {
trEl.className += ' validation-error'
}
const td1 = document.createElement('td')
const button = document.createElement('button')
button.className = 'jsoneditor-schema-error'
td1.appendChild(button)
trEl.appendChild(td1)
const td2 = document.createElement('td')
td2.style = 'white-space: nowrap;'
td2.textContent = (!isNaN(line) ? ('Ln ' + line) : '')
trEl.appendChild(td2)
if (typeof error === 'string') {
const td34 = document.createElement('td')
td34.colSpan = 2
const pre = document.createElement('pre')
pre.appendChild(document.createTextNode(error))
td34.appendChild(pre)
trEl.appendChild(td34)
} else {
const td3 = document.createElement('td')
td3.appendChild(document.createTextNode(error.dataPath || ''))
trEl.appendChild(td3)
const td4 = document.createElement('td')
const pre = document.createElement('pre')
pre.appendChild(document.createTextNode(error.message))
td4.appendChild(pre)
trEl.appendChild(td4)
}
trEl.onclick = () => {
this.onFocusLine(line)
}
tbody.appendChild(trEl)
})
this.dom.validationErrors = validationErrors
this.dom.validationErrorsContainer.appendChild(validationErrors)
this.dom.additionalErrorsIndication.title = errors.length + ' errors total'
if (this.dom.validationErrorsContainer.clientHeight < this.dom.validationErrorsContainer.scrollHeight) {
this.dom.additionalErrorsIndication.style.display = 'block'
this.dom.validationErrorsContainer.onscroll = () => {
this.dom.additionalErrorsIndication.style.display =
(this.dom.validationErrorsContainer.clientHeight > 0 && this.dom.validationErrorsContainer.scrollTop === 0) ? 'block' : 'none'
}
} else {
this.dom.validationErrorsContainer.onscroll = undefined
}
const height = this.dom.validationErrorsContainer.clientHeight + (this.dom.statusBar ? this.dom.statusBar.clientHeight : 0)
// this.content.style.marginBottom = (-height) + 'px';
// this.content.style.paddingBottom = height + 'px';
this.onChangeHeight(height)
} else {
this.onChangeHeight(0)
}
// update the status bar
const validationErrorsCount = errors.filter(error => error.type !== 'error').length
if (validationErrorsCount > 0) {
this.dom.validationErrorCount.style.display = 'inline'
this.dom.validationErrorCount.innerText = validationErrorsCount
this.dom.validationErrorCount.onclick = this.toggleTableVisibility.bind(this)
this.dom.validationErrorIcon.style.display = 'inline'
this.dom.validationErrorIcon.title = validationErrorsCount + ' schema validation error(s) found'
this.dom.validationErrorIcon.onclick = this.toggleTableVisibility.bind(this)
} else {
this.dom.validationErrorCount.style.display = 'none'
this.dom.validationErrorIcon.style.display = 'none'
}
// update the parse error icon
const hasParseErrors = errors.some(error => error.type === 'error')
if (hasParseErrors) {
const line = errors[0].line
this.dom.parseErrorIndication.style.display = 'block'
this.dom.parseErrorIndication.title = !isNaN(line)
? ('parse error on line ' + line)
: 'parse error - check that the json is valid'
this.dom.parseErrorIndication.onclick = this.toggleTableVisibility.bind(this)
} else {
this.dom.parseErrorIndication.style.display = 'none'
}
}
}

View File

@ -1,100 +0,0 @@
'use strict'
/**
* @constructor FocusTracker
* A custom focus tracker for a DOM element with complex internal DOM structure
* @param {[Object]} config A set of configurations for the FocusTracker
* {DOM Object} target * The DOM object to track (required)
* {Function} onFocus onFocus callback
* {Function} onBlur onBlur callback
*
* @return
*/
export class FocusTracker {
constructor (config) {
this.target = config.target || null
if (!this.target) {
throw new Error('FocusTracker constructor called without a "target" to track.')
}
this.onFocus = (typeof config.onFocus === 'function') ? config.onFocus : null
this.onBlur = (typeof config.onBlur === 'function') ? config.onBlur : null
this._onClick = this._onEvent.bind(this)
this._onKeyUp = function (event) {
if (event.which === 9 || event.keyCode === 9) {
this._onEvent(event)
}
}.bind(this)
this.focusFlag = false
this.firstEventFlag = true
/*
Adds required (click and keyup) event listeners to the 'document' object
to track the focus of the given 'target'
*/
if (this.onFocus || this.onBlur) {
document.addEventListener('click', this._onClick)
document.addEventListener('keyup', this._onKeyUp)
}
}
/**
* Removes the event listeners on the 'document' object
* that were added to track the focus of the given 'target'
*/
destroy () {
document.removeEventListener('click', this._onClick)
document.removeEventListener('keyup', this._onKeyUp)
this._onEvent({ target: document.body }) // calling _onEvent with body element in the hope that the FocusTracker is added to an element inside the body tag
}
/**
* Tracks the focus of the target and calls the onFocus and onBlur
* event callbacks if available.
* @param {Event} [event] The 'click' or 'keyup' event object,
* from the respective events set on
* document object
* @private
*/
_onEvent (event) {
const target = event.target
let focusFlag
if (target === this.target) {
focusFlag = true
} else if (this.target.contains(target) || this.target.contains(document.activeElement)) {
focusFlag = true
} else {
focusFlag = false
}
if (focusFlag) {
if (!this.focusFlag) {
// trigger the onFocus callback
if (this.onFocus) {
this.onFocus({ type: 'focus', target: this.target })
}
this.focusFlag = true
}
} else {
if (this.focusFlag || this.firstEventFlag) {
// trigger the onBlur callback
if (this.onBlur) {
this.onBlur({ type: 'blur', target: this.target })
}
this.focusFlag = false
/*
When switching from one mode to another in the editor, the FocusTracker gets recreated.
At that time, this.focusFlag will be init to 'false' and will fail the above if condition, when blur occurs
this.firstEventFlag is added to overcome that issue
*/
if (this.firstEventFlag) {
this.firstEventFlag = false
}
}
}
}
}

View File

@ -1,86 +0,0 @@
'use strict'
/**
* The highlighter can highlight/unhighlight a node, and
* animate the visibility of a context menu.
* @constructor Highlighter
*/
export class Highlighter {
constructor () {
this.locked = false
}
/**
* Hightlight given node and its childs
* @param {Node} node
*/
highlight (node) {
if (this.locked) {
return
}
if (this.node !== node) {
// unhighlight current node
if (this.node) {
this.node.setHighlight(false)
}
// highlight new node
this.node = node
this.node.setHighlight(true)
}
// cancel any current timeout
this._cancelUnhighlight()
}
/**
* Unhighlight currently highlighted node.
* Will be done after a delay
*/
unhighlight () {
if (this.locked) {
return
}
const me = this
if (this.node) {
this._cancelUnhighlight()
// do the unhighlighting after a small delay, to prevent re-highlighting
// the same node when moving from the drag-icon to the contextmenu-icon
// or vice versa.
this.unhighlightTimer = setTimeout(() => {
me.node.setHighlight(false)
me.node = undefined
me.unhighlightTimer = undefined
}, 0)
}
}
/**
* Cancel an unhighlight action (if before the timeout of the unhighlight action)
* @private
*/
_cancelUnhighlight () {
if (this.unhighlightTimer) {
clearTimeout(this.unhighlightTimer)
this.unhighlightTimer = undefined
}
}
/**
* Lock highlighting or unhighlighting nodes.
* methods highlight and unhighlight do not work while locked.
*/
lock () {
this.locked = true
}
/**
* Unlock highlighting or unhighlighting nodes
*/
unlock () {
this.locked = false
}
}

View File

@ -1,85 +0,0 @@
/**
* Keep track on any history, be able
* @param {function} onChange
* @param {function} calculateItemSize
* @param {number} limit Maximum size of all items in history
* @constructor
*/
export class History {
constructor (onChange, calculateItemSize, limit) {
this.onChange = onChange
this.calculateItemSize = calculateItemSize || (() => 1)
this.limit = limit
this.items = []
this.index = -1
}
add (item) {
// limit number of items in history so that the total size doesn't
// always keep at least one item in memory
while (this._calculateHistorySize() > this.limit && this.items.length > 1) {
this.items.shift()
this.index--
}
// cleanup any redo action that are not valid anymore
this.items = this.items.slice(0, this.index + 1)
this.items.push(item)
this.index++
this.onChange()
}
_calculateHistorySize () {
const calculateItemSize = this.calculateItemSize
let totalSize = 0
this.items.forEach(item => {
totalSize += calculateItemSize(item)
})
return totalSize
}
undo () {
if (!this.canUndo()) {
return
}
this.index--
this.onChange()
return this.items[this.index]
}
redo () {
if (!this.canRedo()) {
return
}
this.index++
this.onChange()
return this.items[this.index]
}
canUndo () {
return this.index > 0
}
canRedo () {
return this.index < this.items.length - 1
}
clear () {
this.items = []
this.index = -1
this.onChange()
}
}

View File

@ -1,492 +0,0 @@
'use strict'
const ace = require('./ace') // may be undefined in case of minimalist bundle
const VanillaPicker = require('./vanilla-picker') // may be undefined in case of minimalist bundle
const { treeModeMixins } = require('./treemode')
const { textModeMixins } = require('./textmode')
const { previewModeMixins } = require('./previewmode')
const { clear, extend, getInnerText, getInternetExplorerVersion, parse } = require('./util')
const { tryRequireAjv } = require('./tryRequireAjv')
const { showTransformModal } = require('./showTransformModal')
const { showSortModal } = require('./showSortModal')
const Ajv = tryRequireAjv()
if (typeof Promise === 'undefined') {
console.error('Promise undefined. Please load a Promise polyfill in the browser in order to use JSONEditor')
}
/**
* @constructor JSONEditor
* @param {Element} container Container element
* @param {Object} [options] Object with options. available options:
* {String} mode Editor mode. Available values:
* 'tree' (default), 'view',
* 'form', 'text', and 'code'.
* {function} onChange Callback method, triggered
* on change of contents.
* Does not pass the contents itself.
* See also `onChangeJSON` and
* `onChangeText`.
* {function} onChangeJSON Callback method, triggered
* in modes on change of contents,
* passing the changed contents
* as JSON.
* Only applicable for modes
* 'tree', 'view', and 'form'.
* {function} onChangeText Callback method, triggered
* in modes on change of contents,
* passing the changed contents
* as stringified JSON.
* {function} onError Callback method, triggered
* when an error occurs
* {Boolean} search Enable search box.
* True by default
* Only applicable for modes
* 'tree', 'view', and 'form'
* {Boolean} history Enable history (undo/redo).
* True by default
* Only applicable for modes
* 'tree', 'view', and 'form'
* {String} name Field name for the root node.
* Only applicable for modes
* 'tree', 'view', and 'form'
* {Number} indentation Number of indentation
* spaces. 4 by default.
* Only applicable for
* modes 'text' and 'code'
* {boolean} escapeUnicode If true, unicode
* characters are escaped.
* false by default.
* {boolean} sortObjectKeys If true, object keys are
* sorted before display.
* false by default.
* {function} onSelectionChange Callback method,
* triggered on node selection change
* Only applicable for modes
* 'tree', 'view', and 'form'
* {function} onTextSelectionChange Callback method,
* triggered on text selection change
* Only applicable for modes
* {HTMLElement} modalAnchor The anchor element to apply an
* overlay and display the modals in a
* centered location.
* Defaults to document.body
* 'text' and 'code'
* {function} onEvent Callback method, triggered
* when an event occurs in
* a JSON field or value.
* Only applicable for
* modes 'form', 'tree' and
* 'view'
* {function} onFocus Callback method, triggered
* when the editor comes into focus,
* passing an object {type, target},
* Applicable for all modes
* {function} onBlur Callback method, triggered
* when the editor goes out of focus,
* passing an object {type, target},
* Applicable for all modes
* {function} onClassName Callback method, triggered
* when a Node DOM is rendered. Function returns
* a css class name to be set on a node.
* Only applicable for
* modes 'form', 'tree' and
* 'view'
* {Number} maxVisibleChilds Number of children allowed for a node
* in 'tree', 'view', or 'form' mode before
* the "show more/show all" buttons appear.
* 100 by default.
*
* @param {Object | undefined} json JSON object
*/
function JSONEditor (container, options, json) {
if (!(this instanceof JSONEditor)) {
throw new Error('JSONEditor constructor called without "new".')
}
// check for unsupported browser (IE8 and older)
const ieVersion = getInternetExplorerVersion()
if (ieVersion !== -1 && ieVersion < 9) {
throw new Error('Unsupported browser, IE9 or newer required. ' +
'Please install the newest version of your browser.')
}
if (options) {
// check for deprecated options
if (options.error) {
console.warn('Option "error" has been renamed to "onError"')
options.onError = options.error
delete options.error
}
if (options.change) {
console.warn('Option "change" has been renamed to "onChange"')
options.onChange = options.change
delete options.change
}
if (options.editable) {
console.warn('Option "editable" has been renamed to "onEditable"')
options.onEditable = options.editable
delete options.editable
}
// warn if onChangeJSON is used when mode can be `text` or `code`
if (options.onChangeJSON) {
if (options.mode === 'text' || options.mode === 'code' ||
(options.modes && (options.modes.indexOf('text') !== -1 || options.modes.indexOf('code') !== -1))) {
console.warn('Option "onChangeJSON" is not applicable to modes "text" and "code". ' +
'Use "onChangeText" or "onChange" instead.')
}
}
// validate options
if (options) {
Object.keys(options).forEach(option => {
if (JSONEditor.VALID_OPTIONS.indexOf(option) === -1) {
console.warn('Unknown option "' + option + '". This option will be ignored')
}
})
}
}
if (arguments.length) {
this._create(container, options, json)
}
}
/**
* Configuration for all registered modes. Example:
* {
* tree: {
* mixin: TreeEditor,
* data: 'json'
* },
* text: {
* mixin: TextEditor,
* data: 'text'
* }
* }
*
* @type { Object.<String, {mixin: Object, data: String} > }
*/
JSONEditor.modes = {}
// debounce interval for JSON schema validation in milliseconds
JSONEditor.prototype.DEBOUNCE_INTERVAL = 150
JSONEditor.VALID_OPTIONS = [
'ajv', 'schema', 'schemaRefs', 'templates',
'ace', 'theme', 'autocomplete',
'onChange', 'onChangeJSON', 'onChangeText',
'onEditable', 'onError', 'onEvent', 'onModeChange', 'onNodeName', 'onValidate', 'onCreateMenu',
'onSelectionChange', 'onTextSelectionChange', 'onClassName',
'onFocus', 'onBlur',
'colorPicker', 'onColorPicker',
'timestampTag', 'timestampFormat',
'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation',
'sortObjectKeys', 'navigationBar', 'statusBar', 'mainMenuBar', 'languages', 'language', 'enableSort', 'enableTransform', 'limitDragging',
'maxVisibleChilds', 'onValidationError',
'modalAnchor', 'popupAnchor',
'createQuery', 'executeQuery', 'queryDescription'
]
/**
* Create the JSONEditor
* @param {Element} container Container element
* @param {Object} [options] See description in constructor
* @param {Object | undefined} json JSON object
* @private
*/
JSONEditor.prototype._create = function (container, options, json) {
this.container = container
this.options = options || {}
this.json = json || {}
const mode = this.options.mode || (this.options.modes && this.options.modes[0]) || 'tree'
this.setMode(mode)
}
/**
* Destroy the editor. Clean up DOM, event listeners, and web workers.
*/
JSONEditor.prototype.destroy = () => {}
/**
* Set JSON object in editor
* @param {Object | undefined} json JSON data
*/
JSONEditor.prototype.set = function (json) {
this.json = json
}
/**
* Get JSON from the editor
* @returns {Object} json
*/
JSONEditor.prototype.get = function () {
return this.json
}
/**
* Set string containing JSON for the editor
* @param {String | undefined} jsonText
*/
JSONEditor.prototype.setText = function (jsonText) {
this.json = parse(jsonText)
}
/**
* Get stringified JSON contents from the editor
* @returns {String} jsonText
*/
JSONEditor.prototype.getText = function () {
return JSON.stringify(this.json)
}
/**
* Set a field name for the root node.
* @param {String | undefined} name
*/
JSONEditor.prototype.setName = function (name) {
if (!this.options) {
this.options = {}
}
this.options.name = name
}
/**
* Get the field name for the root node.
* @return {String | undefined} name
*/
JSONEditor.prototype.getName = function () {
return this.options && this.options.name
}
/**
* Change the mode of the editor.
* JSONEditor will be extended with all methods needed for the chosen mode.
* @param {String} mode Available modes: 'tree' (default), 'view', 'form',
* 'text', and 'code'.
*/
JSONEditor.prototype.setMode = function (mode) {
// if the mode is the same as current mode (and it's not the first time), do nothing.
if (mode === this.options.mode && this.create) {
return
}
const container = this.container
const options = extend({}, this.options)
const oldMode = options.mode
let data
let name
options.mode = mode
const config = JSONEditor.modes[mode]
if (config) {
try {
const asText = (config.data === 'text')
name = this.getName()
data = this[asText ? 'getText' : 'get']() // get text or json
this.destroy()
clear(this)
extend(this, config.mixin)
this.create(container, options)
this.setName(name)
this[asText ? 'setText' : 'set'](data) // set text or json
if (typeof config.load === 'function') {
try {
config.load.call(this)
} catch (err) {
console.error(err)
}
}
if (typeof options.onModeChange === 'function' && mode !== oldMode) {
try {
options.onModeChange(mode, oldMode)
} catch (err) {
console.error(err)
}
}
} catch (err) {
this._onError(err)
}
} else {
throw new Error('Unknown mode "' + options.mode + '"')
}
}
/**
* Get the current mode
* @return {string}
*/
JSONEditor.prototype.getMode = function () {
return this.options.mode
}
/**
* Throw an error. If an error callback is configured in options.error, this
* callback will be invoked. Else, a regular error is thrown.
* @param {Error} err
* @private
*/
JSONEditor.prototype._onError = function (err) {
if (this.options && typeof this.options.onError === 'function') {
this.options.onError(err)
} else {
throw err
}
}
/**
* Set a JSON schema for validation of the JSON object.
* To remove the schema, call JSONEditor.setSchema(null)
* @param {Object | null} schema
* @param {Object.<string, Object>=} schemaRefs Schemas that are referenced using the `$ref` property from the JSON schema that are set in the `schema` option,
+ the object structure in the form of `{reference_key: schemaObject}`
*/
JSONEditor.prototype.setSchema = function (schema, schemaRefs) {
// compile a JSON schema validator if a JSON schema is provided
if (schema) {
let ajv
try {
// grab ajv from options if provided, else create a new instance
if (this.options.ajv) {
ajv = this.options.ajv
} else {
ajv = Ajv({
allErrors: true,
verbose: true,
schemaId: 'auto',
$data: true
})
// support both draft-04 and draft-06 alongside the latest draft-07
ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-04.json'))
ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-06.json'))
}
} 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) {
if (schemaRefs) {
for (const ref in schemaRefs) {
ajv.removeSchema(ref) // When updating a schema - old refs has to be removed first
if (schemaRefs[ref]) {
ajv.addSchema(schemaRefs[ref], ref)
}
}
this.options.schemaRefs = schemaRefs
}
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()
}
this.refresh() // update DOM
} else {
// remove current schema
this.validateSchema = null
this.options.schema = null
this.options.schemaRefs = null
this.validate() // to clear current error messages
this.refresh() // update DOM
}
}
/**
* Validate current JSON object against the configured JSON schema
* Throws an exception when no JSON schema is configured
*/
JSONEditor.prototype.validate = () => {
// must be implemented by treemode and textmode
}
/**
* Refresh the rendered contents
*/
JSONEditor.prototype.refresh = () => {
// can be implemented by treemode and textmode
}
/**
* Register a plugin with one ore multiple modes for the JSON Editor.
*
* A mode is described as an object with properties:
*
* - `mode: String` The name of the mode.
* - `mixin: Object` An object containing the mixin functions which
* will be added to the JSONEditor. Must contain functions
* create, get, getText, set, and setText. May have
* additional functions.
* When the JSONEditor switches to a mixin, all mixin
* functions are added to the JSONEditor, and then
* the function `create(container, options)` is executed.
* - `data: 'text' | 'json'` The type of data that will be used to load the mixin.
* - `[load: function]` An optional function called after the mixin
* has been loaded.
*
* @param {Object | Array} mode A mode object or an array with multiple mode objects.
*/
JSONEditor.registerMode = mode => {
let i, prop
if (Array.isArray(mode)) {
// multiple modes
for (i = 0; i < mode.length; i++) {
JSONEditor.registerMode(mode[i])
}
} else {
// validate the new mode
if (!('mode' in mode)) throw new Error('Property "mode" missing')
if (!('mixin' in mode)) throw new Error('Property "mixin" missing')
if (!('data' in mode)) throw new Error('Property "data" missing')
const name = mode.mode
if (name in JSONEditor.modes) {
throw new Error('Mode "' + name + '" already registered')
}
// validate the mixin
if (typeof mode.mixin.create !== 'function') {
throw new Error('Required function "create" missing on mixin')
}
const reserved = ['setMode', 'registerMode', 'modes']
for (i = 0; i < reserved.length; i++) {
prop = reserved[i]
if (prop in mode.mixin) {
throw new Error('Reserved property "' + prop + '" not allowed in mixin')
}
}
JSONEditor.modes[name] = mode
}
}
// register tree, text, and preview modes
JSONEditor.registerMode(treeModeMixins)
JSONEditor.registerMode(textModeMixins)
JSONEditor.registerMode(previewModeMixins)
// expose some of the libraries that can be used customized
JSONEditor.ace = ace
JSONEditor.Ajv = Ajv
JSONEditor.VanillaPicker = VanillaPicker
// expose some utils (this is undocumented, unofficial)
JSONEditor.showTransformModal = showTransformModal
JSONEditor.showSortModal = showSortModal
JSONEditor.getInnerText = getInnerText
// default export for TypeScript ES6 projects
JSONEditor.default = JSONEditor
module.exports = JSONEditor

View File

@ -1,123 +0,0 @@
'use strict'
import { ContextMenu } from './ContextMenu'
import { translate } from './i18n'
/**
* Create a select box to be used in the editor menu's, which allows to switch mode
* @param {HTMLElement} container
* @param {String[]} modes Available modes: 'code', 'form', 'text', 'tree', 'view', 'preview'
* @param {String} current Available modes: 'code', 'form', 'text', 'tree', 'view', 'preview'
* @param {function(mode: string)} onSwitch Callback invoked on switch
* @constructor
*/
export class ModeSwitcher {
constructor (container, modes, current, onSwitch) {
// available modes
const availableModes = {
code: {
text: translate('modeCodeText'),
title: translate('modeCodeTitle'),
click: function () {
onSwitch('code')
}
},
form: {
text: translate('modeFormText'),
title: translate('modeFormTitle'),
click: function () {
onSwitch('form')
}
},
text: {
text: translate('modeTextText'),
title: translate('modeTextTitle'),
click: function () {
onSwitch('text')
}
},
tree: {
text: translate('modeTreeText'),
title: translate('modeTreeTitle'),
click: function () {
onSwitch('tree')
}
},
view: {
text: translate('modeViewText'),
title: translate('modeViewTitle'),
click: function () {
onSwitch('view')
}
},
preview: {
text: translate('modePreviewText'),
title: translate('modePreviewTitle'),
click: function () {
onSwitch('preview')
}
}
}
// list the selected modes
const items = []
for (let i = 0; i < modes.length; i++) {
const mode = modes[i]
const item = availableModes[mode]
if (!item) {
throw new Error('Unknown mode "' + mode + '"')
}
item.className = 'jsoneditor-type-modes' + ((current === mode) ? ' jsoneditor-selected' : '')
items.push(item)
}
// retrieve the title of current mode
const currentMode = availableModes[current]
if (!currentMode) {
throw new Error('Unknown mode "' + current + '"')
}
const currentTitle = currentMode.text
// create the html element
const box = document.createElement('button')
box.type = 'button'
box.className = 'jsoneditor-modes jsoneditor-separator'
box.textContent = currentTitle + ' \u25BE'
box.title = translate('modeEditorTitle')
box.onclick = () => {
const menu = new ContextMenu(items)
menu.show(box, container)
}
const frame = document.createElement('div')
frame.className = 'jsoneditor-modes'
frame.style.position = 'relative'
frame.appendChild(box)
container.appendChild(frame)
this.dom = {
container: container,
box: box,
frame: frame
}
}
/**
* Set focus to switcher
*/
focus () {
this.dom.box.focus()
}
/**
* Destroy the ModeSwitcher, remove from DOM
*/
destroy () {
if (this.dom && this.dom.frame && this.dom.frame.parentNode) {
this.dom.frame.parentNode.removeChild(this.dom.frame)
}
this.dom = null
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,333 +0,0 @@
'use strict'
import { findUniqueName } from './util'
/**
* @constructor History
* Store action history, enables undo and redo
* @param {JSONEditor} editor
*/
export class NodeHistory {
constructor (editor) {
this.editor = editor
this.history = []
this.index = -1
this.clear()
// helper function to find a Node from a path
function findNode (path) {
return editor.node.findNodeByInternalPath(path)
}
// map with all supported actions
this.actions = {
editField: {
undo: function (params) {
const parentNode = findNode(params.parentPath)
const node = parentNode.childs[params.index]
node.updateField(params.oldValue)
},
redo: function (params) {
const parentNode = findNode(params.parentPath)
const node = parentNode.childs[params.index]
node.updateField(params.newValue)
}
},
editValue: {
undo: function (params) {
findNode(params.path).updateValue(params.oldValue)
},
redo: function (params) {
findNode(params.path).updateValue(params.newValue)
}
},
changeType: {
undo: function (params) {
findNode(params.path).changeType(params.oldType)
},
redo: function (params) {
findNode(params.path).changeType(params.newType)
}
},
appendNodes: {
undo: function (params) {
const parentNode = findNode(params.parentPath)
params.paths.map(findNode).forEach(node => {
parentNode.removeChild(node)
})
},
redo: function (params) {
const parentNode = findNode(params.parentPath)
params.nodes.forEach(node => {
parentNode.appendChild(node)
})
}
},
insertBeforeNodes: {
undo: function (params) {
const parentNode = findNode(params.parentPath)
params.paths.map(findNode).forEach(node => {
parentNode.removeChild(node)
})
},
redo: function (params) {
const parentNode = findNode(params.parentPath)
const beforeNode = findNode(params.beforePath)
params.nodes.forEach(node => {
parentNode.insertBefore(node, beforeNode)
})
}
},
insertAfterNodes: {
undo: function (params) {
const parentNode = findNode(params.parentPath)
params.paths.map(findNode).forEach(node => {
parentNode.removeChild(node)
})
},
redo: function (params) {
const parentNode = findNode(params.parentPath)
let afterNode = findNode(params.afterPath)
params.nodes.forEach(node => {
parentNode.insertAfter(node, afterNode)
afterNode = node
})
}
},
removeNodes: {
undo: function (params) {
const parentNode = findNode(params.parentPath)
const beforeNode = parentNode.childs[params.index] || parentNode.append
params.nodes.forEach(node => {
parentNode.insertBefore(node, beforeNode)
})
},
redo: function (params) {
const parentNode = findNode(params.parentPath)
params.paths.map(findNode).forEach(node => {
parentNode.removeChild(node)
})
}
},
duplicateNodes: {
undo: function (params) {
const parentNode = findNode(params.parentPath)
params.clonePaths.map(findNode).forEach(node => {
parentNode.removeChild(node)
})
},
redo: function (params) {
const parentNode = findNode(params.parentPath)
let afterNode = findNode(params.afterPath)
const nodes = params.paths.map(findNode)
nodes.forEach(node => {
const clone = node.clone()
if (parentNode.type === 'object') {
const existingFieldNames = parentNode.getFieldNames()
clone.field = findUniqueName(node.field, existingFieldNames)
}
parentNode.insertAfter(clone, afterNode)
afterNode = clone
})
}
},
moveNodes: {
undo: function (params) {
const oldParentNode = findNode(params.oldParentPath)
const newParentNode = findNode(params.newParentPath)
const oldBeforeNode = oldParentNode.childs[params.oldIndex] || oldParentNode.append
// first copy the nodes, then move them
const nodes = newParentNode.childs.slice(params.newIndex, params.newIndex + params.count)
nodes.forEach((node, index) => {
node.field = params.fieldNames[index]
oldParentNode.moveBefore(node, oldBeforeNode)
})
// This is a hack to work around an issue that we don't know tha original
// path of the new parent after dragging, as the node is already moved at that time.
if (params.newParentPathRedo === null) {
params.newParentPathRedo = newParentNode.getInternalPath()
}
},
redo: function (params) {
const oldParentNode = findNode(params.oldParentPathRedo)
const newParentNode = findNode(params.newParentPathRedo)
const newBeforeNode = newParentNode.childs[params.newIndexRedo] || newParentNode.append
// first copy the nodes, then move them
const nodes = oldParentNode.childs.slice(params.oldIndexRedo, params.oldIndexRedo + params.count)
nodes.forEach((node, index) => {
node.field = params.fieldNames[index]
newParentNode.moveBefore(node, newBeforeNode)
})
}
},
sort: {
undo: function (params) {
const node = findNode(params.path)
node.hideChilds()
node.childs = params.oldChilds
node.updateDom({ updateIndexes: true })
node.showChilds()
},
redo: function (params) {
const node = findNode(params.path)
node.hideChilds()
node.childs = params.newChilds
node.updateDom({ updateIndexes: true })
node.showChilds()
}
},
transform: {
undo: function (params) {
findNode(params.path).setInternalValue(params.oldValue)
// TODO: would be nice to restore the state of the node and childs
},
redo: function (params) {
findNode(params.path).setInternalValue(params.newValue)
// TODO: would be nice to restore the state of the node and childs
}
}
// TODO: restore the original caret position and selection with each undo
// TODO: implement history for actions "expand", "collapse", "scroll", "setDocument"
}
}
/**
* The method onChange is executed when the History is changed, and can
* be overloaded.
*/
onChange () {}
/**
* Add a new action to the history
* @param {String} action The executed action. Available actions: "editField",
* "editValue", "changeType", "appendNode",
* "removeNode", "duplicateNode", "moveNode"
* @param {Object} params Object containing parameters describing the change.
* The parameters in params depend on the action (for
* example for "editValue" the Node, old value, and new
* value are provided). params contains all information
* needed to undo or redo the action.
*/
add (action, params) {
this.index++
this.history[this.index] = {
action: action,
params: params,
timestamp: new Date()
}
// remove redo actions which are invalid now
if (this.index < this.history.length - 1) {
this.history.splice(this.index + 1, this.history.length - this.index - 1)
}
// fire onchange event
this.onChange()
}
/**
* Clear history
*/
clear () {
this.history = []
this.index = -1
// fire onchange event
this.onChange()
}
/**
* Check if there is an action available for undo
* @return {Boolean} canUndo
*/
canUndo () {
return (this.index >= 0)
}
/**
* Check if there is an action available for redo
* @return {Boolean} canRedo
*/
canRedo () {
return (this.index < this.history.length - 1)
}
/**
* Undo the last action
*/
undo () {
if (this.canUndo()) {
const obj = this.history[this.index]
if (obj) {
const action = this.actions[obj.action]
if (action && action.undo) {
action.undo(obj.params)
if (obj.params.oldSelection) {
try {
this.editor.setDomSelection(obj.params.oldSelection)
} catch (err) {
console.error(err)
}
}
} else {
console.error(new Error('unknown action "' + obj.action + '"'))
}
}
this.index--
// fire onchange event
this.onChange()
}
}
/**
* Redo the last action
*/
redo () {
if (this.canRedo()) {
this.index++
const obj = this.history[this.index]
if (obj) {
const action = this.actions[obj.action]
if (action && action.redo) {
action.redo(obj.params)
if (obj.params.newSelection) {
try {
this.editor.setDomSelection(obj.params.newSelection)
} catch (err) {
console.error(err)
}
}
} else {
console.error(new Error('unknown action "' + obj.action + '"'))
}
}
// fire onchange event
this.onChange()
}
}
/**
* Destroy history
*/
destroy () {
this.editor = null
this.history = []
this.index = -1
}
}

View File

@ -1,325 +0,0 @@
'use strict'
import { translate } from './i18n'
/**
* @constructor SearchBox
* Create a search box in given HTML container
* @param {JSONEditor} editor The JSON Editor to attach to
* @param {Element} container HTML container element of where to
* create the search box
*/
export class SearchBox {
constructor (editor, container) {
const searchBox = this
this.editor = editor
this.timeout = undefined
this.delay = 200 // ms
this.lastText = undefined
this.results = null
this.dom = {}
this.dom.container = container
const wrapper = document.createElement('div')
this.dom.wrapper = wrapper
wrapper.className = 'jsoneditor-search'
container.appendChild(wrapper)
const results = document.createElement('div')
this.dom.results = results
results.className = 'jsoneditor-results'
wrapper.appendChild(results)
const divInput = document.createElement('div')
this.dom.input = divInput
divInput.className = 'jsoneditor-frame'
divInput.title = translate('searchTitle')
wrapper.appendChild(divInput)
const refreshSearch = document.createElement('button')
refreshSearch.type = 'button'
refreshSearch.className = 'jsoneditor-refresh'
divInput.appendChild(refreshSearch)
const search = document.createElement('input')
search.type = 'text'
this.dom.search = search
search.oninput = event => {
searchBox._onDelayedSearch(event)
}
search.onchange = event => {
// For IE 9
searchBox._onSearch()
}
search.onkeydown = event => {
searchBox._onKeyDown(event)
}
search.onkeyup = event => {
searchBox._onKeyUp(event)
}
refreshSearch.onclick = event => {
search.select()
}
// TODO: ESC in FF restores the last input, is a FF bug, https://bugzilla.mozilla.org/show_bug.cgi?id=598819
divInput.appendChild(search)
const searchNext = document.createElement('button')
searchNext.type = 'button'
searchNext.title = translate('searchNextResultTitle')
searchNext.className = 'jsoneditor-next'
searchNext.onclick = () => {
searchBox.next()
}
divInput.appendChild(searchNext)
const searchPrevious = document.createElement('button')
searchPrevious.type = 'button'
searchPrevious.title = translate('searchPreviousResultTitle')
searchPrevious.className = 'jsoneditor-previous'
searchPrevious.onclick = () => {
searchBox.previous()
}
divInput.appendChild(searchPrevious)
}
/**
* Go to the next search result
* @param {boolean} [focus] If true, focus will be set to the next result
* focus is false by default.
*/
next (focus) {
if (this.results) {
let index = this.resultIndex !== null ? this.resultIndex + 1 : 0
if (index > this.results.length - 1) {
index = 0
}
this._setActiveResult(index, focus)
}
}
/**
* Go to the prevous search result
* @param {boolean} [focus] If true, focus will be set to the next result
* focus is false by default.
*/
previous (focus) {
if (this.results) {
const max = this.results.length - 1
let index = this.resultIndex !== null ? this.resultIndex - 1 : max
if (index < 0) {
index = max
}
this._setActiveResult(index, focus)
}
}
/**
* Set new value for the current active result
* @param {Number} index
* @param {boolean} [focus] If true, focus will be set to the next result.
* focus is false by default.
* @private
*/
_setActiveResult (index, focus) {
// de-activate current active result
if (this.activeResult) {
const prevNode = this.activeResult.node
const prevElem = this.activeResult.elem
if (prevElem === 'field') {
delete prevNode.searchFieldActive
} else {
delete prevNode.searchValueActive
}
prevNode.updateDom()
}
if (!this.results || !this.results[index]) {
// out of range, set to undefined
this.resultIndex = undefined
this.activeResult = undefined
return
}
this.resultIndex = index
// set new node active
const node = this.results[this.resultIndex].node
const elem = this.results[this.resultIndex].elem
if (elem === 'field') {
node.searchFieldActive = true
} else {
node.searchValueActive = true
}
this.activeResult = this.results[this.resultIndex]
node.updateDom()
// TODO: not so nice that the focus is only set after the animation is finished
node.scrollTo(() => {
if (focus) {
node.focus(elem)
}
})
}
/**
* Cancel any running onDelayedSearch.
* @private
*/
_clearDelay () {
if (this.timeout !== undefined) {
clearTimeout(this.timeout)
delete this.timeout
}
}
/**
* Start a timer to execute a search after a short delay.
* Used for reducing the number of searches while typing.
* @param {Event} event
* @private
*/
_onDelayedSearch (event) {
// execute the search after a short delay (reduces the number of
// search actions while typing in the search text box)
this._clearDelay()
const searchBox = this
this.timeout = setTimeout(event => {
searchBox._onSearch()
}, this.delay)
}
/**
* Handle onSearch event
* @param {boolean} [forceSearch] If true, search will be executed again even
* when the search text is not changed.
* Default is false.
* @private
*/
_onSearch (forceSearch) {
this._clearDelay()
const value = this.dom.search.value
const text = value.length > 0 ? value : undefined
if (text !== this.lastText || forceSearch) {
// only search again when changed
this.lastText = text
this.results = this.editor.search(text)
const MAX_SEARCH_RESULTS = this.results[0]
? this.results[0].node.MAX_SEARCH_RESULTS
: Infinity
// try to maintain the current active result if this is still part of the new search results
let activeResultIndex = 0
if (this.activeResult) {
for (let i = 0; i < this.results.length; i++) {
if (this.results[i].node === this.activeResult.node) {
activeResultIndex = i
break
}
}
}
this._setActiveResult(activeResultIndex, false)
// display search results
if (text !== undefined) {
const resultCount = this.results.length
if (resultCount === 0) {
this.dom.results.textContent = 'no\u00A0results'
} else if (resultCount === 1) {
this.dom.results.textContent = '1\u00A0result'
} else if (resultCount > MAX_SEARCH_RESULTS) {
this.dom.results.textContent = MAX_SEARCH_RESULTS + '+\u00A0results'
} else {
this.dom.results.textContent = resultCount + '\u00A0results'
}
} else {
this.dom.results.textContent = ''
}
}
}
/**
* Handle onKeyDown event in the input box
* @param {Event} event
* @private
*/
_onKeyDown (event) {
const keynum = event.which
if (keynum === 27) {
// ESC
this.dom.search.value = '' // clear search
this._onSearch()
event.preventDefault()
event.stopPropagation()
} else if (keynum === 13) {
// Enter
if (event.ctrlKey) {
// force to search again
this._onSearch(true)
} else if (event.shiftKey) {
// move to the previous search result
this.previous()
} else {
// move to the next search result
this.next()
}
event.preventDefault()
event.stopPropagation()
}
}
/**
* Handle onKeyUp event in the input box
* @param {Event} event
* @private
*/
_onKeyUp (event) {
const keynum = event.keyCode
if (keynum !== 27 && keynum !== 13) {
// !show and !Enter
this._onDelayedSearch(event) // For IE 9
}
}
/**
* Clear the search results
*/
clear () {
this.dom.search.value = ''
this._onSearch()
}
/**
* Refresh searchResults if there is a search value
*/
forceSearch () {
this._onSearch(true)
}
/**
* Test whether the search box value is empty
* @returns {boolean} Returns true when empty.
*/
isEmpty () {
return this.dom.search.value === ''
}
/**
* Destroy the search box
*/
destroy () {
this.editor = null
this.dom.container.removeChild(this.dom.wrapper)
this.dom = null
this.results = null
this.activeResult = null
this._clearDelay()
}
}

Some files were not shown because too many files have changed in this diff Show More