Compare commits
955 Commits
Author | SHA1 | Date |
---|---|---|
ZaneYork | ecebf360b3 | |
dependabot-preview[bot] | b64e012da8 | |
Jos de Jong | 8eb4819d0e | |
Jos de Jong | e35e39ff2f | |
Jos de Jong | 58f460a383 | |
dependabot-preview[bot] | 1492f22eea | |
Jos de Jong | 223b78542e | |
Jos de Jong | e1a8077dc1 | |
Jos de Jong | 745a1597dd | |
Jos de Jong | 2a861a2868 | |
Josh Kelley | 69fbe63f0e | |
Jos de Jong | f3694c3126 | |
Žiga Miklič | 6cf627a61a | |
Jos de Jong | 41fbf6973f | |
Jos de Jong | 07e4221fad | |
Jos de Jong | 8855944bae | |
Stephan Ahlf | 09b8ed8af6 | |
Jos de Jong | 2aee4a6008 | |
Jos de Jong | 2314aa74e5 | |
Jos de Jong | 12fd998cc1 | |
Jos de Jong | 60b84bb6bd | |
Jos de Jong | 2cbac6fd5c | |
Jos de Jong | 70c9b0b454 | |
Jos de Jong | 59dd16a538 | |
Jos de Jong | b214915b34 | |
Jos de Jong | b48ec89953 | |
Jos de Jong | 295e771ec4 | |
Jos de Jong | df81d1098d | |
dependabot-preview[bot] | 475902593e | |
Jos de Jong | e92bdf407f | |
jos | f9649d1155 | |
Jos de Jong | e89632d9ce | |
Jos de Jong | 09f2a398ca | |
josdejong | 162756ef69 | |
josdejong | 025c0649fa | |
josdejong | fb994728fd | |
josdejong | 400b1eea37 | |
josdejong | 87bc7b2561 | |
josdejong | 8826c6f2b6 | |
josdejong | 394432d3a6 | |
josdejong | 3a5ddb2ae7 | |
josdejong | b6235a8d23 | |
josdejong | 70a2f94693 | |
patrikx3 | d71c7b4ca0 | |
dependabot[bot] | 3048e710c9 | |
dependabot[bot] | 2d38d0bbc9 | |
josdejong | ae84c74996 | |
josdejong | f94589c1e9 | |
josdejong | 901b8aa8dd | |
josdejong | 1b259e7e47 | |
josdejong | 62025c490d | |
josdejong | c2fa821a31 | |
josdejong | bd69cf9ebd | |
josdejong | 71e209528d | |
josdejong | 27eb02a410 | |
josdejong | 9fbd352c12 | |
josdejong | ad021ec7af | |
dependabot-preview[bot] | 81513d0f4a | |
josdejong | 79beb26d66 | |
josdejong | ea7893a2f6 | |
josdejong | d3231570ab | |
josdejong | 561e582de8 | |
josdejong | 7dafdf8d9a | |
josdejong | fe800bada7 | |
josdejong | cfa5575884 | |
josdejong | 990f481f5f | |
josdejong | 2db9e70ac4 | |
josdejong | a68ecf5297 | |
josdejong | a292b82792 | |
josdejong | 830be6c3df | |
josdejong | 2519c0fee5 | |
josdejong | 894af51861 | |
dependabot-preview[bot] | b05e6059de | |
dependabot-preview[bot] | c42ddd4f65 | |
Tim Gates | fc4927bcf6 | |
dependabot-preview[bot] | 981dd220a0 | |
jos | c32f667396 | |
jos | 5508d421e8 | |
jos | 78ac97c001 | |
jos | d62d2e14db | |
jos | 4f433cb6a9 | |
jos | fd0db5dc73 | |
jos | 0ba8321eb3 | |
jos | 253c02c684 | |
jos | 87d320efc3 | |
Snyk bot | 16a46885fe | |
jos | c76f552e47 | |
greenkeeper[bot] | ac5a24ffce | |
jos | ef88b8ef9a | |
jos | f356c875a1 | |
jos | f954a81c05 | |
jos | a33aa14cc2 | |
jos | b09dbca3fd | |
jos | 3363c2df8a | |
jos | 2316c87a46 | |
dependabot[bot] | 341cc2ca8e | |
dependabot[bot] | 98e9fb222c | |
jos | b81a6d06f4 | |
jos | 0229ba328c | |
jos | 854a407da1 | |
greenkeeper[bot] | d0a2644485 | |
jos | f6152c2103 | |
jos | 3ad5c9f9c1 | |
jos | 582645df70 | |
jos | 30fcdf5ce8 | |
jos | dcc66d5d81 | |
jos | 21aa049588 | |
jos | bdd90847eb | |
greenkeeper[bot] | b8ca5f5f16 | |
jos | ba770f25f8 | |
jos | 5e467ad968 | |
petermanders89 | 11b8a04ff3 | |
jos | 825156dfce | |
jos | 9fd1c0f932 | |
jos | 98fb5114b7 | |
jos | ae372441c2 | |
jos | 4293afe451 | |
jos | df46f721e9 | |
jos | 42672eeef5 | |
jos | 9e9fd72edd | |
jos | c5c64bcde3 | |
greenkeeper[bot] | a20c9f1f9f | |
jos | 7e2fb82b2f | |
jos | 385d22de27 | |
jos | e22829e2af | |
jos | d257c50746 | |
jos | eea9c797ad | |
fls-indinf | bed062dda8 | |
jos | aa08a204f4 | |
jos | 7d4b72fb38 | |
jos | b3c0eedc08 | |
jos | 259b32d441 | |
petermanders89 | dab47eef75 | |
jos | 0f031dc6cd | |
Jos de Jong | 090d41f8d9 | |
Jos de Jong | 0c061b33e3 | |
Jos de Jong | 924ca1afc3 | |
jos | 09827482bc | |
jos | d12a5e7cf2 | |
jos | ad430a3173 | |
jos | 540566f0cd | |
jos | 9ed5d5c5ae | |
jos | 32871f85fd | |
jos | 40d312b987 | |
jos | e09fde628b | |
jos | aba0a58383 | |
jos | 6ece0f9acb | |
jos | 3615b841c5 | |
jos | 042cd1be79 | |
jos | 10a48ca7b2 | |
jos | 275fcc8fee | |
jos | 7729e8b38e | |
jos | c059fdb543 | |
jos | 4937337147 | |
jos | d973464545 | |
jos | 582e0b1fc1 | |
jos | f86f3d4e1c | |
jos | 036c9e1914 | |
jos | 7c3695df4a | |
greenkeeper[bot] | 1f02eda866 | |
jos | c766290bf7 | |
jos | d2332dc308 | |
jos | 4eb55bffde | |
jos | 3aba2c243b | |
jos | 5c7e1e6fe9 | |
jos | 00c02b9bcf | |
jos | 03fa90bd71 | |
jos | a55977830f | |
jos | fd21b1c525 | |
Small | ce15bb4b37 | |
jos | 90423573ab | |
jos | b73a7495fe | |
Meir Rotstein | 84950ac69a | |
jos | 7888dcf660 | |
jos | 45ade363f4 | |
jos | 7f053eab8d | |
Meir Rotstein | 266eeec21a | |
jos | 87691e6693 | |
jos | 0d4525d3d2 | |
jos | eb9fb32038 | |
jos | 9d2067f281 | |
jos | 4e68c54988 | |
jos | 323ee3ddf8 | |
jos | 1026d9102c | |
jos | c1d2f124c2 | |
jos | 51410c363f | |
jos | 7be97ceffb | |
jos | 39dfc41100 | |
jos | 42dd2aeb93 | |
Survesh Jones | 8894420263 | |
jos | a615f7ab91 | |
Jos de Jong | 728c10c137 | |
Jos de Jong | 792e4fa3b9 | |
Jos de Jong | ebc7756b5b | |
Jos de Jong | 6b6c6cb2c3 | |
greenkeeper[bot] | 58c6379e32 | |
jos | c25118bceb | |
jos | f3baeb6ffd | |
jos | 009d896c30 | |
jos | 43e0c129ec | |
jos | 8e15be0f12 | |
jos | da235536bc | |
jos | 55300ce7ef | |
jos | b0fc57ccef | |
jos | 626d3959c9 | |
jos | 73214b6985 | |
jos | 75f16348b9 | |
jos | d3e1aef2d3 | |
yannickyvin | 88b03ae4f2 | |
jos | a9ad446954 | |
Yuta Kiyama | c60f1f65de | |
jos | 9a46d29ab7 | |
greenkeeper[bot] | 42a2f89bae | |
jos | abbf866e08 | |
jos | 9202890844 | |
jos | 37f7bff262 | |
jos | 38c6da4bad | |
Victor | b7c8e3a713 | |
jos | 31e1e08dc4 | |
jos | ecb1674f09 | |
greenkeeper[bot] | 42821e2c53 | |
Jos de Jong | 8c7b6f2b31 | |
Arun | 4c82f5cb3f | |
greenkeeper[bot] | 3997062911 | |
jos | 8bce7b4758 | |
jos | 94520c44c8 | |
greenkeeper[bot] | 3f355ecd63 | |
greenkeeper[bot] | a548ad30fc | |
greenkeeper[bot] | 8633f33420 | |
greenkeeper[bot] | 6cb47746f5 | |
jos | 22f691e4fd | |
jos | fc780bbb10 | |
jos | a60a1125ea | |
jos | 587db80d21 | |
jos | 21b0cd12e9 | |
jos | 8554789aa7 | |
greenkeeper[bot] | c605d79f3c | |
greenkeeper[bot] | fc9d5e9af5 | |
greenkeeper[bot] | 1107bdbbf3 | |
jos | 97cda1457a | |
jos | 18f08d3400 | |
jos | fe14ab5b79 | |
jos | 83e9e0655c | |
jos | e23eb8f191 | |
jos | 8c1f932dc2 | |
Dmitry Kulikov | 9d69a699db | |
greenkeeper[bot] | 017800cea4 | |
Vishwas Navada K | f100c4f403 | |
jos | 2876d49a59 | |
jos | f064dcf965 | |
jos | 60f0470a3c | |
qiuweiwei | 8a1af034c9 | |
jos | 05e0733c24 | |
jos | ccd87d9edd | |
jos | 671cad86fb | |
jos | a78adf6676 | |
jos | 862c3f6822 | |
jos | 2d129f2df5 | |
jos | 299aa3da18 | |
jos | ceb08fe13d | |
jos | 9d018c408a | |
jos | b354ddbe8d | |
jos | 88b785d1d9 | |
jos | 6e5309665b | |
jos | b79885471e | |
jos | f321eb54ee | |
jos | 9ef44bda6b | |
jos | be61222225 | |
jos | a7d501fe3c | |
jos | 6bfede956b | |
jos | 004d1100cd | |
jos | 21d0d532fd | |
jos | d293cbcfc0 | |
greenkeeper[bot] | 0e648f4333 | |
jos | 3397b97f98 | |
jos | ecd65c3ad2 | |
jos | ecaa8d141c | |
jos | 1976a8e2e8 | |
jos | 812b4227b6 | |
jos | e67fa19375 | |
jos | 531ddc5c74 | |
jos | d1a858548d | |
jos | a5d6b8a65b | |
jos | 8e2a7de17c | |
jos | f11b070a1d | |
jos | 6d5d9965c3 | |
jos | c404c1bc1f | |
jos | 09e24ce238 | |
ppetkow | 0d0cf17121 | |
greenkeeper[bot] | 0bce4232a2 | |
dependabot[bot] | 06618fcbd5 | |
dependabot[bot] | e9f301c901 | |
jos | 964fe3e06d | |
jos | 9749a517b1 | |
ppetkow | 97893d40b5 | |
jos | ee64c1fbb3 | |
jos | dcd060f1b7 | |
jos | e4385c030f | |
jos | b05af3dd44 | |
jos | 16e46878ba | |
jos | 2b76640611 | |
jos | 174918f4eb | |
jos | ca6e384e8d | |
jos | 9892249e49 | |
jos | f0097afcc0 | |
jos | 79e54a1d3a | |
Sargeras.Wang | dba54806df | |
jos | ce7433fd46 | |
jos | 14cdd0e61b | |
jos | eff2fe85a0 | |
jos | ea02a5be68 | |
jos | 3f182a1f04 | |
jos | cec16b9de1 | |
jos | df952ac61d | |
jos | e5169018c5 | |
jos | 89bb66fe42 | |
jos | e90ca1c422 | |
jos | fb30ded5fa | |
jos | 2b6caba3df | |
jos | 72455e3302 | |
jos | 6bef66aaba | |
jos | 745a4f3665 | |
jos | 3ed0318624 | |
jos | 21b3cca592 | |
jos | e82ef3ed31 | |
jos | 8c06c41f02 | |
jos | 6f6f58bb33 | |
greenkeeper[bot] | a077e660e3 | |
jos | e490d7a512 | |
jos | bec0e71fc8 | |
jos | 939826d41f | |
jos | e3e3886da8 | |
jos | 92bf65f4d4 | |
dependabot[bot] | 23463740df | |
dependabot[bot] | f6e2ec0461 | |
dependabot[bot] | fe7b0eaa2a | |
dependabot[bot] | 47630710af | |
jos | bc0e99ab4a | |
jos | 477037dc46 | |
greenkeeper[bot] | 59c2846f02 | |
jos | df386b6f1b | |
greenkeeper[bot] | ec474a0328 | |
jos | 95cef491a9 | |
greenkeeper[bot] | 7d1306f0a3 | |
dependabot[bot] | 05753a00ef | |
dependabot[bot] | 4d12b1d000 | |
jos | 102b6d2b0c | |
jos | abc242c873 | |
jos | 9ed18da7b6 | |
greenkeeper[bot] | e0b86551e7 | |
jos | 726f829541 | |
greenkeeper[bot] | a8b083dfe3 | |
jos | 14f7dcdf28 | |
jos | 3920215f73 | |
jos | cda54f95fc | |
jos | 1e1ee3463c | |
greenkeeper[bot] | 7f5e0c6870 | |
jos | d509d4e542 | |
jos | 8a95b5b640 | |
jos | f83bb3e5cd | |
jos | 797541cd6b | |
jos | d712e642cc | |
jos | 7311e78b53 | |
jos | 74b816a554 | |
jos | 12dc0408e8 | |
jos | 436c56dd20 | |
jos | 7da4cd09f8 | |
jos | 10daf40b56 | |
jos | 4813cd79a1 | |
jos | 9dfc1aab39 | |
jos | b78ad35670 | |
jos | b1a4bce3d8 | |
jos | ab4a6a2f5e | |
jos | a8d246778f | |
jos | 7bf25b3129 | |
Gcaufy | 85e0710097 | |
jos | 59290dd6c2 | |
jos | 041243b117 | |
Gcaufy | 73e05a6604 | |
jos | 5ba71998bb | |
jos | d2ef76abb5 | |
jos | 006ff56fc0 | |
jos | aee1d2dcde | |
jos | a9abad2cd4 | |
jos | f1b5e2a692 | |
Jos de Jong | 3ccdeeec40 | |
jos | f005c437db | |
jos | a773d5cf8f | |
jos | b781a47702 | |
jos | 70b7e7914b | |
jos | d51090b7c9 | |
jos | c685813538 | |
jos | 965584efe6 | |
jos | 271cb2b512 | |
jos | b38816a88b | |
jos | 35ff268759 | |
jos | 8cc4bf7efa | |
jos | b279ed3069 | |
jos | ff8be9635a | |
jos | 7624919a6c | |
jos | ebe7bafe51 | |
jos | 801921867d | |
jos | 4818c4bb27 | |
jos | 144be4a16d | |
jos | 2a551117b2 | |
jos | 9e3b6fb196 | |
jos | 12d908d08a | |
jos | 19a625fa6e | |
jos | 6ccf5c651d | |
jos | d31917390c | |
jos | 00baaacacc | |
jos | 55c4c91370 | |
jos | 4c5b19e7fa | |
Adam Vigneaux | 09ab92017c | |
jos | 560dd033ad | |
tobiasfriden | 4763bdf293 | |
jos | 0fbe7eee9a | |
jos | 3e7e1cebfd | |
jos | 7c398aeef7 | |
Adam Vigneaux | c79bea4eb8 | |
jos | 7a2e89c329 | |
jos | 1d0870af36 | |
Adam Vigneaux | 4f4a733fd6 | |
jos | 88972a62fc | |
jos | a01ff4a892 | |
Adam Vigneaux | f36cecdfde | |
Adam Vigneaux | c0915548de | |
DappWind | 92fbe410a3 | |
Adam Vigneaux | c93b8f1305 | |
jos | 1acd2d6116 | |
jos | 868dc38ceb | |
adf0001 | 390afbdae0 | |
jos | afead89e3b | |
jos | 829225849e | |
jos | 2dfde82197 | |
Adam Vigneaux | c8aeb1134d | |
Adam Vigneaux | 803563003c | |
Adam Vigneaux | 03d019a554 | |
jos | a4d704f792 | |
jos | 03c833bad6 | |
jos | b5e9cfb34b | |
jos | 83b6c9a892 | |
jos | 1857e80fcb | |
RobAley | b83090d412 | |
RobAley | edca7a7a62 | |
RobAley | 74272397b4 | |
RobAley | b48f084cf5 | |
RobAley | 43ac83520d | |
RobAley | b801affd9c | |
RobAley | 1c743bed1d | |
RobAley | aec7308c78 | |
RobAley | aa577d2437 | |
RobAley | 981ce535d1 | |
jos | 8fc8e50bf1 | |
jos | 704a50d415 | |
RobAley | 5d833d2131 | |
RobAley | 2bd4ca67af | |
jos | df4673146f | |
Adam Vigneaux | f8279537d0 | |
jos | 53a4f57dda | |
jos | c28cef0a9a | |
jos | 7c17ef9001 | |
Adam Vigneaux | 9377ee825d | |
jos | 5098095e86 | |
jos | a0ad953c4c | |
jos | dc55c11015 | |
Berat Postalcioglu | ae2e8018c5 | |
Berat Postalcioglu | 07f7e0fcb4 | |
Adam Vigneaux | dc357061a7 | |
jos | 53a8803e06 | |
long2ice | 10bcf425f7 | |
jos | 4c6f2cdd4f | |
jos | cb2f343d1d | |
jos | 21ae2180e7 | |
jos | 3f9ea75f20 | |
jos | 7d9db67d69 | |
jos | 958463a9cd | |
jos | 3334241ab9 | |
jos | db9f5480c7 | |
jos | 20e42ab8b0 | |
jos | c7d054406c | |
jos | a7cc8527bd | |
Pawel Raszewski | 1c5d7d71ac | |
jos | 160c82f378 | |
Ben Chadwick | a20908f462 | |
jos | 4e62cf5ba5 | |
jos | 182150ea30 | |
Tyler Chen | 4f9fc926f8 | |
jos | 5a93d3df6d | |
Meir Rotstein | 02d7d0fc71 | |
jos | e9f6a299f7 | |
jos | b59da1a5c9 | |
jos | 8c74bc7ef9 | |
jos | 1e29d2a94a | |
jos | 535a47c347 | |
jos | b6e34ea476 | |
Bastian Nanchen | 93232a09cc | |
jos | b202627f6e | |
Meir Rotstein | 78194051b0 | |
jos | bc5c133b52 | |
Anthony Fu | ea119df821 | |
jos | 72ab51002c | |
jos | 6551701153 | |
jos | 550e0a2c4e | |
Pawel Raszewski | 404fa036f9 | |
jos | 9ac82e24d2 | |
jos | db8652baa6 | |
jos | 2cd9cc168a | |
Jacob Page | 3065dad0f5 | |
jos | bd8bac03bd | |
Tanmay Rajani | d7551da7e6 | |
jos | 4e24601823 | |
jos | d0b49fbf12 | |
jos | 67ef58bef3 | |
jos | 07b341546e | |
Tanmay Rajani | 6403c0bd17 | |
jos | 9c23ca9791 | |
jos | e08250c3cb | |
jos | 7d2d669191 | |
jos | 37e609d4d8 | |
jos | b45993ccd5 | |
Meir Rotstein | 4d7bb3c6e3 | |
Mark Herhold | 68aba366ad | |
jos | ef764df37d | |
jos | 655990c2a7 | |
jos | f27bd97d9d | |
jos | 70140b0712 | |
jos | c680a1ca4c | |
jos | 36f79de242 | |
jos | 1736b11b41 | |
jos | 1f1a92354d | |
jos | 384859b132 | |
jos | 53da7fb8df | |
jos | 321f947e72 | |
jos | ed9a6d48f3 | |
Jos de Jong | 9ae7c22286 | |
jos | d528c37909 | |
Meir Rotstein | d720a94d45 | |
jos | ed28e91b9f | |
jos | 2644cb9d1c | |
jos | d3192e9fbe | |
jos | 00f2ab0b76 | |
jos | 4c364dc404 | |
jos | 2b938a27f9 | |
jos | fe4144f5f2 | |
jos | 181140f733 | |
jos | 5ca264d037 | |
jos | 1a99acd36d | |
jos | f913d4e08a | |
jos | 61039c665e | |
jos | 30d7a7b2a6 | |
jos | 38a54ab9de | |
jos | 9833c2dd9c | |
jos | b853ec3f64 | |
jos | 4f72c5e113 | |
jos | 72bcb6802d | |
jos | ffe727849e | |
jos | eb56fc38b4 | |
jos | f11f763171 | |
jos | 620c5e0b89 | |
jos | d57beb9f47 | |
jos | 8bb2962505 | |
jos | ed81af02ec | |
jos | 9dec9617b1 | |
jos | 482b9a74a2 | |
jos | 13bb4d7bb1 | |
jos | c7a29d74c5 | |
jos | 260a428249 | |
jos | ae3fb78486 | |
Meir Rotstein | d387de366a | |
jos | 6a6c34fd00 | |
jos | 03543883b8 | |
Cristina | bb699e1473 | |
jos | ea4b064ab7 | |
jos | 5f749e1f6e | |
jos | eb9f250725 | |
jos | 672b6491cd | |
jos | d81e2b8dab | |
jos | 2ee39cbca8 | |
jos | 5686e2003a | |
jos | 751c3b5b32 | |
jos | 07f04be182 | |
jos | 872bd2d186 | |
jos | 476d44d11c | |
jos | 3a632cf6f9 | |
jos | b93ba1106c | |
jos | f47d17e377 | |
jos | 48b73cafcf | |
jos | 0cebd8f618 | |
jos | 3e518e4742 | |
jos | d89eaee231 | |
jos | d85419b2c7 | |
jos | b0acd3f1cd | |
jos | 73bec80df5 | |
jos | e794943e20 | |
jos | 393dc3f809 | |
jos | 983fafdf9c | |
jos | d1ac1cb694 | |
jos | 54cae20630 | |
jos | 235410c59f | |
jos | d49518a9ba | |
jos | a7da2349e5 | |
jos | 3a439ba795 | |
jos | 338df99410 | |
jos | ab8e6322d2 | |
jos | 9ae30ea63d | |
jos | e16a8fb429 | |
jos | 80e5da9728 | |
jos | 3d433741d2 | |
jos | e8e684a516 | |
jos | 94871dd2d8 | |
jos | ca86cb54bc | |
jos | 46593c24c5 | |
jos | 21199eb9e0 | |
Cristina | 5adf77a193 | |
jos | 0ea0059696 | |
jos | ebcfa301ad | |
jos | 53b42184a3 | |
jos | 91241c6684 | |
jos | 69e88537c3 | |
Cristina | ef74ede75e | |
Cristina | 9de11c04cd | |
jos | d05231977c | |
jos | 6edfac4ef1 | |
jos | 28215132f7 | |
jos | 6288139aa7 | |
jos | 9244f4719e | |
jos | 77e9303ace | |
jos | 7f9fdac9d1 | |
jos | e0d4ab27a3 | |
jos | 7662874036 | |
jos | 228a9e9f12 | |
jos | 0e674a6b02 | |
jos | fdbfa8a951 | |
jos | 066f5d37e6 | |
Cristina | ecd9bf021f | |
jos | 8e619dea2f | |
jos | b53317e431 | |
jos | 12ba61f935 | |
jos | fbf20b5031 | |
jos | cab3211e05 | |
jos | 463276a3d9 | |
jos | 86d2c60fb4 | |
jos | 866c520a71 | |
jos | df477ed199 | |
jos | bcca373931 | |
jos | a5a43bbc7b | |
jos | d85a151243 | |
jos | 05c259dfb4 | |
jos | daee0d05c3 | |
jos | a2e0b22349 | |
jos | 0f0ec480f4 | |
jos | 3b23ef88a2 | |
jos | 185a81e03a | |
jos | b28f73ee13 | |
jos | 41aa876b08 | |
jos | 95d5d33f56 | |
jos | bd87ac83d5 | |
jos | 2e207196df | |
jos | 1106404822 | |
jos | 8b77111393 | |
jos | 9eb9c4fe0b | |
jos | f00c837388 | |
jos | d9babab497 | |
jos | 916c657e28 | |
jos | 02ae08173b | |
jos | 8eaa488318 | |
jos | 0fd1cbabb4 | |
jos | abe274869c | |
jos | 2c806bd105 | |
jos | c0a5774005 | |
jos | 53a49107d0 | |
jos | 8dff972dce | |
jos | 3d8ca6df33 | |
jos | 402afe92e2 | |
jos | 6a15c04053 | |
jos | 92a431e37d | |
jos | 10a2447caa | |
jos | 497c20019d | |
jos | 904110d141 | |
jos | 358ef3086c | |
jos | 9a77045e78 | |
jos | a3c79d0270 | |
Jos de Jong | 63d8280e85 | |
Meir Rotstein | bbff682533 | |
Meir Rotstein | 1a66dbcedd | |
Meir Rotstein | e80a840a33 | |
Meir Rotstein | ea939591fe | |
Meir Rotstein | 1579e787bf | |
Meir Rotstein | dfc03fa4b5 | |
Meir Rotstein | be0e781359 | |
Jos de Jong | 924b6a708f | |
Dmitry Kulikov | b826ee398b | |
Jos de Jong | c7fd2ba180 | |
Meir Rotstein | e1f91cb1ac | |
Meir Rotstein | 3b186633e7 | |
Meir Rotstein | e57c292f30 | |
Meir Rotstein | 39e8d36f72 | |
jos | fed496881a | |
jos | e72b1fe839 | |
Jos de Jong | fa7af9b3da | |
Meir Rotstein | 7e90161057 | |
Meir Rotstein | fb85ffdd5b | |
Cyrille Meichel | 04cff49f89 | |
jos | 1c596ee84d | |
jos | 36e83445ef | |
jos | 9fb29a644d | |
Jos de Jong | 6f4729885b | |
jos | 4b17f56169 | |
Jos de Jong | 4e6f43412c | |
Mario Mol | 5305030337 | |
Mario Mol | 2f13f7fa54 | |
Mario Mol | 466c2c548b | |
James Garbutt | e75043e51d | |
Mario Mol | 40d577732d | |
Mario Mol | c42bf9dd4c | |
43081j | 106a75c46a | |
Meir Rotstein | 8cbe15aa1f | |
jos | 97cc0f39f4 | |
Jos de Jong | d40d470c2a | |
James Garbutt | 00e99a791a | |
43081j | bfbd334b71 | |
Jos de Jong | 5e7f81050e | |
James Garbutt | 803daf4253 | |
jos | c6c592c399 | |
jos | 4c8c4d4a02 | |
Meir Rotstein | 242f3fc3a4 | |
Meir Rotstein | ad15c8a85f | |
Meir Rotstein | 84c015ee93 | |
Meir Rotstein | 803ce34ed4 | |
Meir Rotstein | 55674f5b0f | |
Meir Rotstein | f04eff7b4e | |
Meir Rotstein | 6bb7f734cf | |
Meir Rotstein | 47ba66a5a9 | |
Meir Rotstein | 3c31476377 | |
jos | c5f3723b9c | |
jos | f03b64ffec | |
jos | f4dbd1938b | |
Meir Rotstein | d66d2d6e38 | |
jos | f5da46d2cc | |
Jos de Jong | fbe65d122c | |
Linus Lewandowski | 11cc2929bb | |
jos | 24d9920e0d | |
jos | 50c6a3ac9f | |
jos | 43832dd532 | |
jos | 3f1c4c682a | |
jos | a4cceef13e | |
jos | 8aef543fa6 | |
Jos de Jong | ddf6e1f16a | |
Meir Rotstein | 0a2d113e56 | |
jos | 509ab7e275 | |
Jos de Jong | 2a9107db79 | |
Meir Rotstein | a5f549a289 | |
Meir Rotstein | 5468c35a79 | |
Meir Rotstein | 1dde8b2ac9 | |
jos | 679a966d15 | |
Jos de Jong | 14f0956d7a | |
Meir Rotstein | 95affe7186 | |
Meir Rotstein | 91f763b9b9 | |
Meir Rotstein | ed030c0518 | |
jos | 22e99aa801 | |
jos | da26baec0c | |
Jos de Jong | 8d0b0c5b89 | |
Israel | 017cd22fd6 | |
Israel | f2492e32dc | |
Israel | 168a65cda4 | |
Israel | 89601c3115 | |
Israel | 371a7b2d14 | |
jos | 179d80a26f | |
jos | a8253afb35 | |
jos | 9d93b3b808 | |
jos | ae50af0877 | |
Jos de Jong | 129ad5594a | |
jos | b5d4e4500d | |
Jos de Jong | 5dac87c424 | |
Omar Alshaker | dd11f6ec8c | |
plany | 723f9f5b3f | |
plany | c029f716da | |
jos | c4cff2e1a0 | |
jos | 9e105276d9 | |
jos | b28677d6d1 | |
jos | 40e4ac9302 | |
jos | 42ede262d1 | |
jos | 4875288cb7 | |
jos | bf4e977427 | |
jos | a958e229f9 | |
jos | cba5659e78 | |
jos | a733533af1 | |
Jos de Jong | ea939d48cc | |
Jos de Jong | ac4716a309 | |
Meir Rotstein | 83fe0c86f4 | |
Meir Rotstein | 9c78ea7959 | |
Meir Rotstein | 05dda45265 | |
Meir Rotstein | 5d2b5e5202 | |
Meir Rotstein | 7899724810 | |
jos | 5d5b6473b6 | |
jos | 968e90edd0 | |
jos | de71499269 | |
Jos de Jong | 6a0ac9549a | |
Meir Rotstein | b4e053030b | |
hachichaud | b0266d90ab | |
jos | 8bc9e8d596 | |
Jos de Jong | b6ce1c0653 | |
hachichaud | fc1a81a6f5 | |
Meir Rotstein | 422284cf0d | |
Meir Rotstein | b36df94cfe | |
Meir Rotstein | 7ae0c690ef | |
Meir Rotstein | 1f57894a4a | |
Meir Rotstein | 1238d47bff | |
Meir Rotstein | 11e425e2ff | |
Meir Rotstein | b643eeffb4 | |
Meir Rotstein | 6d4aa7d082 | |
Meir Rotstein | d06c5c3eca | |
Meir Rotstein | aff04b9cd0 | |
jos | a418fbab01 | |
jos | d5ba548902 | |
jos | d9746e3a84 | |
jos | 916fa174be | |
jos | 1504cfc216 | |
Dave Hughes | 1ae040243b | |
Dave Hughes | 66578f4add | |
jos | 262b65fc6c | |
jos | a9e2f73089 | |
jos | b92ec827f5 | |
Jos de Jong | 7c7ca44313 | |
jos | f2b2756634 | |
jos | 2457932400 | |
Thiago Bovi de Mendonca | 6689759793 | |
jos | 308f3b2bde | |
jos | ea6b71986c | |
Israel Garcia | 3654e46f08 | |
Israel Garcia | 97891621e3 | |
jos | 694e766fbf | |
jos | 84ab5107dd | |
Owen Garland | a9584e015f | |
jos | a0f317d1d6 | |
Jos de Jong | 9ee8700661 | |
Tomek Wytrebowicz | 63c0689a61 | |
Tomek Wytrebowicz | b1a939d680 | |
Israel Garcia | 1651c50c01 | |
jos | c51db94f88 | |
jos | 06bbf2d1a5 | |
jos | 6ad7552c3e | |
jos | 2110d251bb | |
Jos de Jong | b69d52a46b | |
Dave Hughes | 6b1546f803 | |
Jos de Jong | 595c4f48df | |
Dave Hughes | 475dbc04b2 | |
jos | f6e699e4cc | |
jos | 524d00e15e | |
jos | 3e4c975b70 | |
jos | 2046d98936 | |
Jos de Jong | 860aa31ddb | |
jos | a00ec59241 | |
jos | 22fb4ca501 | |
jos | 7ac3f5aee6 | |
Jos de Jong | ccb9ea6d94 | |
Jos de Jong | 15ed4da608 | |
Thiago Bovi de Mendonca | e8684d7d42 | |
Meir Rotstein | 0b9c1f8d34 | |
jos | b84621d054 | |
jos | ee85fb099d | |
Jos de Jong | ea06b877b8 | |
Israel Garcia | 495ed38063 | |
Israel Garcia | d423a70a5d | |
jos | fec677883b | |
jos | 3e7a7c08f0 | |
Jos de Jong | 6d56b1ba76 | |
Israel Garcia | f9d8a039e2 | |
Owen Garland | f6f2fce422 | |
Meir Rotstein | b77deb969c | |
jos | 3a8aa1755c | |
jos | a6bd4646ca | |
jos | 5559b0d417 | |
jos | 0aed6e481e | |
jos | 02555b8510 | |
Jos de Jong | 1f29f5912a | |
Israel Garcia | 088d7d6c90 | |
Jos de Jong | 3e431bc745 | |
Jos de Jong | 294dfbe60e | |
jos | 9e5dd53e8d | |
Israel Garcia | f71aa6c5b9 | |
Israel Garcia | 4036f5cd28 | |
jos | a1780c7cdf | |
Jos de Jong | f0904b92f2 | |
Israel Garcia | 00ba443acf | |
Andrey Kaipov | f0897d534b | |
Israel Garcia | fc4562fea1 | |
Israel Garcia | df4cb21146 | |
Israel Garcia | 0391ad11b4 | |
jos | 5f8b90f35e | |
Israel Garcia | 5411ad19ac | |
Israel Garcia | 8707432837 | |
Israel Garcia | 2a0d9ec2bf | |
Israel Garcia | ae287d48e9 | |
Israel Garcia | c6121dfe5c | |
Jos de Jong | c20e24366e | |
Israel Garcia | a4c4948934 | |
Israel Garcia | 75ecd91593 | |
Israel Garcia | 8a96f06df4 | |
Israel Garcia | 1b998c5b1a | |
Israel Garcia | 715343b028 | |
Israel Garcia | 26a1a84602 | |
Israel Garcia | 1393b148db | |
Israel Garcia | 131e8f106d | |
jos | 0ddc9407b0 | |
Jos de Jong | 913af51aab | |
Israel Garcia | a5f91f8f99 | |
Israel Garcia | 3a9e55b3ae | |
Israel Garcia | 38ce7760dd | |
jos | 56c450bf0f | |
jos | 09c1375c84 | |
jos | 0adf824f5b | |
jos | fd91632904 | |
jos | 3d2bf6bd48 | |
jos | fcecb3fc2a | |
jos | 77b7e10220 | |
jos | 66dced1dd3 | |
jos | 0007ee8de4 | |
jos | fe3dffacf3 | |
jos | d258167837 | |
jos | ac7ec05d1d | |
jos | d152aea2ad | |
jos | 23b5b301c6 | |
jos | b26024b6e3 | |
jos | e497f54f6d | |
Jos de Jong | eadf5c6403 | |
Walker Randolph Smith | c0b7139fd2 | |
Walker Randolph Smith | 3539f40dc5 | |
Walker Randolph Smith | c29bcba5ff | |
Walker Randolph Smith | 2c72173366 | |
Jos de Jong | cfc5a805e7 | |
Jos de Jong | 1265ed78a9 | |
Xianming Zhong | a768784643 | |
Xianming Zhong | f5edad2d31 | |
jos | e1f686b8e5 | |
Jos de Jong | 6b5b54052c | |
Paul Biester | 4bde72f7cf | |
jos | 717ed48474 | |
jos | 3117789ed7 | |
jos | 2f4f221c9a | |
jos | 74b9aaf5fa | |
jos | 1c8ea64c2a | |
jos | 94ca26e457 | |
jos | 8dc4752872 | |
jos | 4bc339f6fe | |
jos | df12832a6b | |
jos | d73665acf3 | |
jos | 8913ce1f6f | |
jos | cee259f2a5 | |
jos | 4aa9e7db7f | |
Jos de Jong | b4c9417b7a | |
Stephen Thompson | fe459e64c3 | |
Stephen Thompson | 48408f4ded | |
jos | 02f81ea8de |
|
@ -0,0 +1 @@
|
|||
github: josdejong
|
|
@ -1,6 +1,10 @@
|
|||
.idea
|
||||
*.iml
|
||||
.vscode
|
||||
build
|
||||
dist
|
||||
downloads
|
||||
node_modules
|
||||
*.zip
|
||||
npm-debug.log
|
||||
/.vs
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
bower.json
|
||||
CONTRIBUTING.md
|
||||
downloads
|
||||
misc
|
||||
node_modules
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- "lts/*"
|
||||
|
||||
script: npm test && npm run lint
|
|
@ -6,10 +6,18 @@ up with ideas and suggestions, and contribute to the code.
|
|||
|
||||
There are a few preferences regarding code contributions:
|
||||
|
||||
- `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`, not to the builds
|
||||
which are located under the `./dist` folder.
|
||||
- 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
|
||||
```
|
||||
|
||||
Thanks!
|
||||
|
|
917
HISTORY.md
917
HISTORY.md
|
@ -3,7 +3,916 @@
|
|||
https://github.com/josdejong/jsoneditor
|
||||
|
||||
|
||||
## not yet released, version 5.5.7
|
||||
## 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
|
||||
|
||||
- Fixed #308: wrong positioning of label "empty array" when `onEditable`
|
||||
returns false.
|
||||
|
@ -455,7 +1364,7 @@ https://github.com/josdejong/jsoneditor
|
|||
|
||||
## 2012-08-12, version 1.2.0
|
||||
|
||||
- New: Added search functionality. Search results are expanded and highlighed.
|
||||
- New: Added search functionality. Search results are expanded and highlighted.
|
||||
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
|
||||
|
@ -502,7 +1411,7 @@ https://github.com/josdejong/jsoneditor
|
|||
## 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 browers.
|
||||
- Improved drag and drop: better visualized, and now working in all browsers.
|
||||
- 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
|
||||
|
@ -535,7 +1444,7 @@ https://github.com/josdejong/jsoneditor
|
|||
|
||||
## 2012-01-09, version 0.9.7
|
||||
|
||||
- Added functionallity to expand/collapse a node and all its childs. Click
|
||||
- Added functionality to expand/collapse a node and all its childs. Click
|
||||
the expand button of a node while holding Ctrl down.
|
||||
- Small interface improvements
|
||||
|
||||
|
|
2
NOTICE
2
NOTICE
|
@ -1,7 +1,7 @@
|
|||
JSON Editor
|
||||
https://github.com/josdejong/jsoneditor
|
||||
|
||||
Copyright (C) 2011-2015 Jos de Jong
|
||||
Copyright (C) 2011-2020 Jos de Jong
|
||||
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
|
85
README.md
85
README.md
|
@ -1,5 +1,11 @@
|
|||
# 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.
|
||||
|
@ -7,32 +13,50 @@ 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, Internet Explorer 9+.
|
||||
Supported browsers: Chrome, Firefox, Safari, Opera, Edge, Internet Explorer 11.
|
||||
|
||||
<img alt="json editor" src="https://raw.github.com/josdejong/jsoneditor/master/misc/jsoneditor.png"> <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
|
||||
|
||||
### Tree editor
|
||||
- Edit, add, move, remove, and duplicate fields and values.
|
||||
- Change type of values.
|
||||
JSONEditor has various modes, with the following features.
|
||||
|
||||
### Tree mode
|
||||
|
||||
- Change, add, move, remove, and duplicate fields and 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 editor
|
||||
### Code mode
|
||||
|
||||
- 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 editor
|
||||
### Text mode
|
||||
|
||||
- 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
|
||||
|
||||
|
@ -51,26 +75,18 @@ with npm (recommended):
|
|||
|
||||
npm install jsoneditor
|
||||
|
||||
with bower:
|
||||
|
||||
bower install jsoneditor
|
||||
|
||||
|
||||
#### 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)
|
||||
> Note that to use JSONEditor in Internet Explorer 11, it is necessary
|
||||
> to load a polyfill for `Promise` in your application.
|
||||
|
||||
|
||||
## Use
|
||||
|
||||
```html
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- when using the mode "code", it's important to specify charset utf-8 -->
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||
<meta charset="utf-8">
|
||||
|
||||
<link href="jsoneditor/dist/jsoneditor.min.css" rel="stylesheet" type="text/css">
|
||||
<script src="jsoneditor/dist/jsoneditor.min.js"></script>
|
||||
|
@ -80,23 +96,23 @@ There is a directive available for using JSONEditor in Angular.js:
|
|||
|
||||
<script>
|
||||
// create the editor
|
||||
var container = document.getElementById("jsoneditor");
|
||||
var options = {};
|
||||
var editor = new JSONEditor(container, options);
|
||||
const container = document.getElementById("jsoneditor")
|
||||
const options = {}
|
||||
const editor = new JSONEditor(container, options)
|
||||
|
||||
// set json
|
||||
var json = {
|
||||
const initialJson = {
|
||||
"Array": [1, 2, 3],
|
||||
"Boolean": true,
|
||||
"Null": null,
|
||||
"Number": 123,
|
||||
"Object": {"a": "b", "c": "d"},
|
||||
"String": "Hello World"
|
||||
};
|
||||
editor.set(json);
|
||||
}
|
||||
editor.set(initialJson)
|
||||
|
||||
// get json
|
||||
var json = editor.get();
|
||||
const updatedJson = editor.get()
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -126,7 +142,7 @@ jsoneditor:
|
|||
- To automatically build when a source file has changed:
|
||||
|
||||
```
|
||||
npm run watch
|
||||
npm start
|
||||
```
|
||||
|
||||
This will update `./jsoneditor.js` and `./jsoneditor.css` in the dist folder
|
||||
|
@ -134,6 +150,21 @@ jsoneditor:
|
|||
an expensive operation.
|
||||
|
||||
|
||||
## 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:
|
||||
|
@ -144,7 +175,7 @@ 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 75% of the total
|
||||
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
|
||||
|
|
32
bower.json
32
bower.json
|
@ -1,32 +0,0 @@
|
|||
{
|
||||
"name": "jsoneditor",
|
||||
"description": "A web-based tool to view, edit and format JSON",
|
||||
"tags": [
|
||||
"json",
|
||||
"editor",
|
||||
"viewer",
|
||||
"formatter"
|
||||
],
|
||||
"homepage": "http://jsoneditoronline.org/",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/josdejong/jsoneditor.git"
|
||||
},
|
||||
"main": [
|
||||
"./dist/jsoneditor.min.js",
|
||||
"./dist/jsoneditor.min.css"
|
||||
],
|
||||
"bugs": "https://github.com/josdejong/jsoneditor/issues",
|
||||
"ignore": [
|
||||
"misc",
|
||||
"node_modules",
|
||||
"test",
|
||||
"tools",
|
||||
"gulpfile.js",
|
||||
"npm-debug.log",
|
||||
".idea",
|
||||
".npmignore",
|
||||
".gitignore"
|
||||
],
|
||||
"dependencies": {}
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,929 +0,0 @@
|
|||
/* reset styling (prevent conflicts with bootstrap, materialize.css, etc.) */
|
||||
|
||||
div.jsoneditor input {
|
||||
height: auto;
|
||||
border: inherit;
|
||||
}
|
||||
|
||||
div.jsoneditor input:focus {
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
div.jsoneditor table {
|
||||
border-collapse: collapse;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
div.jsoneditor td,
|
||||
div.jsoneditor th {
|
||||
padding: 0;
|
||||
display: table-cell;
|
||||
text-align: left;
|
||||
vertical-align: inherit;
|
||||
border-radius: inherit;
|
||||
}
|
||||
|
||||
|
||||
div.jsoneditor-field,
|
||||
div.jsoneditor-value,
|
||||
div.jsoneditor-readonly {
|
||||
border: 1px solid transparent;
|
||||
min-height: 16px;
|
||||
min-width: 32px;
|
||||
padding: 2px;
|
||||
margin: 1px;
|
||||
word-wrap: break-word;
|
||||
float: left;
|
||||
}
|
||||
|
||||
/* adjust margin of p elements inside editable divs, needed for Opera, IE */
|
||||
|
||||
div.jsoneditor-field p,
|
||||
div.jsoneditor-value p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-value {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
div.jsoneditor-readonly {
|
||||
min-width: 16px;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
div.jsoneditor-empty {
|
||||
border-color: lightgray;
|
||||
border-style: dashed;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
div.jsoneditor-field.jsoneditor-empty::after,
|
||||
div.jsoneditor-value.jsoneditor-empty::after {
|
||||
pointer-events: none;
|
||||
color: lightgray;
|
||||
font-size: 8pt;
|
||||
}
|
||||
|
||||
div.jsoneditor-field.jsoneditor-empty::after {
|
||||
content: "field";
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-empty::after {
|
||||
content: "value";
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-url,
|
||||
a.jsoneditor-value.jsoneditor-url {
|
||||
color: green;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a.jsoneditor-value.jsoneditor-url {
|
||||
display: inline-block;
|
||||
padding: 2px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
a.jsoneditor-value.jsoneditor-url:hover,
|
||||
a.jsoneditor-value.jsoneditor-url:focus {
|
||||
color: #ee422e;
|
||||
}
|
||||
|
||||
div.jsoneditor td.jsoneditor-separator {
|
||||
padding: 3px 0;
|
||||
vertical-align: top;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
div.jsoneditor-field[contenteditable=true]:focus,
|
||||
div.jsoneditor-field[contenteditable=true]:hover,
|
||||
div.jsoneditor-value[contenteditable=true]:focus,
|
||||
div.jsoneditor-value[contenteditable=true]:hover,
|
||||
div.jsoneditor-field.jsoneditor-highlight,
|
||||
div.jsoneditor-value.jsoneditor-highlight {
|
||||
background-color: #FFFFAB;
|
||||
border: 1px solid yellow;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
div.jsoneditor-field.jsoneditor-highlight-active,
|
||||
div.jsoneditor-field.jsoneditor-highlight-active:focus,
|
||||
div.jsoneditor-field.jsoneditor-highlight-active:hover,
|
||||
div.jsoneditor-value.jsoneditor-highlight-active,
|
||||
div.jsoneditor-value.jsoneditor-highlight-active:focus,
|
||||
div.jsoneditor-value.jsoneditor-highlight-active:hover {
|
||||
background-color: #ffee00;
|
||||
border: 1px solid #ffc700;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-string {
|
||||
color: #008000;
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-object,
|
||||
div.jsoneditor-value.jsoneditor-array {
|
||||
min-width: 16px;
|
||||
color: #808080;
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-number {
|
||||
color: #ee422e;
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-boolean {
|
||||
color: #ff8c00;
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-null {
|
||||
color: #004ED0;
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-invalid {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree button {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
background: transparent url("img/jsoneditor-icons.svg");
|
||||
}
|
||||
|
||||
div.jsoneditor-mode-view tr.jsoneditor-expandable td.jsoneditor-tree,
|
||||
div.jsoneditor-mode-form tr.jsoneditor-expandable td.jsoneditor-tree {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree button.jsoneditor-collapsed {
|
||||
background-position: 0 -48px;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree button.jsoneditor-expanded {
|
||||
background-position: 0 -72px;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree button.jsoneditor-contextmenu {
|
||||
background-position: -48px -72px;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree button.jsoneditor-contextmenu:hover,
|
||||
div.jsoneditor-tree button.jsoneditor-contextmenu:focus,
|
||||
div.jsoneditor-tree button.jsoneditor-contextmenu.jsoneditor-selected,
|
||||
tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-contextmenu {
|
||||
background-position: -48px -48px;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree *:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree button:focus {
|
||||
/* TODO: nice outline for buttons with focus
|
||||
outline: #97B0F8 solid 2px;
|
||||
box-shadow: 0 0 8px #97B0F8;
|
||||
*/
|
||||
background-color: #f5f5f5;
|
||||
outline: #e5e5e5 solid 1px;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree button.jsoneditor-invisible {
|
||||
visibility: hidden;
|
||||
background: none;
|
||||
}
|
||||
|
||||
div.jsoneditor {
|
||||
color: #1A1A1A;
|
||||
border: 1px solid #3883fa;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree table.jsoneditor-tree {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-outer {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: -35px 0 0 0;
|
||||
padding: 35px 0 0 0;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
textarea.jsoneditor-text,
|
||||
.ace-jsoneditor {
|
||||
min-height: 150px;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
textarea.jsoneditor-text {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
outline-width: 0;
|
||||
border: none;
|
||||
background-color: white;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
tr.jsoneditor-highlight,
|
||||
tr.jsoneditor-selected {
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
|
||||
tr.jsoneditor-selected button.jsoneditor-dragarea,
|
||||
tr.jsoneditor-selected button.jsoneditor-contextmenu {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-dragarea,
|
||||
tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-contextmenu {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree button.jsoneditor-dragarea {
|
||||
background: url("img/jsoneditor-icons.svg") -72px -72px;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree button.jsoneditor-dragarea:hover,
|
||||
div.jsoneditor-tree button.jsoneditor-dragarea:focus,
|
||||
tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-dragarea {
|
||||
background-position: -72px -48px;
|
||||
}
|
||||
|
||||
div.jsoneditor tr,
|
||||
div.jsoneditor th,
|
||||
div.jsoneditor td {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.jsoneditor td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
div.jsoneditor td.jsoneditor-tree {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
div.jsoneditor-field,
|
||||
div.jsoneditor-value,
|
||||
div.jsoneditor td,
|
||||
div.jsoneditor th,
|
||||
div.jsoneditor textarea,
|
||||
.jsoneditor-schema-error {
|
||||
font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif;
|
||||
font-size: 10pt;
|
||||
color: #1A1A1A;
|
||||
}
|
||||
|
||||
/* popover */
|
||||
|
||||
.jsoneditor-schema-error {
|
||||
cursor: default;
|
||||
display: inline-block;
|
||||
/*font-family: arial, sans-serif;*/
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree .jsoneditor-schema-error {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
margin: 0 4px 0 0;
|
||||
background: url("img/jsoneditor-icons.svg") -168px -48px;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover {
|
||||
background-color: #4c4c4c;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 0 5px rgba(0,0,0,0.4);
|
||||
color: #fff;
|
||||
display: none;
|
||||
padding: 7px 10px;
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-above {
|
||||
bottom: 32px;
|
||||
left: -98px;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-below {
|
||||
top: 32px;
|
||||
left: -98px;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-left {
|
||||
top: -7px;
|
||||
right: 32px;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-right {
|
||||
top: -7px;
|
||||
left: 32px;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover:before {
|
||||
border-right: 7px solid transparent;
|
||||
border-left: 7px solid transparent;
|
||||
content: '';
|
||||
display: block;
|
||||
left: 50%;
|
||||
margin-left: -7px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-above:before {
|
||||
border-top: 7px solid #4c4c4c;
|
||||
bottom: -7px;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-below:before {
|
||||
border-bottom: 7px solid #4c4c4c;
|
||||
top: -7px;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-left:before {
|
||||
border-left: 7px solid #4c4c4c;
|
||||
border-top: 7px solid transparent;
|
||||
border-bottom: 7px solid transparent;
|
||||
content: '';
|
||||
top: 19px;
|
||||
right: -14px;
|
||||
left: inherit;
|
||||
margin-left: inherit;
|
||||
margin-top: -7px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-right:before {
|
||||
border-right: 7px solid #4c4c4c;
|
||||
border-top: 7px solid transparent;
|
||||
border-bottom: 7px solid transparent;
|
||||
content: '';
|
||||
top: 19px;
|
||||
left: -14px;
|
||||
margin-left: inherit;
|
||||
margin-top: -7px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error:hover .jsoneditor-popover,
|
||||
.jsoneditor-schema-error:focus .jsoneditor-popover {
|
||||
display: block;
|
||||
-webkit-animation: fade-in .3s linear 1, move-up .3s linear 1;
|
||||
-moz-animation: fade-in .3s linear 1, move-up .3s linear 1;
|
||||
-ms-animation: fade-in .3s linear 1, move-up .3s linear 1;
|
||||
}
|
||||
|
||||
@-webkit-keyframes fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@-moz-keyframes fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
@-ms-keyframes fade-in {
|
||||
from {
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
to {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
/*@-webkit-keyframes move-up {*/
|
||||
|
||||
/*from { bottom: 24px; }*/
|
||||
|
||||
/*to { bottom: 32px; }*/
|
||||
|
||||
/*}*/
|
||||
|
||||
/*@-moz-keyframes move-up {*/
|
||||
|
||||
/*from { bottom: 24px; }*/
|
||||
|
||||
/*to { bottom: 32px; }*/
|
||||
|
||||
/*}*/
|
||||
|
||||
/*@-ms-keyframes move-up {*/
|
||||
|
||||
/*from { bottom: 24px; }*/
|
||||
|
||||
/*to { bottom: 32px; }*/
|
||||
|
||||
/*}*/
|
||||
|
||||
/* JSON schema errors displayed at the bottom of the editor in mode text and code */
|
||||
|
||||
.jsoneditor .jsoneditor-text-errors {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background-color: #ffef8b;
|
||||
border-top: 1px solid #ffd700;
|
||||
}
|
||||
|
||||
.jsoneditor .jsoneditor-text-errors td {
|
||||
padding: 3px 6px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.jsoneditor-text-errors .jsoneditor-schema-error {
|
||||
border: none;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
margin: 0 4px 0 0;
|
||||
background: url("img/jsoneditor-icons.svg") -168px -48px;
|
||||
}
|
||||
/* ContextMenu - main menu */
|
||||
|
||||
div.jsoneditor-contextmenu-root {
|
||||
position: relative;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu {
|
||||
position: absolute;
|
||||
box-sizing: content-box;
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul,
|
||||
div.jsoneditor-contextmenu li {
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul {
|
||||
position: relative;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 124px;
|
||||
background: white;
|
||||
border: 1px solid #d3d3d3;
|
||||
box-shadow: 2px 2px 12px rgba(128, 128, 128, 0.3);
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li button {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 124px;
|
||||
height: 24px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: #4d4d4d;
|
||||
background: transparent;
|
||||
font-size: 10pt;
|
||||
font-family: arial, sans-serif;
|
||||
box-sizing: border-box;
|
||||
line-height: 26px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* Fix button padding in firefox */
|
||||
|
||||
div.jsoneditor-contextmenu ul li button::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li button:hover,
|
||||
div.jsoneditor-contextmenu ul li button:focus {
|
||||
color: #1a1a1a;
|
||||
background-color: #f5f5f5;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li button.jsoneditor-default {
|
||||
width: 92px;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li button.jsoneditor-expand {
|
||||
float: right;
|
||||
width: 32px;
|
||||
height: 24px;
|
||||
border-left: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu div.jsoneditor-icon {
|
||||
float: left;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-image: url("img/jsoneditor-icons.svg");
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li button div.jsoneditor-expand {
|
||||
float: right;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
margin: 0 4px 0 0;
|
||||
background: url("img/jsoneditor-icons.svg") 0 -72px;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li button:hover div.jsoneditor-expand,
|
||||
div.jsoneditor-contextmenu ul li button:focus div.jsoneditor-expand,
|
||||
div.jsoneditor-contextmenu ul li.jsoneditor-selected div.jsoneditor-expand,
|
||||
div.jsoneditor-contextmenu ul li button.jsoneditor-expand:hover div.jsoneditor-expand,
|
||||
div.jsoneditor-contextmenu ul li button.jsoneditor-expand:focus div.jsoneditor-expand {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu div.jsoneditor-separator {
|
||||
height: 0;
|
||||
border-top: 1px solid #e5e5e5;
|
||||
padding-top: 5px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-remove > div.jsoneditor-icon {
|
||||
background-position: -24px -24px;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-remove:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-remove:focus > div.jsoneditor-icon {
|
||||
background-position: -24px 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-append > div.jsoneditor-icon {
|
||||
background-position: 0 -24px;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-append:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-append:focus > div.jsoneditor-icon {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-insert > div.jsoneditor-icon {
|
||||
background-position: 0 -24px;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-insert:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-insert:focus > div.jsoneditor-icon {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-duplicate > div.jsoneditor-icon {
|
||||
background-position: -48px -24px;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-duplicate:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-duplicate:focus > div.jsoneditor-icon {
|
||||
background-position: -48px 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-sort-asc > div.jsoneditor-icon {
|
||||
background-position: -168px -24px;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-sort-asc:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-sort-asc:focus > div.jsoneditor-icon {
|
||||
background-position: -168px 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-sort-desc > div.jsoneditor-icon {
|
||||
background-position: -192px -24px;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-sort-desc:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-sort-desc:focus > div.jsoneditor-icon {
|
||||
background-position: -192px 0;
|
||||
}
|
||||
|
||||
/* ContextMenu - sub menu */
|
||||
|
||||
div.jsoneditor-contextmenu ul li button.jsoneditor-selected,
|
||||
div.jsoneditor-contextmenu ul li button.jsoneditor-selected:hover,
|
||||
div.jsoneditor-contextmenu ul li button.jsoneditor-selected:focus {
|
||||
color: white;
|
||||
background-color: #ee422e;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li ul {
|
||||
display: none;
|
||||
position: relative;
|
||||
left: -10px;
|
||||
top: 0;
|
||||
border: none;
|
||||
box-shadow: inset 0 0 10px rgba(128, 128, 128, 0.5);
|
||||
padding: 0 10px;
|
||||
/* TODO: transition is not supported on IE8-9 */
|
||||
-webkit-transition: all 0.3s ease-out;
|
||||
-moz-transition: all 0.3s ease-out;
|
||||
-o-transition: all 0.3s ease-out;
|
||||
transition: all 0.3s ease-out;
|
||||
}
|
||||
|
||||
|
||||
|
||||
div.jsoneditor-contextmenu ul li ul li button {
|
||||
padding-left: 24px;
|
||||
animation: all ease-in-out 1s;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li ul li button:hover,
|
||||
div.jsoneditor-contextmenu ul li ul li button:focus {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-string > div.jsoneditor-icon {
|
||||
background-position: -144px -24px;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-string:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-string:focus > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-string.jsoneditor-selected > div.jsoneditor-icon {
|
||||
background-position: -144px 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-auto > div.jsoneditor-icon {
|
||||
background-position: -120px -24px;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-auto:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-auto:focus > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-auto.jsoneditor-selected > div.jsoneditor-icon {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-object > div.jsoneditor-icon {
|
||||
background-position: -72px -24px;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-object:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-object:focus > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-object.jsoneditor-selected > div.jsoneditor-icon {
|
||||
background-position: -72px 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-array > div.jsoneditor-icon {
|
||||
background-position: -96px -24px;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-array:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-array:focus > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-array.jsoneditor-selected > div.jsoneditor-icon {
|
||||
background-position: -96px 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-modes > div.jsoneditor-icon {
|
||||
background-image: none;
|
||||
width: 6px;
|
||||
}
|
||||
div.jsoneditor-menu {
|
||||
width: 100%;
|
||||
height: 35px;
|
||||
padding: 2px;
|
||||
margin: 0;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
color: white;
|
||||
background-color: #3883fa;
|
||||
border-bottom: 1px solid #3883fa;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > button,
|
||||
div.jsoneditor-menu > div.jsoneditor-modes > button {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
margin: 2px;
|
||||
padding: 0;
|
||||
border-radius: 2px;
|
||||
border: 1px solid transparent;
|
||||
background: transparent url("img/jsoneditor-icons.svg");
|
||||
color: white;
|
||||
opacity: 0.8;
|
||||
font-family: arial, sans-serif;
|
||||
font-size: 10pt;
|
||||
float: left;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > button:hover,
|
||||
div.jsoneditor-menu > div.jsoneditor-modes > button:hover {
|
||||
background-color: rgba(255,255,255,0.2);
|
||||
border: 1px solid rgba(255,255,255,0.4);
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > button:focus,
|
||||
div.jsoneditor-menu > button:active,
|
||||
div.jsoneditor-menu > div.jsoneditor-modes > button:focus,
|
||||
div.jsoneditor-menu > div.jsoneditor-modes > button:active {
|
||||
background-color: rgba(255,255,255,0.3);
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > button:disabled,
|
||||
div.jsoneditor-menu > div.jsoneditor-modes > button:disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > button.jsoneditor-collapse-all {
|
||||
background-position: 0 -96px;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > button.jsoneditor-expand-all {
|
||||
background-position: 0 -120px;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > button.jsoneditor-undo {
|
||||
background-position: -24px -96px;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > button.jsoneditor-undo:disabled {
|
||||
background-position: -24px -120px;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > button.jsoneditor-redo {
|
||||
background-position: -48px -96px;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > button.jsoneditor-redo:disabled {
|
||||
background-position: -48px -120px;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > button.jsoneditor-compact {
|
||||
background-position: -72px -96px;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > button.jsoneditor-format {
|
||||
background-position: -72px -120px;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > div.jsoneditor-modes {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > div.jsoneditor-modes > button {
|
||||
background-image: none;
|
||||
width: auto;
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > button.jsoneditor-separator,
|
||||
div.jsoneditor-menu > div.jsoneditor-modes > button.jsoneditor-separator {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu a {
|
||||
font-family: arial, sans-serif;
|
||||
font-size: 10pt;
|
||||
color: white;
|
||||
opacity: 0.8;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu a:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu a.jsoneditor-poweredBy {
|
||||
font-size: 8pt;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
padding: 10px;
|
||||
}
|
||||
table.jsoneditor-search input,
|
||||
table.jsoneditor-search div.jsoneditor-results {
|
||||
font-family: arial, sans-serif;
|
||||
font-size: 10pt;
|
||||
color: #1A1A1A;
|
||||
background: transparent;
|
||||
/* For Firefox */
|
||||
}
|
||||
|
||||
table.jsoneditor-search div.jsoneditor-results {
|
||||
color: white;
|
||||
padding-right: 5px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
table.jsoneditor-search {
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
top: 4px;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
table.jsoneditor-search div.jsoneditor-frame {
|
||||
border: 1px solid transparent;
|
||||
background-color: white;
|
||||
padding: 0 2px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
table.jsoneditor-search div.jsoneditor-frame table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table.jsoneditor-search input {
|
||||
width: 120px;
|
||||
border: none;
|
||||
outline: none;
|
||||
margin: 1px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
table.jsoneditor-search button {
|
||||
width: 16px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background: url("img/jsoneditor-icons.svg");
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table.jsoneditor-search button:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
table.jsoneditor-search button.jsoneditor-refresh {
|
||||
width: 18px;
|
||||
background-position: -99px -73px;
|
||||
}
|
||||
|
||||
table.jsoneditor-search button.jsoneditor-next {
|
||||
cursor: pointer;
|
||||
background-position: -124px -73px;
|
||||
}
|
||||
|
||||
table.jsoneditor-search button.jsoneditor-next:hover {
|
||||
background-position: -124px -49px;
|
||||
}
|
||||
|
||||
table.jsoneditor-search button.jsoneditor-previous {
|
||||
cursor: pointer;
|
||||
background-position: -148px -73px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
|
||||
table.jsoneditor-search button.jsoneditor-previous:hover {
|
||||
background-position: -148px -49px;
|
||||
}
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,41 +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.
|
||||
|
||||
This reduces the the size of the minified and gzipped JavaScript file from
|
||||
about 160 kB to about 40 kB.
|
||||
|
||||
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.
|
||||
|
||||
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
|
||||
|
809
docs/api.md
809
docs/api.md
|
@ -35,6 +35,8 @@ Constructs a new JSONEditor.
|
|||
|
||||
Provide a custom version of the [Ace editor](http://ace.c9.io/) and use this instead of the version that comes embedded with JSONEditor. Only applicable when `mode` is `code`.
|
||||
|
||||
Note that when using the minimalist version of JSONEditor (which has Ace excluded), JSONEditor will try to load the Ace plugins `ace/mode/json` and `ace/ext/searchbox`. These plugins must be loaded beforehand or be available in the folder of the Ace editor.
|
||||
|
||||
- `{Object} ajv`
|
||||
|
||||
Provide a custom instance of [ajv](https://github.com/epoberezkin/ajv), the
|
||||
|
@ -46,15 +48,65 @@ Constructs a new JSONEditor.
|
|||
}
|
||||
```
|
||||
|
||||
- `{function} onChange`
|
||||
- `{function} onChange()`
|
||||
|
||||
Set a callback function triggered when the contents of the JSONEditor change. Called without parameters. Will only be triggered on changes made by the user, not in case of programmatic changes via the functions `set` or `setText`.
|
||||
Set a callback function triggered when the contents of the JSONEditor change.
|
||||
This callback does not pass the changed contents, use `get()` or `getText()` for that.
|
||||
Note that `get()` can throw an exception in mode `text`, `code`, or `preview`, when the editor contains invalid JSON.
|
||||
Will only be triggered on changes made by the user, not in case of programmatic changes via the functions `set`, `setText`, `update`, or `updateText`.
|
||||
See also callback functions `onChangeJSON(json)` and `onChangeText(jsonString)`.
|
||||
|
||||
- `{function} onEditable`
|
||||
- `{function} onChangeJSON(json)`
|
||||
|
||||
Set a callback function to determine whether individual nodes are editable or read-only. Only applicable when option `mode` is `tree`. The callback is invoked as `editable(node)`, where `node` is an object `{field: string, value: string, path: string[]}`. The function must either return a boolean value to set both the nodes field and value editable or read-only, or return an object `{field: boolean, value: boolean}`.
|
||||
Set a callback function triggered when the contents of the JSONEditor change.
|
||||
Passes the changed JSON document.
|
||||
Only applicable when option `mode` is `tree`, `form`, or `view`.
|
||||
The callback will only be triggered on changes made by the user, not in case of programmatic changes via the functions `set`, `setText`, `update`, or `updateText`.
|
||||
Also see the callback function `onChangeText(jsonString)`.
|
||||
|
||||
- `{function} onError`
|
||||
- `{function} onChangeText(jsonString)`
|
||||
|
||||
Set a callback function triggered when the contents of the JSONEditor change.
|
||||
Passes the changed JSON document inside a string (stringified).
|
||||
The callback will only be triggered on changes made by the user, not in case of programmatic changes via the functions `set`, `setText`, `update`, or `updateText`.
|
||||
Also see the callback function `onChangeJSON(json)`.
|
||||
|
||||
- `{function} onClassName({ path, field, value })`
|
||||
|
||||
Set a callback function to add custom CSS classes to the rendered nodes. Only applicable when option `mode` is `tree`, `form`, or `view`.
|
||||
|
||||
The callback is invoked with an object containing `path`, `field` and `value`:
|
||||
|
||||
```
|
||||
{
|
||||
path: string[],
|
||||
field: string,
|
||||
value: string
|
||||
}
|
||||
```
|
||||
The function must either return a string containing CSS class names, or return `undefined` in order to do nothing for a specific node.
|
||||
|
||||
In order to update css classes when they depend on external state, you can call `editor.refresh()`.
|
||||
|
||||
- `{function} onEditable({ path, field, value })`
|
||||
|
||||
Set a callback function to determine whether individual nodes are editable or read-only. Only applicable when option `mode` is `tree`, `text`, or `code`.
|
||||
|
||||
In case of mode `tree`, the callback is invoked as `editable(node)`, where the first parameter is an object:
|
||||
|
||||
```
|
||||
{
|
||||
field: string,
|
||||
value: string,
|
||||
path: string[]
|
||||
}
|
||||
```
|
||||
|
||||
The function must either return a boolean value to set both the nodes field and value editable or read-only, or return an object `{field: boolean, value: boolean}` to set set the read-only attribute for field and value individually.
|
||||
|
||||
In modes `text` and `code`, the callback is invoked as `editable(node)` where `node` is an empty object (no field, value, or path). In that case the function can return false to make the text or code editor completely read-only.
|
||||
|
||||
- `{function} onError(error)`
|
||||
|
||||
Set a callback function triggered when an error occurs. Invoked with the error as first argument. The callback is only invoked
|
||||
for errors triggered by a users action, like switching from code mode to tree mode or clicking the Format button whilst the editor doesn't contain valid JSON.
|
||||
|
@ -64,21 +116,131 @@ Constructs a new JSONEditor.
|
|||
Set a callback function triggered right after the mode is changed by the user. Only applicable when
|
||||
the mode can be changed by the user (i.e. when option `modes` is set).
|
||||
|
||||
- `{function} onNodeName({ path, type, size })`
|
||||
|
||||
Customize the name of object and array nodes. By default the names are brackets with the number of childs inside,
|
||||
like `{5}` and `[32]`. The number inside can be customized. using `onNodeName`.
|
||||
|
||||
The first parameter is an object containing the following properties:
|
||||
|
||||
```
|
||||
{
|
||||
path: string[],
|
||||
type: 'object' | 'array',
|
||||
size: number
|
||||
}
|
||||
```
|
||||
|
||||
The `onNodeName` function should return a string containing the name for the node. If nothing is returned,
|
||||
the size (number of childs) will be displayed.
|
||||
|
||||
- `{function} onValidate(json)`
|
||||
|
||||
Set a callback function for custom validation. Available in all modes.
|
||||
|
||||
On a change of the JSON, the callback function is invoked with the changed data. The function should return
|
||||
an array with errors or null if there are no errors. The function can also return a `Promise` resolving with
|
||||
the errors retrieved via an asynchronous validation (like sending a request to a server for validation).
|
||||
The returned errors must have the following structure: `{path: Array.<string | number>, message: string}`.
|
||||
Example:
|
||||
|
||||
```js
|
||||
var options = {
|
||||
onValidate: function (json) {
|
||||
var errors = [];
|
||||
|
||||
if (json && json.customer && !json.customer.address) {
|
||||
errors.push({
|
||||
path: ['customer'],
|
||||
message: 'Required property "address" missing.'
|
||||
});
|
||||
}
|
||||
|
||||
return errors;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Also see the option `schema` for JSON schema validation.
|
||||
|
||||
- `{function} onValidationError(errors)`
|
||||
|
||||
Set a callback function for validation and parse errors. Available in all modes.
|
||||
|
||||
On validation of the json, if errors of any kind were found this callback is invoked with the errors data.
|
||||
|
||||
On change, the callback will be invoked only if errors were changed.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
var options = {
|
||||
/**
|
||||
* @param {Array} errors validation errors
|
||||
*/
|
||||
onValidationError: function (errors) {
|
||||
errors.forEach((error) => {
|
||||
switch (error.type) {
|
||||
case 'validation': // schema validation error
|
||||
...
|
||||
break;
|
||||
case 'customValidation': // custom validation error
|
||||
...
|
||||
break;
|
||||
case 'error': // json parse error
|
||||
...
|
||||
break;
|
||||
...
|
||||
}
|
||||
});
|
||||
...
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
- `{function} onCreateMenu(items, node)`
|
||||
|
||||
Customize context menus in tree mode.
|
||||
|
||||
Sets a callback function to customize the context menu in tree mode. Each time the user clicks on the context menu button, an array of menu items is created. If this callback is configured, the array with menu items is passed to this function. The menu items can be customized in this function in any aspect of these menu items, including deleting them and/or adding new items. The function should return the final array of menu items to be displayed to the user.
|
||||
|
||||
Each menu item is represented by an object, which may also contain a submenu array of items. See the source code of example 21 in the examples folder for more info on the format of the items and submenu objects.
|
||||
|
||||
The second argument `node` is an object containing the following properties:
|
||||
|
||||
```
|
||||
{
|
||||
type: 'single' | 'multiple' | 'append'
|
||||
path: Array,
|
||||
paths: Array with paths
|
||||
}
|
||||
```
|
||||
|
||||
The property `path` containing the path of the node, and `paths` contains the same path or in case there are multiple selected nodes it contains the paths of all selected nodes.
|
||||
When the user opens the context menu of an append node (in an empty object or array), the `type` will be `'append'` and the `path` will contain the path of the parent node.
|
||||
|
||||
- `{boolean} escapeUnicode`
|
||||
|
||||
If true, unicode characters are escaped and displayed as their hexadecimal code (like `\u260E`) instead of of the character itself (like `☎`). False by default.
|
||||
If `true`, unicode characters are escaped and displayed as their hexadecimal code (like `\u260E`) instead of of the character itself (like `☎`). `false` by default.
|
||||
|
||||
- `{boolean} sortObjectKeys`
|
||||
|
||||
If true, object keys in 'tree', 'view' or 'form' mode list be listed alphabetically instead by their insertion order. Sorting is performed using a natural sort algorithm, which makes it easier to see objects that have string numbers as keys. False by default.
|
||||
If `true`, object keys in 'tree', 'view' or 'form' mode list be listed alphabetically instead by their insertion order. Sorting is performed using a natural sort algorithm, which makes it easier to see objects that have string numbers as keys. `false` by default.
|
||||
|
||||
- `{boolean} limitDragging`
|
||||
|
||||
If `false`, nodes can be dragged from any parent node to any other parent node. If `true`, nodes can only be dragged inside the same parent node, which effectively only allows reordering of nodes. By default, `limitDragging` is `true` when no JSON `schema` is defined, and `false` otherwise.
|
||||
|
||||
- `{boolean} history`
|
||||
|
||||
Enables history, adds a button Undo and Redo to the menu of the JSONEditor. True by default. Only applicable when `mode` is 'tree' or 'form'.
|
||||
Enables history, adds a button Undo and Redo to the menu of the JSONEditor. `true` by default. Only applicable when `mode` is `'tree'`, `'form'`, or `'preview'`.
|
||||
|
||||
- `{String} mode`
|
||||
|
||||
Set the editor mode. Available values: 'tree' (default), 'view', 'form', 'code', 'text'. In 'view' mode, the data and datastructure is read-only. In 'form' mode, only the value can be changed, the datastructure is read-only. Mode 'code' requires the Ace editor to be loaded on the page. Mode 'text' shows the data as plain text.
|
||||
Set the editor mode. Available values: 'tree' (default), 'view', 'form', 'code', 'text', 'preview'. In 'view' mode, the data and datastructure is read-only. In 'form' mode, only the value can be changed, the data structure is read-only. Mode 'code' requires the Ace editor to be loaded on the page. Mode 'text' shows the data as plain text.
|
||||
The 'preview' mode can handle large JSON documents up to 500 MiB. It shows a preview of the data, and allows to
|
||||
transform, sort, filter, format, or compact the data.
|
||||
|
||||
- `{String[]} modes`
|
||||
|
||||
|
@ -86,7 +248,7 @@ Constructs a new JSONEditor.
|
|||
|
||||
- `{String} name`
|
||||
|
||||
Initial field name for the root node, is undefined by default. Can also be set using `JSONEditor.setName(name)`. Only applicable when `mode` is 'tree', 'view', or 'form'.
|
||||
Initial field name for the root node, is `undefined` by default. Can also be set using `JSONEditor.setName(name)`. Only applicable when `mode` is 'tree', 'view', or 'form'.
|
||||
|
||||
- `{Object} schema`
|
||||
|
||||
|
@ -96,17 +258,397 @@ Constructs a new JSONEditor.
|
|||
|
||||
See [http://json-schema.org/](http://json-schema.org/) for more information.
|
||||
|
||||
Also see the option `onValidate` for custom validation.
|
||||
|
||||
- `{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}`
|
||||
|
||||
- `{boolean} search`
|
||||
|
||||
Enables a search box in the upper right corner of the JSONEditor. True by default. Only applicable when `mode` is 'tree', 'view', or 'form'.
|
||||
Enables a search box in the upper right corner of the JSONEditor. `true` by default. Only applicable when `mode` is 'tree', 'view', or 'form'.
|
||||
|
||||
- `{Number} indentation`
|
||||
|
||||
Number of indentation spaces. 2 by default. Only applicable when `mode` is 'code' or 'text'.
|
||||
Number of indentation spaces. `2` by default. Only applicable when `mode` is 'code', 'text', or 'preview'.
|
||||
|
||||
- `{String} theme`
|
||||
|
||||
Set the Ace editor theme, uses included 'ace/theme/jsoneditor' by default. Please note that only the default theme is included with jsoneditor, so if you specify another one you need to make sure it is loaded.
|
||||
Set the Ace editor theme, uses included 'ace/theme/jsoneditor' by default. Please note that only the default theme is included with JSONEditor, so if you specify another one you need to make sure it is loaded.
|
||||
|
||||
- `{Object} templates`
|
||||
|
||||
Array of templates that will appear in the context menu, Each template is a json object precreated that can be added as a object value to any node in your document.
|
||||
|
||||
The following example allow you can create a "Person" node and a "Address" node, each one will appear in your context menu, once you selected the whole json object will be created.
|
||||
|
||||
```js
|
||||
var 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': ""
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
- `{Object} autocomplete`
|
||||
|
||||
*autocomplete* will enable this feature in your editor in tree mode, the object have the following **subelements**:
|
||||
|
||||
- `{string} filter`
|
||||
- `{Function} filter`
|
||||
|
||||
Indicate the filter method of the autocomplete. Default to `start`.
|
||||
|
||||
- `start` : Match your input from the start, e.g. `ap` match `apple` but `pl` does not.
|
||||
- `contain` : Contain your input or not, e.g. `pl` match `apple` too.
|
||||
- Custom Function : Define custom filter rule, return `true` will match you input.
|
||||
|
||||
- `{string} trigger`
|
||||
|
||||
Indicate the way to trigger autocomplete menu. Default to `keydown`
|
||||
|
||||
- `keydown` : When you type something in the field or value, it will trigger autocomplete.
|
||||
- `focus` : When you focus in the field or value, it will trigger the autocomplete.
|
||||
|
||||
- `{number[]} confirmKeys`
|
||||
|
||||
Indicate the KeyCodes for trigger confirm completion, by default those keys are: `[39, 35, 9]` which are the code for [right, end, tab]
|
||||
|
||||
- `{boolean} caseSensitive`
|
||||
|
||||
Indicate if the autocomplete is going to be strict case-sensitive to match the options.
|
||||
|
||||
- `{Function} getOptions (text: string, path: string[], input: string, editor: JSONEditor)`
|
||||
|
||||
This function will return your possible options for create the autocomplete selection, you can control dynamically which options you want to display according to the current active editing node.
|
||||
|
||||
*Parameters:*
|
||||
|
||||
- `text` : The text in the current node part. (basically the text that the user is editing)
|
||||
- `path` : The path of the node that is being edited as an array with strings.
|
||||
- `input` : Can be "field" or "value" depending if the user is editing a field name or a value of a node.
|
||||
- `editor` : The editor instance object that is being edited.
|
||||
|
||||
*Returns:*
|
||||
|
||||
- Can return an array with autocomplete options (strings), for example `['apple','cranberry','raspberry','pie']`
|
||||
- Can return `null` when there are no autocomplete options.
|
||||
- Can return an object `{startFrom: number, options: string[]}`. Here `startFrom` determines the start character from where the existing text will be replaced. `startFrom` is `0` by default, replacing the whole text.
|
||||
- Can return a `Promise` resolving one of the return types above to support asynchronously retrieving a list with options.
|
||||
|
||||
- `{boolean} mainMenuBar`
|
||||
|
||||
Adds main menu bar - Contains format, sort, transform, search etc. functionality. `true` by default. Applicable in all types of `mode`.
|
||||
|
||||
- `{boolean} navigationBar`
|
||||
|
||||
Adds navigation bar to the menu - the navigation bar visualize the current position on the tree structure as well as allows breadcrumbs navigation. `true` by default. Only applicable when `mode` is 'tree', 'form' or 'view'.
|
||||
|
||||
- `{boolean} statusBar`
|
||||
|
||||
Adds status bar to the bottom of the editor - the status bar shows the cursor position and a count of the selected characters. `true` by default. Only applicable when `mode` is 'code', 'text', or 'preview'.
|
||||
|
||||
- `{function} onTextSelectionChange(start, end, text)`
|
||||
|
||||
Set a callback function triggered when a text is selected in the JSONEditor.
|
||||
|
||||
callback signature should be:
|
||||
```js
|
||||
/**
|
||||
* @param {{row:Number, column:Number}} start Selection start position
|
||||
* @param {{row:Number, column:Number}} end Selected end position
|
||||
* @param {String} text selected text
|
||||
*/
|
||||
function onTextSelectionChange(start, end, text) {
|
||||
...
|
||||
}
|
||||
```
|
||||
Only applicable when `mode` is 'code' or 'text'.
|
||||
|
||||
- `{function} onSelectionChange(start, end)`
|
||||
|
||||
Set a callback function triggered when Nodes are selected in the JSONEditor.
|
||||
|
||||
callback signature should be:
|
||||
```js
|
||||
/**
|
||||
* @typedef {{value: String|Object|Number|Boolean, path: Array.<String|Number>}} SerializableNode
|
||||
*
|
||||
* @param {SerializableNode=} start
|
||||
* @param {SerializableNode=} end
|
||||
*/
|
||||
function onSelectionChange(start, end) {
|
||||
...
|
||||
}
|
||||
```
|
||||
Only applicable when `mode` is 'tree'.
|
||||
|
||||
- `{function} onEvent({ field, path, value? }, event)`
|
||||
|
||||
Set a callback function that will be triggered when an event will occur in
|
||||
a JSON field or value.
|
||||
|
||||
In case of field event, node information will be
|
||||
|
||||
```
|
||||
{
|
||||
field: string,
|
||||
path: {string|number}[]
|
||||
}
|
||||
```
|
||||
|
||||
In case of value event, node information will be
|
||||
|
||||
```
|
||||
{
|
||||
field: string,
|
||||
path: {string|number}[],
|
||||
value: string
|
||||
}
|
||||
```
|
||||
|
||||
signature should be:
|
||||
```js
|
||||
/**
|
||||
* @param {Node} the Node where event has been triggered
|
||||
identified by {field: string, path: {string|number}[] [, value: string]}`
|
||||
* @param {event} the event fired
|
||||
*/
|
||||
function onEvent(node, event) {
|
||||
...
|
||||
}
|
||||
```
|
||||
Only applicable when `mode` is 'form', 'tree' or 'view'.
|
||||
|
||||
- `{function} onFocus({ type: 'focus', target })`
|
||||
Callback method, triggered when the editor comes into focus,
|
||||
passing an object `{type, target}`, Applicable for all modes.
|
||||
|
||||
- `{function} onBlur({ type: 'blur', target })`
|
||||
Callback method, triggered when the editor goes out of focus,
|
||||
passing an object `{type, target}`, Applicable for all modes.
|
||||
|
||||
- `{boolean} colorPicker`
|
||||
|
||||
If `true` (default), values containing a color name or color code will have a color picker rendered on their left side.
|
||||
|
||||
- `{function} onColorPicker(parent, color, onChange)`
|
||||
|
||||
Callback function triggered when the user clicks a color.
|
||||
Can be used to implement a custom color picker.
|
||||
The callback is invoked with three arguments:
|
||||
`parent` is an HTML element where the color picker can be attached,
|
||||
`color` is the current color,
|
||||
`onChange(newColor)` is a callback which has to be invoked with the new color selected in the color picker.
|
||||
JSONEditor comes with a built-in color picker, powered by [vanilla-picker](https://github.com/Sphinxxxx/vanilla-picker).
|
||||
|
||||
A simple example of `onColorPicker` using `vanilla-picker`:
|
||||
|
||||
```js
|
||||
var options = {
|
||||
onColorPicker: function (parent, color, onChange) {
|
||||
new VanillaPicker({
|
||||
parent: parent,
|
||||
color: color,
|
||||
onDone: function (color) {
|
||||
onChange(color.hex)
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- `{boolean | function({field, value, path}) -> boolean} timestampTag`
|
||||
|
||||
If `true` (default), a tag with the date/time of a timestamp is displayed
|
||||
right from values containing a timestamp. By default, a value is
|
||||
considered a timestamp when it is an integer number with a value larger
|
||||
than Jan 1th 2000, `946684800000`.
|
||||
|
||||
When `timestampTag` a is a function, a timestamp tag will be displayed when
|
||||
this function returns `true`, and no timestamp is displayed when the function
|
||||
returns `false`. When the function returns a non-boolean value like `null`
|
||||
or `undefined`, JSONEditor will fallback on the built-in rules to determine
|
||||
whether or not to show a timestamp.
|
||||
|
||||
The function is invoked with an object as first parameter:
|
||||
|
||||
```
|
||||
{
|
||||
field: string,
|
||||
value: string,
|
||||
path: string[]
|
||||
}
|
||||
```
|
||||
|
||||
Whether a value is a timestamp can be determined implicitly based on
|
||||
the `value`, or explicitly based on `field` or `path`. You can for example
|
||||
test whether a field name contains a string like: `'date'` or `'time'`.
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
var options = {
|
||||
timestampTag: function ({ field, value, path }) {
|
||||
if (field === 'dateCreated') {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Only applicable for modes `tree`, `form`, and `view`.
|
||||
|
||||
- `{ function({field, value, path}) -> string|null } timestampFormat`
|
||||
|
||||
Customizing the way formating the timestamp. Called when a value is timestamp after `timestampTag`. If it returns null, the timestamp would be formatted with default setting (`new Date(value).toISOString()`).
|
||||
|
||||
parameter:
|
||||
|
||||
```
|
||||
{
|
||||
field: string,
|
||||
value: string,
|
||||
path: string[]
|
||||
}
|
||||
```
|
||||
|
||||
Example:
|
||||
|
||||
```js
|
||||
var options = {
|
||||
timestampFormat: function ({ field, value, path }) {
|
||||
if (field === 'customTime') {
|
||||
return new Date(value*1000).toString()
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Only applicable for modes `tree`, `form`, and `view`.
|
||||
|
||||
- `{string} language`
|
||||
|
||||
The default language comes from the browser navigator, but you can force a specific language. So use here string as 'en' or 'pt-BR'. Built-in languages: `en`, `zh-CN`, `pt-BR`, `tr`, `ja`, `fr-FR`, `de`. Other translations can be specified via the option `languages`.
|
||||
|
||||
- `{Object} languages`
|
||||
|
||||
You can override existing translations or provide a new translation for a specific language. To do it provide an object at languages with language and the keys/values to be inserted. For example:
|
||||
|
||||
```
|
||||
'languages': {
|
||||
'pt-BR': {
|
||||
'auto': 'Automático testing'
|
||||
},
|
||||
'en': {
|
||||
'auto': 'Auto testing'
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
All available fields for translation can be found in the source file `src/js/i18n.js`.
|
||||
|
||||
- `{HTMLElement} modalAnchor`
|
||||
|
||||
The container element where modals (like for sorting and filtering) are attached: an overlay will be created on top
|
||||
of this container, and the modal will be created in the center of this container.
|
||||
|
||||
- `{HTMLElement} popupAnchor`
|
||||
|
||||
The container element where popups (for example drop down menus, for JSON Schema error
|
||||
tooltips, and color pickers) will be absolutely positioned.
|
||||
By default, this is the root DIV element of the editor itself.
|
||||
|
||||
When the JSONEditor is inside a DIV element which hides overflowing contents
|
||||
(CSS `overflow: auto` or `overflow: hidden`), tooltips will be visible only partly.
|
||||
In this case, a `popupAnchor` outside of the element without hidden overflow will allow
|
||||
the tooltips to be visible when overflowing the DIV element of the JSONEditor.
|
||||
|
||||
- `{boolean} enableSort`
|
||||
|
||||
Enable sorting of arrays and object properties. Only applicable for mode 'tree'. `true` by default.
|
||||
|
||||
- `{boolean} enableTransform`
|
||||
|
||||
Enable filtering, sorting, and transforming JSON using a [JMESPath](http://jmespath.org/) query. Only applicable for mode 'tree'. `true` by default.
|
||||
|
||||
- `{Number} maxVisibleChilds`
|
||||
|
||||
Number of children allowed for a given node before the "show more / show all" message appears (in 'tree', 'view', or 'form' modes). `100` by default.
|
||||
|
||||
- `{ function(json: JSON, queryOptions: QueryOptions) -> string } createQuery`
|
||||
|
||||
Create a query string based on query options filled in the Transform Wizard in the Transform modal.
|
||||
Normally used in combination with `executeQuery`.
|
||||
The input for the function are the entered query options and the current JSON, and the output
|
||||
must be a string containing the query. This query will be executed using `executeQuery`.
|
||||
|
||||
The query options have the following structure:
|
||||
|
||||
```
|
||||
interface QueryOptions {
|
||||
filter?: {
|
||||
field: string | '@'
|
||||
relation: '==' | '!=' | '<' | '<=' | '>' | '>='
|
||||
value: string
|
||||
}
|
||||
sort?: {
|
||||
field: string | '@'
|
||||
direction: 'asc' | 'desc'
|
||||
}
|
||||
projection?: {
|
||||
fields: string[]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note that there is a special case `'@'` for `filter.field` and `sort.field`.
|
||||
It means that the field itself is selected, for example when having an array containing numbers.
|
||||
|
||||
A usage example can be found in `examples/23_custom_query_language.html`.
|
||||
|
||||
|
||||
- `{ function(json: JSON, query: string) -> JSON } executeQuery`
|
||||
|
||||
Replace the build-in query language used in the Transform modal with a custom language.
|
||||
Normally used in combination with `createQuery`.
|
||||
The input for the function is the current JSON and a query string, and output must be the transformed JSON.
|
||||
|
||||
A usage example can be found in `examples/23_custom_query_language.html`.
|
||||
|
||||
- `{string} queryDescription`
|
||||
|
||||
A text description displayed on top of the Transform modal.
|
||||
Can be used to explain a custom query language implemented via `createQuery` and `executeQuery`.
|
||||
The text can contain HTML code like a link to a web page.
|
||||
|
||||
A usage example can be found in `examples/23_custom_query_language.html`.
|
||||
|
||||
|
||||
### Methods
|
||||
|
@ -127,66 +669,12 @@ Expand all fields. Only applicable for mode 'tree', 'view', and 'form'.
|
|||
|
||||
Set focus to the JSONEditor.
|
||||
|
||||
#### `JSONEditor.set(json)`
|
||||
|
||||
Set JSON data.
|
||||
|
||||
*Parameters:*
|
||||
|
||||
- `{JSON} json`
|
||||
|
||||
JSON data to be displayed in the JSONEditor.
|
||||
|
||||
#### `JSONEditor.setMode(mode)`
|
||||
|
||||
Switch mode. Mode `code` requires the [Ace editor](http://ace.ajax.org/).
|
||||
|
||||
*Parameters:*
|
||||
|
||||
- `{String} mode`
|
||||
|
||||
Available values: `tree`, `view`, `form`, `code`, `text`.
|
||||
|
||||
#### `JSONEditor.setName(name)`
|
||||
|
||||
Set a field name for the root node.
|
||||
|
||||
*Parameters:*
|
||||
|
||||
- `{String | undefined} name`
|
||||
|
||||
Field name of the root node. If undefined, the current name will be removed.
|
||||
|
||||
#### `JSONEditor.setSchema(schema)`
|
||||
|
||||
Set a JSON schema for validation of the JSON object. See also option `schema`.
|
||||
See [http://json-schema.org/](http://json-schema.org/) for more information on the JSON schema definition.
|
||||
|
||||
*Parameters:*
|
||||
|
||||
- `{Object} schema`
|
||||
|
||||
A JSON schema.
|
||||
|
||||
#### `JSONEditor.setText(jsonString)`
|
||||
|
||||
Set text data in the editor.
|
||||
|
||||
This method throws an exception when the provided jsonString does not contain
|
||||
valid JSON and the editor is in mode `tree`, `view`, or `form`.
|
||||
|
||||
*Parameters:*
|
||||
|
||||
- `{String} jsonString`
|
||||
|
||||
Contents of the editor as string.
|
||||
|
||||
#### `JSONEditor.get()`
|
||||
|
||||
Get JSON data.
|
||||
|
||||
This method throws an exception when the editor does not contain valid JSON,
|
||||
which can be the case when the editor is in mode `code` or `text`.
|
||||
which can be the case when the editor is in mode `code`, `text`, or `preview`.
|
||||
|
||||
*Returns:*
|
||||
|
||||
|
@ -202,7 +690,7 @@ Retrieve the current mode of the editor.
|
|||
|
||||
- `{String} mode`
|
||||
|
||||
Current mode of the editor for example `tree` or `code`.
|
||||
Current mode of the editor, for example `tree` or `code`.
|
||||
|
||||
#### `JSONEditor.getName()`
|
||||
|
||||
|
@ -214,6 +702,30 @@ Retrieve the current field name of the root node.
|
|||
|
||||
Current field name of the root node, or undefined if not set.
|
||||
|
||||
#### `JSONEditor.getNodesByRange(start, end)`
|
||||
|
||||
A utility function for getting a list of `SerializableNode` under certain range.
|
||||
|
||||
This function can be used as complementary to `getSelection` and `onSelectionChange` if a list of __all__ the selected nodes is required.
|
||||
|
||||
*Parameters:*
|
||||
|
||||
- `{path: Array.<String>} start`
|
||||
|
||||
Path for the first node in range
|
||||
|
||||
- `{path: Array.<String>} end`
|
||||
|
||||
Path for the last node in range
|
||||
|
||||
#### `JSONEditor.getSelection()`
|
||||
|
||||
Get the current selected nodes, Only applicable for mode 'tree'.
|
||||
|
||||
*Returns:*
|
||||
|
||||
- `{start:SerializableNode, end: SerializableNode}`
|
||||
|
||||
#### `JSONEditor.getText()`
|
||||
|
||||
Get JSON data as string.
|
||||
|
@ -222,11 +734,166 @@ Get JSON data as string.
|
|||
|
||||
- `{String} jsonString`
|
||||
|
||||
Contents of the editor as string. When the editor is in code `text` or `code`,
|
||||
Contents of the editor as string. When the editor is in code `text`, `code` or `preview`,
|
||||
the returned text is returned as-is. For the other modes, the returned text
|
||||
is a compacted string. In order to get the JSON formatted with a certain
|
||||
number of spaces, use `JSON.stringify(JSONEditor.get(), null, 2)`.
|
||||
|
||||
#### `JSONEditor.getTextSelection()`
|
||||
|
||||
Get the current selected text with the selection range, Only applicable for mode 'text' and 'code'.
|
||||
|
||||
*Returns:*
|
||||
|
||||
- `{start:{row:Number, column:Number},end:{row:Number, column:Number},text:String} selection`
|
||||
|
||||
|
||||
#### `JSONEditor.refresh()`
|
||||
|
||||
Force the editor to refresh the user interface and update all rendered HTML. This can be useful for example when using `onClassName` and the returned class name depends on external factors.
|
||||
|
||||
|
||||
#### `JSONEditor.set(json)`
|
||||
|
||||
Set JSON data.
|
||||
Resets the state of the editor (expanded nodes, search, selection).
|
||||
See also `JSONEditor.update(json)`.
|
||||
|
||||
*Parameters:*
|
||||
|
||||
- `{JSON} json`
|
||||
|
||||
JSON data to be displayed in the JSONEditor.
|
||||
|
||||
#### `JSONEditor.setMode(mode)`
|
||||
|
||||
Switch mode. Mode `code` requires the [Ace editor](https://ace.c9.io/).
|
||||
|
||||
*Parameters:*
|
||||
|
||||
- `{String} mode`
|
||||
|
||||
Available values: `tree`, `view`, `form`, `code`, `text`, `preview`.
|
||||
|
||||
#### `JSONEditor.setName(name)`
|
||||
|
||||
Set a field name for the root node.
|
||||
|
||||
*Parameters:*
|
||||
|
||||
- `{String | undefined} name`
|
||||
|
||||
Field name of the root node. If undefined, the current name will be removed.
|
||||
|
||||
#### `JSONEditor.setSchema(schema [,schemaRefs])`
|
||||
|
||||
Set a JSON schema for validation of the JSON object. See also option `schema`.
|
||||
See [http://json-schema.org/](http://json-schema.org/) for more information on the JSON schema definition.
|
||||
|
||||
*Parameters:*
|
||||
|
||||
- `{Object} schema`
|
||||
|
||||
A JSON schema.
|
||||
|
||||
- `{Object} schemaRefs`
|
||||
|
||||
Optional, Schemas that are referenced using the `$ref` property from the JSON schema, the object structure in the form of `{reference_key: schemaObject}`
|
||||
|
||||
#### `JSONEditor.setSelection(start, end)`
|
||||
|
||||
Set selection for a range of nodes, Only applicable for mode 'tree'.
|
||||
|
||||
- If no parameters sent - the current selection will be removed, if exists.
|
||||
- For single node selecion send only the `start` parameter.
|
||||
- If the nodes are not from the same level the first common parent will be selected
|
||||
|
||||
*Parameters:*
|
||||
|
||||
- `{path: Array.<String>} start`
|
||||
|
||||
Path for the start node
|
||||
|
||||
- `{path: Array.<String>} end`
|
||||
|
||||
Path for the end node
|
||||
|
||||
#### `JSONEditor.setText(jsonString)`
|
||||
|
||||
Set text data in the editor.
|
||||
|
||||
This method throws an exception when the provided jsonString does not contain
|
||||
valid JSON and the editor is in mode `tree`, `view`, or `form`.
|
||||
|
||||
*Parameters:*
|
||||
|
||||
- `{String} jsonString`
|
||||
|
||||
Contents of the editor as string.
|
||||
|
||||
#### `JSONEditor.setTextSelection(startPos, endPos)`
|
||||
|
||||
Set text selection for a range, Only applicable for mode 'text' and 'code'.
|
||||
|
||||
*Parameters:*
|
||||
|
||||
- `{row:Number, column:Number} startPos`
|
||||
|
||||
Position for selection start
|
||||
|
||||
- `{row:Number, column:Number} endPos`
|
||||
|
||||
Position for selection end
|
||||
|
||||
#### `JSONEditor.update(json)`
|
||||
|
||||
Replace JSON data when the new data contains changes.
|
||||
In modes `tree`, `form`, and `view`, the state of the editor will be maintained (expanded nodes, search, selection).
|
||||
See also `JSONEditor.set(json)`.
|
||||
|
||||
*Parameters:*
|
||||
|
||||
- `{JSON} json`
|
||||
|
||||
JSON data to be displayed in the JSONEditor.
|
||||
|
||||
#### `JSONEditor.updateText (json)`
|
||||
|
||||
Replace text data when the new data contains changes.
|
||||
In modes `tree`, `form`, and `view`, the state of the editor will be maintained (expanded nodes, search, selection).
|
||||
Also see `JSONEditor.setText(jsonString)`.
|
||||
|
||||
This method throws an exception when the provided jsonString does not contain
|
||||
valid JSON and the editor is in mode `tree`, `view`, or `form`.
|
||||
|
||||
*Parameters:*
|
||||
|
||||
- `{String} jsonString`
|
||||
|
||||
Contents of the editor as string.
|
||||
|
||||
### Static properties
|
||||
|
||||
- `{string[]} JSONEditor.VALID_OPTIONS`
|
||||
|
||||
An array with the names of all known options.
|
||||
|
||||
- `{object} ace`
|
||||
|
||||
Access to the bundled Ace editor, via the [`brace` library](https://github.com/thlorenz/brace).
|
||||
Ace is used in code mode.
|
||||
Same as `var ace = require('brace');`.
|
||||
|
||||
- `{function} Ajv`
|
||||
|
||||
Access to the bundled [`ajv` library](https://github.com/epoberezkin/ajv), used for JSON schema validation.
|
||||
Same as `var Ajv = require('ajv');`.
|
||||
|
||||
- `{function} VanillaPicker`
|
||||
|
||||
Access to the bundled [`vanilla-picker` library](https://github.com/Sphinxxxx/vanilla-picker), used as color picker.
|
||||
Same as `var VanillaPicker = require('vanilla-picker');`.
|
||||
|
||||
|
||||
### Examples
|
||||
|
||||
|
@ -275,7 +942,7 @@ var json = editor.get();
|
|||
|
||||
## JSON parsing and stringification
|
||||
|
||||
In general to parse or stringify JSON data, the browsers built in JSON parser can be used. To create a formatted string from a JSON object, use:
|
||||
In general, to parse or stringify JSON data, the browsers built in JSON parser can be used. To create a formatted string from a JSON object, use:
|
||||
|
||||
```js
|
||||
var formattedString = JSON.stringify(json, null, 2);
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# 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
|
|
@ -2,21 +2,10 @@
|
|||
|
||||
### Install
|
||||
|
||||
with npm:
|
||||
Install via npm:
|
||||
|
||||
npm install jsoneditor
|
||||
|
||||
with bower:
|
||||
|
||||
bower install jsoneditor
|
||||
|
||||
download:
|
||||
|
||||
[http://jsoneditoronline.org/downloads/](http://jsoneditoronline.org/downloads/)
|
||||
|
||||
The library consists of three files: one javascript file, one css file and an
|
||||
image. Both full and minified version are available.
|
||||
|
||||
## Load
|
||||
|
||||
To implement JSONEditor in a web application, load the javascript and css file
|
||||
|
@ -29,7 +18,7 @@ in the head of the HTML page:
|
|||
|
||||
## Use
|
||||
|
||||
In the body, create an div element with an id and a size:
|
||||
In the body, create a div element with an id and a size:
|
||||
|
||||
```html
|
||||
<div id="jsoneditor" style="width: 400px; height: 400px;"></div>
|
||||
|
@ -70,10 +59,10 @@ var json = editor.get();
|
|||
|
||||
```html
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<!-- when using the mode "code", it's important to specify charset utf-8 -->
|
||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
|
||||
<meta charset="utf-8">
|
||||
|
||||
<link href="jsoneditor/dist/jsoneditor.min.css" rel="stylesheet" type="text/css">
|
||||
<script src="jsoneditor/dist/jsoneditor.min.js"></script>
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>JSONEditor | Basic usage</title>
|
||||
|
||||
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
|
||||
|
@ -22,28 +24,31 @@
|
|||
|
||||
<script>
|
||||
// create the editor
|
||||
var container = document.getElementById('jsoneditor');
|
||||
var options = {};
|
||||
var editor = new JSONEditor(container, options);
|
||||
const container = document.getElementById('jsoneditor')
|
||||
const options = {}
|
||||
const editor = new JSONEditor(container, options)
|
||||
|
||||
// set json
|
||||
document.getElementById('setJSON').onclick = function () {
|
||||
var json = {
|
||||
const json = {
|
||||
'array': [1, 2, 3],
|
||||
'boolean': true,
|
||||
'color': '#82b92c',
|
||||
'null': null,
|
||||
'number': 123,
|
||||
'object': {'a': 'b', 'c': 'd'},
|
||||
'string': 'Hello World'
|
||||
};
|
||||
editor.set(json);
|
||||
};
|
||||
'time': 1575599819000,
|
||||
'string': 'Hello World',
|
||||
'onlineDemo': 'https://jsoneditoronline.org/'
|
||||
}
|
||||
editor.set(json)
|
||||
}
|
||||
|
||||
// get json
|
||||
document.getElementById('getJSON').onclick = function () {
|
||||
var json = editor.get();
|
||||
alert(JSON.stringify(json, null, 2));
|
||||
};
|
||||
const json = editor.get()
|
||||
alert(JSON.stringify(json, null, 2))
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>JSONEditor | Viewer</title>
|
||||
|
||||
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
|
||||
|
@ -23,22 +25,22 @@
|
|||
<div id="jsoneditor"></div>
|
||||
|
||||
<script>
|
||||
var container = document.getElementById('jsoneditor');
|
||||
const container = document.getElementById('jsoneditor')
|
||||
|
||||
var options = {
|
||||
const options = {
|
||||
mode: 'view'
|
||||
};
|
||||
}
|
||||
|
||||
var json = {
|
||||
const json = {
|
||||
'array': [1, 2, 3],
|
||||
'boolean': true,
|
||||
'null': null,
|
||||
'number': 123,
|
||||
'object': {'a': 'b', 'c': 'd'},
|
||||
'string': 'Hello World'
|
||||
};
|
||||
}
|
||||
|
||||
var editor = new JSONEditor(container, options, json);
|
||||
const editor = new JSONEditor(container, options, json)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>JSONEditor | Switch mode</title>
|
||||
|
||||
<!-- when using the mode "code", it's important to specify charset utf-8 -->
|
||||
<meta http-equiv="Content-Type" content="text/html;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>
|
||||
|
@ -38,29 +38,29 @@
|
|||
<div id="jsoneditor"></div>
|
||||
|
||||
<script>
|
||||
var container = document.getElementById('jsoneditor');
|
||||
const container = document.getElementById('jsoneditor')
|
||||
|
||||
var options = {
|
||||
const options = {
|
||||
mode: 'tree',
|
||||
modes: ['code', 'form', 'text', 'tree', 'view'], // allowed modes
|
||||
modes: ['code', 'form', 'text', 'tree', 'view', 'preview'], // allowed modes
|
||||
onError: function (err) {
|
||||
alert(err.toString());
|
||||
alert(err.toString())
|
||||
},
|
||||
onModeChange: function (newMode, oldMode) {
|
||||
console.log('Mode switched from', oldMode, 'to', newMode);
|
||||
console.log('Mode switched from', oldMode, 'to', newMode)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var json = {
|
||||
const json = {
|
||||
"array": [1, 2, 3],
|
||||
"boolean": true,
|
||||
"null": null,
|
||||
"number": 123,
|
||||
"object": {"a": "b", "c": "d"},
|
||||
"string": "Hello World"
|
||||
};
|
||||
}
|
||||
|
||||
var editor = new JSONEditor(container, options, json);
|
||||
const editor = new JSONEditor(container, options, json)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>JSONEditor | Load and save</title>
|
||||
|
||||
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
|
||||
|
@ -38,36 +40,36 @@
|
|||
|
||||
<script>
|
||||
// create the editor
|
||||
var editor = new JSONEditor(document.getElementById('jsoneditor'));
|
||||
const editor = new JSONEditor(document.getElementById('jsoneditor'))
|
||||
|
||||
// Load a JSON document
|
||||
FileReaderJS.setupInput(document.getElementById('loadDocument'), {
|
||||
readAsDefault: 'Text',
|
||||
on: {
|
||||
load: function (event, file) {
|
||||
editor.setText(event.target.result);
|
||||
editor.setText(event.target.result)
|
||||
}
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
// Save a JSON document
|
||||
document.getElementById('saveDocument').onclick = function () {
|
||||
// Save Dialog
|
||||
fname = window.prompt("Save as...");
|
||||
let fname = window.prompt("Save as...")
|
||||
|
||||
// Check json extension in file name
|
||||
if(fname.indexOf(".")==-1){
|
||||
fname = fname + ".json";
|
||||
}else{
|
||||
if(fname.split('.').pop().toLowerCase() == "json"){
|
||||
if (fname.indexOf(".") === -1) {
|
||||
fname = fname + ".json"
|
||||
} else {
|
||||
if (fname.split('.').pop().toLowerCase() === "json") {
|
||||
// Nothing to do
|
||||
}else{
|
||||
fname = fname.split('.')[0] + ".json";
|
||||
} else {
|
||||
fname = fname.split('.')[0] + ".json"
|
||||
}
|
||||
}
|
||||
var blob = new Blob([editor.getText()], {type: 'application/json;charset=utf-8'});
|
||||
saveAs(blob, fname);
|
||||
};
|
||||
const blob = new Blob([editor.getText()], {type: 'application/json;charset=utf-8'})
|
||||
saveAs(blob, fname)
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<!DOCTYPE HTML>
|
||||
<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">
|
||||
|
@ -25,9 +27,9 @@
|
|||
<div id="jsoneditor"></div>
|
||||
|
||||
<script>
|
||||
var container = document.getElementById('jsoneditor');
|
||||
const container = document.getElementById('jsoneditor')
|
||||
|
||||
var options = {
|
||||
const options = {
|
||||
onEditable: function (node) {
|
||||
// node is an object like:
|
||||
// {
|
||||
|
@ -37,27 +39,27 @@
|
|||
// }
|
||||
switch (node.field) {
|
||||
case '_id':
|
||||
return false;
|
||||
return false
|
||||
|
||||
case 'name':
|
||||
return {
|
||||
field: false,
|
||||
value: true
|
||||
};
|
||||
}
|
||||
|
||||
default:
|
||||
return true;
|
||||
return true
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
var json = {
|
||||
const json = {
|
||||
_id: 123456,
|
||||
name: 'John',
|
||||
age: 32
|
||||
};
|
||||
}
|
||||
|
||||
var editor = new JSONEditor(container, options, json);
|
||||
const editor = new JSONEditor(container, options, json)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,51 +1,53 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>JSONEditor | Custom styling</title>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
|
||||
<script src="../dist/jsoneditor.js"></script>
|
||||
<title>JSONEditor | Custom styling</title>
|
||||
|
||||
<style type="text/css">
|
||||
#jsoneditor {
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
}
|
||||
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
|
||||
<script src="../dist/jsoneditor.js"></script>
|
||||
|
||||
p {
|
||||
width: 500px;
|
||||
font-family: "DejaVu Sans", sans-serif;
|
||||
}
|
||||
</style>
|
||||
<style type="text/css">
|
||||
#jsoneditor {
|
||||
width: 500px;
|
||||
height: 500px;
|
||||
}
|
||||
|
||||
<link href="./css/darktheme.css" rel="stylesheet" type="text/css">
|
||||
p {
|
||||
width: 500px;
|
||||
font-family: "DejaVu Sans", sans-serif;
|
||||
}
|
||||
</style>
|
||||
|
||||
<link href="./css/darktheme.css" rel="stylesheet" type="text/css">
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<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
|
||||
var container = document.getElementById('jsoneditor');
|
||||
var options = {
|
||||
modes: ['text', 'tree']
|
||||
};
|
||||
var json = {
|
||||
const container = document.getElementById('jsoneditor')
|
||||
const options = {
|
||||
modes: ['tree', 'text']
|
||||
}
|
||||
const json = {
|
||||
'array': [1, 2, 3],
|
||||
'boolean': true,
|
||||
'null': null,
|
||||
'number': 123,
|
||||
'object': {'a': 'b', 'c': 'd'},
|
||||
'string': 'Hello World'
|
||||
};
|
||||
var editor = new JSONEditor(container, options, json);
|
||||
}
|
||||
const editor = new JSONEditor(container, options, json)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<title>JSONEditor | JSON schema validation</title>
|
||||
|
||||
<link href="../dist/jsoneditor.css" rel="stylesheet" type="text/css">
|
||||
|
@ -16,12 +18,16 @@
|
|||
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 <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 like <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.
|
||||
|
@ -30,42 +36,103 @@
|
|||
<div id="jsoneditor"></div>
|
||||
|
||||
<script>
|
||||
var schema = {
|
||||
"title": "Example Schema",
|
||||
const 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
|
||||
"minimum": 0,
|
||||
"examples": [28, 32]
|
||||
},
|
||||
"job": {
|
||||
"$ref": "job"
|
||||
}
|
||||
},
|
||||
"required": ["firstName", "lastName"]
|
||||
};
|
||||
}
|
||||
|
||||
var json = {
|
||||
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 = {
|
||||
firstName: 'John',
|
||||
lastName: 'Doe',
|
||||
gender: null,
|
||||
age: 28
|
||||
};
|
||||
age: "28",
|
||||
availableToHire: true,
|
||||
job: {
|
||||
company: 'freelance',
|
||||
role: 'developer',
|
||||
salary: 100
|
||||
}
|
||||
}
|
||||
|
||||
var options = {
|
||||
schema: schema
|
||||
};
|
||||
const options = {
|
||||
schema: schema,
|
||||
schemaRefs: {"job": job},
|
||||
mode: 'tree',
|
||||
modes: ['code', 'text', 'tree', 'preview']
|
||||
}
|
||||
|
||||
// create the editor
|
||||
var container = document.getElementById('jsoneditor');
|
||||
var editor = new JSONEditor(container, options, json);
|
||||
const container = document.getElementById('jsoneditor')
|
||||
const editor = new JSONEditor(container, options, json)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<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">
|
||||
<script src="../dist/jsoneditor-minimalist.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>
|
||||
<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.
|
||||
</p>
|
||||
|
||||
<div id="jsoneditor"></div>
|
||||
|
||||
<script>
|
||||
// create the editor
|
||||
const container = document.getElementById('jsoneditor')
|
||||
const options = {
|
||||
modes: ['text', 'code', 'tree', 'form', 'view'],
|
||||
mode: 'code',
|
||||
ace: ace
|
||||
}
|
||||
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>
|
|
@ -0,0 +1,73 @@
|
|||
<!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>
|
|
@ -0,0 +1,73 @@
|
|||
<!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>
|
|
@ -0,0 +1,52 @@
|
|||
<!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>
|
|
@ -0,0 +1,73 @@
|
|||
<!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>
|
|
@ -0,0 +1,109 @@
|
|||
<!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>
|
|
@ -0,0 +1,57 @@
|
|||
<!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>
|
|
@ -0,0 +1,124 @@
|
|||
<!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": '"',
|
||||
"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>
|
|
@ -0,0 +1,66 @@
|
|||
<!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>
|
|
@ -0,0 +1,96 @@
|
|||
<!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": '"',
|
||||
"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>
|
|
@ -0,0 +1,109 @@
|
|||
<!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>
|
|
@ -0,0 +1,92 @@
|
|||
<!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>
|
|
@ -0,0 +1,160 @@
|
|||
<!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": '"',
|
||||
"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": '"',
|
||||
"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>
|
|
@ -0,0 +1,148 @@
|
|||
<!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>
|
|
@ -0,0 +1,153 @@
|
|||
<!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>
|
|
@ -0,0 +1,123 @@
|
|||
<!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>
|
|
@ -0,0 +1,89 @@
|
|||
<!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>
|
|
@ -0,0 +1 @@
|
|||
SKIP_PREFLIGHT_CHECK=true
|
|
@ -0,0 +1,21 @@
|
|||
# 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*
|
|
@ -0,0 +1,21 @@
|
|||
# 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
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"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"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<!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.
|
||||
|
||||
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 advanced demo</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>
|
|
@ -0,0 +1,13 @@
|
|||
.app .contents {
|
||||
width: 500px;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.app .contents .mode {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.app .contents .code {
|
||||
background: #f5f5f5;
|
||||
overflow: auto;
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
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;
|
|
@ -0,0 +1,9 @@
|
|||
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);
|
||||
});
|
|
@ -0,0 +1,4 @@
|
|||
.jsoneditor-react-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
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} />
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
body {
|
||||
font-family: sans-serif;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'));
|
|
@ -0,0 +1 @@
|
|||
SKIP_PREFLIGHT_CHECK=true
|
|
@ -0,0 +1,21 @@
|
|||
# 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*
|
|
@ -0,0 +1,21 @@
|
|||
# JSONEditor React 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
|
|
@ -0,0 +1,29 @@
|
|||
{
|
||||
"name": "react_demo",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"jsoneditor": "latest",
|
||||
"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"
|
||||
]
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
<!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.
|
||||
|
||||
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>
|
||||
</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>
|
|
@ -0,0 +1,12 @@
|
|||
.app .contents {
|
||||
width: 500px;
|
||||
height: 400px;
|
||||
}
|
||||
|
||||
.app .contents .menu {
|
||||
padding: 10px 0;
|
||||
}
|
||||
|
||||
.app .contents .code {
|
||||
background: #f5f5f5;
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
import React, { Component } from 'react';
|
||||
|
||||
import JSONEditorDemo from './JSONEditorDemo';
|
||||
import './App.css';
|
||||
|
||||
class App extends Component {
|
||||
state = {
|
||||
json: {
|
||||
'array': [1, 2, 3],
|
||||
'boolean': true,
|
||||
'null': null,
|
||||
'number': 123,
|
||||
'object': {'a': 'b', 'c': 'd'},
|
||||
'string': 'Hello World'
|
||||
}
|
||||
};
|
||||
|
||||
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
|
||||
json={this.state.json}
|
||||
onChangeJSON={this.onChangeJSON}
|
||||
/>
|
||||
<div className="code">
|
||||
<pre>
|
||||
<code>
|
||||
{JSON.stringify(this.state.json, null, 2)}
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
onChangeJSON = (json) => {
|
||||
this.setState({ json });
|
||||
};
|
||||
|
||||
updateTime = () => {
|
||||
const time = new Date().toISOString();
|
||||
|
||||
this.setState({
|
||||
json: Object.assign({}, this.state.json, { time })
|
||||
})
|
||||
};
|
||||
}
|
||||
|
||||
export default App;
|
|
@ -0,0 +1,9 @@
|
|||
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);
|
||||
});
|
|
@ -0,0 +1,4 @@
|
|||
.jsoneditor-react-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
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} />
|
||||
);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
body {
|
||||
font-family: sans-serif;
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import './index.css';
|
||||
import App from './App';
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'));
|
|
@ -9,7 +9,7 @@
|
|||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="../../dist/jsoneditor.css">
|
||||
<script data-main="scripts/main" src="scripts/require.js"></script>
|
||||
<script data-main="scripts/main" src="https://requirejs.org/docs/release/2.3.6/minified/require.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
var module = '../../../dist/jsoneditor';
|
||||
const module = '../../../dist/jsoneditor'
|
||||
require([module], function (JSONEditor) {
|
||||
// create the editor
|
||||
var container = document.getElementById('jsoneditor');
|
||||
var editor = new JSONEditor(container);
|
||||
const container = document.getElementById('jsoneditor')
|
||||
const editor = new JSONEditor(container)
|
||||
|
||||
// set json
|
||||
document.getElementById('setJSON').onclick = function () {
|
||||
var json = {
|
||||
'array': [1, 2, 3],
|
||||
'boolean': true,
|
||||
'null': null,
|
||||
'number': 123,
|
||||
'object': {'a': 'b', 'c': 'd'},
|
||||
'string': 'Hello World'
|
||||
};
|
||||
editor.set(json);
|
||||
};
|
||||
const 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 () {
|
||||
var json = editor.get();
|
||||
alert(JSON.stringify(json, null, 2));
|
||||
};
|
||||
});
|
||||
const json = editor.get()
|
||||
window.alert(JSON.stringify(json, null, 2))
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
RequireJS 2.1.13 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
|
||||
Available via the MIT or new BSD license.
|
||||
see: http://github.com/jrburke/requirejs for details
|
||||
*/
|
||||
var requirejs,require,define;
|
||||
(function(ba){function G(b){return"[object Function]"===K.call(b)}function H(b){return"[object Array]"===K.call(b)}function v(b,c){if(b){var d;for(d=0;d<b.length&&(!b[d]||!c(b[d],d,b));d+=1);}}function T(b,c){if(b){var d;for(d=b.length-1;-1<d&&(!b[d]||!c(b[d],d,b));d-=1);}}function t(b,c){return fa.call(b,c)}function m(b,c){return t(b,c)&&b[c]}function B(b,c){for(var d in b)if(t(b,d)&&c(b[d],d))break}function U(b,c,d,e){c&&B(c,function(c,g){if(d||!t(b,g))e&&"object"===typeof c&&c&&!H(c)&&!G(c)&&!(c instanceof
|
||||
RegExp)?(b[g]||(b[g]={}),U(b[g],c,d,e)):b[g]=c});return b}function u(b,c){return function(){return c.apply(b,arguments)}}function ca(b){throw b;}function da(b){if(!b)return b;var c=ba;v(b.split("."),function(b){c=c[b]});return c}function C(b,c,d,e){c=Error(c+"\nhttp://requirejs.org/docs/errors.html#"+b);c.requireType=b;c.requireModules=e;d&&(c.originalError=d);return c}function ga(b){function c(a,k,b){var f,l,c,d,e,g,i,p,k=k&&k.split("/"),h=j.map,n=h&&h["*"];if(a){a=a.split("/");l=a.length-1;j.nodeIdCompat&&
|
||||
Q.test(a[l])&&(a[l]=a[l].replace(Q,""));"."===a[0].charAt(0)&&k&&(l=k.slice(0,k.length-1),a=l.concat(a));l=a;for(c=0;c<l.length;c++)if(d=l[c],"."===d)l.splice(c,1),c-=1;else if(".."===d&&!(0===c||1==c&&".."===l[2]||".."===l[c-1])&&0<c)l.splice(c-1,2),c-=2;a=a.join("/")}if(b&&h&&(k||n)){l=a.split("/");c=l.length;a:for(;0<c;c-=1){e=l.slice(0,c).join("/");if(k)for(d=k.length;0<d;d-=1)if(b=m(h,k.slice(0,d).join("/")))if(b=m(b,e)){f=b;g=c;break a}!i&&(n&&m(n,e))&&(i=m(n,e),p=c)}!f&&i&&(f=i,g=p);f&&(l.splice(0,
|
||||
g,f),a=l.join("/"))}return(f=m(j.pkgs,a))?f:a}function d(a){z&&v(document.getElementsByTagName("script"),function(k){if(k.getAttribute("data-requiremodule")===a&&k.getAttribute("data-requirecontext")===i.contextName)return k.parentNode.removeChild(k),!0})}function e(a){var k=m(j.paths,a);if(k&&H(k)&&1<k.length)return k.shift(),i.require.undef(a),i.makeRequire(null,{skipMap:!0})([a]),!0}function n(a){var k,c=a?a.indexOf("!"):-1;-1<c&&(k=a.substring(0,c),a=a.substring(c+1,a.length));return[k,a]}function p(a,
|
||||
k,b,f){var l,d,e=null,g=k?k.name:null,j=a,p=!0,h="";a||(p=!1,a="_@r"+(K+=1));a=n(a);e=a[0];a=a[1];e&&(e=c(e,g,f),d=m(r,e));a&&(e?h=d&&d.normalize?d.normalize(a,function(a){return c(a,g,f)}):c(a,g,f):(h=c(a,g,f),a=n(h),e=a[0],h=a[1],b=!0,l=i.nameToUrl(h)));b=e&&!d&&!b?"_unnormalized"+(O+=1):"";return{prefix:e,name:h,parentMap:k,unnormalized:!!b,url:l,originalName:j,isDefine:p,id:(e?e+"!"+h:h)+b}}function s(a){var k=a.id,b=m(h,k);b||(b=h[k]=new i.Module(a));return b}function q(a,k,b){var f=a.id,c=m(h,
|
||||
f);if(t(r,f)&&(!c||c.defineEmitComplete))"defined"===k&&b(r[f]);else if(c=s(a),c.error&&"error"===k)b(c.error);else c.on(k,b)}function w(a,b){var c=a.requireModules,f=!1;if(b)b(a);else if(v(c,function(b){if(b=m(h,b))b.error=a,b.events.error&&(f=!0,b.emit("error",a))}),!f)g.onError(a)}function x(){R.length&&(ha.apply(A,[A.length,0].concat(R)),R=[])}function y(a){delete h[a];delete V[a]}function F(a,b,c){var f=a.map.id;a.error?a.emit("error",a.error):(b[f]=!0,v(a.depMaps,function(f,d){var e=f.id,g=
|
||||
m(h,e);g&&(!a.depMatched[d]&&!c[e])&&(m(b,e)?(a.defineDep(d,r[e]),a.check()):F(g,b,c))}),c[f]=!0)}function D(){var a,b,c=(a=1E3*j.waitSeconds)&&i.startTime+a<(new Date).getTime(),f=[],l=[],g=!1,h=!0;if(!W){W=!0;B(V,function(a){var i=a.map,j=i.id;if(a.enabled&&(i.isDefine||l.push(a),!a.error))if(!a.inited&&c)e(j)?g=b=!0:(f.push(j),d(j));else if(!a.inited&&(a.fetched&&i.isDefine)&&(g=!0,!i.prefix))return h=!1});if(c&&f.length)return a=C("timeout","Load timeout for modules: "+f,null,f),a.contextName=
|
||||
i.contextName,w(a);h&&v(l,function(a){F(a,{},{})});if((!c||b)&&g)if((z||ea)&&!X)X=setTimeout(function(){X=0;D()},50);W=!1}}function E(a){t(r,a[0])||s(p(a[0],null,!0)).init(a[1],a[2])}function I(a){var a=a.currentTarget||a.srcElement,b=i.onScriptLoad;a.detachEvent&&!Y?a.detachEvent("onreadystatechange",b):a.removeEventListener("load",b,!1);b=i.onScriptError;(!a.detachEvent||Y)&&a.removeEventListener("error",b,!1);return{node:a,id:a&&a.getAttribute("data-requiremodule")}}function J(){var a;for(x();A.length;){a=
|
||||
A.shift();if(null===a[0])return w(C("mismatch","Mismatched anonymous define() module: "+a[a.length-1]));E(a)}}var W,Z,i,L,X,j={waitSeconds:7,baseUrl:"./",paths:{},bundles:{},pkgs:{},shim:{},config:{}},h={},V={},$={},A=[],r={},S={},aa={},K=1,O=1;L={require:function(a){return a.require?a.require:a.require=i.makeRequire(a.map)},exports:function(a){a.usingExports=!0;if(a.map.isDefine)return a.exports?r[a.map.id]=a.exports:a.exports=r[a.map.id]={}},module:function(a){return a.module?a.module:a.module=
|
||||
{id:a.map.id,uri:a.map.url,config:function(){return m(j.config,a.map.id)||{}},exports:a.exports||(a.exports={})}}};Z=function(a){this.events=m($,a.id)||{};this.map=a;this.shim=m(j.shim,a.id);this.depExports=[];this.depMaps=[];this.depMatched=[];this.pluginMaps={};this.depCount=0};Z.prototype={init:function(a,b,c,f){f=f||{};if(!this.inited){this.factory=b;if(c)this.on("error",c);else this.events.error&&(c=u(this,function(a){this.emit("error",a)}));this.depMaps=a&&a.slice(0);this.errback=c;this.inited=
|
||||
!0;this.ignore=f.ignore;f.enabled||this.enabled?this.enable():this.check()}},defineDep:function(a,b){this.depMatched[a]||(this.depMatched[a]=!0,this.depCount-=1,this.depExports[a]=b)},fetch:function(){if(!this.fetched){this.fetched=!0;i.startTime=(new Date).getTime();var a=this.map;if(this.shim)i.makeRequire(this.map,{enableBuildCallback:!0})(this.shim.deps||[],u(this,function(){return a.prefix?this.callPlugin():this.load()}));else return a.prefix?this.callPlugin():this.load()}},load:function(){var a=
|
||||
this.map.url;S[a]||(S[a]=!0,i.load(this.map.id,a))},check:function(){if(this.enabled&&!this.enabling){var a,b,c=this.map.id;b=this.depExports;var f=this.exports,l=this.factory;if(this.inited)if(this.error)this.emit("error",this.error);else{if(!this.defining){this.defining=!0;if(1>this.depCount&&!this.defined){if(G(l)){if(this.events.error&&this.map.isDefine||g.onError!==ca)try{f=i.execCb(c,l,b,f)}catch(d){a=d}else f=i.execCb(c,l,b,f);this.map.isDefine&&void 0===f&&((b=this.module)?f=b.exports:this.usingExports&&
|
||||
(f=this.exports));if(a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",w(this.error=a)}else f=l;this.exports=f;if(this.map.isDefine&&!this.ignore&&(r[c]=f,g.onResourceLoad))g.onResourceLoad(i,this.map,this.depMaps);y(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=
|
||||
this.map,b=a.id,d=p(a.prefix);this.depMaps.push(d);q(d,"defined",u(this,function(f){var l,d;d=m(aa,this.map.id);var e=this.map.name,P=this.map.parentMap?this.map.parentMap.name:null,n=i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(f.normalize&&(e=f.normalize(e,function(a){return c(a,P,!0)})||""),f=p(a.prefix+"!"+e,this.map.parentMap),q(f,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(h,f.id)){this.depMaps.push(f);
|
||||
if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else d?(this.map.url=i.nameToUrl(d),this.load()):(l=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),l.error=u(this,function(a){this.inited=!0;this.error=a;a.requireModules=[b];B(h,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&y(a.map.id)});w(a)}),l.fromText=u(this,function(f,c){var d=a.name,e=p(d),P=M;c&&(f=c);P&&(M=!1);s(e);t(j.config,b)&&(j.config[d]=j.config[b]);try{g.exec(f)}catch(h){return w(C("fromtexteval",
|
||||
"fromText eval for "+b+" failed: "+h,h,[b]))}P&&(M=!0);this.depMaps.push(e);i.completeLoad(d);n([d],l)}),f.load(a.name,n,l,j))}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=this;this.enabling=this.enabled=!0;v(this.depMaps,u(this,function(a,b){var c,f;if("string"===typeof a){a=p(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(L,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;q(a,"defined",u(this,function(a){this.defineDep(b,
|
||||
a);this.check()}));this.errback&&q(a,"error",u(this,this.errback))}c=a.id;f=h[c];!t(L,c)&&(f&&!f.enabled)&&i.enable(a,this)}));B(this.pluginMaps,u(this,function(a){var b=m(h,a.id);b&&!b.enabled&&i.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){v(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:j,contextName:b,registry:h,defined:r,urlFetched:S,defQueue:A,Module:Z,makeModuleMap:p,
|
||||
nextTick:g.nextTick,onError:w,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=j.shim,c={paths:!0,bundles:!0,config:!0,map:!0};B(a,function(a,b){c[b]?(j[b]||(j[b]={}),U(j[b],a,!0,!0)):j[b]=a});a.bundles&&B(a.bundles,function(a,b){v(a,function(a){a!==b&&(aa[a]=b)})});a.shim&&(B(a.shim,function(a,c){H(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);b[c]=a}),j.shim=b);a.packages&&v(a.packages,function(a){var b,
|
||||
a="string"===typeof a?{name:a}:a;b=a.name;a.location&&(j.paths[b]=a.location);j.pkgs[b]=a.name+"/"+(a.main||"main").replace(ia,"").replace(Q,"")});B(h,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=p(b))});if(a.deps||a.callback)i.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(ba,arguments));return b||a.exports&&da(a.exports)}},makeRequire:function(a,e){function j(c,d,m){var n,q;e.enableBuildCallback&&(d&&G(d))&&(d.__requireJsBuild=
|
||||
!0);if("string"===typeof c){if(G(d))return w(C("requireargs","Invalid require call"),m);if(a&&t(L,c))return L[c](h[a.id]);if(g.get)return g.get(i,c,a,j);n=p(c,a,!1,!0);n=n.id;return!t(r,n)?w(C("notloaded",'Module name "'+n+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):r[n]}J();i.nextTick(function(){J();q=s(p(null,a));q.skipMap=e.skipMap;q.init(c,d,m,{enabled:!0});D()});return j}e=e||{};U(j,{isBrowser:z,toUrl:function(b){var d,e=b.lastIndexOf("."),k=b.split("/")[0];if(-1!==
|
||||
e&&(!("."===k||".."===k)||1<e))d=b.substring(e,b.length),b=b.substring(0,e);return i.nameToUrl(c(b,a&&a.id,!0),d,!0)},defined:function(b){return t(r,p(b,a,!1,!0).id)},specified:function(b){b=p(b,a,!1,!0).id;return t(r,b)||t(h,b)}});a||(j.undef=function(b){x();var c=p(b,a,!0),e=m(h,b);d(b);delete r[b];delete S[c.url];delete $[b];T(A,function(a,c){a[0]===b&&A.splice(c,1)});e&&(e.events.defined&&($[b]=e.events),y(b))});return j},enable:function(a){m(h,a.id)&&s(a).enable()},completeLoad:function(a){var b,
|
||||
c,d=m(j.shim,a)||{},g=d.exports;for(x();A.length;){c=A.shift();if(null===c[0]){c[0]=a;if(b)break;b=!0}else c[0]===a&&(b=!0);E(c)}c=m(h,a);if(!b&&!t(r,a)&&c&&!c.inited){if(j.enforceDefine&&(!g||!da(g)))return e(a)?void 0:w(C("nodefine","No define call for "+a,null,[a]));E([a,d.deps||[],d.exportsFn])}D()},nameToUrl:function(a,b,c){var d,e,h;(d=m(j.pkgs,a))&&(a=d);if(d=m(aa,a))return i.nameToUrl(d,b,c);if(g.jsExtRegExp.test(a))d=a+(b||"");else{d=j.paths;a=a.split("/");for(e=a.length;0<e;e-=1)if(h=a.slice(0,
|
||||
e).join("/"),h=m(d,h)){H(h)&&(h=h[0]);a.splice(0,e,h);break}d=a.join("/");d+=b||(/^data\:|\?/.test(d)||c?"":".js");d=("/"===d.charAt(0)||d.match(/^[\w\+\.\-]+:/)?"":j.baseUrl)+d}return j.urlArgs?d+((-1===d.indexOf("?")?"?":"&")+j.urlArgs):d},load:function(a,b){g.load(i,a,b)},execCb:function(a,b,c,d){return b.apply(d,c)},onScriptLoad:function(a){if("load"===a.type||ja.test((a.currentTarget||a.srcElement).readyState))N=null,a=I(a),i.completeLoad(a.id)},onScriptError:function(a){var b=I(a);if(!e(b.id))return w(C("scripterror",
|
||||
"Script error for: "+b.id,a,[b.id]))}};i.require=i.makeRequire();return i}var g,x,y,D,I,E,N,J,s,O,ka=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,la=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,Q=/\.js$/,ia=/^\.\//;x=Object.prototype;var K=x.toString,fa=x.hasOwnProperty,ha=Array.prototype.splice,z=!!("undefined"!==typeof window&&"undefined"!==typeof navigator&&window.document),ea=!z&&"undefined"!==typeof importScripts,ja=z&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,
|
||||
Y="undefined"!==typeof opera&&"[object Opera]"===opera.toString(),F={},q={},R=[],M=!1;if("undefined"===typeof define){if("undefined"!==typeof requirejs){if(G(requirejs))return;q=requirejs;requirejs=void 0}"undefined"!==typeof require&&!G(require)&&(q=require,require=void 0);g=requirejs=function(b,c,d,e){var n,p="_";!H(b)&&"string"!==typeof b&&(n=b,H(c)?(b=c,c=d,d=e):b=[]);n&&n.context&&(p=n.context);(e=m(F,p))||(e=F[p]=g.s.newContext(p));n&&e.configure(n);return e.require(b,c,d)};g.config=function(b){return g(b)};
|
||||
g.nextTick="undefined"!==typeof setTimeout?function(b){setTimeout(b,4)}:function(b){b()};require||(require=g);g.version="2.1.13";g.jsExtRegExp=/^\/|:|\?|\.js$/;g.isBrowser=z;x=g.s={contexts:F,newContext:ga};g({});v(["toUrl","undef","defined","specified"],function(b){g[b]=function(){var c=F._;return c.require[b].apply(c,arguments)}});if(z&&(y=x.head=document.getElementsByTagName("head")[0],D=document.getElementsByTagName("base")[0]))y=x.head=D.parentNode;g.onError=ca;g.createNode=function(b){var c=
|
||||
b.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script");c.type=b.scriptType||"text/javascript";c.charset="utf-8";c.async=!0;return c};g.load=function(b,c,d){var e=b&&b.config||{};if(z)return e=g.createNode(e,c,d),e.setAttribute("data-requirecontext",b.contextName),e.setAttribute("data-requiremodule",c),e.attachEvent&&!(e.attachEvent.toString&&0>e.attachEvent.toString().indexOf("[native code"))&&!Y?(M=!0,e.attachEvent("onreadystatechange",b.onScriptLoad)):
|
||||
(e.addEventListener("load",b.onScriptLoad,!1),e.addEventListener("error",b.onScriptError,!1)),e.src=d,J=e,D?y.insertBefore(e,D):y.appendChild(e),J=null,e;if(ea)try{importScripts(d),b.completeLoad(c)}catch(m){b.onError(C("importscripts","importScripts failed for "+c+" at "+d,m,[c]))}};z&&!q.skipDataMain&&T(document.getElementsByTagName("script"),function(b){y||(y=b.parentNode);if(I=b.getAttribute("data-main"))return s=I,q.baseUrl||(E=s.split("/"),s=E.pop(),O=E.length?E.join("/")+"/":"./",q.baseUrl=
|
||||
O),s=s.replace(Q,""),g.jsExtRegExp.test(s)&&(s=I),q.deps=q.deps?q.deps.concat(s):[s],!0});define=function(b,c,d){var e,g;"string"!==typeof b&&(d=c,c=b,b=null);H(c)||(d=c,c=null);!c&&G(d)&&(c=[],d.length&&(d.toString().replace(ka,"").replace(la,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c)));if(M){if(!(e=J))N&&"interactive"===N.readyState||T(document.getElementsByTagName("script"),function(b){if("interactive"===b.readyState)return N=b}),e=N;e&&(b||
|
||||
(b=e.getAttribute("data-requiremodule")),g=F[e.getAttribute("data-requirecontext")])}(g?g.defQueue:R).push([b,c,d])};define.amd={jQuery:!0};g.exec=function(b){return eval(b)};g(q)}})(this);
|
|
@ -0,0 +1,11 @@
|
|||
{
|
||||
"groups": {
|
||||
"default": {
|
||||
"packages": [
|
||||
"examples/react_advanced_demo/package.json",
|
||||
"examples/react_demo/package.json",
|
||||
"package.json"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
279
gulpfile.js
279
gulpfile.js
|
@ -1,38 +1,59 @@
|
|||
var fs = require('fs');
|
||||
var gulp = require('gulp');
|
||||
var gutil = require('gulp-util');
|
||||
var concatCss = require('gulp-concat-css');
|
||||
var minifyCSS = require('gulp-clean-css');
|
||||
var shell = require('gulp-shell');
|
||||
var mkdirp = require('mkdirp');
|
||||
var webpack = require('webpack');
|
||||
var uglify = require('uglify-js');
|
||||
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')
|
||||
|
||||
var NAME = 'jsoneditor';
|
||||
var NAME_MINIMALIST = 'jsoneditor-minimalist';
|
||||
var ENTRY = './src/js/JSONEditor.js';
|
||||
var HEADER = './src/js/header.js';
|
||||
var IMAGE = './src/css/img/jsoneditor-icons.svg';
|
||||
var DOCS = './src/docs/*';
|
||||
var DIST = './dist';
|
||||
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() {
|
||||
var today = gutil.date(new Date(), 'yyyy-mm-dd'); // today, formatted as yyyy-mm-dd
|
||||
var version = require('./package.json').version; // math.js 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);
|
||||
.replace('@@date', today)
|
||||
.replace('@@version', version)
|
||||
}
|
||||
|
||||
var bannerPlugin = new webpack.BannerPlugin(createBanner(), {
|
||||
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
|
||||
var compiler = webpack({
|
||||
const compiler = webpack({
|
||||
entry: ENTRY,
|
||||
output: {
|
||||
library: 'JSONEditor',
|
||||
|
@ -40,17 +61,21 @@ var compiler = webpack({
|
|||
path: DIST,
|
||||
filename: NAME + '.js'
|
||||
},
|
||||
plugins: [ bannerPlugin ],
|
||||
module: {
|
||||
loaders: [
|
||||
{ test: /\.json$/, loader: "json" }
|
||||
]
|
||||
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
|
||||
var compilerMinimalist = webpack({
|
||||
const compilerMinimalist = webpack({
|
||||
entry: ENTRY,
|
||||
output: {
|
||||
library: 'JSONEditor',
|
||||
|
@ -58,131 +83,161 @@ var compilerMinimalist = webpack({
|
|||
path: DIST,
|
||||
filename: NAME_MINIMALIST + '.js'
|
||||
},
|
||||
module: webpackConfigModule,
|
||||
plugins: [
|
||||
bannerPlugin,
|
||||
new webpack.IgnorePlugin(new RegExp('^brace$')),
|
||||
new webpack.IgnorePlugin(new RegExp('^ajv'))
|
||||
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) {
|
||||
var result = uglify.minify([DIST + '/' + name + '.js'], {
|
||||
outSourceMap: name + '.map',
|
||||
function minify (name) {
|
||||
const code = String(fs.readFileSync(DIST + '/' + name + '.js'))
|
||||
const result = uglify.minify(code, {
|
||||
sourceMap: {
|
||||
url: name + '.map'
|
||||
},
|
||||
output: {
|
||||
comments: /@license/
|
||||
comments: /@license/,
|
||||
max_line_len: 64000 // extra large because we have embedded code for workers
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
var fileMin = DIST + '/' + name + '.min.js';
|
||||
var fileMap = DIST + '/' + name + '.map';
|
||||
if (result.error) {
|
||||
throw result.error
|
||||
}
|
||||
|
||||
fs.writeFileSync(fileMin, result.code);
|
||||
fs.writeFileSync(fileMap, result.map);
|
||||
const fileMin = DIST + '/' + name + '.min.js'
|
||||
const fileMap = DIST + '/' + name + '.map'
|
||||
|
||||
gutil.log('Minified ' + fileMin);
|
||||
gutil.log('Mapped ' + fileMap);
|
||||
fs.writeFileSync(fileMin, result.code)
|
||||
fs.writeFileSync(fileMap, result.map)
|
||||
|
||||
log('Minified ' + fileMin)
|
||||
log('Mapped ' + fileMap)
|
||||
}
|
||||
|
||||
// make dist and dist/img folders
|
||||
gulp.task('mkdir', function () {
|
||||
mkdirp.sync(DIST);
|
||||
mkdirp.sync(DIST + '/img');
|
||||
});
|
||||
// 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', ['mkdir'], function (done) {
|
||||
gulp.task('bundle', function (done) {
|
||||
// update the banner contents (has a date in it which should stay up to date)
|
||||
bannerPlugin.banner = createBanner();
|
||||
bannerPlugin.banner = createBanner()
|
||||
|
||||
compiler.run(function (err, stats) {
|
||||
if (err) {
|
||||
gutil.log(err);
|
||||
log(err)
|
||||
}
|
||||
|
||||
gutil.log('bundled ' + NAME + '.js');
|
||||
log('bundled ' + NAME + '.js')
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
// bundle minimalist version of javascript
|
||||
gulp.task('bundle-minimalist', ['mkdir'], function (done) {
|
||||
gulp.task('bundle-minimalist', function (done) {
|
||||
// update the banner contents (has a date in it which should stay up to date)
|
||||
bannerPlugin.banner = createBanner();
|
||||
bannerPlugin.banner = createBanner()
|
||||
|
||||
compilerMinimalist.run(function (err, stats) {
|
||||
if (err) {
|
||||
gutil.log(err);
|
||||
log(err)
|
||||
}
|
||||
|
||||
gutil.log('bundled ' + NAME_MINIMALIST + '.js');
|
||||
log('bundled ' + NAME_MINIMALIST + '.js')
|
||||
|
||||
done();
|
||||
});
|
||||
});
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
// bundle css
|
||||
gulp.task('bundle-css', ['mkdir'], function () {
|
||||
gulp.src([
|
||||
'src/css/reset.css',
|
||||
'src/css/jsoneditor.css',
|
||||
'src/css/contextmenu.css',
|
||||
'src/css/menu.css',
|
||||
'src/css/searchbox.css'
|
||||
])
|
||||
.pipe(concatCss(NAME + '.css'))
|
||||
.pipe(gulp.dest(DIST))
|
||||
.pipe(concatCss(NAME + '.min.css'))
|
||||
.pipe(minifyCSS())
|
||||
.pipe(gulp.dest(DIST));
|
||||
|
||||
gutil.log('bundled ' + DIST + '/' + NAME + '.css');
|
||||
gutil.log('bundled ' + DIST + '/' + NAME + '.min.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', ['mkdir'], function () {
|
||||
gulp.src(IMAGE)
|
||||
.pipe(gulp.dest(DIST +'/img'));
|
||||
gutil.log('Copied images');
|
||||
});
|
||||
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', ['mkdir'], function () {
|
||||
gulp.src(DOCS)
|
||||
.pipe(gulp.dest(DIST));
|
||||
gutil.log('Copied doc');
|
||||
});
|
||||
gulp.task('copy-docs', function (done) {
|
||||
gulp.src(DOCS).pipe(gulp.dest(DIST))
|
||||
log('Copied doc')
|
||||
|
||||
gulp.task('minify', ['bundle'], function () {
|
||||
done()
|
||||
})
|
||||
|
||||
gulp.task('minify', function (done) {
|
||||
minify(NAME)
|
||||
});
|
||||
|
||||
gulp.task('minify-minimalist', ['bundle-minimalist'], function () {
|
||||
done()
|
||||
})
|
||||
|
||||
gulp.task('minify-minimalist', function (done) {
|
||||
minify(NAME_MINIMALIST)
|
||||
});
|
||||
|
||||
// TODO: zip file using archiver
|
||||
var pkg = 'jsoneditor-' + require('./package.json').version + '.zip';
|
||||
gulp.task('zip', shell.task([
|
||||
'zip ' + pkg + ' ' + 'README.md NOTICE LICENSE HISTORY.md index.html src dist docs examples -r '
|
||||
]));
|
||||
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', ['bundle', 'bundle-css', 'copy-img'], function () {
|
||||
gulp.watch(['src/**/*'], ['bundle', 'bundle-css', 'copy-img']);
|
||||
});
|
||||
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', [
|
||||
'bundle',
|
||||
'bundle-minimalist',
|
||||
'bundle-css',
|
||||
'copy-img',
|
||||
'copy-docs',
|
||||
'minify',
|
||||
'minify-minimalist'
|
||||
]);
|
||||
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')
|
||||
)
|
||||
))
|
||||
|
|
2
index.js
2
index.js
|
@ -1 +1 @@
|
|||
module.exports = require('./src/js/JSONEditor');
|
||||
module.exports = require('./dist/jsoneditor')
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 8.3 KiB |
File diff suppressed because it is too large
Load Diff
After Width: | Height: | Size: 950 KiB |
|
@ -7,6 +7,10 @@ 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
|
||||
|
||||
|
@ -33,13 +37,8 @@ correct date and version number in the header.
|
|||
|
||||
## Test
|
||||
|
||||
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.
|
||||
Test whether the npm library is ok by opening some examples, and check whether
|
||||
the files under `dists` are created and have contents.
|
||||
|
||||
|
||||
## Commit
|
||||
|
@ -60,9 +59,6 @@ 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
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
68
package.json
68
package.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "jsoneditor",
|
||||
"version": "5.5.6",
|
||||
"main": "./index",
|
||||
"version": "9.1.1",
|
||||
"main": "./dist/jsoneditor.min.js",
|
||||
"description": "A web-based tool to view, edit, format, and validate JSON",
|
||||
"tags": [
|
||||
"json",
|
||||
|
@ -19,24 +19,58 @@
|
|||
"bugs": "https://github.com/josdejong/jsoneditor/issues",
|
||||
"scripts": {
|
||||
"build": "gulp",
|
||||
"watch": "gulp watch",
|
||||
"test": "mocha test"
|
||||
"minify": "gulp minify",
|
||||
"start": "gulp watch",
|
||||
"test": "mocha test --require @babel/register",
|
||||
"lint": "standard --env=mocha",
|
||||
"prepublishOnly": "npm test && npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"ajv": "3.8.8",
|
||||
"brace": "0.8.0",
|
||||
"javascript-natural-sort": "0.7.1"
|
||||
"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"
|
||||
},
|
||||
"devDependencies": {
|
||||
"gulp": "3.9.1",
|
||||
"gulp-clean-css": "2.0.5",
|
||||
"gulp-concat-css": "2.2.0",
|
||||
"gulp-shell": "0.5.2",
|
||||
"gulp-util": "3.0.7",
|
||||
"json-loader": "0.5.4",
|
||||
"mkdirp": "0.5.1",
|
||||
"mocha": "2.4.5",
|
||||
"uglify-js": "2.6.2",
|
||||
"webpack": "1.12.14"
|
||||
"@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"
|
||||
},
|
||||
"files": [
|
||||
"dist",
|
||||
"docs",
|
||||
"examples",
|
||||
"src",
|
||||
"HISTORY.md",
|
||||
"index.js",
|
||||
"LICENSE",
|
||||
"NOTICE",
|
||||
"README.md"
|
||||
],
|
||||
"standard": {
|
||||
"ignore": [
|
||||
"src/js/assets",
|
||||
"examples/react*"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,244 +0,0 @@
|
|||
|
||||
/* ContextMenu - main menu */
|
||||
|
||||
div.jsoneditor-contextmenu-root {
|
||||
position: relative;
|
||||
width: 0;
|
||||
height: 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu {
|
||||
position: absolute;
|
||||
box-sizing: content-box;
|
||||
z-index: 99999;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul,
|
||||
div.jsoneditor-contextmenu li {
|
||||
box-sizing: content-box;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul {
|
||||
position: relative;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 124px;
|
||||
|
||||
background: white;
|
||||
border: 1px solid #d3d3d3;
|
||||
box-shadow: 2px 2px 12px rgba(128, 128, 128, 0.3);
|
||||
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li button {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
width: 124px;
|
||||
height: 24px;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
color: #4d4d4d;
|
||||
background: transparent;
|
||||
|
||||
font-size: 10pt;
|
||||
font-family: arial, sans-serif;
|
||||
|
||||
box-sizing: border-box;
|
||||
|
||||
line-height: 26px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/* Fix button padding in firefox */
|
||||
div.jsoneditor-contextmenu ul li button::-moz-focus-inner {
|
||||
padding: 0;
|
||||
border: 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li button:hover,
|
||||
div.jsoneditor-contextmenu ul li button:focus {
|
||||
color: #1a1a1a;
|
||||
background-color: #f5f5f5;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li button.jsoneditor-default {
|
||||
width: 92px;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li button.jsoneditor-expand {
|
||||
float: right;
|
||||
width: 32px;
|
||||
height: 24px;
|
||||
border-left: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu div.jsoneditor-icon {
|
||||
float: left;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-image: url('img/jsoneditor-icons.svg');
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li button div.jsoneditor-expand {
|
||||
float: right;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
margin: 0 4px 0 0;
|
||||
background: url('img/jsoneditor-icons.svg') 0 -72px;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li button:hover div.jsoneditor-expand,
|
||||
div.jsoneditor-contextmenu ul li button:focus div.jsoneditor-expand,
|
||||
div.jsoneditor-contextmenu ul li.jsoneditor-selected div.jsoneditor-expand,
|
||||
div.jsoneditor-contextmenu ul li button.jsoneditor-expand:hover div.jsoneditor-expand,
|
||||
div.jsoneditor-contextmenu ul li button.jsoneditor-expand:focus div.jsoneditor-expand {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu div.jsoneditor-separator {
|
||||
height: 0;
|
||||
border-top: 1px solid #e5e5e5;
|
||||
padding-top: 5px;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-remove > div.jsoneditor-icon {
|
||||
background-position: -24px -24px;
|
||||
}
|
||||
div.jsoneditor-contextmenu button.jsoneditor-remove:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-remove:focus > div.jsoneditor-icon {
|
||||
background-position: -24px 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-append > div.jsoneditor-icon {
|
||||
background-position: 0 -24px;
|
||||
}
|
||||
div.jsoneditor-contextmenu button.jsoneditor-append:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-append:focus > div.jsoneditor-icon {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-insert > div.jsoneditor-icon {
|
||||
background-position: 0 -24px;
|
||||
}
|
||||
div.jsoneditor-contextmenu button.jsoneditor-insert:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-insert:focus > div.jsoneditor-icon {
|
||||
background-position: 0 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-duplicate > div.jsoneditor-icon {
|
||||
background-position: -48px -24px;
|
||||
}
|
||||
div.jsoneditor-contextmenu button.jsoneditor-duplicate:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-duplicate:focus > div.jsoneditor-icon {
|
||||
background-position: -48px 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-sort-asc > div.jsoneditor-icon {
|
||||
background-position: -168px -24px;
|
||||
}
|
||||
div.jsoneditor-contextmenu button.jsoneditor-sort-asc:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-sort-asc:focus > div.jsoneditor-icon {
|
||||
background-position: -168px 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-sort-desc > div.jsoneditor-icon {
|
||||
background-position: -192px -24px;
|
||||
}
|
||||
div.jsoneditor-contextmenu button.jsoneditor-sort-desc:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-sort-desc:focus > div.jsoneditor-icon {
|
||||
background-position: -192px 0;
|
||||
}
|
||||
|
||||
/* ContextMenu - sub menu */
|
||||
|
||||
div.jsoneditor-contextmenu ul li button.jsoneditor-selected,
|
||||
div.jsoneditor-contextmenu ul li button.jsoneditor-selected:hover,
|
||||
div.jsoneditor-contextmenu ul li button.jsoneditor-selected:focus {
|
||||
color: white;
|
||||
background-color: #ee422e;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li ul {
|
||||
display: none;
|
||||
position: relative;
|
||||
left: -10px;
|
||||
top: 0;
|
||||
|
||||
border: none;
|
||||
box-shadow: inset 0 0 10px rgba(128, 128, 128, 0.5);
|
||||
padding: 0 10px;
|
||||
|
||||
/* TODO: transition is not supported on IE8-9 */
|
||||
-webkit-transition: all 0.3s ease-out;
|
||||
-moz-transition: all 0.3s ease-out;
|
||||
-o-transition: all 0.3s ease-out;
|
||||
transition: all 0.3s ease-out;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li.jsoneditor-selected ul {
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li ul li button {
|
||||
padding-left: 24px;
|
||||
animation: all ease-in-out 1s;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu ul li ul li button:hover,
|
||||
div.jsoneditor-contextmenu ul li ul li button:focus {
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-string > div.jsoneditor-icon {
|
||||
background-position: -144px -24px;
|
||||
}
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-string:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-string:focus > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-string.jsoneditor-selected > div.jsoneditor-icon{
|
||||
background-position: -144px 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-auto > div.jsoneditor-icon {
|
||||
background-position: -120px -24px;
|
||||
}
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-auto:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-auto:focus > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-auto.jsoneditor-selected > div.jsoneditor-icon {
|
||||
background-position: -120px 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-object > div.jsoneditor-icon {
|
||||
background-position: -72px -24px;
|
||||
}
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-object:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-object:focus > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-object.jsoneditor-selected > div.jsoneditor-icon{
|
||||
background-position: -72px 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-array > div.jsoneditor-icon {
|
||||
background-position: -96px -24px;
|
||||
}
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-array:hover > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-array:focus > div.jsoneditor-icon,
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-array.jsoneditor-selected > div.jsoneditor-icon{
|
||||
background-position: -96px 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-contextmenu button.jsoneditor-type-modes > div.jsoneditor-icon {
|
||||
background-image: none;
|
||||
width: 6px;
|
||||
}
|
|
@ -1,893 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="216"
|
||||
height="144"
|
||||
id="svg4136"
|
||||
version="1.1"
|
||||
inkscape:version="0.91 r"
|
||||
sodipodi:docname="jsoneditor-icons.svg">
|
||||
<title
|
||||
id="title6512">JSON Editor Icons</title>
|
||||
<metadata
|
||||
id="metadata4148">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>JSON Editor Icons</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<defs
|
||||
id="defs4146" />
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1028"
|
||||
id="namedview4144"
|
||||
showgrid="true"
|
||||
inkscape:zoom="4"
|
||||
inkscape:cx="97.217248"
|
||||
inkscape:cy="59.950227"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg4136"
|
||||
showguides="false"
|
||||
borderlayer="false"
|
||||
inkscape:showpageshadow="true"
|
||||
showborder="true">
|
||||
<inkscape:grid
|
||||
type="xygrid"
|
||||
id="grid4640"
|
||||
empspacing="24" />
|
||||
</sodipodi:namedview>
|
||||
<!-- Created with SVG-edit - http://svg-edit.googlecode.com/ -->
|
||||
<g
|
||||
id="g4394">
|
||||
<rect
|
||||
x="4"
|
||||
y="4"
|
||||
width="16"
|
||||
height="16"
|
||||
id="svg_1"
|
||||
style="fill:#1aae1c;fill-opacity:1;stroke:none;stroke-width:0" />
|
||||
<rect
|
||||
style="fill:#ec3f29;fill-opacity:0.94117647;stroke:none;stroke-width:0"
|
||||
x="28.000006"
|
||||
y="3.999995"
|
||||
width="16"
|
||||
height="16"
|
||||
id="svg_1-7" />
|
||||
<rect
|
||||
id="rect4165"
|
||||
height="16"
|
||||
width="16"
|
||||
y="3.999995"
|
||||
x="52.000004"
|
||||
style="fill:#4c4c4c;fill-opacity:1;stroke:none;stroke-width:0" />
|
||||
<rect
|
||||
style="fill:#4c4c4c;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
x="172.00002"
|
||||
y="3.9999852"
|
||||
width="16"
|
||||
height="16"
|
||||
id="rect4175" />
|
||||
<rect
|
||||
style="fill:#4c4c4c;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
x="196"
|
||||
y="3.999995"
|
||||
width="16"
|
||||
height="16"
|
||||
id="rect4175-3" />
|
||||
<g
|
||||
style="stroke:none"
|
||||
id="g4299">
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="svg_1-1"
|
||||
height="1.9999986"
|
||||
width="9.9999924"
|
||||
y="10.999998"
|
||||
x="7.0000048" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="svg_1-1-1"
|
||||
height="9.9999838"
|
||||
width="1.9999955"
|
||||
y="7.0000114"
|
||||
x="11.000005" />
|
||||
</g>
|
||||
<g
|
||||
style="stroke:none"
|
||||
transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,19.029435,12.000001)"
|
||||
id="g4299-3">
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="svg_1-1-0"
|
||||
height="1.9999986"
|
||||
width="9.9999924"
|
||||
y="10.999998"
|
||||
x="7.0000048" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="svg_1-1-1-9"
|
||||
height="9.9999838"
|
||||
width="1.9999955"
|
||||
y="7.0000114"
|
||||
x="11.000005" />
|
||||
</g>
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||
x="55.000004"
|
||||
y="7.0000048"
|
||||
width="6.9999909"
|
||||
height="6.9999905"
|
||||
id="svg_1-7-5" />
|
||||
<rect
|
||||
id="rect4354"
|
||||
height="6.9999905"
|
||||
width="6.9999909"
|
||||
y="10.00001"
|
||||
x="58"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#4c4c4c;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#3c80df;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:0.94117647"
|
||||
x="58.000004"
|
||||
y="10.000005"
|
||||
width="6.9999909"
|
||||
height="6.9999905"
|
||||
id="svg_1-7-5-7" />
|
||||
<g
|
||||
id="g4378">
|
||||
<rect
|
||||
id="svg_1-7-5-3"
|
||||
height="1.9999965"
|
||||
width="7.9999909"
|
||||
y="10.999999"
|
||||
x="198"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||
x="198"
|
||||
y="7.0000005"
|
||||
width="11.999995"
|
||||
height="1.9999946"
|
||||
id="rect4374" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||
x="198"
|
||||
y="14.999996"
|
||||
width="3.9999928"
|
||||
height="1.9999995"
|
||||
id="rect4376" />
|
||||
</g>
|
||||
<g
|
||||
id="g4383"
|
||||
transform="matrix(1,0,0,-1,-23.999995,23.999995)">
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||
x="198"
|
||||
y="10.999999"
|
||||
width="7.9999909"
|
||||
height="1.9999965"
|
||||
id="rect4385" />
|
||||
<rect
|
||||
id="rect4387"
|
||||
height="1.9999946"
|
||||
width="11.999995"
|
||||
y="7.0000005"
|
||||
x="198"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
|
||||
<rect
|
||||
id="rect4389"
|
||||
height="1.9999995"
|
||||
width="3.9999928"
|
||||
y="14.999996"
|
||||
x="198"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
|
||||
</g>
|
||||
<rect
|
||||
y="3.9999199"
|
||||
x="76"
|
||||
height="16"
|
||||
width="16"
|
||||
id="rect3754-4"
|
||||
style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4351"
|
||||
d="m 85.10447,6.0157384 -0.0156,1.4063 c 3.02669,-0.2402 0.33008,3.6507996 2.48438,4.5780996 -2.18694,1.0938 0.49191,4.9069 -2.45313,4.5781 l -0.0156,1.4219 c 5.70828,0.559 1.03264,-5.1005 4.70313,-5.2656 l 0,-1.4063 c -3.61303,-0.027 1.11893,-5.7069996 -4.70313,-5.3124996 z"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4351-9"
|
||||
d="m 82.78125,5.9984384 0.0156,1.4063 c -3.02668,-0.2402 -0.33007,3.6506996 -2.48437,4.5780996 2.18694,1.0938 -0.49192,4.9069 2.45312,4.5781 l 0.0156,1.4219 c -5.70827,0.559 -1.03263,-5.1004 -4.70312,-5.2656 l 0,-1.4063 c 3.61303,-0.027 -1.11894,-5.7070996 4.70312,-5.3124996 z"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
y="3.9999199"
|
||||
x="100"
|
||||
height="16"
|
||||
width="16"
|
||||
id="rect3754-25"
|
||||
style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path2987"
|
||||
d="m 103.719,5.6719384 0,12.7187996 3.03125,0 0,-1.5313 -1.34375,0 0,-9.6249996 1.375,0 0,-1.5625 z"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path2987-1"
|
||||
d="m 112.2185,5.6721984 0,12.7187996 -3.03125,0 0,-1.5313 1.34375,0 0,-9.6249996 -1.375,0 0,-1.5625 z"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none" />
|
||||
<rect
|
||||
y="3.9999199"
|
||||
x="124"
|
||||
height="16"
|
||||
width="16"
|
||||
id="rect3754-73"
|
||||
style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3780"
|
||||
d="m 126.2824,17.602938 1.78957,0 1.14143,-2.8641 5.65364,0 1.14856,2.8641 1.76565,0 -4.78687,-11.1610996 -1.91903,0 z"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3782"
|
||||
d="m 129.72704,13.478838 4.60852,0.01 -2.30426,-5.5497996 z"
|
||||
style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
|
||||
<rect
|
||||
y="3.9999199"
|
||||
x="148"
|
||||
height="16"
|
||||
width="16"
|
||||
id="rect3754-35"
|
||||
style="fill:#4c4c4c;fill-opacity:1;stroke:none" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5008-2"
|
||||
d="m 156.47655,5.8917384 0,2.1797 0.46093,2.3983996 1.82813,0 0.39844,-2.3983996 0,-2.1797 z"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5008-2-8"
|
||||
d="m 152.51561,5.8906384 0,2.1797 0.46094,2.3983996 1.82812,0 0.39844,-2.3983996 0,-2.1797 z"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none" />
|
||||
</g>
|
||||
<rect
|
||||
x="4"
|
||||
y="27.999994"
|
||||
width="16"
|
||||
height="16"
|
||||
id="rect4432"
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0" />
|
||||
<rect
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
x="28.000006"
|
||||
y="27.99999"
|
||||
width="16"
|
||||
height="16"
|
||||
id="rect4434" />
|
||||
<rect
|
||||
id="rect4436"
|
||||
height="16"
|
||||
width="16"
|
||||
y="27.99999"
|
||||
x="52.000004"
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:#000000;stroke-width:0" />
|
||||
<rect
|
||||
style="fill:#d3d3d3;stroke:#000000;stroke-width:0"
|
||||
x="172.00002"
|
||||
y="27.999981"
|
||||
width="16"
|
||||
height="16"
|
||||
id="rect4446" />
|
||||
<rect
|
||||
style="fill:#d3d3d3;stroke:#000000;stroke-width:0"
|
||||
x="196"
|
||||
y="27.99999"
|
||||
width="16"
|
||||
height="16"
|
||||
id="rect4448" />
|
||||
<g
|
||||
id="g4466"
|
||||
style="stroke:none"
|
||||
transform="translate(0,23.999995)">
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="rect4468"
|
||||
height="1.9999986"
|
||||
width="9.9999924"
|
||||
y="10.999998"
|
||||
x="7.0000048" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="rect4470"
|
||||
height="9.9999838"
|
||||
width="1.9999955"
|
||||
y="7.0000114"
|
||||
x="11.000005" />
|
||||
</g>
|
||||
<g
|
||||
transform="matrix(0.70710678,-0.70710678,0.70710678,0.70710678,19.029435,35.999996)"
|
||||
id="g4472"
|
||||
style="stroke:none">
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="rect4474"
|
||||
height="1.9999986"
|
||||
width="9.9999924"
|
||||
y="10.999998"
|
||||
x="7.0000048" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:0"
|
||||
id="rect4476"
|
||||
height="9.9999838"
|
||||
width="1.9999955"
|
||||
y="7.0000114"
|
||||
x="11.000005" />
|
||||
</g>
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||
x="55.000004"
|
||||
y="31"
|
||||
width="6.9999909"
|
||||
height="6.9999905"
|
||||
id="rect4478" />
|
||||
<rect
|
||||
id="rect4480"
|
||||
height="6.9999905"
|
||||
width="6.9999909"
|
||||
y="34.000008"
|
||||
x="58"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#d3d3d3;stroke-width:2;stroke-miterlimit:4;stroke-dasharray:none" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#d3d3d3;stroke-width:0;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
x="58.000004"
|
||||
y="34.000004"
|
||||
width="6.9999909"
|
||||
height="6.9999905"
|
||||
id="rect4482" />
|
||||
<g
|
||||
id="g4484"
|
||||
transform="translate(0,23.999995)">
|
||||
<rect
|
||||
id="rect4486"
|
||||
height="1.9999965"
|
||||
width="7.9999909"
|
||||
y="10.999999"
|
||||
x="198"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||
x="198"
|
||||
y="7.0000005"
|
||||
width="11.999995"
|
||||
height="1.9999946"
|
||||
id="rect4488" />
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||
x="198"
|
||||
y="14.999996"
|
||||
width="3.9999928"
|
||||
height="1.9999995"
|
||||
id="rect4490" />
|
||||
</g>
|
||||
<g
|
||||
id="g4492"
|
||||
transform="matrix(1,0,0,-1,-23.999995,47.99999)">
|
||||
<rect
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0"
|
||||
x="198"
|
||||
y="10.999999"
|
||||
width="7.9999909"
|
||||
height="1.9999965"
|
||||
id="rect4494" />
|
||||
<rect
|
||||
id="rect4496"
|
||||
height="1.9999946"
|
||||
width="11.999995"
|
||||
y="7.0000005"
|
||||
x="198"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
|
||||
<rect
|
||||
id="rect4498"
|
||||
height="1.9999995"
|
||||
width="3.9999928"
|
||||
y="14.999996"
|
||||
x="198"
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#000000;stroke-width:0" />
|
||||
</g>
|
||||
<rect
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none"
|
||||
id="rect3754-8"
|
||||
width="16"
|
||||
height="16"
|
||||
x="76"
|
||||
y="27.99992" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 85.10448,30.015537 -0.0156,1.4063 c 3.02668,-0.2402 0.33007,3.6508 2.48438,4.5781 -2.18695,1.0938 0.49191,4.90688 -2.45313,4.57808 l -0.0156,1.4219 c 5.70827,0.559 1.03263,-5.10048 4.70313,-5.26558 l 0,-1.4063 c -3.61304,-0.027 1.11893,-5.707 -4.70313,-5.3125 z"
|
||||
id="path4351-1"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccc" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:#ffffff;stroke-width:0.2;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 82.78126,29.998237 0.0156,1.4063 c -3.02668,-0.2402 -0.33008,3.6507 -2.48438,4.5781 2.18694,1.0938 -0.49191,4.90688 2.45313,4.57808 l 0.0156,1.4219 c -5.70828,0.559 -1.03264,-5.10038 -4.70313,-5.26558 l 0,-1.4063 c 3.61303,-0.027 -1.11893,-5.7071 4.70313,-5.3125 z"
|
||||
id="path4351-9-5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccc" />
|
||||
<rect
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none"
|
||||
id="rect3754-65"
|
||||
width="16"
|
||||
height="16"
|
||||
x="100"
|
||||
y="27.99992" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
||||
d="m 103.719,29.671937 0,12.71878 3.03125,0 0,-1.5313 -1.34375,0 0,-9.62498 1.375,0 0,-1.5625 z"
|
||||
id="path2987-8"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
||||
d="m 112.2185,29.671937 0,12.71878 -3.03125,0 0,-1.5313 1.34375,0 0,-9.62498 -1.375,0 0,-1.5625 z"
|
||||
id="path2987-1-9"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none"
|
||||
id="rect3754-92"
|
||||
width="16"
|
||||
height="16"
|
||||
x="124"
|
||||
y="27.99992" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
||||
d="m 126.2824,41.602917 1.78957,0 1.14143,-2.86408 5.65364,0 1.14856,2.86408 1.76565,0 -4.78687,-11.16108 -1.91902,0 z"
|
||||
id="path3780-9"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccccc" />
|
||||
<path
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none"
|
||||
d="m 129.72704,37.478837 4.60852,0.01 -2.30426,-5.5498 z"
|
||||
id="path3782-2"
|
||||
inkscape:connector-curvature="0" />
|
||||
<rect
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none"
|
||||
id="rect3754-47"
|
||||
width="16"
|
||||
height="16"
|
||||
x="148"
|
||||
y="27.99992" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
||||
d="m 156.47656,29.891737 0,2.1797 0.46093,2.3984 1.82813,0 0.39844,-2.3984 0,-2.1797 z"
|
||||
id="path5008-2-1"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccc" />
|
||||
<path
|
||||
style="fill:#ffffff;fill-opacity:1;stroke:none"
|
||||
d="m 152.51562,29.890637 0,2.1797 0.46094,2.3984 1.82812,0 0.39844,-2.3984 0,-2.1797 z"
|
||||
id="path5008-2-8-8"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="ccccccc" />
|
||||
<rect
|
||||
id="svg_1-7-2"
|
||||
height="1.9999961"
|
||||
width="11.999996"
|
||||
y="64"
|
||||
x="54"
|
||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
|
||||
<rect
|
||||
id="svg_1-7-2-2"
|
||||
height="2.9999905"
|
||||
width="2.9999907"
|
||||
y="52"
|
||||
x="80.000008"
|
||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
|
||||
<rect
|
||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
||||
x="85.000008"
|
||||
y="52"
|
||||
width="2.9999907"
|
||||
height="2.9999905"
|
||||
id="rect4561" />
|
||||
<rect
|
||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
||||
x="80.000008"
|
||||
y="58"
|
||||
width="2.9999907"
|
||||
height="2.9999905"
|
||||
id="rect4563" />
|
||||
<rect
|
||||
id="rect4565"
|
||||
height="2.9999905"
|
||||
width="2.9999907"
|
||||
y="58"
|
||||
x="85.000008"
|
||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
|
||||
<rect
|
||||
id="rect4567"
|
||||
height="2.9999905"
|
||||
width="2.9999907"
|
||||
y="64"
|
||||
x="80.000008"
|
||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
|
||||
<rect
|
||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
||||
x="85.000008"
|
||||
y="64"
|
||||
width="2.9999907"
|
||||
height="2.9999905"
|
||||
id="rect4569" />
|
||||
<circle
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#4c4c4c;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
id="path4571"
|
||||
cx="110.06081"
|
||||
cy="57.939209"
|
||||
r="4.7438836" />
|
||||
<rect
|
||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
||||
x="116.64566"
|
||||
y="-31.79752"
|
||||
width="4.229713"
|
||||
height="6.4053884"
|
||||
id="rect4563-2"
|
||||
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)" />
|
||||
<path
|
||||
style="fill:#4c4c4c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 125,56 138.77027,56.095 132,64 Z"
|
||||
id="path4613"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4615"
|
||||
d="M 149,64 162.77027,63.905 156,56 Z"
|
||||
style="fill:#4c4c4c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
||||
x="54"
|
||||
y="53"
|
||||
width="11.999996"
|
||||
height="1.9999961"
|
||||
id="rect4638" />
|
||||
<rect
|
||||
id="svg_1-7-2-24"
|
||||
height="1.9999957"
|
||||
width="12.99999"
|
||||
y="-56"
|
||||
x="53"
|
||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
||||
transform="matrix(0,1,-1,0,0,0)" />
|
||||
<rect
|
||||
transform="matrix(0,1,-1,0,0,0)"
|
||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0"
|
||||
x="53"
|
||||
y="-66"
|
||||
width="12.99999"
|
||||
height="1.9999957"
|
||||
id="rect4657" />
|
||||
<rect
|
||||
id="rect4659"
|
||||
height="0.99999291"
|
||||
width="11.999999"
|
||||
y="57"
|
||||
x="54"
|
||||
style="fill:#4c4c4c;fill-opacity:0.98431373;stroke:none;stroke-width:0" />
|
||||
<rect
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
||||
x="54"
|
||||
y="88.000122"
|
||||
width="11.999996"
|
||||
height="1.9999961"
|
||||
id="rect4661" />
|
||||
<rect
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
||||
x="80.000008"
|
||||
y="76.000122"
|
||||
width="2.9999907"
|
||||
height="2.9999905"
|
||||
id="rect4663" />
|
||||
<rect
|
||||
id="rect4665"
|
||||
height="2.9999905"
|
||||
width="2.9999907"
|
||||
y="76.000122"
|
||||
x="85.000008"
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
|
||||
<rect
|
||||
id="rect4667"
|
||||
height="2.9999905"
|
||||
width="2.9999907"
|
||||
y="82.000122"
|
||||
x="80.000008"
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
|
||||
<rect
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
||||
x="85.000008"
|
||||
y="82.000122"
|
||||
width="2.9999907"
|
||||
height="2.9999905"
|
||||
id="rect4669" />
|
||||
<rect
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
||||
x="80.000008"
|
||||
y="88.000122"
|
||||
width="2.9999907"
|
||||
height="2.9999905"
|
||||
id="rect4671" />
|
||||
<rect
|
||||
id="rect4673"
|
||||
height="2.9999905"
|
||||
width="2.9999907"
|
||||
y="88.000122"
|
||||
x="85.000008"
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
|
||||
<circle
|
||||
r="4.7438836"
|
||||
cy="81.939331"
|
||||
cx="110.06081"
|
||||
id="circle4675"
|
||||
style="opacity:1;fill:none;fill-opacity:1;stroke:#d3d3d3;stroke-width:2;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<rect
|
||||
transform="matrix(0.70710678,0.70710678,-0.70710678,0.70710678,0,0)"
|
||||
id="rect4677"
|
||||
height="6.4053884"
|
||||
width="4.229713"
|
||||
y="-14.826816"
|
||||
x="133.6163"
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:#d3d3d3;stroke-width:0;stroke-opacity:1" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4679"
|
||||
d="m 125,80.000005 13.77027,0.09499 L 132,87.999992 Z"
|
||||
style="fill:#d3d3d3;fill-opacity:1;fill-rule:evenodd;stroke:#d3d3d3;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:#d3d3d3;fill-opacity:1;fill-rule:evenodd;stroke:#d3d3d3;stroke-width:0;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 149,88.0002 162.77027,87.9052 156,80.0002 Z"
|
||||
id="path4681"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<rect
|
||||
id="rect4683"
|
||||
height="1.9999961"
|
||||
width="11.999996"
|
||||
y="77.000122"
|
||||
x="54"
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1" />
|
||||
<rect
|
||||
transform="matrix(0,1,-1,0,0,0)"
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
||||
x="77.000122"
|
||||
y="-56"
|
||||
width="12.99999"
|
||||
height="1.9999957"
|
||||
id="rect4685" />
|
||||
<rect
|
||||
id="rect4687"
|
||||
height="1.9999957"
|
||||
width="12.99999"
|
||||
y="-66"
|
||||
x="77.000122"
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
||||
transform="matrix(0,1,-1,0,0,0)" />
|
||||
<rect
|
||||
style="fill:#d3d3d3;fill-opacity:1;stroke:none;stroke-width:0;stroke-opacity:1"
|
||||
x="54"
|
||||
y="81.000122"
|
||||
width="11.999999"
|
||||
height="0.99999291"
|
||||
id="rect4689" />
|
||||
<rect
|
||||
id="rect4761-1"
|
||||
height="1.9999945"
|
||||
width="15.99999"
|
||||
y="101"
|
||||
x="76.000008"
|
||||
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
|
||||
<rect
|
||||
id="rect4761-0"
|
||||
height="1.9999945"
|
||||
width="15.99999"
|
||||
y="105"
|
||||
x="76.000008"
|
||||
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
|
||||
<rect
|
||||
id="rect4761-7"
|
||||
height="1.9999945"
|
||||
width="9"
|
||||
y="109"
|
||||
x="76.000008"
|
||||
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
|
||||
<rect
|
||||
id="rect4761-1-1"
|
||||
height="1.9999945"
|
||||
width="12"
|
||||
y="125"
|
||||
x="76.000008"
|
||||
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
|
||||
<rect
|
||||
id="rect4761-1-1-4"
|
||||
height="1.9999945"
|
||||
width="10"
|
||||
y="137"
|
||||
x="76.000008"
|
||||
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
|
||||
<rect
|
||||
id="rect4761-1-1-4-4"
|
||||
height="1.9999945"
|
||||
width="10"
|
||||
y="129"
|
||||
x="82"
|
||||
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
|
||||
<rect
|
||||
id="rect4761-1-1-4-4-3"
|
||||
height="1.9999945"
|
||||
width="9"
|
||||
y="133"
|
||||
x="82"
|
||||
style="fill:#ffffff;fill-opacity:0.80000007;stroke:none;stroke-width:0" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 36.398438,100.0254 c -0.423362,-0.013 -0.846847,0.01 -1.265626,0.062 -1.656562,0.2196 -3.244567,0.9739 -4.507812,2.2266 L 29,100.5991 l -2.324219,7.7129 7.826172,-1.9062 -1.804687,-1.9063 c 1.597702,-1.5308 4.048706,-1.8453 5.984375,-0.7207 1.971162,1.1452 2.881954,3.3975 2.308593,5.5508 -0.573361,2.1533 -2.533865,3.6953 -4.830078,3.6953 l 0,3.0742 c 3.550756,0 6.710442,-2.4113 7.650391,-5.9414 0.939949,-3.5301 -0.618463,-7.2736 -3.710938,-9.0703 -1.159678,-0.6738 -2.431087,-1.0231 -3.701171,-1.0625 z"
|
||||
id="path4138" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.8;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 59.722656,99.9629 c -1.270084,0.039 -2.541493,0.3887 -3.701172,1.0625 -3.092475,1.7967 -4.650886,5.5402 -3.710937,9.0703 0.939949,3.5301 4.09768,5.9414 7.648437,5.9414 l 0,-3.0742 c -2.296214,0 -4.256717,-1.542 -4.830078,-3.6953 -0.573361,-2.1533 0.337432,-4.4056 2.308594,-5.5508 1.935731,-1.1246 4.38863,-0.8102 5.986326,0.7207 l -1.806638,1.9063 7.828128,1.9062 -2.32422,-7.7129 -1.62696,1.7168 c -1.26338,-1.2531 -2.848917,-2.0088 -4.505855,-2.2285 -0.418778,-0.055 -0.842263,-0.076 -1.265625,-0.062 z"
|
||||
id="path4138-1" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.966;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="m 10.5,100 0,2 -2.4999996,0 L 12,107 l 4,-5 -2.5,0 0,-2 -3,0 z"
|
||||
id="path3055-0-77" />
|
||||
<path
|
||||
style="opacity:0.8;fill:none;stroke:#ffffff;stroke-width:1.966;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 4.9850574,108.015 14.0298856,-0.03"
|
||||
id="path5244-5-0-5"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
style="opacity:0.8;fill:none;stroke:#ffffff;stroke-width:1.966;stroke-linecap:square;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="m 4.9849874,132.015 14.0298866,-0.03"
|
||||
id="path5244-5-0-5-8"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cc" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 36.398438,123.9629 c -0.423362,-0.013 -0.846847,0.01 -1.265626,0.062 -1.656562,0.2196 -3.244567,0.9739 -4.507812,2.2266 L 29,124.5366 l -2.324219,7.7129 7.826172,-1.9062 -1.804687,-1.9063 c 1.597702,-1.5308 4.048706,-1.8453 5.984375,-0.7207 1.971162,1.1453 2.881954,3.3975 2.308593,5.5508 -0.573361,2.1533 -2.533864,3.6953 -4.830078,3.6953 l 0,3.0742 c 3.550757,0 6.710442,-2.4093 7.650391,-5.9394 0.939949,-3.5301 -0.618463,-7.2756 -3.710938,-9.0723 -1.159678,-0.6737 -2.431087,-1.0231 -3.701171,-1.0625 z"
|
||||
id="path4138-12" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;baseline-shift:baseline;text-anchor:start;white-space:normal;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;opacity:0.4;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;fill:#4d4d4d;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:2.66157866;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate"
|
||||
d="m 59.722656,123.9629 c -1.270084,0.039 -2.541493,0.3888 -3.701172,1.0625 -3.092475,1.7967 -4.650886,5.5422 -3.710937,9.0723 0.939949,3.5301 4.09768,5.9394 7.648437,5.9394 l 0,-3.0742 c -2.296214,0 -4.256717,-1.542 -4.830078,-3.6953 -0.573361,-2.1533 0.337432,-4.4055 2.308594,-5.5508 1.935731,-1.1246 4.38863,-0.8102 5.986326,0.7207 l -1.806638,1.9063 7.828128,1.9062 -2.32422,-7.7129 -1.62696,1.7168 c -1.26338,-1.2531 -2.848917,-2.0088 -4.505855,-2.2285 -0.418778,-0.055 -0.842263,-0.076 -1.265625,-0.062 z"
|
||||
id="path4138-1-3" />
|
||||
<path
|
||||
id="path6191"
|
||||
d="m 10.5,116 0,-2 -2.4999996,0 L 12,109 l 4,5 -2.5,0 0,2 -3,0 z"
|
||||
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.966;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
inkscape:connector-curvature="0"
|
||||
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.966;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
d="m 10.5,129 0,-2 -2.4999996,0 L 12,122 l 4,5 -2.5,0 0,2 -3,0 z"
|
||||
id="path6193" />
|
||||
<path
|
||||
id="path6195"
|
||||
d="m 10.5,135 0,2 -2.4999996,0 L 12,142 l 4,-5 -2.5,0 0,-2 -3,0 z"
|
||||
style="opacity:0.8;fill:#ffffff;fill-opacity:1;stroke:none;stroke-width:1.966;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
sodipodi:type="star"
|
||||
style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
id="path4500"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="11.55581"
|
||||
sodipodi:cy="60.073242"
|
||||
sodipodi:r1="5.1116104"
|
||||
sodipodi:r2="2.5558052"
|
||||
sodipodi:arg1="0"
|
||||
sodipodi:arg2="1.0471976"
|
||||
inkscape:flatsided="false"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 16.66742,60.073242 -3.833708,2.213392 -3.8337072,2.213393 0,-4.426785 0,-4.426784 3.8337082,2.213392 z"
|
||||
inkscape:transform-center-x="-1.2779026" />
|
||||
<path
|
||||
inkscape:transform-center-x="1.277902"
|
||||
d="m -31.500004,60.073242 -3.833708,2.213392 -3.833707,2.213393 0,-4.426785 0,-4.426784 3.833707,2.213392 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="false"
|
||||
sodipodi:arg2="1.0471976"
|
||||
sodipodi:arg1="0"
|
||||
sodipodi:r2="2.5558052"
|
||||
sodipodi:r1="5.1116104"
|
||||
sodipodi:cy="60.073242"
|
||||
sodipodi:cx="-36.611614"
|
||||
sodipodi:sides="3"
|
||||
id="path4502"
|
||||
style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
sodipodi:type="star"
|
||||
transform="scale(-1,1)" />
|
||||
<path
|
||||
d="m 16.66742,60.073212 -3.833708,2.213392 -3.8337072,2.213392 0,-4.426784 0,-4.426785 3.8337082,2.213392 z"
|
||||
inkscape:randomized="0"
|
||||
inkscape:rounded="0"
|
||||
inkscape:flatsided="false"
|
||||
sodipodi:arg2="1.0471976"
|
||||
sodipodi:arg1="0"
|
||||
sodipodi:r2="2.5558052"
|
||||
sodipodi:r1="5.1116104"
|
||||
sodipodi:cy="60.073212"
|
||||
sodipodi:cx="11.55581"
|
||||
sodipodi:sides="3"
|
||||
id="path4504"
|
||||
style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
sodipodi:type="star"
|
||||
transform="matrix(0,1,-1,0,72.0074,71.7877)"
|
||||
inkscape:transform-center-y="1.2779029" />
|
||||
<path
|
||||
inkscape:transform-center-y="-1.2779026"
|
||||
transform="matrix(0,-1,-1,0,96,96)"
|
||||
sodipodi:type="star"
|
||||
style="fill:#4d4d4d;fill-opacity:0.90196078;stroke:#d3d3d3;stroke-width:0;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none"
|
||||
id="path4506"
|
||||
sodipodi:sides="3"
|
||||
sodipodi:cx="11.55581"
|
||||
sodipodi:cy="60.073212"
|
||||
sodipodi:r1="5.1116104"
|
||||
sodipodi:r2="2.5558052"
|
||||
sodipodi:arg1="0"
|
||||
sodipodi:arg2="1.0471976"
|
||||
inkscape:flatsided="false"
|
||||
inkscape:rounded="0"
|
||||
inkscape:randomized="0"
|
||||
d="m 16.66742,60.073212 -3.833708,2.213392 -3.8337072,2.213392 0,-4.426784 0,-4.426785 3.8337082,2.213392 z" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path4615-5"
|
||||
d="m 171.82574,65.174193 16.34854,0 -8.17427,-13.348454 z"
|
||||
style="fill:#fbb917;fill-opacity:1;fill-rule:evenodd;stroke:#fbb917;stroke-width:1.65161395;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 179,55 0,6 2,0 0,-6"
|
||||
id="path4300"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
<path
|
||||
style="opacity:1;fill:#ffffff;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="m 179,62 0,2 2,0 0,-2"
|
||||
id="path4300-6"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</svg>
|
Before Width: | Height: | Size: 35 KiB |
|
@ -1,449 +0,0 @@
|
|||
|
||||
div.jsoneditor {
|
||||
|
||||
}
|
||||
|
||||
div.jsoneditor-field,
|
||||
div.jsoneditor-value,
|
||||
div.jsoneditor-readonly {
|
||||
border: 1px solid transparent;
|
||||
min-height: 16px;
|
||||
min-width: 32px;
|
||||
padding: 2px;
|
||||
margin: 1px;
|
||||
word-wrap: break-word;
|
||||
float: left;
|
||||
}
|
||||
|
||||
/* adjust margin of p elements inside editable divs, needed for Opera, IE */
|
||||
div.jsoneditor-field p,
|
||||
div.jsoneditor-value p {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-value {
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
div.jsoneditor-readonly {
|
||||
min-width: 16px;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
div.jsoneditor-empty {
|
||||
border-color: lightgray;
|
||||
border-style: dashed;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
div.jsoneditor-field.jsoneditor-empty::after,
|
||||
div.jsoneditor-value.jsoneditor-empty::after {
|
||||
pointer-events: none;
|
||||
color: lightgray;
|
||||
font-size: 8pt;
|
||||
}
|
||||
|
||||
div.jsoneditor-field.jsoneditor-empty::after {
|
||||
content: "field";
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-empty::after {
|
||||
content: "value";
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-url,
|
||||
a.jsoneditor-value.jsoneditor-url {
|
||||
color: green;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
a.jsoneditor-value.jsoneditor-url {
|
||||
display: inline-block;
|
||||
padding: 2px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
a.jsoneditor-value.jsoneditor-url:hover,
|
||||
a.jsoneditor-value.jsoneditor-url:focus {
|
||||
color: #ee422e;
|
||||
}
|
||||
|
||||
div.jsoneditor td.jsoneditor-separator {
|
||||
padding: 3px 0;
|
||||
vertical-align: top;
|
||||
color: gray;
|
||||
}
|
||||
|
||||
div.jsoneditor-field[contenteditable=true]:focus,
|
||||
div.jsoneditor-field[contenteditable=true]:hover,
|
||||
div.jsoneditor-value[contenteditable=true]:focus,
|
||||
div.jsoneditor-value[contenteditable=true]:hover,
|
||||
div.jsoneditor-field.jsoneditor-highlight,
|
||||
div.jsoneditor-value.jsoneditor-highlight {
|
||||
background-color: #FFFFAB;
|
||||
border: 1px solid yellow;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
div.jsoneditor-field.jsoneditor-highlight-active,
|
||||
div.jsoneditor-field.jsoneditor-highlight-active:focus,
|
||||
div.jsoneditor-field.jsoneditor-highlight-active:hover,
|
||||
div.jsoneditor-value.jsoneditor-highlight-active,
|
||||
div.jsoneditor-value.jsoneditor-highlight-active:focus,
|
||||
div.jsoneditor-value.jsoneditor-highlight-active:hover {
|
||||
background-color: #ffee00;
|
||||
border: 1px solid #ffc700;
|
||||
border-radius: 2px;
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-string {
|
||||
color: #008000;
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-object,
|
||||
div.jsoneditor-value.jsoneditor-array {
|
||||
min-width: 16px;
|
||||
color: #808080;
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-number {
|
||||
color: #ee422e;
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-boolean {
|
||||
color: #ff8c00;
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-null {
|
||||
color: #004ED0;
|
||||
}
|
||||
|
||||
div.jsoneditor-value.jsoneditor-invalid {
|
||||
color: #000000;
|
||||
}
|
||||
|
||||
|
||||
|
||||
div.jsoneditor-tree button {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
background: transparent url('img/jsoneditor-icons.svg');
|
||||
}
|
||||
|
||||
div.jsoneditor-mode-view tr.jsoneditor-expandable td.jsoneditor-tree,
|
||||
div.jsoneditor-mode-form tr.jsoneditor-expandable td.jsoneditor-tree {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree button.jsoneditor-collapsed {
|
||||
background-position: 0 -48px;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree button.jsoneditor-expanded {
|
||||
background-position: 0 -72px;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree button.jsoneditor-contextmenu {
|
||||
background-position: -48px -72px;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree button.jsoneditor-contextmenu:hover,
|
||||
div.jsoneditor-tree button.jsoneditor-contextmenu:focus,
|
||||
div.jsoneditor-tree button.jsoneditor-contextmenu.jsoneditor-selected,
|
||||
tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-contextmenu {
|
||||
background-position: -48px -48px;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree *:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree button:focus {
|
||||
/* TODO: nice outline for buttons with focus
|
||||
outline: #97B0F8 solid 2px;
|
||||
box-shadow: 0 0 8px #97B0F8;
|
||||
*/
|
||||
background-color: #f5f5f5;
|
||||
outline: #e5e5e5 solid 1px;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree button.jsoneditor-invisible {
|
||||
visibility: hidden;
|
||||
background: none;
|
||||
}
|
||||
|
||||
div.jsoneditor {
|
||||
color: #1A1A1A;
|
||||
border: 1px solid #3883fa;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
padding: 0;
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
|
||||
div.jsoneditor-tree table.jsoneditor-tree {
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.jsoneditor-outer {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: -35px 0 0 0;
|
||||
padding: 35px 0 0 0;
|
||||
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
textarea.jsoneditor-text,
|
||||
.ace-jsoneditor {
|
||||
min-height: 150px;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
textarea.jsoneditor-text {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
|
||||
outline-width: 0;
|
||||
border: none;
|
||||
background-color: white;
|
||||
resize: none;
|
||||
}
|
||||
|
||||
tr.jsoneditor-highlight,
|
||||
tr.jsoneditor-selected {
|
||||
background-color: #e6e6e6;
|
||||
}
|
||||
|
||||
tr.jsoneditor-selected button.jsoneditor-dragarea,
|
||||
tr.jsoneditor-selected button.jsoneditor-contextmenu {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-dragarea,
|
||||
tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-contextmenu {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree button.jsoneditor-dragarea {
|
||||
background: url('img/jsoneditor-icons.svg') -72px -72px;
|
||||
cursor: move;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree button.jsoneditor-dragarea:hover,
|
||||
div.jsoneditor-tree button.jsoneditor-dragarea:focus,
|
||||
tr.jsoneditor-selected.jsoneditor-first button.jsoneditor-dragarea {
|
||||
background-position: -72px -48px;
|
||||
}
|
||||
|
||||
div.jsoneditor tr,
|
||||
div.jsoneditor th,
|
||||
div.jsoneditor td {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
div.jsoneditor td {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
div.jsoneditor td.jsoneditor-tree {
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
div.jsoneditor-field,
|
||||
div.jsoneditor-value,
|
||||
div.jsoneditor td,
|
||||
div.jsoneditor th,
|
||||
div.jsoneditor textarea,
|
||||
.jsoneditor-schema-error {
|
||||
font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif;
|
||||
font-size: 10pt;
|
||||
color: #1A1A1A;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* popover */
|
||||
.jsoneditor-schema-error {
|
||||
cursor: default;
|
||||
display: inline-block;
|
||||
/*font-family: arial, sans-serif;*/
|
||||
height: 24px;
|
||||
line-height: 24px;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
width: 24px;
|
||||
}
|
||||
|
||||
div.jsoneditor-tree .jsoneditor-schema-error {
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
margin: 0 4px 0 0;
|
||||
background: url('img/jsoneditor-icons.svg') -168px -48px;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover {
|
||||
background-color: #4c4c4c;
|
||||
border-radius: 3px;
|
||||
box-shadow: 0 0 5px rgba(0,0,0,0.4);
|
||||
color: #fff;
|
||||
display: none;
|
||||
padding: 7px 10px;
|
||||
position: absolute;
|
||||
width: 200px;
|
||||
z-index: 4;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-above {
|
||||
bottom: 32px;
|
||||
left: -98px;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-below {
|
||||
top: 32px;
|
||||
left: -98px;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-left {
|
||||
top: -7px;
|
||||
right: 32px;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-right {
|
||||
top: -7px;
|
||||
left: 32px;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover:before {
|
||||
border-right: 7px solid transparent;
|
||||
border-left: 7px solid transparent;
|
||||
content: '';
|
||||
display: block;
|
||||
left: 50%;
|
||||
margin-left: -7px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-above:before {
|
||||
border-top: 7px solid #4c4c4c;
|
||||
bottom: -7px;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-below:before {
|
||||
border-bottom: 7px solid #4c4c4c;
|
||||
top: -7px;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-left:before {
|
||||
border-left: 7px solid #4c4c4c;
|
||||
border-top: 7px solid transparent;
|
||||
border-bottom: 7px solid transparent;
|
||||
content: '';
|
||||
top: 19px;
|
||||
right: -14px;
|
||||
left: inherit;
|
||||
margin-left: inherit;
|
||||
margin-top: -7px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error .jsoneditor-popover.jsoneditor-right:before {
|
||||
border-right: 7px solid #4c4c4c;
|
||||
border-top: 7px solid transparent;
|
||||
border-bottom: 7px solid transparent;
|
||||
content: '';
|
||||
top: 19px;
|
||||
left: -14px;
|
||||
margin-left: inherit;
|
||||
margin-top: -7px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.jsoneditor-schema-error:hover .jsoneditor-popover,
|
||||
.jsoneditor-schema-error:focus .jsoneditor-popover {
|
||||
display: block;
|
||||
-webkit-animation: fade-in .3s linear 1, move-up .3s linear 1;
|
||||
-moz-animation: fade-in .3s linear 1, move-up .3s linear 1;
|
||||
-ms-animation: fade-in .3s linear 1, move-up .3s linear 1;
|
||||
}
|
||||
|
||||
@-webkit-keyframes fade-in {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
@-moz-keyframes fade-in {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
@-ms-keyframes fade-in {
|
||||
from { opacity: 0; }
|
||||
to { opacity: 1; }
|
||||
}
|
||||
/*@-webkit-keyframes move-up {*/
|
||||
/*from { bottom: 24px; }*/
|
||||
/*to { bottom: 32px; }*/
|
||||
/*}*/
|
||||
/*@-moz-keyframes move-up {*/
|
||||
/*from { bottom: 24px; }*/
|
||||
/*to { bottom: 32px; }*/
|
||||
/*}*/
|
||||
/*@-ms-keyframes move-up {*/
|
||||
/*from { bottom: 24px; }*/
|
||||
/*to { bottom: 32px; }*/
|
||||
/*}*/
|
||||
|
||||
|
||||
/* JSON schema errors displayed at the bottom of the editor in mode text and code */
|
||||
|
||||
.jsoneditor .jsoneditor-text-errors {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
background-color: #ffef8b;
|
||||
border-top: 1px solid #ffd700;
|
||||
}
|
||||
|
||||
.jsoneditor .jsoneditor-text-errors td {
|
||||
padding: 3px 6px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.jsoneditor-text-errors .jsoneditor-schema-error {
|
||||
border: none;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
margin: 0 4px 0 0;
|
||||
background: url('img/jsoneditor-icons.svg') -168px -48px;
|
||||
}
|
||||
|
110
src/css/menu.css
110
src/css/menu.css
|
@ -1,110 +0,0 @@
|
|||
|
||||
div.jsoneditor-menu {
|
||||
width: 100%;
|
||||
height: 35px;
|
||||
padding: 2px;
|
||||
margin: 0;
|
||||
-moz-box-sizing: border-box;
|
||||
-webkit-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
|
||||
color: white;
|
||||
background-color: #3883fa;
|
||||
border-bottom: 1px solid #3883fa;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > button,
|
||||
div.jsoneditor-menu > div.jsoneditor-modes > button {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
margin: 2px;
|
||||
padding: 0;
|
||||
border-radius: 2px;
|
||||
border: 1px solid transparent;
|
||||
background: transparent url('img/jsoneditor-icons.svg');
|
||||
color: white;
|
||||
opacity: 0.8;
|
||||
|
||||
font-family: arial, sans-serif;
|
||||
font-size: 10pt;
|
||||
|
||||
float: left;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > button:hover,
|
||||
div.jsoneditor-menu > div.jsoneditor-modes > button:hover {
|
||||
background-color: rgba(255,255,255,0.2);
|
||||
border: 1px solid rgba(255,255,255,0.4);
|
||||
}
|
||||
div.jsoneditor-menu > button:focus,
|
||||
div.jsoneditor-menu > button:active,
|
||||
div.jsoneditor-menu > div.jsoneditor-modes > button:focus,
|
||||
div.jsoneditor-menu > div.jsoneditor-modes > button:active {
|
||||
background-color: rgba(255,255,255,0.3);
|
||||
}
|
||||
div.jsoneditor-menu > button:disabled,
|
||||
div.jsoneditor-menu > div.jsoneditor-modes > button:disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > button.jsoneditor-collapse-all {
|
||||
background-position: 0 -96px;
|
||||
}
|
||||
div.jsoneditor-menu > button.jsoneditor-expand-all {
|
||||
background-position: 0 -120px;
|
||||
}
|
||||
div.jsoneditor-menu > button.jsoneditor-undo {
|
||||
background-position: -24px -96px;
|
||||
}
|
||||
div.jsoneditor-menu > button.jsoneditor-undo:disabled {
|
||||
background-position: -24px -120px;
|
||||
}
|
||||
div.jsoneditor-menu > button.jsoneditor-redo {
|
||||
background-position: -48px -96px;
|
||||
}
|
||||
div.jsoneditor-menu > button.jsoneditor-redo:disabled {
|
||||
background-position: -48px -120px;
|
||||
}
|
||||
div.jsoneditor-menu > button.jsoneditor-compact {
|
||||
background-position: -72px -96px;
|
||||
}
|
||||
div.jsoneditor-menu > button.jsoneditor-format {
|
||||
background-position: -72px -120px;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > div.jsoneditor-modes {
|
||||
display: inline-block;
|
||||
float: left;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > div.jsoneditor-modes > button {
|
||||
background-image: none;
|
||||
width: auto;
|
||||
padding-left: 6px;
|
||||
padding-right: 6px;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu > button.jsoneditor-separator,
|
||||
div.jsoneditor-menu > div.jsoneditor-modes > button.jsoneditor-separator {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu a {
|
||||
font-family: arial, sans-serif;
|
||||
font-size: 10pt;
|
||||
color: white;
|
||||
opacity: 0.8;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu a:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
div.jsoneditor-menu a.jsoneditor-poweredBy {
|
||||
font-size: 8pt;
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
padding: 10px;
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
/* reset styling (prevent conflicts with bootstrap, materialize.css, etc.) */
|
||||
|
||||
div.jsoneditor input {
|
||||
height: auto;
|
||||
border: inherit;
|
||||
}
|
||||
|
||||
div.jsoneditor input:focus {
|
||||
border: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
div.jsoneditor table {
|
||||
border-collapse: collapse;
|
||||
width: auto;
|
||||
}
|
||||
|
||||
div.jsoneditor td,
|
||||
div.jsoneditor th {
|
||||
padding: 0;
|
||||
display: table-cell;
|
||||
text-align: left;
|
||||
vertical-align: inherit;
|
||||
border-radius: inherit;
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
|
||||
table.jsoneditor-search input,
|
||||
table.jsoneditor-search div.jsoneditor-results {
|
||||
font-family: arial, sans-serif;
|
||||
font-size: 10pt;
|
||||
color: #1A1A1A;
|
||||
background: transparent; /* For Firefox */
|
||||
}
|
||||
|
||||
table.jsoneditor-search div.jsoneditor-results {
|
||||
color: white;
|
||||
padding-right: 5px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
table.jsoneditor-search {
|
||||
position: absolute;
|
||||
right: 4px;
|
||||
top: 4px;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
|
||||
table.jsoneditor-search div.jsoneditor-frame {
|
||||
border: 1px solid transparent;
|
||||
background-color: white;
|
||||
padding: 0 2px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
table.jsoneditor-search div.jsoneditor-frame table {
|
||||
border-collapse: collapse;
|
||||
}
|
||||
|
||||
table.jsoneditor-search input {
|
||||
width: 120px;
|
||||
border: none;
|
||||
outline: none;
|
||||
margin: 1px;
|
||||
line-height: 20px;
|
||||
}
|
||||
|
||||
table.jsoneditor-search button {
|
||||
width: 16px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
background: url('img/jsoneditor-icons.svg');
|
||||
vertical-align: top;
|
||||
}
|
||||
|
||||
table.jsoneditor-search button:hover {
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
table.jsoneditor-search button.jsoneditor-refresh {
|
||||
width: 18px;
|
||||
background-position: -99px -73px;
|
||||
}
|
||||
|
||||
table.jsoneditor-search button.jsoneditor-next {
|
||||
cursor: pointer;
|
||||
background-position: -124px -73px;
|
||||
}
|
||||
table.jsoneditor-search button.jsoneditor-next:hover {
|
||||
background-position: -124px -49px;
|
||||
}
|
||||
|
||||
table.jsoneditor-search button.jsoneditor-previous {
|
||||
cursor: pointer;
|
||||
background-position: -148px -73px;
|
||||
margin-right: 2px;
|
||||
}
|
||||
table.jsoneditor-search button.jsoneditor-previous:hover {
|
||||
background-position: -148px -49px;
|
||||
}
|
|
@ -21,9 +21,10 @@ 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 160 kB to about 40 kB.
|
||||
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?
|
||||
|
||||
|
@ -31,6 +32,8 @@ When to use the minimalist version?
|
|||
- 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?
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
'use strict';
|
||||
'use strict'
|
||||
|
||||
var util = require('./util');
|
||||
import { createAbsoluteAnchor } from './createAbsoluteAnchor'
|
||||
import { addClassName, getSelection, removeClassName, setSelection } from './util'
|
||||
import { translate } from './i18n'
|
||||
|
||||
/**
|
||||
* A context menu
|
||||
|
@ -11,447 +13,423 @@ var util = require('./util');
|
|||
* context menu is being closed.
|
||||
* @constructor
|
||||
*/
|
||||
function ContextMenu (items, options) {
|
||||
this.dom = {};
|
||||
export class ContextMenu {
|
||||
constructor (items, options) {
|
||||
this.dom = {}
|
||||
|
||||
var me = this;
|
||||
var 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;
|
||||
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
|
||||
var root = document.createElement('div');
|
||||
root.className = 'jsoneditor-contextmenu-root';
|
||||
dom.root = root;
|
||||
// create root element
|
||||
const root = document.createElement('div')
|
||||
root.className = 'jsoneditor-contextmenu-root'
|
||||
dom.root = root
|
||||
|
||||
// create a container element
|
||||
var menu = document.createElement('div');
|
||||
menu.className = 'jsoneditor-contextmenu';
|
||||
dom.menu = menu;
|
||||
root.appendChild(menu);
|
||||
// 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
|
||||
var list = document.createElement('ul');
|
||||
list.className = 'jsoneditor-menu';
|
||||
menu.appendChild(list);
|
||||
dom.list = list;
|
||||
dom.items = []; // list with all buttons
|
||||
// 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
|
||||
var focusButton = document.createElement('button');
|
||||
dom.focusButton = focusButton;
|
||||
var li = document.createElement('li');
|
||||
li.style.overflow = 'hidden';
|
||||
li.style.height = '0';
|
||||
li.appendChild(focusButton);
|
||||
list.appendChild(li);
|
||||
// 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(function (item) {
|
||||
if (item.type == 'separator') {
|
||||
// create a separator
|
||||
var separator = document.createElement('div');
|
||||
separator.className = 'jsoneditor-separator';
|
||||
li = document.createElement('li');
|
||||
li.appendChild(separator);
|
||||
list.appendChild(li);
|
||||
}
|
||||
else {
|
||||
var domItem = {};
|
||||
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
|
||||
var li = document.createElement('li');
|
||||
list.appendChild(li);
|
||||
// create a menu item
|
||||
const li = document.createElement('li')
|
||||
list.appendChild(li)
|
||||
|
||||
// create a button in the menu item
|
||||
var button = document.createElement('button');
|
||||
button.className = item.className;
|
||||
domItem.button = button;
|
||||
if (item.title) {
|
||||
button.title = item.title;
|
||||
}
|
||||
if (item.click) {
|
||||
button.onclick = function (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
|
||||
var divIcon = document.createElement('div');
|
||||
divIcon.className = 'jsoneditor-icon';
|
||||
button.appendChild(divIcon);
|
||||
button.appendChild(document.createTextNode(item.text));
|
||||
|
||||
var buttonSubmenu;
|
||||
// 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) {
|
||||
// submenu and a button with a click handler
|
||||
button.className += ' jsoneditor-default';
|
||||
button.onclick = event => {
|
||||
event.preventDefault()
|
||||
me.hide()
|
||||
item.click()
|
||||
}
|
||||
}
|
||||
li.appendChild(button)
|
||||
|
||||
var buttonExpand = document.createElement('button');
|
||||
domItem.buttonExpand = buttonExpand;
|
||||
buttonExpand.className = 'jsoneditor-expand';
|
||||
buttonExpand.innerHTML = '<div class="jsoneditor-expand"></div>';
|
||||
li.appendChild(buttonExpand);
|
||||
if (item.submenuTitle) {
|
||||
buttonExpand.title = item.submenuTitle;
|
||||
// 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
|
||||
}
|
||||
|
||||
buttonSubmenu = buttonExpand;
|
||||
}
|
||||
else {
|
||||
// submenu and a button without a click handler
|
||||
var divExpand = document.createElement('div');
|
||||
divExpand.className = 'jsoneditor-expand';
|
||||
button.appendChild(divExpand);
|
||||
// attach a handler to expand/collapse the submenu
|
||||
buttonSubmenu.onclick = event => {
|
||||
event.preventDefault()
|
||||
me._onExpandItem(domItem)
|
||||
buttonSubmenu.focus()
|
||||
}
|
||||
|
||||
buttonSubmenu = button;
|
||||
// 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)
|
||||
}
|
||||
|
||||
// attach a handler to expand/collapse the submenu
|
||||
buttonSubmenu.onclick = function (event) {
|
||||
event.preventDefault();
|
||||
me._onExpandItem(domItem);
|
||||
buttonSubmenu.focus();
|
||||
};
|
||||
|
||||
// create the submenu
|
||||
var domSubItems = [];
|
||||
domItem.subItems = domSubItems;
|
||||
var 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
|
||||
button.innerHTML = '<div class="jsoneditor-icon"></div>' + item.text;
|
||||
domItems.push(domItem)
|
||||
}
|
||||
})
|
||||
}
|
||||
createMenuItems(list, this.dom.items, items)
|
||||
|
||||
domItems.push(domItem);
|
||||
}
|
||||
});
|
||||
// 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)
|
||||
})
|
||||
}
|
||||
createMenuItems(list, this.dom.items, items);
|
||||
|
||||
// TODO: when the editor is small, show the submenu on the right instead of inline?
|
||||
/**
|
||||
* 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
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
// calculate the max height of the menu with one submenu expanded
|
||||
this.maxHeight = 0; // height in pixels
|
||||
items.forEach(function (item) {
|
||||
var height = (items.length + (item.submenu ? item.submenu.length : 0)) * 24;
|
||||
me.maxHeight = Math.max(me.maxHeight, height);
|
||||
});
|
||||
}
|
||||
return buttons
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently visible buttons
|
||||
* @return {Array.<HTMLElement>} buttons
|
||||
* @private
|
||||
*/
|
||||
ContextMenu.prototype._getVisibleButtons = function () {
|
||||
var buttons = [];
|
||||
var me = this;
|
||||
this.dom.items.forEach(function (item) {
|
||||
buttons.push(item.button);
|
||||
if (item.buttonExpand) {
|
||||
buttons.push(item.buttonExpand);
|
||||
}
|
||||
if (item.subItems && item == me.expandedItem) {
|
||||
item.subItems.forEach(function (subItem) {
|
||||
buttons.push(subItem.button);
|
||||
if (subItem.buttonExpand) {
|
||||
buttons.push(subItem.buttonExpand);
|
||||
}
|
||||
// TODO: change to fully recursive method
|
||||
});
|
||||
}
|
||||
});
|
||||
/**
|
||||
* 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()
|
||||
|
||||
return buttons;
|
||||
};
|
||||
// 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()
|
||||
|
||||
// currently displayed context menu, a singleton. We may only have one visible context menu
|
||||
ContextMenu.visibleMenu = undefined;
|
||||
const me = this
|
||||
this.dom.absoluteAnchor = createAbsoluteAnchor(anchor, frame, () => {
|
||||
me.hide()
|
||||
})
|
||||
|
||||
/**
|
||||
* Attach the menu to an anchor
|
||||
* @param {HTMLElement} anchor Anchor where the menu will be attached
|
||||
* as sibling.
|
||||
* @param {HTMLElement} [contentWindow] The DIV with with the (scrollable) contents
|
||||
*/
|
||||
ContextMenu.prototype.show = function (anchor, contentWindow) {
|
||||
this.hide();
|
||||
|
||||
// determine whether to display the menu below or above the anchor
|
||||
var showBelow = true;
|
||||
if (contentWindow) {
|
||||
var anchorRect = anchor.getBoundingClientRect();
|
||||
var contentRect = contentWindow.getBoundingClientRect();
|
||||
|
||||
if (anchorRect.bottom + this.maxHeight < contentRect.bottom) {
|
||||
if (anchorRect.bottom + this.maxHeight < frameRect.bottom) {
|
||||
// fits below -> show below
|
||||
}
|
||||
else if (anchorRect.top - this.maxHeight > contentRect.top) {
|
||||
} else if (anchorRect.top - this.maxHeight > frameRect.top) {
|
||||
// fits above -> show above
|
||||
showBelow = false;
|
||||
}
|
||||
else {
|
||||
showBelow = false
|
||||
} else {
|
||||
// doesn't fit above nor below -> show below
|
||||
}
|
||||
}
|
||||
|
||||
// position the menu
|
||||
if (showBelow) {
|
||||
// display the menu below the anchor
|
||||
var anchorHeight = anchor.offsetHeight;
|
||||
this.dom.menu.style.left = '0px';
|
||||
this.dom.menu.style.top = anchorHeight + 'px';
|
||||
this.dom.menu.style.bottom = '';
|
||||
}
|
||||
else {
|
||||
// display the menu above the anchor
|
||||
this.dom.menu.style.left = '0px';
|
||||
this.dom.menu.style.top = '';
|
||||
this.dom.menu.style.bottom = '0px';
|
||||
}
|
||||
const topGap = ignoreParent ? 0 : (anchorRect.top - parentRect.top)
|
||||
|
||||
// attach the menu to the parent of the anchor
|
||||
var parent = anchor.parentNode;
|
||||
parent.insertBefore(this.dom.root, parent.firstChild);
|
||||
|
||||
// create and attach event listeners
|
||||
var me = this;
|
||||
var list = this.dom.list;
|
||||
this.eventListeners.mousedown = util.addEventListener(window, 'mousedown', function (event) {
|
||||
// hide menu on click outside of the menu
|
||||
var target = event.target;
|
||||
if ((target != list) && !me._isChildOf(target, list)) {
|
||||
me.hide();
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
this.eventListeners.keydown = util.addEventListener(window, 'keydown', function (event) {
|
||||
me._onKeyDown(event);
|
||||
});
|
||||
|
||||
// move focus to the first button in the context menu
|
||||
this.selection = util.getSelection();
|
||||
this.anchor = anchor;
|
||||
setTimeout(function () {
|
||||
me.dom.focusButton.focus();
|
||||
}, 0);
|
||||
|
||||
if (ContextMenu.visibleMenu) {
|
||||
ContextMenu.visibleMenu.hide();
|
||||
}
|
||||
ContextMenu.visibleMenu = this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Hide the context menu if visible
|
||||
*/
|
||||
ContextMenu.prototype.hide = function () {
|
||||
// remove the menu from the DOM
|
||||
if (this.dom.root.parentNode) {
|
||||
this.dom.root.parentNode.removeChild(this.dom.root);
|
||||
if (this.onClose) {
|
||||
this.onClose();
|
||||
}
|
||||
}
|
||||
|
||||
// remove all event listeners
|
||||
// all event listeners are supposed to be attached to document.
|
||||
for (var name in this.eventListeners) {
|
||||
if (this.eventListeners.hasOwnProperty(name)) {
|
||||
var fn = this.eventListeners[name];
|
||||
if (fn) {
|
||||
util.removeEventListener(window, name, fn);
|
||||
}
|
||||
delete this.eventListeners[name];
|
||||
}
|
||||
}
|
||||
|
||||
if (ContextMenu.visibleMenu == this) {
|
||||
ContextMenu.visibleMenu = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Expand a submenu
|
||||
* Any currently expanded submenu will be hided.
|
||||
* @param {Object} domItem
|
||||
* @private
|
||||
*/
|
||||
ContextMenu.prototype._onExpandItem = function (domItem) {
|
||||
var me = this;
|
||||
var alreadyVisible = (domItem == this.expandedItem);
|
||||
|
||||
// hide the currently visible submenu
|
||||
var expandedItem = this.expandedItem;
|
||||
if (expandedItem) {
|
||||
//var ul = expandedItem.ul;
|
||||
expandedItem.ul.style.height = '0';
|
||||
expandedItem.ul.style.padding = '';
|
||||
setTimeout(function () {
|
||||
if (me.expandedItem != expandedItem) {
|
||||
expandedItem.ul.style.display = '';
|
||||
util.removeClassName(expandedItem.ul.parentNode, 'jsoneditor-selected');
|
||||
}
|
||||
}, 300); // timeout duration must match the css transition duration
|
||||
this.expandedItem = undefined;
|
||||
}
|
||||
|
||||
if (!alreadyVisible) {
|
||||
var ul = domItem.ul;
|
||||
ul.style.display = 'block';
|
||||
var height = ul.clientHeight; // force a reflow in Firefox
|
||||
setTimeout(function () {
|
||||
if (me.expandedItem == domItem) {
|
||||
ul.style.height = (ul.childNodes.length * 24) + 'px';
|
||||
ul.style.padding = '5px 10px';
|
||||
}
|
||||
}, 0);
|
||||
util.addClassName(ul.parentNode, 'jsoneditor-selected');
|
||||
this.expandedItem = domItem;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle onkeydown event
|
||||
* @param {Event} event
|
||||
* @private
|
||||
*/
|
||||
ContextMenu.prototype._onKeyDown = function (event) {
|
||||
var target = event.target;
|
||||
var keynum = event.which;
|
||||
var handled = false;
|
||||
var buttons, targetIndex, prevButton, nextButton;
|
||||
|
||||
if (keynum == 27) { // ESC
|
||||
// hide the menu on ESC key
|
||||
|
||||
// restore previous selection and focus
|
||||
if (this.selection) {
|
||||
util.setSelection(this.selection);
|
||||
}
|
||||
if (this.anchor) {
|
||||
this.anchor.focus();
|
||||
// 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'
|
||||
}
|
||||
|
||||
this.hide();
|
||||
// attach the menu to the temporary, absolute anchor
|
||||
// parent.insertBefore(this.dom.root, anchor);
|
||||
this.dom.absoluteAnchor.appendChild(this.dom.root)
|
||||
|
||||
handled = true;
|
||||
// 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
|
||||
}
|
||||
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;
|
||||
|
||||
/**
|
||||
* 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()
|
||||
}
|
||||
}
|
||||
else { // Shift+Tab
|
||||
buttons = this._getVisibleButtons();
|
||||
targetIndex = buttons.indexOf(target);
|
||||
if (targetIndex == 0) {
|
||||
|
||||
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
|
||||
buttons[buttons.length - 1].focus();
|
||||
handled = true;
|
||||
prevButton = buttons[buttons.length - 1]
|
||||
}
|
||||
}
|
||||
}
|
||||
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();
|
||||
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
|
||||
}
|
||||
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
|
||||
// TODO: arrow left and right
|
||||
|
||||
if (handled) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Test if an element is a child of a parent element.
|
||||
* @param {Element} child
|
||||
* @param {Element} parent
|
||||
* @return {boolean} isChild
|
||||
*/
|
||||
ContextMenu.prototype._isChildOf = function (child, parent) {
|
||||
var e = child.parentNode;
|
||||
while (e) {
|
||||
if (e == parent) {
|
||||
return true;
|
||||
if (handled) {
|
||||
event.stopPropagation()
|
||||
event.preventDefault()
|
||||
}
|
||||
e = e.parentNode;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
module.exports = ContextMenu;
|
||||
// currently displayed context menu, a singleton. We may only have one visible context menu
|
||||
ContextMenu.visibleMenu = undefined
|
||||
|
|
|
@ -0,0 +1,194 @@
|
|||
/**
|
||||
* 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'
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
'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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,86 +1,86 @@
|
|||
'use strict';
|
||||
'use strict'
|
||||
|
||||
/**
|
||||
* The highlighter can highlight/unhighlight a node, and
|
||||
* animate the visibility of a context menu.
|
||||
* @constructor Highlighter
|
||||
*/
|
||||
function Highlighter () {
|
||||
this.locked = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hightlight given node and its childs
|
||||
* @param {Node} node
|
||||
*/
|
||||
Highlighter.prototype.highlight = function (node) {
|
||||
if (this.locked) {
|
||||
return;
|
||||
export class Highlighter {
|
||||
constructor () {
|
||||
this.locked = false
|
||||
}
|
||||
|
||||
if (this.node != node) {
|
||||
// unhighlight current node
|
||||
if (this.node) {
|
||||
this.node.setHighlight(false);
|
||||
/**
|
||||
* Hightlight given node and its childs
|
||||
* @param {Node} node
|
||||
*/
|
||||
highlight (node) {
|
||||
if (this.locked) {
|
||||
return
|
||||
}
|
||||
|
||||
// highlight new node
|
||||
this.node = node;
|
||||
this.node.setHighlight(true);
|
||||
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()
|
||||
}
|
||||
|
||||
// cancel any current timeout
|
||||
this._cancelUnhighlight();
|
||||
};
|
||||
/**
|
||||
* Unhighlight currently highlighted node.
|
||||
* Will be done after a delay
|
||||
*/
|
||||
unhighlight () {
|
||||
if (this.locked) {
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* Unhighlight currently highlighted node.
|
||||
* Will be done after a delay
|
||||
*/
|
||||
Highlighter.prototype.unhighlight = function () {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
||||
var 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(function () {
|
||||
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
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Cancel an unhighlight action (if before the timeout of the unhighlight action)
|
||||
* @private
|
||||
*/
|
||||
Highlighter.prototype._cancelUnhighlight = function () {
|
||||
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
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Lock highlighting or unhighlighting nodes.
|
||||
* methods highlight and unhighlight do not work while locked.
|
||||
*/
|
||||
Highlighter.prototype.lock = function () {
|
||||
this.locked = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Unlock highlighting or unhighlighting nodes
|
||||
*/
|
||||
Highlighter.prototype.unlock = function () {
|
||||
this.locked = false;
|
||||
};
|
||||
|
||||
module.exports = Highlighter;
|
||||
/**
|
||||
* Unlock highlighting or unhighlighting nodes
|
||||
*/
|
||||
unlock () {
|
||||
this.locked = false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,267 +1,85 @@
|
|||
'use strict';
|
||||
|
||||
var util = require('./util');
|
||||
|
||||
/**
|
||||
* @constructor History
|
||||
* Store action history, enables undo and redo
|
||||
* @param {JSONEditor} editor
|
||||
* Keep track on any history, be able
|
||||
* @param {function} onChange
|
||||
* @param {function} calculateItemSize
|
||||
* @param {number} limit Maximum size of all items in history
|
||||
* @constructor
|
||||
*/
|
||||
function History (editor) {
|
||||
this.editor = editor;
|
||||
this.history = [];
|
||||
this.index = -1;
|
||||
export class History {
|
||||
constructor (onChange, calculateItemSize, limit) {
|
||||
this.onChange = onChange
|
||||
this.calculateItemSize = calculateItemSize || (() => 1)
|
||||
this.limit = limit
|
||||
|
||||
this.clear();
|
||||
this.items = []
|
||||
this.index = -1
|
||||
}
|
||||
|
||||
// map with all supported actions
|
||||
this.actions = {
|
||||
'editField': {
|
||||
'undo': function (params) {
|
||||
params.node.updateField(params.oldValue);
|
||||
},
|
||||
'redo': function (params) {
|
||||
params.node.updateField(params.newValue);
|
||||
}
|
||||
},
|
||||
'editValue': {
|
||||
'undo': function (params) {
|
||||
params.node.updateValue(params.oldValue);
|
||||
},
|
||||
'redo': function (params) {
|
||||
params.node.updateValue(params.newValue);
|
||||
}
|
||||
},
|
||||
'changeType': {
|
||||
'undo': function (params) {
|
||||
params.node.changeType(params.oldType);
|
||||
},
|
||||
'redo': function (params) {
|
||||
params.node.changeType(params.newType);
|
||||
}
|
||||
},
|
||||
|
||||
'appendNodes': {
|
||||
'undo': function (params) {
|
||||
params.nodes.forEach(function (node) {
|
||||
params.parent.removeChild(node);
|
||||
});
|
||||
},
|
||||
'redo': function (params) {
|
||||
params.nodes.forEach(function (node) {
|
||||
params.parent.appendChild(node);
|
||||
});
|
||||
}
|
||||
},
|
||||
'insertBeforeNodes': {
|
||||
'undo': function (params) {
|
||||
params.nodes.forEach(function (node) {
|
||||
params.parent.removeChild(node);
|
||||
});
|
||||
},
|
||||
'redo': function (params) {
|
||||
params.nodes.forEach(function (node) {
|
||||
params.parent.insertBefore(node, params.beforeNode);
|
||||
});
|
||||
}
|
||||
},
|
||||
'insertAfterNodes': {
|
||||
'undo': function (params) {
|
||||
params.nodes.forEach(function (node) {
|
||||
params.parent.removeChild(node);
|
||||
});
|
||||
},
|
||||
'redo': function (params) {
|
||||
var afterNode = params.afterNode;
|
||||
params.nodes.forEach(function (node) {
|
||||
params.parent.insertAfter(params.node, afterNode);
|
||||
afterNode = node;
|
||||
});
|
||||
}
|
||||
},
|
||||
'removeNodes': {
|
||||
'undo': function (params) {
|
||||
var parent = params.parent;
|
||||
var beforeNode = parent.childs[params.index] || parent.append;
|
||||
params.nodes.forEach(function (node) {
|
||||
parent.insertBefore(node, beforeNode);
|
||||
});
|
||||
},
|
||||
'redo': function (params) {
|
||||
params.nodes.forEach(function (node) {
|
||||
params.parent.removeChild(node);
|
||||
});
|
||||
}
|
||||
},
|
||||
'duplicateNodes': {
|
||||
'undo': function (params) {
|
||||
params.nodes.forEach(function (node) {
|
||||
params.parent.removeChild(node);
|
||||
});
|
||||
},
|
||||
'redo': function (params) {
|
||||
var afterNode = params.afterNode;
|
||||
params.nodes.forEach(function (node) {
|
||||
params.parent.insertAfter(node, afterNode);
|
||||
afterNode = node;
|
||||
});
|
||||
}
|
||||
},
|
||||
'moveNodes': {
|
||||
'undo': function (params) {
|
||||
params.nodes.forEach(function (node) {
|
||||
params.oldBeforeNode.parent.moveBefore(node, params.oldBeforeNode);
|
||||
});
|
||||
},
|
||||
'redo': function (params) {
|
||||
params.nodes.forEach(function (node) {
|
||||
params.newBeforeNode.parent.moveBefore(node, params.newBeforeNode);
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
'sort': {
|
||||
'undo': function (params) {
|
||||
var node = params.node;
|
||||
node.hideChilds();
|
||||
node.sort = params.oldSort;
|
||||
node.childs = params.oldChilds;
|
||||
node.showChilds();
|
||||
},
|
||||
'redo': function (params) {
|
||||
var node = params.node;
|
||||
node.hideChilds();
|
||||
node.sort = params.newSort;
|
||||
node.childs = params.newChilds;
|
||||
node.showChilds();
|
||||
}
|
||||
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--
|
||||
}
|
||||
|
||||
// TODO: restore the original caret position and selection with each undo
|
||||
// TODO: implement history for actions "expand", "collapse", "scroll", "setDocument"
|
||||
};
|
||||
// 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()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The method onChange is executed when the History is changed, and can
|
||||
* be overloaded.
|
||||
*/
|
||||
History.prototype.onChange = function () {};
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
History.prototype.add = function (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
|
||||
*/
|
||||
History.prototype.clear = function () {
|
||||
this.history = [];
|
||||
this.index = -1;
|
||||
|
||||
// fire onchange event
|
||||
this.onChange();
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if there is an action available for undo
|
||||
* @return {Boolean} canUndo
|
||||
*/
|
||||
History.prototype.canUndo = function () {
|
||||
return (this.index >= 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if there is an action available for redo
|
||||
* @return {Boolean} canRedo
|
||||
*/
|
||||
History.prototype.canRedo = function () {
|
||||
return (this.index < this.history.length - 1);
|
||||
};
|
||||
|
||||
/**
|
||||
* Undo the last action
|
||||
*/
|
||||
History.prototype.undo = function () {
|
||||
if (this.canUndo()) {
|
||||
var obj = this.history[this.index];
|
||||
if (obj) {
|
||||
var action = this.actions[obj.action];
|
||||
if (action && action.undo) {
|
||||
action.undo(obj.params);
|
||||
if (obj.params.oldSelection) {
|
||||
this.editor.setSelection(obj.params.oldSelection);
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.error(new Error('unknown action "' + obj.action + '"'));
|
||||
}
|
||||
}
|
||||
this.index--;
|
||||
|
||||
// fire onchange event
|
||||
this.onChange();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Redo the last action
|
||||
*/
|
||||
History.prototype.redo = function () {
|
||||
if (this.canRedo()) {
|
||||
this.index++;
|
||||
|
||||
var obj = this.history[this.index];
|
||||
if (obj) {
|
||||
var action = this.actions[obj.action];
|
||||
if (action && action.redo) {
|
||||
action.redo(obj.params);
|
||||
if (obj.params.newSelection) {
|
||||
this.editor.setSelection(obj.params.newSelection);
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.error(new Error('unknown action "' + obj.action + '"'));
|
||||
}
|
||||
}
|
||||
|
||||
// fire onchange event
|
||||
this.onChange();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroy history
|
||||
*/
|
||||
History.prototype.destroy = function () {
|
||||
this.editor = null;
|
||||
|
||||
this.history = [];
|
||||
this.index = -1;
|
||||
};
|
||||
|
||||
module.exports = History;
|
||||
|
|
|
@ -1,16 +1,20 @@
|
|||
'use strict';
|
||||
'use strict'
|
||||
|
||||
var Ajv;
|
||||
try {
|
||||
Ajv = require('ajv');
|
||||
}
|
||||
catch (err) {
|
||||
// no problem... when we need Ajv we will throw a neat exception
|
||||
}
|
||||
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')
|
||||
|
||||
var treemode = require('./treemode');
|
||||
var textmode = require('./textmode');
|
||||
var util = require('./util');
|
||||
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
|
||||
|
@ -20,7 +24,20 @@ var util = require('./util');
|
|||
* 'tree' (default), 'view',
|
||||
* 'form', 'text', and 'code'.
|
||||
* {function} onChange Callback method, triggered
|
||||
* on change of contents
|
||||
* 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.
|
||||
|
@ -44,57 +61,96 @@ var util = require('./util');
|
|||
* {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".');
|
||||
throw new Error('JSONEditor constructor called without "new".')
|
||||
}
|
||||
|
||||
// check for unsupported browser (IE8 and older)
|
||||
var ieVersion = util.getInternetExplorerVersion();
|
||||
if (ieVersion != -1 && ieVersion < 9) {
|
||||
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.');
|
||||
'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;
|
||||
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;
|
||||
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;
|
||||
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) {
|
||||
var VALID_OPTIONS = [
|
||||
'ace', 'theme',
|
||||
'ajv', 'schema',
|
||||
'onChange', 'onEditable', 'onError', 'onModeChange',
|
||||
'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation', 'sortObjectKeys'
|
||||
];
|
||||
|
||||
Object.keys(options).forEach(function (option) {
|
||||
if (VALID_OPTIONS.indexOf(option) === -1) {
|
||||
console.warn('Unknown option "' + option + '". This option will be ignored');
|
||||
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);
|
||||
this._create(container, options, json)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,10 +169,26 @@ function JSONEditor (container, options, json) {
|
|||
*
|
||||
* @type { Object.<String, {mixin: Object, data: String} > }
|
||||
*/
|
||||
JSONEditor.modes = {};
|
||||
JSONEditor.modes = {}
|
||||
|
||||
// debounce interval for JSON schema vaidation in milliseconds
|
||||
JSONEditor.prototype.DEBOUNCE_INTERVAL = 150;
|
||||
// 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
|
||||
|
@ -126,50 +198,50 @@ JSONEditor.prototype.DEBOUNCE_INTERVAL = 150;
|
|||
* @private
|
||||
*/
|
||||
JSONEditor.prototype._create = function (container, options, json) {
|
||||
this.container = container;
|
||||
this.options = options || {};
|
||||
this.json = json || {};
|
||||
this.container = container
|
||||
this.options = options || {}
|
||||
this.json = json || {}
|
||||
|
||||
var mode = this.options.mode || 'tree';
|
||||
this.setMode(mode);
|
||||
};
|
||||
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 = function () {};
|
||||
JSONEditor.prototype.destroy = () => {}
|
||||
|
||||
/**
|
||||
* Set JSON object in editor
|
||||
* @param {Object | undefined} json JSON data
|
||||
*/
|
||||
JSONEditor.prototype.set = function (json) {
|
||||
this.json = json;
|
||||
};
|
||||
this.json = json
|
||||
}
|
||||
|
||||
/**
|
||||
* Get JSON from the editor
|
||||
* @returns {Object} json
|
||||
*/
|
||||
JSONEditor.prototype.get = function () {
|
||||
return this.json;
|
||||
};
|
||||
return this.json
|
||||
}
|
||||
|
||||
/**
|
||||
* Set string containing JSON for the editor
|
||||
* @param {String | undefined} jsonText
|
||||
*/
|
||||
JSONEditor.prototype.setText = function (jsonText) {
|
||||
this.json = util.parse(jsonText);
|
||||
};
|
||||
this.json = parse(jsonText)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get stringified JSON contents from the editor
|
||||
* @returns {String} jsonText
|
||||
*/
|
||||
JSONEditor.prototype.getText = function () {
|
||||
return JSON.stringify(this.json);
|
||||
};
|
||||
return JSON.stringify(this.json)
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a field name for the root node.
|
||||
|
@ -177,18 +249,18 @@ JSONEditor.prototype.getText = function () {
|
|||
*/
|
||||
JSONEditor.prototype.setName = function (name) {
|
||||
if (!this.options) {
|
||||
this.options = {};
|
||||
this.options = {}
|
||||
}
|
||||
this.options.name = name;
|
||||
};
|
||||
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;
|
||||
};
|
||||
return this.options && this.options.name
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the mode of the editor.
|
||||
|
@ -197,62 +269,63 @@ JSONEditor.prototype.getName = function () {
|
|||
* 'text', and 'code'.
|
||||
*/
|
||||
JSONEditor.prototype.setMode = function (mode) {
|
||||
var container = this.container;
|
||||
var options = util.extend({}, this.options);
|
||||
var oldMode = options.mode;
|
||||
var data;
|
||||
var name;
|
||||
// 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
|
||||
}
|
||||
|
||||
options.mode = mode;
|
||||
var config = JSONEditor.modes[mode];
|
||||
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 {
|
||||
var asText = (config.data == 'text');
|
||||
name = this.getName();
|
||||
data = this[asText ? 'getText' : 'get'](); // get text or json
|
||||
const asText = (config.data === 'text')
|
||||
name = this.getName()
|
||||
data = this[asText ? 'getText' : 'get']() // get text or json
|
||||
|
||||
this.destroy();
|
||||
util.clear(this);
|
||||
util.extend(this, config.mixin);
|
||||
this.create(container, options);
|
||||
this.destroy()
|
||||
clear(this)
|
||||
extend(this, config.mixin)
|
||||
this.create(container, options)
|
||||
|
||||
this.setName(name);
|
||||
this[asText ? 'setText' : 'set'](data); // set text or json
|
||||
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);
|
||||
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);
|
||||
options.onModeChange(mode, oldMode)
|
||||
} catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
this._onError(err)
|
||||
}
|
||||
catch (err) {
|
||||
this._onError(err);
|
||||
}
|
||||
} else {
|
||||
throw new Error('Unknown mode "' + options.mode + '"')
|
||||
}
|
||||
else {
|
||||
throw new Error('Unknown mode "' + options.mode + '"');
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current mode
|
||||
* @return {string}
|
||||
*/
|
||||
JSONEditor.prototype.getMode = function () {
|
||||
return this.options.mode;
|
||||
};
|
||||
return this.options.mode
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw an error. If an error callback is configured in options.error, this
|
||||
|
@ -260,69 +333,90 @@ JSONEditor.prototype.getMode = function () {
|
|||
* @param {Error} err
|
||||
* @private
|
||||
*/
|
||||
JSONEditor.prototype._onError = function(err) {
|
||||
JSONEditor.prototype._onError = function (err) {
|
||||
if (this.options && typeof this.options.onError === 'function') {
|
||||
this.options.onError(err);
|
||||
this.options.onError(err)
|
||||
} else {
|
||||
throw 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) {
|
||||
JSONEditor.prototype.setSchema = function (schema, schemaRefs) {
|
||||
// compile a JSON schema validator if a JSON schema is provided
|
||||
if (schema) {
|
||||
var ajv;
|
||||
let ajv
|
||||
try {
|
||||
// grab ajv from options if provided, else create a new instance
|
||||
ajv = this.options.ajv || Ajv({ allErrors: true, verbose: true });
|
||||
if (this.options.ajv) {
|
||||
ajv = this.options.ajv
|
||||
} else {
|
||||
ajv = Ajv({
|
||||
allErrors: true,
|
||||
verbose: true,
|
||||
schemaId: 'auto',
|
||||
$data: true
|
||||
})
|
||||
|
||||
}
|
||||
catch (err) {
|
||||
console.warn('Failed to create an instance of Ajv, JSON Schema validation is not available. Please use a JSONEditor bundle including Ajv, or pass an instance of Ajv as via the configuration option `ajv`.');
|
||||
// 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) {
|
||||
this.validateSchema = ajv.compile(schema);
|
||||
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;
|
||||
this.options.schema = schema
|
||||
|
||||
// validate now
|
||||
this.validate();
|
||||
this.validate()
|
||||
}
|
||||
|
||||
this.refresh(); // update DOM
|
||||
}
|
||||
else {
|
||||
this.refresh() // update DOM
|
||||
} else {
|
||||
// remove current schema
|
||||
this.validateSchema = null;
|
||||
this.options.schema = null;
|
||||
this.validate(); // to clear current error messages
|
||||
this.refresh(); // update DOM
|
||||
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 = function () {
|
||||
JSONEditor.prototype.validate = () => {
|
||||
// must be implemented by treemode and textmode
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh the rendered contents
|
||||
*/
|
||||
JSONEditor.prototype.refresh = function () {
|
||||
JSONEditor.prototype.refresh = () => {
|
||||
// can be implemented by treemode and textmode
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a plugin with one ore multiple modes for the JSON Editor.
|
||||
|
@ -343,43 +437,56 @@ JSONEditor.prototype.refresh = function () {
|
|||
*
|
||||
* @param {Object | Array} mode A mode object or an array with multiple mode objects.
|
||||
*/
|
||||
JSONEditor.registerMode = function (mode) {
|
||||
var i, prop;
|
||||
JSONEditor.registerMode = mode => {
|
||||
let i, prop
|
||||
|
||||
if (util.isArray(mode)) {
|
||||
if (Array.isArray(mode)) {
|
||||
// multiple modes
|
||||
for (i = 0; i < mode.length; i++) {
|
||||
JSONEditor.registerMode(mode[i]);
|
||||
JSONEditor.registerMode(mode[i])
|
||||
}
|
||||
}
|
||||
else {
|
||||
} 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');
|
||||
var name = mode.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');
|
||||
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');
|
||||
throw new Error('Required function "create" missing on mixin')
|
||||
}
|
||||
var reserved = ['setMode', 'registerMode', 'modes'];
|
||||
const reserved = ['setMode', 'registerMode', 'modes']
|
||||
for (i = 0; i < reserved.length; i++) {
|
||||
prop = reserved[i];
|
||||
prop = reserved[i]
|
||||
if (prop in mode.mixin) {
|
||||
throw new Error('Reserved property "' + prop + '" not allowed in mixin');
|
||||
throw new Error('Reserved property "' + prop + '" not allowed in mixin')
|
||||
}
|
||||
}
|
||||
|
||||
JSONEditor.modes[name] = mode;
|
||||
JSONEditor.modes[name] = mode
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// register tree and text modes
|
||||
JSONEditor.registerMode(treemode);
|
||||
JSONEditor.registerMode(textmode);
|
||||
// register tree, text, and preview modes
|
||||
JSONEditor.registerMode(treeModeMixins)
|
||||
JSONEditor.registerMode(textModeMixins)
|
||||
JSONEditor.registerMode(previewModeMixins)
|
||||
|
||||
module.exports = JSONEditor;
|
||||
// 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
|
||||
|
|
|
@ -1,114 +1,123 @@
|
|||
'use strict';
|
||||
'use strict'
|
||||
|
||||
var ContextMenu = require('./ContextMenu');
|
||||
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'
|
||||
* @param {String} current Available modes: 'code', 'form', 'text', 'tree', 'view'
|
||||
* @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
|
||||
*/
|
||||
function ModeSwitcher(container, modes, current, onSwitch) {
|
||||
// available modes
|
||||
var availableModes = {
|
||||
code: {
|
||||
'text': 'Code',
|
||||
'title': 'Switch to code highlighter',
|
||||
'click': function () {
|
||||
onSwitch('code')
|
||||
}
|
||||
},
|
||||
form: {
|
||||
'text': 'Form',
|
||||
'title': 'Switch to form editor',
|
||||
'click': function () {
|
||||
onSwitch('form');
|
||||
}
|
||||
},
|
||||
text: {
|
||||
'text': 'Text',
|
||||
'title': 'Switch to plain text editor',
|
||||
'click': function () {
|
||||
onSwitch('text');
|
||||
}
|
||||
},
|
||||
tree: {
|
||||
'text': 'Tree',
|
||||
'title': 'Switch to tree editor',
|
||||
'click': function () {
|
||||
onSwitch('tree');
|
||||
}
|
||||
},
|
||||
view: {
|
||||
'text': 'View',
|
||||
'title': 'Switch to tree view',
|
||||
'click': function () {
|
||||
onSwitch('view');
|
||||
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
|
||||
var items = [];
|
||||
for (var i = 0; i < modes.length; i++) {
|
||||
var mode = modes[i];
|
||||
var item = availableModes[mode];
|
||||
if (!item) {
|
||||
throw new Error('Unknown mode "' + mode + '"');
|
||||
// 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)
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
// retrieve the title of current mode
|
||||
var currentMode = availableModes[current];
|
||||
if (!currentMode) {
|
||||
throw new Error('Unknown mode "' + current + '"');
|
||||
/**
|
||||
* Set focus to switcher
|
||||
*/
|
||||
focus () {
|
||||
this.dom.box.focus()
|
||||
}
|
||||
var currentTitle = currentMode.text;
|
||||
|
||||
// create the html element
|
||||
var box = document.createElement('button');
|
||||
box.className = 'jsoneditor-modes jsoneditor-separator';
|
||||
box.innerHTML = currentTitle + ' ▾';
|
||||
box.title = 'Switch editor mode';
|
||||
box.onclick = function () {
|
||||
var menu = new ContextMenu(items);
|
||||
menu.show(box);
|
||||
};
|
||||
|
||||
var 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
|
||||
};
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set focus to switcher
|
||||
*/
|
||||
ModeSwitcher.prototype.focus = function () {
|
||||
this.dom.box.focus();
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroy the ModeSwitcher, remove from DOM
|
||||
*/
|
||||
ModeSwitcher.prototype.destroy = function () {
|
||||
if (this.dom && this.dom.frame && this.dom.frame.parentNode) {
|
||||
this.dom.frame.parentNode.removeChild(this.dom.frame);
|
||||
}
|
||||
this.dom = null;
|
||||
};
|
||||
|
||||
module.exports = ModeSwitcher;
|
||||
|
|
7514
src/js/Node.js
7514
src/js/Node.js
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,333 @@
|
|||
'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
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
'use strict';
|
||||
'use strict'
|
||||
import { translate } from './i18n'
|
||||
|
||||
/**
|
||||
* @constructor SearchBox
|
||||
|
@ -7,306 +8,318 @@
|
|||
* @param {Element} container HTML container element of where to
|
||||
* create the search box
|
||||
*/
|
||||
function SearchBox (editor, container) {
|
||||
var searchBox = this;
|
||||
export class SearchBox {
|
||||
constructor (editor, container) {
|
||||
const searchBox = this
|
||||
|
||||
this.editor = editor;
|
||||
this.timeout = undefined;
|
||||
this.delay = 200; // ms
|
||||
this.lastText = undefined;
|
||||
this.editor = editor
|
||||
this.timeout = undefined
|
||||
this.delay = 200 // ms
|
||||
this.lastText = undefined
|
||||
this.results = null
|
||||
|
||||
this.dom = {};
|
||||
this.dom.container = container;
|
||||
this.dom = {}
|
||||
this.dom.container = container
|
||||
|
||||
var table = document.createElement('table');
|
||||
this.dom.table = table;
|
||||
table.className = 'jsoneditor-search';
|
||||
container.appendChild(table);
|
||||
var tbody = document.createElement('tbody');
|
||||
this.dom.tbody = tbody;
|
||||
table.appendChild(tbody);
|
||||
var tr = document.createElement('tr');
|
||||
tbody.appendChild(tr);
|
||||
const wrapper = document.createElement('div')
|
||||
this.dom.wrapper = wrapper
|
||||
wrapper.className = 'jsoneditor-search'
|
||||
container.appendChild(wrapper)
|
||||
|
||||
var td = document.createElement('td');
|
||||
tr.appendChild(td);
|
||||
var results = document.createElement('div');
|
||||
this.dom.results = results;
|
||||
results.className = 'jsoneditor-results';
|
||||
td.appendChild(results);
|
||||
const results = document.createElement('div')
|
||||
this.dom.results = results
|
||||
results.className = 'jsoneditor-results'
|
||||
wrapper.appendChild(results)
|
||||
|
||||
td = document.createElement('td');
|
||||
tr.appendChild(td);
|
||||
var divInput = document.createElement('div');
|
||||
this.dom.input = divInput;
|
||||
divInput.className = 'jsoneditor-frame';
|
||||
divInput.title = 'Search fields and values';
|
||||
td.appendChild(divInput);
|
||||
const divInput = document.createElement('div')
|
||||
this.dom.input = divInput
|
||||
divInput.className = 'jsoneditor-frame'
|
||||
divInput.title = translate('searchTitle')
|
||||
wrapper.appendChild(divInput)
|
||||
|
||||
// table to contain the text input and search button
|
||||
var tableInput = document.createElement('table');
|
||||
divInput.appendChild(tableInput);
|
||||
var tbodySearch = document.createElement('tbody');
|
||||
tableInput.appendChild(tbodySearch);
|
||||
tr = document.createElement('tr');
|
||||
tbodySearch.appendChild(tr);
|
||||
const refreshSearch = document.createElement('button')
|
||||
refreshSearch.type = 'button'
|
||||
refreshSearch.className = 'jsoneditor-refresh'
|
||||
divInput.appendChild(refreshSearch)
|
||||
|
||||
var refreshSearch = document.createElement('button');
|
||||
refreshSearch.className = 'jsoneditor-refresh';
|
||||
td = document.createElement('td');
|
||||
td.appendChild(refreshSearch);
|
||||
tr.appendChild(td);
|
||||
|
||||
var search = document.createElement('input');
|
||||
this.dom.search = search;
|
||||
search.oninput = function (event) {
|
||||
searchBox._onDelayedSearch(event);
|
||||
};
|
||||
search.onchange = function (event) { // For IE 9
|
||||
searchBox._onSearch();
|
||||
};
|
||||
search.onkeydown = function (event) {
|
||||
searchBox._onKeyDown(event);
|
||||
};
|
||||
search.onkeyup = function (event) {
|
||||
searchBox._onKeyUp(event);
|
||||
};
|
||||
refreshSearch.onclick = function (event) {
|
||||
search.select();
|
||||
};
|
||||
|
||||
// TODO: ESC in FF restores the last input, is a FF bug, https://bugzilla.mozilla.org/show_bug.cgi?id=598819
|
||||
td = document.createElement('td');
|
||||
td.appendChild(search);
|
||||
tr.appendChild(td);
|
||||
|
||||
var searchNext = document.createElement('button');
|
||||
searchNext.title = 'Next result (Enter)';
|
||||
searchNext.className = 'jsoneditor-next';
|
||||
searchNext.onclick = function () {
|
||||
searchBox.next();
|
||||
};
|
||||
td = document.createElement('td');
|
||||
td.appendChild(searchNext);
|
||||
tr.appendChild(td);
|
||||
|
||||
var searchPrevious = document.createElement('button');
|
||||
searchPrevious.title = 'Previous result (Shift+Enter)';
|
||||
searchPrevious.className = 'jsoneditor-previous';
|
||||
searchPrevious.onclick = function () {
|
||||
searchBox.previous();
|
||||
};
|
||||
td = document.createElement('td');
|
||||
td.appendChild(searchPrevious);
|
||||
tr.appendChild(td);
|
||||
}
|
||||
|
||||
/**
|
||||
* Go to the next search result
|
||||
* @param {boolean} [focus] If true, focus will be set to the next result
|
||||
* focus is false by default.
|
||||
*/
|
||||
SearchBox.prototype.next = function(focus) {
|
||||
if (this.results != undefined) {
|
||||
var index = (this.resultIndex != undefined) ? this.resultIndex + 1 : 0;
|
||||
if (index > this.results.length - 1) {
|
||||
index = 0;
|
||||
const search = document.createElement('input')
|
||||
search.type = 'text'
|
||||
this.dom.search = search
|
||||
search.oninput = event => {
|
||||
searchBox._onDelayedSearch(event)
|
||||
}
|
||||
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.
|
||||
*/
|
||||
SearchBox.prototype.previous = function(focus) {
|
||||
if (this.results != undefined) {
|
||||
var max = this.results.length - 1;
|
||||
var index = (this.resultIndex != undefined) ? this.resultIndex - 1 : max;
|
||||
if (index < 0) {
|
||||
index = max;
|
||||
search.onchange = event => {
|
||||
// For IE 9
|
||||
searchBox._onSearch()
|
||||
}
|
||||
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
|
||||
*/
|
||||
SearchBox.prototype._setActiveResult = function(index, focus) {
|
||||
// de-activate current active result
|
||||
if (this.activeResult) {
|
||||
var prevNode = this.activeResult.node;
|
||||
var prevElem = this.activeResult.elem;
|
||||
if (prevElem == 'field') {
|
||||
delete prevNode.searchFieldActive;
|
||||
search.onkeydown = event => {
|
||||
searchBox._onKeyDown(event)
|
||||
}
|
||||
else {
|
||||
delete prevNode.searchValueActive;
|
||||
search.onkeyup = event => {
|
||||
searchBox._onKeyUp(event)
|
||||
}
|
||||
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
|
||||
var node = this.results[this.resultIndex].node;
|
||||
var 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(function () {
|
||||
if (focus) {
|
||||
node.focus(elem);
|
||||
refreshSearch.onclick = event => {
|
||||
search.select()
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Cancel any running onDelayedSearch.
|
||||
* @private
|
||||
*/
|
||||
SearchBox.prototype._clearDelay = function() {
|
||||
if (this.timeout != undefined) {
|
||||
clearTimeout(this.timeout);
|
||||
delete this.timeout;
|
||||
// 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)
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Start a timer to execute a search after a short delay.
|
||||
* Used for reducing the number of searches while typing.
|
||||
* @param {Event} event
|
||||
* @private
|
||||
*/
|
||||
SearchBox.prototype._onDelayedSearch = function (event) {
|
||||
// execute the search after a short delay (reduces the number of
|
||||
// search actions while typing in the search text box)
|
||||
this._clearDelay();
|
||||
var searchBox = this;
|
||||
this.timeout = setTimeout(function (event) {
|
||||
searchBox._onSearch();
|
||||
},
|
||||
this.delay);
|
||||
};
|
||||
/**
|
||||
* 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)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
SearchBox.prototype._onSearch = function (forceSearch) {
|
||||
this._clearDelay();
|
||||
/**
|
||||
* 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)
|
||||
}
|
||||
}
|
||||
|
||||
var value = this.dom.search.value;
|
||||
var 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);
|
||||
this._setActiveResult(undefined);
|
||||
/**
|
||||
* 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()
|
||||
}
|
||||
|
||||
// display search results
|
||||
if (text != undefined) {
|
||||
var resultCount = this.results.length;
|
||||
switch (resultCount) {
|
||||
case 0: this.dom.results.innerHTML = 'no results'; break;
|
||||
case 1: this.dom.results.innerHTML = '1 result'; break;
|
||||
default: this.dom.results.innerHTML = resultCount + ' results'; break;
|
||||
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 = ''
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.dom.results.innerHTML = '';
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 onKeyDown event in the input box
|
||||
* @param {Event} event
|
||||
* @private
|
||||
*/
|
||||
SearchBox.prototype._onKeyDown = function (event) {
|
||||
var 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);
|
||||
/**
|
||||
* 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
|
||||
}
|
||||
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
|
||||
*/
|
||||
SearchBox.prototype._onKeyUp = function (event) {
|
||||
var 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()
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Clear the search results
|
||||
*/
|
||||
SearchBox.prototype.clear = function () {
|
||||
this.dom.search.value = '';
|
||||
this._onSearch();
|
||||
};
|
||||
/**
|
||||
* Refresh searchResults if there is a search value
|
||||
*/
|
||||
forceSearch () {
|
||||
this._onSearch(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the search box
|
||||
*/
|
||||
SearchBox.prototype.destroy = function () {
|
||||
this.editor = null;
|
||||
this.dom.container.removeChild(this.dom.table);
|
||||
this.dom = null;
|
||||
/**
|
||||
* Test whether the search box value is empty
|
||||
* @returns {boolean} Returns true when empty.
|
||||
*/
|
||||
isEmpty () {
|
||||
return this.dom.search.value === ''
|
||||
}
|
||||
|
||||
this.results = null;
|
||||
this.activeResult = null;
|
||||
/**
|
||||
* Destroy the search box
|
||||
*/
|
||||
destroy () {
|
||||
this.editor = null
|
||||
this.dom.container.removeChild(this.dom.wrapper)
|
||||
this.dom = null
|
||||
|
||||
this._clearDelay();
|
||||
this.results = null
|
||||
this.activeResult = null
|
||||
|
||||
};
|
||||
|
||||
module.exports = SearchBox;
|
||||
this._clearDelay()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,142 @@
|
|||
'use strict'
|
||||
|
||||
import { ContextMenu } from './ContextMenu'
|
||||
import { translate } from './i18n'
|
||||
import { addClassName, removeClassName } from './util'
|
||||
|
||||
/**
|
||||
* Creates a component that visualize path selection in tree based editors
|
||||
* @param {HTMLElement} container
|
||||
* @param {HTMLElement} root
|
||||
* @constructor
|
||||
*/
|
||||
export class TreePath {
|
||||
constructor (container, root) {
|
||||
if (container) {
|
||||
this.root = root
|
||||
this.path = document.createElement('div')
|
||||
this.path.className = 'jsoneditor-treepath'
|
||||
this.path.setAttribute('tabindex', 0)
|
||||
this.contentMenuClicked = false
|
||||
container.appendChild(this.path)
|
||||
this.reset()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset component to initial status
|
||||
*/
|
||||
reset () {
|
||||
this.path.textContent = translate('selectNode')
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the component UI according to a given path objects
|
||||
* @param {Array<{name: String, childs: Array}>} pathObjs a list of path objects
|
||||
*
|
||||
*/
|
||||
setPath (pathObjs) {
|
||||
const me = this
|
||||
|
||||
this.path.textContent = ''
|
||||
|
||||
if (pathObjs && pathObjs.length) {
|
||||
pathObjs.forEach((pathObj, idx) => {
|
||||
const pathEl = document.createElement('span')
|
||||
let sepEl
|
||||
pathEl.className = 'jsoneditor-treepath-element'
|
||||
pathEl.innerText = pathObj.name
|
||||
pathEl.onclick = _onSegmentClick.bind(me, pathObj)
|
||||
|
||||
me.path.appendChild(pathEl)
|
||||
|
||||
if (pathObj.children.length) {
|
||||
sepEl = document.createElement('span')
|
||||
sepEl.className = 'jsoneditor-treepath-seperator'
|
||||
sepEl.textContent = '\u25BA'
|
||||
|
||||
sepEl.onclick = () => {
|
||||
me.contentMenuClicked = true
|
||||
const items = []
|
||||
pathObj.children.forEach(child => {
|
||||
items.push({
|
||||
text: child.name,
|
||||
className: 'jsoneditor-type-modes' + (pathObjs[idx + 1] + 1 && pathObjs[idx + 1].name === child.name ? ' jsoneditor-selected' : ''),
|
||||
click: _onContextMenuItemClick.bind(me, pathObj, child.name)
|
||||
})
|
||||
})
|
||||
const menu = new ContextMenu(items)
|
||||
menu.show(sepEl, me.root, true)
|
||||
}
|
||||
|
||||
me.path.appendChild(sepEl)
|
||||
}
|
||||
|
||||
if (idx === pathObjs.length - 1) {
|
||||
const leftRectPos = (sepEl || pathEl).getBoundingClientRect().right
|
||||
if (me.path.offsetWidth < leftRectPos) {
|
||||
me.path.scrollLeft = leftRectPos
|
||||
}
|
||||
|
||||
if (me.path.scrollLeft) {
|
||||
const showAllBtn = document.createElement('span')
|
||||
showAllBtn.className = 'jsoneditor-treepath-show-all-btn'
|
||||
showAllBtn.title = 'show all path'
|
||||
showAllBtn.textContent = '...'
|
||||
showAllBtn.onclick = _onShowAllClick.bind(me, pathObjs)
|
||||
me.path.insertBefore(showAllBtn, me.path.firstChild)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function _onShowAllClick (pathObjs) {
|
||||
me.contentMenuClicked = false
|
||||
addClassName(me.path, 'show-all')
|
||||
me.path.style.width = me.path.parentNode.getBoundingClientRect().width - 10 + 'px'
|
||||
me.path.onblur = () => {
|
||||
if (me.contentMenuClicked) {
|
||||
me.contentMenuClicked = false
|
||||
me.path.focus()
|
||||
return
|
||||
}
|
||||
removeClassName(me.path, 'show-all')
|
||||
me.path.onblur = undefined
|
||||
me.path.style.width = ''
|
||||
me.setPath(pathObjs)
|
||||
}
|
||||
}
|
||||
|
||||
function _onSegmentClick (pathObj) {
|
||||
if (this.selectionCallback) {
|
||||
this.selectionCallback(pathObj)
|
||||
}
|
||||
}
|
||||
|
||||
function _onContextMenuItemClick (pathObj, selection) {
|
||||
if (this.contextMenuCallback) {
|
||||
this.contextMenuCallback(pathObj, selection)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set a callback function for selection of path section
|
||||
* @param {Function} callback function to invoke when section is selected
|
||||
*/
|
||||
onSectionSelected (callback) {
|
||||
if (typeof callback === 'function') {
|
||||
this.selectionCallback = callback
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* set a callback function for selection of path section
|
||||
* @param {Function} callback function to invoke when section is selected
|
||||
*/
|
||||
onContextMenuItemSelected (callback) {
|
||||
if (typeof callback === 'function') {
|
||||
this.contextMenuCallback = callback
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +1,25 @@
|
|||
// load brace
|
||||
var ace = require('brace');
|
||||
let ace
|
||||
if (window.ace) {
|
||||
// use the already loaded instance of Ace
|
||||
ace = window.ace
|
||||
} else {
|
||||
try {
|
||||
// load Ace editor
|
||||
ace = require('ace-builds/src-noconflict/ace')
|
||||
|
||||
// load required ace modules
|
||||
require('brace/mode/json');
|
||||
require('brace/ext/searchbox');
|
||||
require('./theme-jsoneditor');
|
||||
// load required Ace plugins
|
||||
require('ace-builds/src-noconflict/mode-json')
|
||||
require('ace-builds/src-noconflict/mode-text')
|
||||
require('ace-builds/src-noconflict/ext-searchbox')
|
||||
|
||||
module.exports = ace;
|
||||
// embed Ace json worker
|
||||
// https://github.com/ajaxorg/ace/issues/3913
|
||||
const jsonWorkerDataUrl = require('../generated/worker-json-data-url')
|
||||
ace.config.setModuleUrl('ace/mode/json_worker', jsonWorkerDataUrl)
|
||||
} catch (err) {
|
||||
// failed to load Ace (can be minimalist bundle).
|
||||
// No worries, the editor will fall back to plain text if needed.
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = ace
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue