Changed to new build system, removed flow
This commit is contained in:
parent
b011b196e1
commit
29fed7099f
22
LICENSE
22
LICENSE
|
@ -1,21 +1,7 @@
|
|||
The MIT License (MIT)
|
||||
Copyright 2015-2017 Jos de Jong
|
||||
|
||||
Copyright (c) 2011-2016 Jos de Jong
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -3,11 +3,12 @@
|
|||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"devDependencies": {
|
||||
"react-scripts": "0.8.4"
|
||||
"react-scripts": "1.0.17"
|
||||
},
|
||||
"dependencies": {
|
||||
"react": "15.4.1",
|
||||
"react-dom": "15.4.1"
|
||||
"jsoneditor": "file:../..",
|
||||
"react": "16.2.0",
|
||||
"react-dom": "16.2.0"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "react-scripts start",
|
||||
|
|
|
@ -7,7 +7,7 @@ import './App.css'
|
|||
//
|
||||
// import JSONEditor from 'jsoneditor/react'
|
||||
//
|
||||
import JSONEditor from '../../../react'
|
||||
import JSONEditor from 'jsoneditor/lib/components/JSONEditor'
|
||||
|
||||
|
||||
const json = {
|
||||
|
@ -21,7 +21,7 @@ const json = {
|
|||
|
||||
class App extends Component {
|
||||
state = {
|
||||
text: JSON.stringify(json)
|
||||
json
|
||||
}
|
||||
|
||||
render() {
|
||||
|
@ -30,7 +30,7 @@ class App extends Component {
|
|||
<JSONEditor
|
||||
mode="tree"
|
||||
modes={['text', 'code', 'tree', 'form', 'view']}
|
||||
text={this.state.text}
|
||||
json={this.state.json}
|
||||
onChange={this.onChange}
|
||||
onChangeText={this.onChangeText}
|
||||
/>
|
||||
|
|
268
gulpfile.js
268
gulpfile.js
|
@ -1,268 +0,0 @@
|
|||
const fs = require('fs')
|
||||
const gulp = require('gulp')
|
||||
const gulpMultiProcess = require('gulp-multi-process')
|
||||
const gutil = require('gulp-util')
|
||||
const shell = require('gulp-shell')
|
||||
const mkdirp = require('mkdirp')
|
||||
const babel = require('gulp-babel')
|
||||
const webpack = require('webpack')
|
||||
const browserSync = require('browser-sync').create()
|
||||
|
||||
const WATCH = 'watch'
|
||||
const WATCHING = process.argv[2] === WATCH
|
||||
|
||||
if (WATCHING) {
|
||||
gutil.log('Watching src/*.')
|
||||
gutil.log('The bundle ./dist/jsoneditor.js will be updated automatically ')
|
||||
gutil.log('on changes in the source code this bundle will not be minified.')
|
||||
gutil.log('Also, ./dist/minimalist code is not updated on changes.')
|
||||
}
|
||||
|
||||
const NAME = 'jsoneditor.js'
|
||||
const NAME_MINIMALIST = 'jsoneditor-minimalist.js'
|
||||
const NAME_REACT = 'jsoneditor-react.js'
|
||||
const NAME_REACT_MINIMALIST = 'jsoneditor-react-minimalist.js'
|
||||
const ENTRY = './src/index.js'
|
||||
const ENTRY_REACT = './src/components/JSONEditor.js'
|
||||
const HEADER = './src/header.js'
|
||||
const DIST = './dist'
|
||||
const LIB = './lib'
|
||||
const EMPTY = __dirname + '/src/utils/empty.js'
|
||||
|
||||
// generate banner with today's date and correct version
|
||||
function createBanner() {
|
||||
const today = gutil.date(new Date(), 'yyyy-mm-dd') // today, formatted as yyyy-mm-dd
|
||||
const version = require('./package.json').version // math.js version
|
||||
|
||||
return String(fs.readFileSync(HEADER))
|
||||
.replace('@@date', today)
|
||||
.replace('@@version', version)
|
||||
}
|
||||
|
||||
const bannerPlugin = new webpack.BannerPlugin(createBanner(), {
|
||||
entryOnly: true,
|
||||
raw: true
|
||||
})
|
||||
|
||||
const minifyPlugin = new webpack.optimize.UglifyJsPlugin()
|
||||
|
||||
const excludeAcePlugin = new webpack.NormalModuleReplacementPlugin(new RegExp('/assets/ace$'), EMPTY)
|
||||
|
||||
const excludeAjvPlugin = new webpack.NormalModuleReplacementPlugin(new RegExp('^ajv$'), EMPTY)
|
||||
|
||||
const productionEnvPlugin = new webpack.DefinePlugin({
|
||||
'process.env': {
|
||||
NODE_ENV: JSON.stringify('production')
|
||||
}
|
||||
})
|
||||
|
||||
const loaders = [
|
||||
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' },
|
||||
{ test: /\.json$/, loader: 'json' },
|
||||
{ test: /\.less$/, loaders: '!style!css!less!' },
|
||||
{ test: /\.svg$/, loader: 'svg-url-loader' }
|
||||
]
|
||||
|
||||
// TODO: see if preact can give the same sort of errors and warnings as react does, if so switch to preact for development too
|
||||
const resolve = {
|
||||
'alias': {
|
||||
'react': 'preact-compat',
|
||||
'react-dom': 'preact-compat'
|
||||
}
|
||||
}
|
||||
|
||||
// create a single instance of the compiler to allow caching
|
||||
const compiler = webpack({
|
||||
entry: ENTRY,
|
||||
devtool: 'source-map',
|
||||
debug: true,
|
||||
cache: true,
|
||||
bail: true,
|
||||
output: {
|
||||
library: 'jsoneditor',
|
||||
libraryTarget: 'umd',
|
||||
path: DIST,
|
||||
filename: NAME
|
||||
},
|
||||
plugins: WATCHING
|
||||
? [bannerPlugin]
|
||||
: [bannerPlugin, productionEnvPlugin, minifyPlugin],
|
||||
module: {
|
||||
loaders
|
||||
},
|
||||
resolve: WATCHING ? null : resolve
|
||||
})
|
||||
|
||||
// create a single instance of the compiler to allow caching
|
||||
const compilerMinimalist = webpack({
|
||||
entry: ENTRY,
|
||||
devtool: 'source-map',
|
||||
debug: true,
|
||||
cache: true,
|
||||
output: {
|
||||
library: 'jsoneditor',
|
||||
libraryTarget: 'umd',
|
||||
path: DIST,
|
||||
filename: NAME_MINIMALIST
|
||||
},
|
||||
plugins: [
|
||||
bannerPlugin,
|
||||
productionEnvPlugin,
|
||||
excludeAcePlugin,
|
||||
excludeAjvPlugin,
|
||||
minifyPlugin
|
||||
],
|
||||
module: {
|
||||
loaders
|
||||
},
|
||||
resolve: WATCHING ? null : resolve
|
||||
})
|
||||
|
||||
const externals = {
|
||||
'react': 'commonjs react'
|
||||
}
|
||||
|
||||
// FIXME: get the react bundles working
|
||||
// create a single instance of the compiler to allow caching
|
||||
const compilerReact = webpack({
|
||||
entry: ENTRY_REACT,
|
||||
devtool: 'source-map',
|
||||
debug: true,
|
||||
cache: true,
|
||||
bail: true,
|
||||
output: {
|
||||
library: 'JSONEditor',
|
||||
libraryTarget: 'umd',
|
||||
path: DIST,
|
||||
filename: NAME_REACT
|
||||
},
|
||||
plugins: [
|
||||
bannerPlugin,
|
||||
productionEnvPlugin,
|
||||
minifyPlugin
|
||||
],
|
||||
module: {
|
||||
loaders
|
||||
},
|
||||
externals
|
||||
})
|
||||
|
||||
// FIXME: get the react bundles working
|
||||
// create a single instance of the compiler to allow caching
|
||||
const compilerReactMinimalist = webpack({
|
||||
entry: ENTRY_REACT,
|
||||
devtool: 'source-map',
|
||||
debug: true,
|
||||
cache: true,
|
||||
bail: true,
|
||||
output: {
|
||||
path: DIST,
|
||||
filename: NAME_REACT_MINIMALIST
|
||||
},
|
||||
plugins: [
|
||||
bannerPlugin,
|
||||
productionEnvPlugin,
|
||||
excludeAcePlugin,
|
||||
excludeAjvPlugin,
|
||||
minifyPlugin
|
||||
],
|
||||
module: {
|
||||
loaders
|
||||
},
|
||||
externals
|
||||
})
|
||||
|
||||
function handleCompilerCallback (err, stats) {
|
||||
if (err) {
|
||||
gutil.log(err.toString())
|
||||
}
|
||||
|
||||
if (stats && stats.compilation && stats.compilation.errors) {
|
||||
// output soft errors
|
||||
stats.compilation.errors.forEach(function (err) {
|
||||
gutil.log(err.toString())
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function createBundleTask (compiler) {
|
||||
return function (done) {
|
||||
// update the banner contents (has a date in it which should stay up to date)
|
||||
bannerPlugin.banner = createBanner()
|
||||
|
||||
compiler.run(function (err, stats) {
|
||||
handleCompilerCallback(err, stats)
|
||||
|
||||
done()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// make dist folder
|
||||
gulp.task('mkdir', function () {
|
||||
mkdirp.sync(DIST)
|
||||
mkdirp.sync(LIB)
|
||||
})
|
||||
|
||||
// bundle javascript
|
||||
gulp.task('bundle', ['mkdir'], createBundleTask(compiler))
|
||||
|
||||
// bundle minimalist version of javascript
|
||||
gulp.task('bundle-minimalist', ['mkdir'], createBundleTask(compilerMinimalist))
|
||||
|
||||
// compile the source code into es5 code
|
||||
gulp.task('compile-es5-lib', ['mkdir'], function () {
|
||||
// TODO: compile *.less too
|
||||
return gulp
|
||||
.src([
|
||||
'src/**/*.js',
|
||||
'!src/flow/**/*.js',
|
||||
'!src/resources/**/*.js'
|
||||
])
|
||||
.pipe(babel())
|
||||
.pipe(gulp.dest(LIB));
|
||||
})
|
||||
|
||||
// bundle react version
|
||||
// TODO: remove bundle-react again? (use ./lib instead)
|
||||
gulp.task('bundle-react', ['mkdir'], createBundleTask(compilerReact))
|
||||
|
||||
// bundle react minimalist version
|
||||
// TODO: remove bundle-react-minimalist again? (use ./lib instead)
|
||||
gulp.task('bundle-react-minimalist', ['mkdir'], createBundleTask(compilerReactMinimalist))
|
||||
|
||||
// TODO: zip file using archiver
|
||||
const pkg = 'jsoneditor-' + require('./package.json').version + '.zip'
|
||||
gulp.task('zip', shell.task([
|
||||
'zip ' + pkg + ' ' + 'README.md LICENSE HISTORY.md index.html src dist docs examples -r '
|
||||
]))
|
||||
|
||||
// execute all tasks and reload the browser afterwards
|
||||
gulp.task('bundle-and-reload', ['bundle'], function (done) {
|
||||
browserSync.reload();
|
||||
|
||||
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'], function() {
|
||||
browserSync.init({
|
||||
open: 'local',
|
||||
server: '.',
|
||||
startPath: '/src/develop.html',
|
||||
minify: false
|
||||
})
|
||||
|
||||
gulp.watch('src/**/*', ['bundle-and-reload'])
|
||||
})
|
||||
|
||||
// The default task (called when you run `gulp`)
|
||||
gulp.task('default', function(done) {
|
||||
return gulpMultiProcess([
|
||||
'bundle',
|
||||
'bundle-minimalist',
|
||||
'compile-es5-lib'
|
||||
], done);
|
||||
})
|
File diff suppressed because it is too large
Load Diff
100
package.json
100
package.json
|
@ -17,66 +17,56 @@
|
|||
"url": "https://github.com/josdejong/jsoneditor.git"
|
||||
},
|
||||
"bugs": "https://github.com/josdejong/jsoneditor/issues",
|
||||
"scripts": {
|
||||
"start": "gulp watch",
|
||||
"build": "gulp",
|
||||
"flow": "flow; test $? -eq 0 -o $? -eq 2",
|
||||
"test": "ava --verbose",
|
||||
"test-eson": "ava --verbose test/eson.test.js",
|
||||
"test-patch": "ava --verbose test/patchEson.test.js",
|
||||
"test-actions": "ava --verbose test/actions.test.js",
|
||||
"watch:test": "ava --verbose --watch"
|
||||
},
|
||||
"private": false,
|
||||
"dependencies": {
|
||||
"ajv": "4.10.4",
|
||||
"brace": "0.9.1",
|
||||
"console.table": "0.9.1",
|
||||
"ajv": "5.5.2",
|
||||
"brace": "0.11.0",
|
||||
"javascript-natural-sort": "0.7.1",
|
||||
"lodash": "4.17.4",
|
||||
"prop-types": "15.5.10",
|
||||
"react-hammerjs": "0.5.0"
|
||||
"prop-types": "15.6.0",
|
||||
"react-hammerjs": "1.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^16.0.0",
|
||||
"react-dom": "^16.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"ava": "0.17.0",
|
||||
"babel-core": "6.23.1",
|
||||
"babel-loader": "6.2.10",
|
||||
"babel-plugin-transform-flow-strip-types": "6.21.0",
|
||||
"babel-preset-es2015": "6.24.1",
|
||||
"babel-preset-stage-2": "6.18.0",
|
||||
"babel-preset-stage-3": "6.17.0",
|
||||
"browser-sync": "2.18.6",
|
||||
"css-loader": "0.26.1",
|
||||
"deep-map": "1.5.0",
|
||||
"flow-bin": "0.37.4",
|
||||
"graceful-fs": "4.1.11",
|
||||
"gulp": "3.9.1",
|
||||
"gulp-babel": "6.1.2",
|
||||
"gulp-multi-process": "0.0.4",
|
||||
"gulp-shell": "0.5.2",
|
||||
"gulp-util": "3.0.8",
|
||||
"json-loader": "0.5.4",
|
||||
"less": "2.7.2",
|
||||
"less-loader": "2.2.3",
|
||||
"mkdirp": "0.5.1",
|
||||
"preact": "7.1.0",
|
||||
"preact-compat": "3.9.4",
|
||||
"react": "15.4.1",
|
||||
"react-dom": "15.4.1",
|
||||
"style-loader": "0.13.1",
|
||||
"svg-url-loader": "1.1.0",
|
||||
"webpack": "1.14.0"
|
||||
"babel-cli": "6.26.0",
|
||||
"babel-plugin-external-helpers": "6.22.0",
|
||||
"babel-plugin-transform-class-properties": "6.24.1",
|
||||
"babel-plugin-transform-object-rest-spread": "6.26.0",
|
||||
"babel-plugin-transform-react-jsx": "6.24.1",
|
||||
"babel-preset-env": "1.6.1",
|
||||
"console.table": "0.9.1",
|
||||
"cpy-cli": "1.0.1",
|
||||
"css-loader": "0.28.7",
|
||||
"node-sass-chokidar": "0.0.3",
|
||||
"npm-run-all": "4.1.2",
|
||||
"preact": "8.2.7",
|
||||
"preact-compat": "3.17.0",
|
||||
"react": "16.2.0",
|
||||
"react-dom": "16.2.0",
|
||||
"react-scripts": "1.0.17",
|
||||
"rollup": "0.53.0",
|
||||
"rollup-plugin-babel": "3.0.3",
|
||||
"rollup-plugin-commonjs": "8.2.6",
|
||||
"rollup-plugin-node-resolve": "3.0.0",
|
||||
"rollup-plugin-postcss": "0.5.5",
|
||||
"svg-url-loader": "2.3.1",
|
||||
"webpack": "3.8.1"
|
||||
},
|
||||
"ava": {
|
||||
"files": [
|
||||
"test/**/*.test.js"
|
||||
],
|
||||
"source": [
|
||||
"./src/**/*"
|
||||
],
|
||||
"require": [
|
||||
"babel-register"
|
||||
],
|
||||
"concurrency": 4,
|
||||
"babel": "inherit"
|
||||
"scripts": {
|
||||
"start": "npm-run-all -p watch-css start-js",
|
||||
"build-css": "node-sass-chokidar src/ -o src/",
|
||||
"watch-css": "npm run build-css && node-sass-chokidar src/ -o src/ --watch --recursive",
|
||||
"start-js": "react-scripts start",
|
||||
"build-js": "react-scripts build",
|
||||
"copy-css-lib": "cpy '**/*.css' '**/*.svg' '../../lib' --cwd='src/jsoneditor' --parents",
|
||||
"build-js-lib": "babel src/jsoneditor --out-dir lib --ignore spec.js,test.js",
|
||||
"build-js-bundle": "webpack --config webpack.config.js",
|
||||
"build-js-minimalist": "webpack --config webpack.config.minimalist.js",
|
||||
"build": "npm-run-all build-css copy-css-lib build-js-lib build-js-bundle build-js-minimalist",
|
||||
"test": "react-scripts test --env=jsdom",
|
||||
"eject": "react-scripts eject"
|
||||
}
|
||||
}
|
||||
|
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
@ -0,0 +1,40 @@
|
|||
<!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">
|
||||
<!--
|
||||
manifest.json provides metadata used when your web app is added to the
|
||||
homescreen on Android. See https://developers.google.com/web/fundamentals/engage-and-retain/web-app-manifest/
|
||||
-->
|
||||
<link rel="manifest" href="%PUBLIC_URL%/manifest.json">
|
||||
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
|
||||
<!--
|
||||
Notice the use of %PUBLIC_URL% in the tags above.
|
||||
It will be replaced with the URL of the `public` folder during the build.
|
||||
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 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,15 @@
|
|||
{
|
||||
"short_name": "JSONEditor",
|
||||
"name": "JSONEditor demo",
|
||||
"icons": [
|
||||
{
|
||||
"src": "favicon.ico",
|
||||
"sizes": "64x64 32x32 24x24 16x16",
|
||||
"type": "image/x-icon"
|
||||
}
|
||||
],
|
||||
"start_url": "./index.html",
|
||||
"display": "standalone",
|
||||
"theme_color": "#3883fa",
|
||||
"background_color": "#ffffff"
|
||||
}
|
|
@ -1,144 +0,0 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
ace.define('ace/theme/jsoneditor', ['require', 'exports', 'module', 'ace/lib/dom'], function(acequire, exports, module) {
|
||||
|
||||
exports.isDark = false;
|
||||
exports.cssClass = "ace-jsoneditor";
|
||||
exports.cssText = ".ace-jsoneditor .ace_gutter {\
|
||||
background: #ebebeb;\
|
||||
color: #333\
|
||||
}\
|
||||
\
|
||||
.ace-jsoneditor.ace_editor {\
|
||||
font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif;\
|
||||
line-height: 1.3;\
|
||||
}\
|
||||
.ace-jsoneditor .ace_print-margin {\
|
||||
width: 1px;\
|
||||
background: #e8e8e8\
|
||||
}\
|
||||
.ace-jsoneditor .ace_scroller {\
|
||||
background-color: #FFFFFF\
|
||||
}\
|
||||
.ace-jsoneditor .ace_text-layer {\
|
||||
color: gray\
|
||||
}\
|
||||
.ace-jsoneditor .ace_variable {\
|
||||
color: #1a1a1a\
|
||||
}\
|
||||
.ace-jsoneditor .ace_cursor {\
|
||||
border-left: 2px solid #000000\
|
||||
}\
|
||||
.ace-jsoneditor .ace_overwrite-cursors .ace_cursor {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #000000\
|
||||
}\
|
||||
.ace-jsoneditor .ace_marker-layer .ace_selection {\
|
||||
background: lightgray\
|
||||
}\
|
||||
.ace-jsoneditor.ace_multiselect .ace_selection.ace_start {\
|
||||
box-shadow: 0 0 3px 0px #FFFFFF;\
|
||||
border-radius: 2px\
|
||||
}\
|
||||
.ace-jsoneditor .ace_marker-layer .ace_step {\
|
||||
background: rgb(255, 255, 0)\
|
||||
}\
|
||||
.ace-jsoneditor .ace_marker-layer .ace_bracket {\
|
||||
margin: -1px 0 0 -1px;\
|
||||
border: 1px solid #BFBFBF\
|
||||
}\
|
||||
.ace-jsoneditor .ace_marker-layer .ace_active-line {\
|
||||
background: #FFFBD1\
|
||||
}\
|
||||
.ace-jsoneditor .ace_gutter-active-line {\
|
||||
background-color : #dcdcdc\
|
||||
}\
|
||||
.ace-jsoneditor .ace_marker-layer .ace_selected-word {\
|
||||
border: 1px solid lightgray\
|
||||
}\
|
||||
.ace-jsoneditor .ace_invisible {\
|
||||
color: #BFBFBF\
|
||||
}\
|
||||
.ace-jsoneditor .ace_keyword,\
|
||||
.ace-jsoneditor .ace_meta,\
|
||||
.ace-jsoneditor .ace_support.ace_constant.ace_property-value {\
|
||||
color: #AF956F\
|
||||
}\
|
||||
.ace-jsoneditor .ace_keyword.ace_operator {\
|
||||
color: #484848\
|
||||
}\
|
||||
.ace-jsoneditor .ace_keyword.ace_other.ace_unit {\
|
||||
color: #96DC5F\
|
||||
}\
|
||||
.ace-jsoneditor .ace_constant.ace_language {\
|
||||
color: darkorange\
|
||||
}\
|
||||
.ace-jsoneditor .ace_constant.ace_numeric {\
|
||||
color: red\
|
||||
}\
|
||||
.ace-jsoneditor .ace_constant.ace_character.ace_entity {\
|
||||
color: #BF78CC\
|
||||
}\
|
||||
.ace-jsoneditor .ace_invalid {\
|
||||
color: #FFFFFF;\
|
||||
background-color: #FF002A;\
|
||||
}\
|
||||
.ace-jsoneditor .ace_fold {\
|
||||
background-color: #AF956F;\
|
||||
border-color: #000000\
|
||||
}\
|
||||
.ace-jsoneditor .ace_storage,\
|
||||
.ace-jsoneditor .ace_support.ace_class,\
|
||||
.ace-jsoneditor .ace_support.ace_function,\
|
||||
.ace-jsoneditor .ace_support.ace_other,\
|
||||
.ace-jsoneditor .ace_support.ace_type {\
|
||||
color: #C52727\
|
||||
}\
|
||||
.ace-jsoneditor .ace_string {\
|
||||
color: green\
|
||||
}\
|
||||
.ace-jsoneditor .ace_comment {\
|
||||
color: #BCC8BA\
|
||||
}\
|
||||
.ace-jsoneditor .ace_entity.ace_name.ace_tag,\
|
||||
.ace-jsoneditor .ace_entity.ace_other.ace_attribute-name {\
|
||||
color: #606060\
|
||||
}\
|
||||
.ace-jsoneditor .ace_markup.ace_underline {\
|
||||
text-decoration: underline\
|
||||
}\
|
||||
.ace-jsoneditor .ace_indent-guide {\
|
||||
background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y\
|
||||
}";
|
||||
|
||||
var dom = acequire("../lib/dom");
|
||||
dom.importCssString(exports.cssText, exports.cssClass);
|
||||
});
|
|
@ -0,0 +1,13 @@
|
|||
body, input, select {
|
||||
font-family: sans-serif;
|
||||
font-size: 11pt; }
|
||||
|
||||
.demo .menu {
|
||||
margin: 20px 0; }
|
||||
.demo .menu button, .demo .menu label {
|
||||
margin-right: 10px; }
|
||||
|
||||
.demo .contents {
|
||||
height: 400px;
|
||||
width: 100%;
|
||||
max-width: 800px; }
|
|
@ -0,0 +1,191 @@
|
|||
import React, { Component } from 'react'
|
||||
import JSONEditor from '../jsoneditor/index.react'
|
||||
import { setIn } from '../jsoneditor/utils/immutabilityHelpers'
|
||||
import { largeJson } from './resources/largeJson'
|
||||
|
||||
import './Demo.css'
|
||||
|
||||
const schema = {
|
||||
"title": "Example Schema",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"firstName": {
|
||||
"type": "string"
|
||||
},
|
||||
"lastName": {
|
||||
"type": "string"
|
||||
},
|
||||
"gender": {
|
||||
"enum": ["male", "female"]
|
||||
},
|
||||
"age": {
|
||||
"description": "Age in years",
|
||||
"type": "integer",
|
||||
"minimum": 0
|
||||
}
|
||||
},
|
||||
"required": ["firstName", "lastName"]
|
||||
}
|
||||
|
||||
const json = {
|
||||
'array': [1, 2, 3],
|
||||
'emptyArray': [],
|
||||
'emptyObject': {},
|
||||
'firstName': null,
|
||||
'boolean': true,
|
||||
'null': null,
|
||||
'number': 123,
|
||||
'object': {'a': 'b', 'c': 'd', 'e': [{"first": true}, {"second": true}]},
|
||||
'string': 'Hello World',
|
||||
'unicode': 'A unicode character: \u260E',
|
||||
'url': 'http://jsoneditoronline.org'
|
||||
}
|
||||
|
||||
function expandAll (path) {
|
||||
return true
|
||||
}
|
||||
|
||||
class App extends Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
logging: false,
|
||||
|
||||
options: {
|
||||
json,
|
||||
schema: null,
|
||||
|
||||
name: 'myObject',
|
||||
onPatch: this.handlePatch,
|
||||
onPatchText: this.handlePatchText,
|
||||
onChange: this.handleChange,
|
||||
onChangeText: this.handleChangeText,
|
||||
onChangeMode: this.handleChangeMode,
|
||||
onError: this.handleError,
|
||||
mode: 'tree',
|
||||
modes: ['text', 'code', 'tree', 'form', 'view'],
|
||||
keyBindings: {
|
||||
compact: ['Ctrl+\\', 'Command+\\', 'Ctrl+Alt+1', 'Command+Option+1'],
|
||||
format: ['Ctrl+Shift+\\', 'Command+Shift+\\', 'Ctrl+Alt+2', 'Command+Option+2'],
|
||||
duplicate: ['Ctrl+D', 'Ctrl+Shift+D', 'Command+D', 'Command+Shift+D']
|
||||
},
|
||||
indentation: 4,
|
||||
escapeUnicode: true,
|
||||
history: true,
|
||||
search: true,
|
||||
|
||||
expand: expandAll
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
render() {
|
||||
return <div className="demo">
|
||||
<div className="menu">
|
||||
<button onClick={this.handleSetJson}>Set JSON</button>
|
||||
<button onClick={this.handleGetJson}>Get JSON</button>
|
||||
|
||||
<label>mode:
|
||||
<select value={this.state.options.mode} onChange={this.handleSetMode}>
|
||||
<option value="text">text</option>
|
||||
<option value="code">code</option>
|
||||
<option value="tree">tree</option>
|
||||
<option value="form">form</option>
|
||||
<option value="view">view</option>
|
||||
</select>
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
value={this.state.options.schema !== null}
|
||||
onChange={this.handleToggleJSONSchema} /> JSON Schema
|
||||
</label>
|
||||
|
||||
<label>
|
||||
<input type="checkbox"
|
||||
value={this.state.logging}
|
||||
onChange={this.handleToggleLogging} /> Log events
|
||||
</label>
|
||||
</div>
|
||||
<div className="contents">
|
||||
<JSONEditor {...this.state.options} />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
handleSetJson = () => {
|
||||
this.setState({
|
||||
options: setIn(this.state.options, ['json'], largeJson)
|
||||
})
|
||||
}
|
||||
|
||||
handleGetJson = () => {
|
||||
// FIXME: get updating json in the state working
|
||||
const json = this.state.options.json
|
||||
alert(JSON.stringify(json, null, 2))
|
||||
}
|
||||
|
||||
handleSetMode = (event) => {
|
||||
const mode = event.target.value
|
||||
this.setState({
|
||||
options: setIn(this.state.options, ['mode'], mode)
|
||||
})
|
||||
}
|
||||
|
||||
handleToggleLogging = (event) => {
|
||||
const logging = event.target.checked
|
||||
this.setState({ logging })
|
||||
}
|
||||
|
||||
handleToggleJSONSchema = (event) => {
|
||||
const s = event.target.checked ? schema : null
|
||||
this.setState({
|
||||
options: setIn(this.state.options, ['schema'], s)
|
||||
})
|
||||
}
|
||||
|
||||
handleChange = (json) => {
|
||||
this.log('onChange json=', json)
|
||||
// FIXME: update the json in the state (after JSONEditor neatly updates it instead of generating new json every time
|
||||
// this.setState({
|
||||
// options: setIn(this.state.options, ['json'], json)
|
||||
// })
|
||||
}
|
||||
|
||||
handleChangeText = (text) => {
|
||||
this.log('onChangeText', text)
|
||||
}
|
||||
|
||||
handlePatch = (patch, revert) => {
|
||||
this.log('onPatch patch=', patch, ', revert=', revert)
|
||||
window.patch = patch
|
||||
window.revert = revert
|
||||
}
|
||||
|
||||
handlePatchText = (patch, revert) => {
|
||||
// FIXME: implement onPatchText
|
||||
this.log('onPatchText patch=', patch, ', revert=', revert)
|
||||
}
|
||||
|
||||
handleChangeMode = (mode, prevMode) => {
|
||||
this.log('switched mode from', prevMode, 'to', mode)
|
||||
|
||||
this.setState({
|
||||
options: setIn(this.state.options, ['mode'], mode)
|
||||
})
|
||||
}
|
||||
|
||||
handleError = (err) => {
|
||||
console.error(err)
|
||||
alert(err)
|
||||
}
|
||||
|
||||
log (...args) {
|
||||
if (this.state.logging) {
|
||||
console.log(...args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default App
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
body, input, select {
|
||||
font-family: sans-serif;
|
||||
font-size: 11pt;
|
||||
}
|
||||
|
||||
.demo {
|
||||
.menu {
|
||||
margin: 20px 0;
|
||||
|
||||
button, label {
|
||||
margin-right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.contents {
|
||||
height: 400px;
|
||||
width: 100%;
|
||||
max-width : 800px;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import Demo from './Demo';
|
||||
|
||||
|
||||
|
||||
test('renders without crashing', () => {
|
||||
const div = document.createElement('div');
|
||||
ReactDOM.render(<Demo />, div);
|
||||
});
|
|
@ -1,4 +1,4 @@
|
|||
const largeJson = {
|
||||
export const largeJson = {
|
||||
"version": "1.0",
|
||||
"encoding": "UTF-8",
|
||||
"feed": {
|
|
@ -2,12 +2,12 @@
|
|||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Develop JSONEditor</title>
|
||||
<title>JSONEditor vanilla demo</title>
|
||||
|
||||
<!-- For IE and Edge -->
|
||||
<!--<script src="https://cdnjs.cloudflare.com/ajax/libs/es6-shim/0.35.1/es6-shim.min.js"></script>-->
|
||||
|
||||
<script src="../dist/jsoneditor.js"></script>
|
||||
<script src="../../dist/jsoneditor.js"></script>
|
||||
|
||||
<script src="./resources/largeJson.js"></script>
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
|||
font-family: sans-serif;
|
||||
font-size: 11pt;
|
||||
}
|
||||
#container {
|
||||
#editor {
|
||||
height: 400px;
|
||||
width: 100%;
|
||||
max-width : 800px;
|
||||
|
@ -41,7 +41,7 @@
|
|||
</label>
|
||||
|
||||
<label>
|
||||
<input type="checkbox" id="logEvents" > Log events
|
||||
<input type="checkbox" id="logEvents" /> Log events
|
||||
</label>
|
||||
</p>
|
||||
<div id="container"></div>
|
||||
|
@ -53,7 +53,7 @@
|
|||
const error = console.error
|
||||
|
||||
return function(exception) {
|
||||
if ((exception + '').indexOf('Warning: A component is `contentEditable`') != 0) {
|
||||
if ((exception + '').indexOf('Warning: A component is `contentEditable`') !== 0) {
|
||||
error.apply(console, arguments)
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
// @flow
|
||||
declare export default string
|
279
src/index.js
279
src/index.js
|
@ -1,277 +1,6 @@
|
|||
import React, { createElement as h, Component } from 'react'
|
||||
import ReactDOM, { render, unmountComponentAtNode} from 'react-dom'
|
||||
import JSONEditor from './components/JSONEditor'
|
||||
import CodeMode from './components/CodeMode'
|
||||
import TextMode from './components/TextMode'
|
||||
import TreeMode from './components/TreeMode'
|
||||
import { compileJSONPointer, parseJSONPointer } from './eson'
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
|
||||
import '!style!css!less!./jsoneditor.less'
|
||||
import Demo from './demo/Demo';
|
||||
|
||||
const modes = {
|
||||
code: CodeMode,
|
||||
form: TreeMode,
|
||||
text: TextMode,
|
||||
tree: TreeMode,
|
||||
view: TreeMode
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new json editor
|
||||
* @param {HTMLElement} container
|
||||
* @param {Options} options
|
||||
* @return {Object}
|
||||
* @constructor
|
||||
*/
|
||||
function jsoneditor (container, options = {}) {
|
||||
if (arguments.length > 2) {
|
||||
throw new Error ('Passing JSON via the constructor has been deprecated. ' +
|
||||
'Please pass JSON via editor.set(json).')
|
||||
}
|
||||
|
||||
const editor = {
|
||||
isJSONEditor: true,
|
||||
|
||||
_container: container,
|
||||
_options: options,
|
||||
_schema: null,
|
||||
_modes: modes,
|
||||
_mode: null,
|
||||
_component: null
|
||||
}
|
||||
|
||||
/**
|
||||
* Set JSON object in editor
|
||||
* @param {Object | Array | string | number | boolean | null} json JSON data
|
||||
* @param {SetOptions} [options]
|
||||
*/
|
||||
editor.set = function (json, options = {}) {
|
||||
// TODO: remove options from editor.set, move them to global options instead
|
||||
editor._component.set(json, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get JSON from the editor
|
||||
* @returns {Object | Array | string | number | boolean | null} json
|
||||
*/
|
||||
editor.get = function () {
|
||||
return editor._component.get()
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a string containing a JSON document
|
||||
* @param {string} text
|
||||
*/
|
||||
editor.setText = function (text) {
|
||||
editor._component.setText(text)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JSON document as text
|
||||
* @return {string} text
|
||||
*/
|
||||
editor.getText = function () {
|
||||
return editor._component.getText()
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the json.
|
||||
* Only applicable for mode 'text' and 'code' (in other modes nothing will
|
||||
* happen)
|
||||
*/
|
||||
editor.format = function () {
|
||||
const formatted = TextMode.format(editor._component.getText(), TextMode.getIndentation(this.props))
|
||||
editor._component.setText(formatted)
|
||||
|
||||
// TODO: test whether this doesn't destroy the current state
|
||||
}
|
||||
|
||||
/**
|
||||
* Compact the json.
|
||||
* Only applicable for mode 'text' and 'code' (in other modes nothing will
|
||||
* happen)
|
||||
*/
|
||||
editor.compact = function () {
|
||||
const compacted = TextMode.compact(editor._component.getText())
|
||||
editor._component.setText(compacted)
|
||||
|
||||
// TODO: test whether this doesn't destroy the current state
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a JSON schema for validation of the JSON object.
|
||||
* To remove the schema, call JSONEditor.setSchema(null)
|
||||
* @param {Object | null} schema
|
||||
*/
|
||||
editor.setSchema = function (schema) {
|
||||
editor._schema = schema || null
|
||||
editor._component.setSchema(schema)
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand one or multiple objects or arrays.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* // expand one item at a specific path
|
||||
* editor.expand(['foo', 1, 'bar'])
|
||||
*
|
||||
* // expand all items nested at a maximum depth of 2
|
||||
* editor.expand(function (path) {
|
||||
* return path.length <= 2
|
||||
* })
|
||||
*
|
||||
* @param {Path | function (path: Path) : boolean} callback
|
||||
*/
|
||||
editor.expand = function (callback) {
|
||||
editor._component.expand(callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse one or multiple objects or arrays
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* // collapse one item at a specific path
|
||||
* editor.collapse(['foo', 1, 'bar'])
|
||||
*
|
||||
* // collapse all items nested deeper than 2
|
||||
* editor.collapse(function (path) {
|
||||
* return path.length > 2
|
||||
* })
|
||||
*
|
||||
* @param {Path | function (path: Path) : boolean} callback
|
||||
*/
|
||||
editor.collapse = function (callback) {
|
||||
editor._component.collapse(callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a JSONPatch to the current JSON document
|
||||
* @param {Array} actions JSONPatch actions
|
||||
* @return {Array} Returns a JSONPatch to revert the applied patch
|
||||
*/
|
||||
editor.patch = function (actions) {
|
||||
return editor._component.patch(actions)
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the mode of the editor
|
||||
* @param {'tree' | 'text'} mode
|
||||
*/
|
||||
editor.setMode = function (mode) {
|
||||
// TODO: strongly simplify .setMode, no error handling or logic here
|
||||
|
||||
if (mode === editor._mode) {
|
||||
// mode stays the same. do nothing
|
||||
return
|
||||
}
|
||||
|
||||
let success = false
|
||||
let initialChildCount = editor._container.children.length
|
||||
let component = null
|
||||
try {
|
||||
// find the constructor for the selected mode
|
||||
const constructor = editor._modes[mode]
|
||||
if (!constructor) {
|
||||
throw new Error('Unknown mode "' + mode + '". ' +
|
||||
'Choose from: ' + Object.keys(modes).join(', '))
|
||||
}
|
||||
|
||||
function handleChangeMode (mode) {
|
||||
// we execute editor.setMode on the next tick, after the click event
|
||||
// has been finished. This is a workaround for preact which does not
|
||||
// neatly replace a rendered app whilst the event is still being handled.
|
||||
setTimeout(() => {
|
||||
const prevMode = editor._mode
|
||||
|
||||
editor.setMode(mode)
|
||||
|
||||
if (editor._options.onChangeMode) {
|
||||
editor._options.onChangeMode(mode, prevMode)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function handleError (err) {
|
||||
if (editor._options && editor._options.onError) {
|
||||
editor._options.onError(err)
|
||||
}
|
||||
else {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// create new component
|
||||
component = render(
|
||||
h(constructor, {
|
||||
...options,
|
||||
mode,
|
||||
onChangeMode: handleChangeMode,
|
||||
onError: handleError
|
||||
}),
|
||||
editor._container)
|
||||
|
||||
// apply JSON schema (if any)
|
||||
try {
|
||||
component.setSchema(editor._schema)
|
||||
}
|
||||
catch (err) {
|
||||
handleError(err)
|
||||
}
|
||||
|
||||
// set JSON (this can throw an error)
|
||||
const text = editor._component ? editor._component.getText() : '{}'
|
||||
component.setText(text)
|
||||
|
||||
// when setText didn't fail, we will reach this point
|
||||
success = true
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
finally {
|
||||
if (success) {
|
||||
editor._mode = mode
|
||||
editor._component = component
|
||||
}
|
||||
else {
|
||||
// TODO: fall back to text mode when loading code mode failed?
|
||||
|
||||
// remove the just created component if an error occurred during construction
|
||||
// (for example when construction or setText failed)
|
||||
const childCount = editor._container.children.length
|
||||
if (childCount !== initialChildCount) {
|
||||
editor._container.removeChild(editor._container.lastChild)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the editor from the DOM and clean up workers
|
||||
*/
|
||||
editor.destroy = function () {
|
||||
unmountComponentAtNode(editor._container)
|
||||
}
|
||||
|
||||
const mode = options && options.mode || (options.modes && options.modes[0]) || 'tree';
|
||||
editor.setMode(mode)
|
||||
|
||||
return editor
|
||||
}
|
||||
|
||||
// expose util functions
|
||||
jsoneditor.utils = {
|
||||
compileJSONPointer,
|
||||
parseJSONPointer
|
||||
}
|
||||
|
||||
// expose React component
|
||||
jsoneditor.JSONEditor = JSONEditor
|
||||
|
||||
// expose React itself
|
||||
jsoneditor.React = React
|
||||
jsoneditor.ReactDOM = ReactDOM
|
||||
|
||||
module.exports = jsoneditor
|
||||
ReactDOM.render(<Demo />, document.getElementById('root'));
|
||||
|
|
|
@ -6,10 +6,10 @@ import {
|
|||
compileJSONPointer, esonToJson, findNextProp,
|
||||
pathsFromSelection, findRootPath, findSelectionIndices
|
||||
} from './eson'
|
||||
import { cloneWithSymbols, getIn, setIn } from './utils/immutabilityHelpers'
|
||||
import { getIn } from './utils/immutabilityHelpers'
|
||||
import { findUniqueName } from './utils/stringUtils'
|
||||
import { isObject, stringConvert } from './utils/typeUtils'
|
||||
import { compareAsc, compareDesc, strictShallowEqual } from './utils/arrayUtils'
|
||||
import { compareAsc, compareDesc } from './utils/arrayUtils'
|
||||
|
||||
|
||||
/**
|
||||
|
@ -138,7 +138,7 @@ export function duplicate (eson, selection) {
|
|||
*
|
||||
* @param {ESON} eson
|
||||
* @param {Path} path
|
||||
* @param {Array.<{name?: string, value: JSONType, type?: ESONType}>} values
|
||||
* @param {Array.<{name?: string, value: JSON, type?: ESONType}>} values
|
||||
* @return {Array}
|
||||
*/
|
||||
export function insertBefore (eson, path, values) { // TODO: find a better name and define datastructure for values
|
||||
|
@ -146,7 +146,7 @@ export function insertBefore (eson, path, values) { // TODO: find a better name
|
|||
const parent = getIn(eson, parentPath)
|
||||
|
||||
if (parent[META].type === 'Array') {
|
||||
const startIndex = parseInt(last(path))
|
||||
const startIndex = parseInt(last(path), 10)
|
||||
return values.map((entry, offset) => ({
|
||||
op: 'add',
|
||||
path: compileJSONPointer(parentPath.concat(startIndex + offset)),
|
|
@ -0,0 +1,81 @@
|
|||
'use strict'
|
||||
|
||||
import { sort } from './actions'
|
||||
import { assertDeepEqualEson } from './utils/assertDeepEqualEson'
|
||||
import {esonToJson, expandOne, jsonToEson, META} from './eson'
|
||||
import {patchEson} from './patchEson'
|
||||
|
||||
// TODO: test changeValue
|
||||
// TODO: test changeProperty
|
||||
// TODO: test changeType (or cleanup the function)
|
||||
// TODO: test duplicate
|
||||
// TODO: test insertBefore
|
||||
// TODO: test replace
|
||||
// TODO: test append
|
||||
// TODO: test remove
|
||||
// TODO: test removeAll
|
||||
|
||||
it('sort root Array', () => {
|
||||
const eson = jsonToEson([1,3,2])
|
||||
|
||||
assertDeepEqualEson(patchEson(eson, sort(eson, [])).data, jsonToEson([1,2,3]))
|
||||
assertDeepEqualEson(patchEson(eson, sort(eson, [], 'asc')).data, jsonToEson([1,2,3]))
|
||||
assertDeepEqualEson(patchEson(eson, sort(eson, [], 'desc')).data, jsonToEson([3,2,1]))
|
||||
})
|
||||
|
||||
it('sort nested Array', () => {
|
||||
const eson = jsonToEson({arr: [4,1,8,5,3,9,2,7,6]})
|
||||
const actual = patchEson(eson, sort(eson, ['arr'])).data
|
||||
const expected = jsonToEson({arr: [1,2,3,4,5,6,7,8,9]})
|
||||
assertDeepEqualEson(actual, expected)
|
||||
})
|
||||
|
||||
it('sort nested Array reverse order', () => {
|
||||
// no order provided -> order ascending, but if nothing changes, order descending
|
||||
const eson = jsonToEson({arr: [1,2,3,4,5,6,7,8,9]})
|
||||
const actual = patchEson(eson, sort(eson, ['arr'])).data
|
||||
const expected = jsonToEson({arr: [9,8,7,6,5,4,3,2,1]})
|
||||
assertDeepEqualEson(actual, expected)
|
||||
|
||||
// id's and META should be the same
|
||||
expect(actual.arr[META].id).toEqual(eson.arr[META].id)
|
||||
expect(actual.arr[7][META].id).toEqual(eson.arr[1][META].id)
|
||||
})
|
||||
|
||||
|
||||
it('sort root Object', () => {
|
||||
const eson = jsonToEson({c: 2, b: 3, a:4})
|
||||
|
||||
expect(patchEson(eson, sort(eson, [])).data[META].props).toEqual(['a', 'b', 'c'])
|
||||
expect(patchEson(eson, sort(eson, [], 'asc')).data[META].props).toEqual(['a', 'b', 'c'])
|
||||
expect(patchEson(eson, sort(eson, [], 'desc')).data[META].props).toEqual(['c', 'b', 'a'])
|
||||
})
|
||||
|
||||
it('sort nested Object', () => {
|
||||
const eson = jsonToEson({obj: {c: 2, b: 3, a:4}})
|
||||
eson.obj[META].expanded = true
|
||||
eson.obj.c[META].expanded = true
|
||||
|
||||
const actual = patchEson(eson, sort(eson, ['obj'])).data
|
||||
|
||||
// should keep META data
|
||||
expect(actual.obj[META].props).toEqual(['a', 'b', 'c'])
|
||||
expect(actual.obj[META].expanded).toEqual(true)
|
||||
expect(actual.obj.c[META].expanded).toEqual(true)
|
||||
expect(actual.obj[META].id).toEqual(eson.obj[META].id)
|
||||
expect(actual.obj.a[META].id).toEqual(eson.obj.a[META].id)
|
||||
expect(actual.obj.b[META].id).toEqual(eson.obj.b[META].id)
|
||||
expect(actual.obj.c[META].id).toEqual(eson.obj.c[META].id)
|
||||
|
||||
// asc, desc
|
||||
expect(patchEson(eson, sort(eson, ['obj'])).data.obj[META].props).toEqual(['a', 'b', 'c'])
|
||||
expect(patchEson(eson, sort(eson, ['obj'], 'asc')).data.obj[META].props).toEqual(['a', 'b', 'c'])
|
||||
expect(patchEson(eson, sort(eson, ['obj'], 'desc')).data.obj[META].props).toEqual(['c', 'b', 'a'])
|
||||
})
|
||||
|
||||
it('sort nested Object (larger)', () => {
|
||||
const eson = jsonToEson({obj: {h:1, c:1, e:1, d:1, g:1, b:1, a:1, f:1}})
|
||||
const actual = patchEson(eson, sort(eson, ['obj'])).data
|
||||
|
||||
expect(actual.obj[META].props).toEqual(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'])
|
||||
})
|
|
@ -0,0 +1,144 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
window.ace.define('ace/theme/jsoneditor', ['require', 'exports', 'module', 'ace/lib/dom'], function(acequire, exports, module) {
|
||||
|
||||
exports.isDark = false
|
||||
exports.cssClass = 'ace-jsoneditor'
|
||||
exports.cssText = `.ace-jsoneditor .ace_gutter {
|
||||
background: #ebebeb;
|
||||
color: #333
|
||||
}
|
||||
|
||||
.ace-jsoneditor.ace_editor {
|
||||
font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif;
|
||||
line-height: 1.3;
|
||||
}
|
||||
.ace-jsoneditor .ace_print-margin {
|
||||
width: 1px;
|
||||
background: #e8e8e8
|
||||
}
|
||||
.ace-jsoneditor .ace_scroller {
|
||||
background-color: #FFFFFF
|
||||
}
|
||||
.ace-jsoneditor .ace_text-layer {
|
||||
color: gray
|
||||
}
|
||||
.ace-jsoneditor .ace_variable {
|
||||
color: #1a1a1a
|
||||
}
|
||||
.ace-jsoneditor .ace_cursor {
|
||||
border-left: 2px solid #000000
|
||||
}
|
||||
.ace-jsoneditor .ace_overwrite-cursors .ace_cursor {
|
||||
border-left: 0px;
|
||||
border-bottom: 1px solid #000000
|
||||
}
|
||||
.ace-jsoneditor .ace_marker-layer .ace_selection {
|
||||
background: lightgray
|
||||
}
|
||||
.ace-jsoneditor.ace_multiselect .ace_selection.ace_start {
|
||||
box-shadow: 0 0 3px 0px #FFFFFF;
|
||||
border-radius: 2px
|
||||
}
|
||||
.ace-jsoneditor .ace_marker-layer .ace_step {
|
||||
background: rgb(255, 255, 0)
|
||||
}
|
||||
.ace-jsoneditor .ace_marker-layer .ace_bracket {
|
||||
margin: -1px 0 0 -1px;
|
||||
border: 1px solid #BFBFBF
|
||||
}
|
||||
.ace-jsoneditor .ace_marker-layer .ace_active-line {
|
||||
background: #FFFBD1
|
||||
}
|
||||
.ace-jsoneditor .ace_gutter-active-line {
|
||||
background-color : #dcdcdc
|
||||
}
|
||||
.ace-jsoneditor .ace_marker-layer .ace_selected-word {
|
||||
border: 1px solid lightgray
|
||||
}
|
||||
.ace-jsoneditor .ace_invisible {
|
||||
color: #BFBFBF
|
||||
}
|
||||
.ace-jsoneditor .ace_keyword,
|
||||
.ace-jsoneditor .ace_meta,
|
||||
.ace-jsoneditor .ace_support.ace_constant.ace_property-value {
|
||||
color: #AF956F
|
||||
}
|
||||
.ace-jsoneditor .ace_keyword.ace_operator {
|
||||
color: #484848
|
||||
}
|
||||
.ace-jsoneditor .ace_keyword.ace_other.ace_unit {
|
||||
color: #96DC5F
|
||||
}
|
||||
.ace-jsoneditor .ace_constant.ace_language {
|
||||
color: darkorange
|
||||
}
|
||||
.ace-jsoneditor .ace_constant.ace_numeric {
|
||||
color: red
|
||||
}
|
||||
.ace-jsoneditor .ace_constant.ace_character.ace_entity {
|
||||
color: #BF78CC
|
||||
}
|
||||
.ace-jsoneditor .ace_invalid {
|
||||
color: #FFFFFF;
|
||||
background-color: #FF002A;
|
||||
}
|
||||
.ace-jsoneditor .ace_fold {
|
||||
background-color: #AF956F;
|
||||
border-color: #000000
|
||||
}
|
||||
.ace-jsoneditor .ace_storage,
|
||||
.ace-jsoneditor .ace_support.ace_class,
|
||||
.ace-jsoneditor .ace_support.ace_function,
|
||||
.ace-jsoneditor .ace_support.ace_other,
|
||||
.ace-jsoneditor .ace_support.ace_type {
|
||||
color: #C52727
|
||||
}
|
||||
.ace-jsoneditor .ace_string {
|
||||
color: green
|
||||
}
|
||||
.ace-jsoneditor .ace_comment {
|
||||
color: #BCC8BA
|
||||
}
|
||||
.ace-jsoneditor .ace_entity.ace_name.ace_tag,
|
||||
.ace-jsoneditor .ace_entity.ace_other.ace_attribute-name {
|
||||
color: #606060
|
||||
}
|
||||
.ace-jsoneditor .ace_markup.ace_underline {
|
||||
text-decoration: underline
|
||||
}
|
||||
.ace-jsoneditor .ace_indent-guide {
|
||||
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y
|
||||
}`
|
||||
|
||||
var dom = acequire('../lib/dom')
|
||||
dom.importCssString(exports.cssText, exports.cssClass)
|
||||
})
|
|
@ -13,7 +13,7 @@ var parser = (function(){
|
|||
var $0 = $$.length - 1;
|
||||
switch (yystate) {
|
||||
case 1: // replace escaped characters with actual character
|
||||
this.$ = yytext.replace(/\\(\\|")/g, "$"+"1")
|
||||
this.$ = yytext.replace(/\\(\\|")/g, "$1")
|
||||
.replace(/\\n/g,'\n')
|
||||
.replace(/\\r/g,'\r')
|
||||
.replace(/\\t/g,'\t')
|
||||
|
@ -30,8 +30,8 @@ var parser = (function(){
|
|||
break;
|
||||
case 5:this.$ = false;
|
||||
break;
|
||||
case 6:return this.$ = $$[$0-1];
|
||||
break;
|
||||
case 6:
|
||||
return this.$ = $$[$0-1];
|
||||
case 13:this.$ = {};
|
||||
break;
|
||||
case 14:this.$ = $$[$0-1];
|
||||
|
@ -50,6 +50,8 @@ var parser = (function(){
|
|||
break;
|
||||
case 21:this.$ = $$[$0-2]; $$[$0-2].push($$[$0]);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
},
|
||||
table: [{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],12:1,13:2,15:7,16:8,17:[1,14],23:[1,15]},{1:[3]},{14:[1,16]},{14:[2,7],18:[2,7],22:[2,7],24:[2,7]},{14:[2,8],18:[2,8],22:[2,8],24:[2,8]},{14:[2,9],18:[2,9],22:[2,9],24:[2,9]},{14:[2,10],18:[2,10],22:[2,10],24:[2,10]},{14:[2,11],18:[2,11],22:[2,11],24:[2,11]},{14:[2,12],18:[2,12],22:[2,12],24:[2,12]},{14:[2,3],18:[2,3],22:[2,3],24:[2,3]},{14:[2,4],18:[2,4],22:[2,4],24:[2,4]},{14:[2,5],18:[2,5],22:[2,5],24:[2,5]},{14:[2,1],18:[2,1],21:[2,1],22:[2,1],24:[2,1]},{14:[2,2],18:[2,2],22:[2,2],24:[2,2]},{3:20,4:[1,12],18:[1,17],19:18,20:19},{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],13:23,15:7,16:8,17:[1,14],23:[1,15],24:[1,21],25:22},{1:[2,6]},{14:[2,13],18:[2,13],22:[2,13],24:[2,13]},{18:[1,24],22:[1,25]},{18:[2,16],22:[2,16]},{21:[1,26]},{14:[2,18],18:[2,18],22:[2,18],24:[2,18]},{22:[1,28],24:[1,27]},{22:[2,20],24:[2,20]},{14:[2,14],18:[2,14],22:[2,14],24:[2,14]},{3:20,4:[1,12],20:29},{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],13:30,15:7,16:8,17:[1,14],23:[1,15]},{14:[2,19],18:[2,19],22:[2,19],24:[2,19]},{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],13:31,15:7,16:8,17:[1,14],23:[1,15]},{18:[2,17],22:[2,17]},{18:[2,15],22:[2,15]},{22:[2,21],24:[2,21]}],
|
||||
|
@ -75,7 +77,7 @@ var parser = (function(){
|
|||
this.lexer.setInput(input);
|
||||
this.lexer.yy = this.yy;
|
||||
this.yy.lexer = this.lexer;
|
||||
if (typeof this.lexer.yylloc == 'undefined')
|
||||
if (typeof this.lexer.yylloc === 'undefined')
|
||||
this.lexer.yylloc = {};
|
||||
var yyloc = this.lexer.yylloc;
|
||||
lstack.push(yyloc);
|
||||
|
@ -99,7 +101,7 @@ var parser = (function(){
|
|||
return token;
|
||||
}
|
||||
|
||||
var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected;
|
||||
var symbol, preErrorSymbol, state, action, r, yyval={},p,len,newState, expected;
|
||||
while (true) {
|
||||
// retreive state number from top of stack
|
||||
state = stack[stack.length-1];
|
||||
|
@ -115,60 +117,60 @@ var parser = (function(){
|
|||
}
|
||||
|
||||
// handle parse error
|
||||
_handle_error:
|
||||
if (typeof action === 'undefined' || !action.length || !action[0]) {
|
||||
|
||||
if (!recovering) {
|
||||
// Report error
|
||||
expected = [];
|
||||
for (p in table[state]) if (this.terminals_[p] && p > 2) {
|
||||
expected.push("'"+this.terminals_[p]+"'");
|
||||
}
|
||||
var errStr = '';
|
||||
if (this.lexer.showPosition) {
|
||||
errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+expected.join(', ') + ", got '" + this.terminals_[symbol]+ "'";
|
||||
} else {
|
||||
errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " +
|
||||
(symbol == 1 /*EOF*/ ? "end of input" :
|
||||
("'"+(this.terminals_[symbol] || symbol)+"'"));
|
||||
}
|
||||
this.parseError(errStr,
|
||||
{text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});
|
||||
}
|
||||
if (typeof action === 'undefined' || !action.length || !action[0]) {
|
||||
|
||||
// just recovered from another error
|
||||
if (recovering == 3) {
|
||||
if (symbol == EOF) {
|
||||
throw new Error(errStr || 'Parsing halted.');
|
||||
}
|
||||
|
||||
// discard current lookahead and grab another
|
||||
yyleng = this.lexer.yyleng;
|
||||
yytext = this.lexer.yytext;
|
||||
yylineno = this.lexer.yylineno;
|
||||
yyloc = this.lexer.yylloc;
|
||||
symbol = lex();
|
||||
}
|
||||
|
||||
// try to recover from error
|
||||
while (1) {
|
||||
// check for error recovery rule in this state
|
||||
if ((TERROR.toString()) in table[state]) {
|
||||
break;
|
||||
}
|
||||
if (state == 0) {
|
||||
throw new Error(errStr || 'Parsing halted.');
|
||||
}
|
||||
popStack(1);
|
||||
state = stack[stack.length-1];
|
||||
}
|
||||
|
||||
preErrorSymbol = symbol; // save the lookahead token
|
||||
symbol = TERROR; // insert generic error symbol as new lookahead
|
||||
state = stack[stack.length-1];
|
||||
action = table[state] && table[state][TERROR];
|
||||
recovering = 3; // allow 3 real symbols to be shifted before reporting a new error
|
||||
if (!recovering) {
|
||||
// Report error
|
||||
expected = [];
|
||||
for (p in table[state]) if (this.terminals_[p] && p > 2) {
|
||||
expected.push("'"+this.terminals_[p]+"'");
|
||||
}
|
||||
var errStr = '';
|
||||
if (this.lexer.showPosition) {
|
||||
errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+expected.join(', ') + ", got '" + this.terminals_[symbol]+ "'";
|
||||
} else {
|
||||
errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " +
|
||||
(symbol === 1 /*EOF*/ ? "end of input" :
|
||||
("'"+(this.terminals_[symbol] || symbol)+"'"));
|
||||
}
|
||||
this.parseError(errStr,
|
||||
{text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});
|
||||
}
|
||||
|
||||
// just recovered from another error
|
||||
if (recovering === 3) {
|
||||
if (symbol === EOF) {
|
||||
throw new Error(errStr || 'Parsing halted.');
|
||||
}
|
||||
|
||||
// discard current lookahead and grab another
|
||||
yyleng = this.lexer.yyleng;
|
||||
yytext = this.lexer.yytext;
|
||||
yylineno = this.lexer.yylineno;
|
||||
yyloc = this.lexer.yylloc;
|
||||
symbol = lex();
|
||||
}
|
||||
|
||||
// try to recover from error
|
||||
while (1) {
|
||||
// check for error recovery rule in this state
|
||||
if ((TERROR.toString()) in table[state]) {
|
||||
break;
|
||||
}
|
||||
if (state === 0) {
|
||||
throw new Error(errStr || 'Parsing halted.');
|
||||
}
|
||||
popStack(1);
|
||||
state = stack[stack.length-1];
|
||||
}
|
||||
|
||||
preErrorSymbol = symbol; // save the lookahead token
|
||||
symbol = TERROR; // insert generic error symbol as new lookahead
|
||||
state = stack[stack.length-1];
|
||||
action = table[state] && table[state][TERROR];
|
||||
recovering = 3; // allow 3 real symbols to be shifted before reporting a new error
|
||||
}
|
||||
|
||||
// this shouldn't happen, unless resolve defaults are off
|
||||
if (action[0] instanceof Array && action.length > 1) {
|
||||
|
@ -235,11 +237,11 @@ var parser = (function(){
|
|||
|
||||
case 3: // accept
|
||||
return true;
|
||||
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}};
|
||||
/* Jison generated lexer */
|
||||
var lexer = (function(){
|
||||
|
@ -308,7 +310,6 @@ var parser = (function(){
|
|||
match,
|
||||
tempMatch,
|
||||
index,
|
||||
col,
|
||||
lines;
|
||||
if (!this._more) {
|
||||
this.yytext = '';
|
||||
|
@ -374,35 +375,22 @@ var parser = (function(){
|
|||
lexer.options = {};
|
||||
lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
|
||||
|
||||
var YYSTATE=YY_START
|
||||
switch($avoiding_name_collisions) {
|
||||
case 0:/* skip whitespace */
|
||||
break;
|
||||
case 0: break; /* skip whitespace */
|
||||
case 1:return 6
|
||||
break;
|
||||
case 2:yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2); return 4
|
||||
break;
|
||||
case 3:return 17
|
||||
break;
|
||||
case 4:return 18
|
||||
break;
|
||||
case 5:return 23
|
||||
break;
|
||||
case 6:return 24
|
||||
break;
|
||||
case 7:return 22
|
||||
break;
|
||||
case 8:return 21
|
||||
break;
|
||||
case 9:return 10
|
||||
break;
|
||||
case 10:return 11
|
||||
break;
|
||||
case 11:return 8
|
||||
break;
|
||||
case 12:return 14
|
||||
break;
|
||||
case 13:return 'INVALID'
|
||||
default:
|
||||
break;
|
||||
}
|
||||
};
|
|
@ -153,6 +153,8 @@ const jumper = () => {
|
|||
element = document.querySelector(target)
|
||||
stop = top(element)
|
||||
break
|
||||
|
||||
default:
|
||||
}
|
||||
|
||||
// resolve scroll distance, accounting for offset
|
||||
|
@ -169,6 +171,8 @@ const jumper = () => {
|
|||
case 'function':
|
||||
duration = options.duration(distance)
|
||||
break
|
||||
|
||||
default:
|
||||
}
|
||||
|
||||
// start the loop if we're not already scrolling
|
|
@ -1,7 +1,6 @@
|
|||
// @flow
|
||||
|
||||
import { createElement as h, Component } from 'react'
|
||||
import ace from '../assets/ace'
|
||||
import PropTypes from 'prop-types'
|
||||
|
||||
/**
|
||||
* Usage:
|
||||
|
@ -14,6 +13,12 @@ import ace from '../assets/ace'
|
|||
*
|
||||
*/
|
||||
export default class Ace extends Component {
|
||||
|
||||
static propTypes = {
|
||||
value: PropTypes.string.isRequired,
|
||||
indentation: PropTypes.number
|
||||
}
|
||||
|
||||
aceEditor = null
|
||||
settingValue = false // Used to prevent Ace from emitting onChange event whilst we're setting a value programmatically
|
||||
|
||||
|
@ -73,14 +78,15 @@ export default class Ace extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps: {value: string, indentation?: number}) {
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (this.aceEditor && nextProps.value !== this.aceEditor.getValue()) {
|
||||
this.settingValue = true
|
||||
this.aceEditor.setValue(nextProps.value, -1)
|
||||
this.settingValue = false
|
||||
}
|
||||
|
||||
if (this.aceEditor && nextProps.indentation != undefined) {
|
||||
if (this.aceEditor &&
|
||||
(typeof nextProps.indentation === 'number' || typeof nextProps.indentation === 'string')) {
|
||||
this.aceEditor.getSession().setTabSize(this.props.indentation)
|
||||
}
|
||||
|
|
@ -1,6 +1,4 @@
|
|||
// @flow
|
||||
|
||||
import { createElement as h, Component } from 'react'
|
||||
import { createElement as h } from 'react'
|
||||
import TextMode from './TextMode'
|
||||
import Ace from './Ace'
|
||||
|
||||
|
@ -30,13 +28,12 @@ import Ace from './Ace'
|
|||
*
|
||||
*/
|
||||
export default class CodeMode extends TextMode {
|
||||
constructor (props: {options: {onLoadAce: Function, indentation: number}}) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
text: '{}',
|
||||
compiledSchema: null
|
||||
}
|
||||
// TODO: work out propTypes
|
||||
|
||||
state = {
|
||||
text: '{}',
|
||||
compiledSchema: null
|
||||
}
|
||||
|
||||
render () {
|
|
@ -1,12 +1,19 @@
|
|||
// @flow
|
||||
|
||||
import { createElement as h, Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { createElement as h, PureComponent } from 'react'
|
||||
import CodeMode from './CodeMode'
|
||||
import TextMode from './TextMode'
|
||||
import TreeMode from './TreeMode'
|
||||
|
||||
export default class JSONEditor extends Component {
|
||||
import './jsoneditor.css'
|
||||
|
||||
const DEFAULT_MODE = 'tree'
|
||||
|
||||
export default class JSONEditor extends PureComponent {
|
||||
|
||||
// TODO: work out prop types
|
||||
// static propTypes = {
|
||||
// ...
|
||||
// }
|
||||
|
||||
static modeConstructors = {
|
||||
code: CodeMode,
|
||||
form: TreeMode,
|
||||
|
@ -15,18 +22,14 @@ export default class JSONEditor extends Component {
|
|||
view: TreeMode
|
||||
}
|
||||
|
||||
state = {
|
||||
mode: 'tree'
|
||||
}
|
||||
|
||||
render () {
|
||||
const mode = this.state.mode // We use mode from state, not from props!
|
||||
const mode = this.props.mode || DEFAULT_MODE // We use mode from state, not from props!
|
||||
const ModeConstructor = JSONEditor.modeConstructors[mode]
|
||||
|
||||
if (!ModeConstructor) {
|
||||
// TODO: show an on screen error instead of throwing an error?
|
||||
throw new Error('Unknown mode "' + mode + '". ' +
|
||||
'Choose from: ' + Object.keys(this.props.modes).join(', '))
|
||||
'Choose from: ' + Object.keys(this.props.modes).join(', ')) // FIXME: this.props.modes may be undefined
|
||||
}
|
||||
|
||||
return h(ModeConstructor, {
|
||||
|
@ -37,19 +40,7 @@ export default class JSONEditor extends Component {
|
|||
})
|
||||
}
|
||||
|
||||
componentWillMount () {
|
||||
if (this.props.mode) {
|
||||
this.setState({ mode: this.props.mode })
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps: {mode?: string}) {
|
||||
if (nextProps.mode !== this.props.mode) {
|
||||
this.setState({ mode: nextProps.mode })
|
||||
}
|
||||
}
|
||||
|
||||
handleError = (err: Error) => {
|
||||
handleError = (err) => {
|
||||
if (this.props.onError) {
|
||||
this.props.onError(err)
|
||||
}
|
||||
|
@ -58,17 +49,11 @@ export default class JSONEditor extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
handleChangeMode = (mode: string) => {
|
||||
const prevMode = this.state.mode
|
||||
|
||||
this.setState({ mode })
|
||||
handleChangeMode = (mode) => {
|
||||
console.log('changeMode', mode, this.props.onChangeMode)
|
||||
|
||||
if (this.props.onChangeMode) {
|
||||
this.props.onChangeMode(mode, prevMode)
|
||||
this.props.onChangeMode(mode, this.props.mode)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JSONEditor.propTypes = {
|
||||
mode: PropTypes.string
|
||||
}
|
|
@ -1,5 +1,3 @@
|
|||
// @flow weak
|
||||
|
||||
import { createElement as h, PureComponent } from 'react'
|
||||
import initial from 'lodash/initial'
|
||||
|
||||
|
@ -10,8 +8,6 @@ import { getInnerText, insideRect, findParentWithAttribute } from '../utils/domU
|
|||
import { stringConvert, valueType, isUrl } from '../utils/typeUtils'
|
||||
import { compileJSONPointer, META, SELECTED, SELECTED_END, SELECTED_AFTER, SELECTED_BEFORE } from '../eson'
|
||||
|
||||
import type { ESON, SearchResultStatus, Path } from '../types'
|
||||
|
||||
// TODO: rename SELECTED, SELECTED_END, etc to AREA_*? It's used for both selection and hovering
|
||||
const SELECTED_CLASS_NAMES = {
|
||||
[SELECTED]: ' jsoneditor-selected',
|
||||
|
@ -254,7 +250,15 @@ export default class JSONNode extends PureComponent {
|
|||
}
|
||||
|
||||
// TODO: simplify the method renderProperty
|
||||
renderProperty (prop?: String, index?: number, eson: ESON, options: {escapeUnicode: boolean, isPropertyEditable: (Path) => boolean}) {
|
||||
|
||||
/**
|
||||
* Render a property field of a JSONNode
|
||||
* @param {string} [prop]
|
||||
* @param {string} [index]
|
||||
* @param {ESON} eson
|
||||
* @param {{escapeUnicode: boolean, isPropertyEditable: function(Path) : boolean}} options
|
||||
*/
|
||||
renderProperty (prop, index, eson, options) {
|
||||
const isIndex = typeof index === 'number'
|
||||
const isProp = typeof prop === 'string'
|
||||
|
||||
|
@ -281,6 +285,7 @@ export default class JSONNode extends PureComponent {
|
|||
key: 'property',
|
||||
className: 'jsoneditor-property' + emptyClassName + searchClassName,
|
||||
contentEditable: 'true',
|
||||
suppressContentEditableWarning: true,
|
||||
spellCheck: 'false',
|
||||
onBlur: this.handleChangeProperty
|
||||
}, escapedPropName)
|
||||
|
@ -311,6 +316,7 @@ export default class JSONNode extends PureComponent {
|
|||
className: JSONNode.getValueClass(type, itsAnUrl, isEmpty) +
|
||||
JSONNode.getSearchResultClass(searchResult),
|
||||
contentEditable: 'true',
|
||||
suppressContentEditableWarning: true,
|
||||
spellCheck: 'false',
|
||||
onBlur: this.handleChangeValue,
|
||||
onInput: this.updateValueStyling,
|
||||
|
@ -420,8 +426,9 @@ export default class JSONNode extends PureComponent {
|
|||
|
||||
/**
|
||||
* Get the css style given a search result type
|
||||
* @param {SearchResultStatus} [searchResultStatus]
|
||||
*/
|
||||
static getSearchResultClass (searchResultStatus?: SearchResultStatus) {
|
||||
static getSearchResultClass (searchResultStatus) {
|
||||
if (searchResultStatus === 'active') {
|
||||
return ' jsoneditor-highlight-active'
|
||||
}
|
|
@ -1,9 +1,5 @@
|
|||
// @flow
|
||||
|
||||
import JSONNode from './JSONNode'
|
||||
|
||||
import type { ESON, Path } from '../types'
|
||||
|
||||
/**
|
||||
* JSONNodeForm
|
||||
*
|
||||
|
@ -21,11 +17,17 @@ export default class JSONNodeForm extends JSONNode {
|
|||
return null
|
||||
}
|
||||
|
||||
// render a readonly property
|
||||
renderProperty (prop?: String, index?: number, eson: ESON, options: {escapeUnicode: boolean, isPropertyEditable: (Path) => boolean}) {
|
||||
/**
|
||||
* Render a property field of a JSONNode
|
||||
* @param {string} [prop]
|
||||
* @param {string} [index]
|
||||
* @param {ESON} eson
|
||||
* @param {{escapeUnicode: boolean, isPropertyEditable: function(Path) : boolean}} options
|
||||
*/
|
||||
renderProperty (prop, index, eson, options) {
|
||||
const formOptions = Object.assign({}, options, { isPropertyEditable })
|
||||
|
||||
return JSONNode.prototype.renderProperty.call(this, prop, index, data, formOptions)
|
||||
return JSONNode.prototype.renderProperty.call(this, prop, index, eson, formOptions)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
// @flow weak
|
||||
|
||||
import { createElement as h, Component } from 'react'
|
||||
import Ajv from 'ajv'
|
||||
import { parseJSON } from '../utils/jsonUtils'
|
||||
|
@ -45,22 +43,17 @@ const AJV_OPTIONS = {
|
|||
*
|
||||
*/
|
||||
export default class TextMode extends Component {
|
||||
state: Object
|
||||
|
||||
state = {
|
||||
text: '{}',
|
||||
compiledSchema: null
|
||||
}
|
||||
|
||||
keyDownActions = {
|
||||
'format': (event) => this.handleCompact(),
|
||||
'compact': (event) => this.handleFormat()
|
||||
}
|
||||
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
text: '{}',
|
||||
compiledSchema: null
|
||||
}
|
||||
}
|
||||
|
||||
componentWillMount () {
|
||||
this.applyProps(this.props, {})
|
||||
}
|
||||
|
@ -222,7 +215,7 @@ export default class TextMode extends Component {
|
|||
*/
|
||||
setSchema (schema) {
|
||||
if (schema) {
|
||||
const ajv = this.props.ajv || Ajv && Ajv(AJV_OPTIONS)
|
||||
const ajv = this.props.ajv || (Ajv && Ajv(AJV_OPTIONS))
|
||||
|
||||
if (!ajv) {
|
||||
throw new Error('Cannot validate JSON: ajv not available. ' +
|
||||
|
@ -242,9 +235,11 @@ export default class TextMode extends Component {
|
|||
|
||||
/**
|
||||
* Get the configured indentation. When not configured, returns the default value 2
|
||||
* @param {{indentation?: number}} props
|
||||
* @return {number}
|
||||
*/
|
||||
static getIndentation (props?: {indentation?: number}) : number {
|
||||
return props && props.indentation || 2
|
||||
static getIndentation (props) {
|
||||
return (props && props.indentation) || 2
|
||||
}
|
||||
|
||||
static format (text, indentation) {
|
||||
|
@ -308,8 +303,9 @@ export default class TextMode extends Component {
|
|||
|
||||
/**
|
||||
* Apply new text to the state, and emit an onChangeText event if there is a change
|
||||
* @param {string} text
|
||||
*/
|
||||
handleChangeText = (text: string) => {
|
||||
handleChangeText = (text) => {
|
||||
if (this.props.onChangeText && text !== this.state.text) {
|
||||
const appliedText = this.setText(text)
|
||||
this.props.onChangeText(appliedText)
|
||||
|
@ -364,8 +360,10 @@ export default class TextMode extends Component {
|
|||
|
||||
/**
|
||||
* Set a string containing a JSON document
|
||||
* @param {string} text
|
||||
* @return {string}
|
||||
*/
|
||||
setText (text: string) : string {
|
||||
setText (text) {
|
||||
const normalizedText = this.props.escapeUnicode
|
||||
? escapeUnicodeChars(text)
|
||||
: text
|
|
@ -1,5 +1,3 @@
|
|||
// @flow weak
|
||||
|
||||
import { createElement as h, Component } from 'react'
|
||||
import isEqual from 'lodash/isEqual'
|
||||
import reverse from 'lodash/reverse'
|
||||
|
@ -8,7 +6,7 @@ import Hammer from 'react-hammerjs'
|
|||
import jump from '../assets/jump.js/src/jump'
|
||||
import Ajv from 'ajv'
|
||||
|
||||
import { getIn, setIn, updateIn } from '../utils/immutabilityHelpers'
|
||||
import { getIn, updateIn } from '../utils/immutabilityHelpers'
|
||||
import { parseJSON } from '../utils/jsonUtils'
|
||||
import { enrichSchemaError } from '../utils/schemaUtils'
|
||||
import {
|
||||
|
@ -36,11 +34,6 @@ import {
|
|||
import { createFindKeyBinding } from '../utils/keyBindings'
|
||||
import { KEY_BINDINGS } from '../constants'
|
||||
|
||||
import type {
|
||||
ESON, ESONPatch, Selection, ESONPointer,
|
||||
Path
|
||||
} from '../types'
|
||||
|
||||
const AJV_OPTIONS = {
|
||||
allErrors: true,
|
||||
verbose: true,
|
||||
|
@ -52,19 +45,21 @@ const SEARCH_DEBOUNCE = 300 // milliseconds
|
|||
const SCROLL_DURATION = 400 // milliseconds
|
||||
|
||||
export default class TreeMode extends Component {
|
||||
id: number
|
||||
state: Object
|
||||
id = Math.round(Math.random() * 1e5) // TODO: create a uuid here?
|
||||
|
||||
// TODO: define propTypes
|
||||
|
||||
keyDownActions = null
|
||||
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
const json = this.props.json || {}
|
||||
const expandCallback = this.props.expand || TreeMode.expandRoot
|
||||
const eson = expand(jsonToEson(json), expandCallback)
|
||||
// const json = this.props.json || {}
|
||||
// const expandCallback = this.props.expand || TreeMode.expandRoot
|
||||
// const eson = expand(jsonToEson(json), expandCallback)
|
||||
|
||||
this.id = Math.round(Math.random() * 1e5) // TODO: create a uuid here?
|
||||
const json = {}
|
||||
const eson = jsonToEson(json)
|
||||
|
||||
this.keyDownActions = {
|
||||
'up': this.moveUp,
|
||||
|
@ -88,9 +83,10 @@ export default class TreeMode extends Component {
|
|||
json,
|
||||
eson,
|
||||
|
||||
history: [eson],
|
||||
history: [],
|
||||
historyIndex: 0,
|
||||
|
||||
// TODO: use an event emitter instead? (like with vue.js)
|
||||
events: {
|
||||
onChangeProperty: this.handleChangeProperty,
|
||||
onChangeValue: this.handleChangeValue,
|
||||
|
@ -157,11 +153,17 @@ export default class TreeMode extends Component {
|
|||
}
|
||||
|
||||
// Apply json
|
||||
if (nextProps.json !== currentProps.json) {
|
||||
if (nextProps.json !== this.state.json) {
|
||||
// FIXME: merge meta data from existing eson
|
||||
// FIXME: keep state as is
|
||||
|
||||
const expandCallback = this.props.expand || TreeMode.expandRoot
|
||||
const json = nextProps.json
|
||||
const eson = expand(jsonToEson(json), expandCallback)
|
||||
|
||||
this.setState({
|
||||
json: nextProps.json,
|
||||
eson: jsonToEson(nextProps.json) // FIXME: how to handle expand?
|
||||
json,
|
||||
eson
|
||||
})
|
||||
// TODO: cleanup
|
||||
// this.patch([{
|
||||
|
@ -541,11 +543,20 @@ export default class TreeMode extends Component {
|
|||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle sorting a path
|
||||
* @param {Path} path
|
||||
* @param {string | null} [order]
|
||||
*/
|
||||
handleSort = (path, order = null) => {
|
||||
this.handlePatch(sort(this.state.eson, path, order))
|
||||
}
|
||||
|
||||
handleSelect = (selection: Selection) => {
|
||||
/**
|
||||
* Set selection
|
||||
* @param {Selection} selection
|
||||
*/
|
||||
handleSelect = (selection) => {
|
||||
this.setState({ selection })
|
||||
}
|
||||
|
||||
|
@ -710,7 +721,12 @@ export default class TreeMode extends Component {
|
|||
}
|
||||
}
|
||||
|
||||
findDataPathFromElement (element: Element) : Path | null {
|
||||
/**
|
||||
* Find JSON path from an HTML element
|
||||
* @param {Element} element
|
||||
* @return {Path | null}
|
||||
*/
|
||||
findDataPathFromElement (element) {
|
||||
const base = findBaseNode(element)
|
||||
const attr = base && base.getAttribute && base.getAttribute('data-path')
|
||||
|
||||
|
@ -718,14 +734,25 @@ export default class TreeMode extends Component {
|
|||
return attr ? parseJSONPointer(attr.replace(/\/-$/, '')) : null
|
||||
}
|
||||
|
||||
findESONPointerFromElement (element: Element) : ESONPointer {
|
||||
/**
|
||||
* Find ESON pointer from an HTML element
|
||||
* @param {Element} element
|
||||
* @return {ESONPointer | null}
|
||||
*/
|
||||
findESONPointerFromElement (element) {
|
||||
const path = this.findDataPathFromElement(element)
|
||||
const area = element && element.getAttribute && element.getAttribute('data-area') || null
|
||||
const area = (element && element.getAttribute && element.getAttribute('data-area')) || null
|
||||
|
||||
return path ? { path, area } : null
|
||||
}
|
||||
|
||||
selectionFromESONPointer (pointer: ESONPointer) : Selection {
|
||||
/**
|
||||
* Get selection from an ESON pointer
|
||||
* @param {ESONPointer} pointer
|
||||
* @return {Selection}
|
||||
*/
|
||||
selectionFromESONPointer (pointer) {
|
||||
// FIXME: does pointer have .area === 'after' ? if so adjust type defs
|
||||
if (pointer.area === 'after') {
|
||||
return {after: pointer.path}
|
||||
}
|
||||
|
@ -755,8 +782,11 @@ export default class TreeMode extends Component {
|
|||
/**
|
||||
* Emit an onChange event when there is a listener for it.
|
||||
* @private
|
||||
* @param {ESONPatch} patch
|
||||
* @param {ESONPatch} revert
|
||||
* @param {ESON} eson
|
||||
*/
|
||||
emitOnChange (patch: ESONPatch, revert: ESONPatch, eson: ESON) {
|
||||
emitOnChange (patch, revert, eson) {
|
||||
if (this.props.onPatch) {
|
||||
this.props.onPatch(patch, revert)
|
||||
}
|
||||
|
@ -939,7 +969,7 @@ export default class TreeMode extends Component {
|
|||
// TODO: deduplicate this function, it's also implemented in TextMode
|
||||
setSchema (schema) {
|
||||
if (schema) {
|
||||
const ajv = this.props.ajv || Ajv && Ajv(AJV_OPTIONS)
|
||||
const ajv = (this.props.ajv) || (Ajv && Ajv(AJV_OPTIONS))
|
||||
|
||||
if (!ajv) {
|
||||
throw new Error('Cannot validate JSON: ajv not available. ' +
|
Before Width: | Height: | Size: 35 KiB After Width: | Height: | Size: 35 KiB |
|
@ -0,0 +1,670 @@
|
|||
/* schema error popover */
|
||||
.jsoneditor-schema-error {
|
||||
position: relative;
|
||||
/*@-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; }*/
|
||||
/*}*/ }
|
||||
.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: -10px;
|
||||
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: -10px;
|
||||
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 {
|
||||
.jsoneditor-schema-error from {
|
||||
opacity: 0; }
|
||||
.jsoneditor-schema-error to {
|
||||
opacity: 1; } }
|
||||
|
||||
.jsoneditor {
|
||||
border: 1px solid #3883fa;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
line-height: normal; }
|
||||
|
||||
.jsoneditor-menu {
|
||||
width: 100%;
|
||||
box-sizing: border-box;
|
||||
color: white;
|
||||
background-color: #3883fa;
|
||||
flex: 0 0 auto; }
|
||||
.jsoneditor-menu 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; }
|
||||
.jsoneditor-menu button:hover {
|
||||
background-color: rgba(255, 255, 255, 0.2);
|
||||
border: 1px solid rgba(255, 255, 255, 0.4); }
|
||||
.jsoneditor-menu button:focus,
|
||||
.jsoneditor-menu button:active {
|
||||
background-color: rgba(255, 255, 255, 0.3); }
|
||||
.jsoneditor-menu button:disabled {
|
||||
opacity: 0.5; }
|
||||
.jsoneditor-menu .jsoneditor-vertical-menu-separator {
|
||||
width: 8px;
|
||||
display: inline-block; }
|
||||
.jsoneditor-menu button.jsoneditor-expand-all {
|
||||
background-position: 0 -120px; }
|
||||
.jsoneditor-menu button.jsoneditor-collapse-all {
|
||||
background-position: 0 -96px; }
|
||||
.jsoneditor-menu button.jsoneditor-undo {
|
||||
background-position: -24px -96px; }
|
||||
.jsoneditor-menu button.jsoneditor-undo:disabled {
|
||||
background-position: -24px -120px; }
|
||||
.jsoneditor-menu button.jsoneditor-redo {
|
||||
background-position: -48px -96px; }
|
||||
.jsoneditor-menu button.jsoneditor-redo:disabled {
|
||||
background-position: -48px -120px; }
|
||||
.jsoneditor-menu button.jsoneditor-compact {
|
||||
background-position: -72px -96px; }
|
||||
.jsoneditor-menu button.jsoneditor-format {
|
||||
background-position: -72px -120px; }
|
||||
|
||||
.jsoneditor-contents {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 150px;
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
flex: 1 1 auto; }
|
||||
|
||||
.jsoneditor-tree-contents {
|
||||
padding: 2px 0;
|
||||
overflow: auto; }
|
||||
|
||||
.jsoneditor-node {
|
||||
position: relative;
|
||||
font: 14px Arial;
|
||||
display: inline-flex;
|
||||
flex-direction: row; }
|
||||
|
||||
.jsoneditor-node > div {
|
||||
flex: 0 0 auto; }
|
||||
|
||||
div.jsoneditor-list {
|
||||
list-style-type: none;
|
||||
padding-left: 20px;
|
||||
margin: 0;
|
||||
font-size: 0; }
|
||||
|
||||
/* no left padding for the root div element */
|
||||
.jsoneditor-contents > div.jsoneditor-list {
|
||||
padding-left: 2px;
|
||||
padding-bottom: 24px; }
|
||||
|
||||
.jsoneditor-property,
|
||||
.jsoneditor-value,
|
||||
.jsoneditor-readonly,
|
||||
.jsoneditor-separator {
|
||||
line-height: 20px;
|
||||
font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif;
|
||||
font-size: 10pt; }
|
||||
|
||||
.jsoneditor-property,
|
||||
.jsoneditor-value,
|
||||
.jsoneditor-readonly {
|
||||
min-width: 24px;
|
||||
word-break: normal;
|
||||
padding: 0 5px;
|
||||
color: #1A1A1A;
|
||||
outline: none; }
|
||||
|
||||
.jsoneditor-button-container {
|
||||
font-size: 0; }
|
||||
|
||||
.jsoneditor-property,
|
||||
.jsoneditor-value {
|
||||
border-radius: 1px;
|
||||
flex: 1 1 auto !important; }
|
||||
.jsoneditor-property p,
|
||||
.jsoneditor-value p {
|
||||
margin: 0;
|
||||
padding: 0; }
|
||||
|
||||
.jsoneditor-property:focus,
|
||||
.jsoneditor-value:focus {
|
||||
box-shadow: 0 0 3px 1px #008fd5;
|
||||
z-index: 1; }
|
||||
|
||||
.jsoneditor-property:hover,
|
||||
.jsoneditor-value:hover {
|
||||
background-color: rgba(0, 0, 0, 0.05); }
|
||||
|
||||
.jsoneditor-mode-form .jsoneditor-property:hover {
|
||||
background-color: inherit; }
|
||||
|
||||
.jsoneditor-mode-view .jsoneditor-property:hover,
|
||||
.jsoneditor-mode-view .jsoneditor-value:hover {
|
||||
background-color: inherit; }
|
||||
|
||||
.jsoneditor-separator {
|
||||
color: #808080; }
|
||||
|
||||
.jsoneditor-readonly {
|
||||
color: #808080; }
|
||||
|
||||
.jsoneditor-readonly:focus,
|
||||
.jsoneditor-readonly:hover {
|
||||
border-color: transparent;
|
||||
background-color: inherit; }
|
||||
|
||||
.jsoneditor-value.jsoneditor-string {
|
||||
color: #008000; }
|
||||
|
||||
.jsoneditor-value.jsoneditor-object,
|
||||
.jsoneditor-value.jsoneditor-array {
|
||||
min-width: 16px;
|
||||
color: #808080; }
|
||||
|
||||
.jsoneditor-value.jsoneditor-number {
|
||||
color: #ee422e; }
|
||||
|
||||
.jsoneditor-value.jsoneditor-boolean {
|
||||
color: #ff8c00; }
|
||||
|
||||
.jsoneditor-value.jsoneditor-null {
|
||||
color: #004ED0; }
|
||||
|
||||
.jsoneditor-value.jsoneditor-invalid {
|
||||
color: #000000; }
|
||||
|
||||
div.jsoneditor-value.jsoneditor-url {
|
||||
color: green;
|
||||
text-decoration: underline; }
|
||||
|
||||
div.jsoneditor-empty {
|
||||
border: 1px dotted lightgray;
|
||||
border-radius: 2px;
|
||||
padding: 0 5px;
|
||||
line-height: 17px; }
|
||||
|
||||
div.jsoneditor-empty::after,
|
||||
div.jsoneditor-empty::after {
|
||||
pointer-events: none;
|
||||
color: lightgray;
|
||||
font-size: 8pt; }
|
||||
|
||||
div.jsoneditor-property.jsoneditor-empty::after {
|
||||
content: 'prop'; }
|
||||
|
||||
div.jsoneditor-value.jsoneditor-empty::after {
|
||||
content: 'value'; }
|
||||
|
||||
.jsoneditor-highlight {
|
||||
background-color: yellow; }
|
||||
|
||||
.jsoneditor-highlight:hover {
|
||||
background-color: #f0f000; }
|
||||
|
||||
.jsoneditor-highlight-active {
|
||||
background-color: #ffd700; }
|
||||
|
||||
.jsoneditor-highlight-active:hover {
|
||||
background-color: #f3cd00; }
|
||||
|
||||
.jsoneditor-button-placeholder {
|
||||
width: 20px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
line-height: 20px; }
|
||||
|
||||
button.jsoneditor-button {
|
||||
position: relative;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
background: transparent url("img/jsoneditor-icons.svg"); }
|
||||
|
||||
button.jsoneditor-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; }
|
||||
|
||||
/* FIXME: change icons from size 24x24 to 20x20 */
|
||||
button.jsoneditor-button.jsoneditor-collapsed {
|
||||
background-position: -2px -50px; }
|
||||
|
||||
button.jsoneditor-button.jsoneditor-expanded {
|
||||
background-position: -2px -74px; }
|
||||
|
||||
button.jsoneditor-button.jsoneditor-drag {
|
||||
background-position: -74px -74px;
|
||||
cursor: move; }
|
||||
|
||||
button.jsoneditor-button.jsoneditor-actionmenu {
|
||||
background-position: -50px -74px; }
|
||||
|
||||
button.jsoneditor-button.jsoneditor-actionmenu:hover,
|
||||
button.jsoneditor-button.jsoneditor-actionmenu:focus,
|
||||
button.jsoneditor-button.jsoneditor-actionmenu.jsoneditor-visible {
|
||||
background-position: -50px -50px; }
|
||||
|
||||
/******************************* Action Menu **********************************/
|
||||
div.jsoneditor-actionmenu {
|
||||
position: absolute;
|
||||
box-sizing: border-box;
|
||||
z-index: 99999;
|
||||
top: 20px;
|
||||
left: 18px;
|
||||
/* 20px - 2px where 2px half the difference between 24x24 icons of the menu and the 20x20 icons of the editor */
|
||||
background: white;
|
||||
border: 1px solid #d3d3d3;
|
||||
box-shadow: 2px 2px 12px rgba(128, 128, 128, 0.3); }
|
||||
|
||||
div.jsoneditor-actionmenu.jsoneditor-actionmenu-top {
|
||||
top: auto;
|
||||
bottom: 20px; }
|
||||
|
||||
div.jsoneditor-modemenu.jsoneditor-modemenu {
|
||||
top: 26px;
|
||||
left: 0; }
|
||||
|
||||
div.jsoneditor-menu-item {
|
||||
line-height: 0;
|
||||
font-size: 0; }
|
||||
|
||||
button.jsoneditor-menu-button {
|
||||
width: 136px;
|
||||
height: 24px;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
line-height: 24px;
|
||||
background: transparent;
|
||||
border: transparent;
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
color: #4d4d4d;
|
||||
font-size: 10pt;
|
||||
font-family: arial, sans-serif;
|
||||
text-align: left; }
|
||||
|
||||
button.jsoneditor-menu-button:hover,
|
||||
button.jsoneditor-menu-button:focus {
|
||||
color: #1A1A1A;
|
||||
background-color: #f5f5f5;
|
||||
outline: none; }
|
||||
|
||||
button.jsoneditor-menu-button.jsoneditor-selected {
|
||||
color: white;
|
||||
background-color: #ee422e; }
|
||||
|
||||
button.jsoneditor-menu-default {
|
||||
width: 104px;
|
||||
/* 136px - 32px */ }
|
||||
|
||||
button.jsoneditor-menu-expand {
|
||||
width: 32px;
|
||||
float: right;
|
||||
border-left: 1px solid #e5e5e5; }
|
||||
|
||||
span.jsoneditor-icon {
|
||||
float: left;
|
||||
width: 24px;
|
||||
height: 24px;
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
background-image: url("img/jsoneditor-icons.svg"); }
|
||||
|
||||
span.jsoneditor-icon.jsoneditor-icon-expand {
|
||||
float: right;
|
||||
width: 24px;
|
||||
margin: 0 4px;
|
||||
background-position: 0 -72px !important;
|
||||
opacity: 0.4; }
|
||||
|
||||
div.jsoneditor-menu-item button.jsoneditor-menu-button:hover span.jsoneditor-icon-expand,
|
||||
div.jsoneditor-menu-item button:focus span.jsoneditor-icon-expand {
|
||||
opacity: 1; }
|
||||
|
||||
span.jsoneditor-text {
|
||||
display: inline-block;
|
||||
line-height: 24px; }
|
||||
|
||||
div.jsoneditor-menu-separator {
|
||||
height: 0;
|
||||
border-top: 1px solid #e5e5e5;
|
||||
padding-top: 5px;
|
||||
margin-top: 5px; }
|
||||
|
||||
div.jsoneditor-menu-panel-right {
|
||||
float: right;
|
||||
max-width: 100%; }
|
||||
|
||||
button.jsoneditor-remove span.jsoneditor-icon {
|
||||
background-position: -24px -24px; }
|
||||
|
||||
button.jsoneditor-remove:hover span.jsoneditor-icon,
|
||||
button.jsoneditor-remove:focus span.jsoneditor-icon {
|
||||
background-position: -24px 0; }
|
||||
|
||||
button.jsoneditor-insert span.jsoneditor-icon {
|
||||
background-position: 0 -24px; }
|
||||
|
||||
button.jsoneditor-insert:hover span.jsoneditor-icon,
|
||||
button.jsoneditor-insert:focus span.jsoneditor-icon {
|
||||
background-position: 0 0; }
|
||||
|
||||
button.jsoneditor-duplicate span.jsoneditor-icon {
|
||||
background-position: -48px -24px; }
|
||||
|
||||
button.jsoneditor-duplicate:hover span.jsoneditor-icon,
|
||||
button.jsoneditor-duplicate:focus span.jsoneditor-icon {
|
||||
background-position: -48px 0; }
|
||||
|
||||
button.jsoneditor-sort-asc span.jsoneditor-icon {
|
||||
background-position: -168px -24px; }
|
||||
|
||||
button.jsoneditor-sort-asc:hover span.jsoneditor-icon,
|
||||
button.jsoneditor-sort-asc:focus span.jsoneditor-icon {
|
||||
background-position: -168px 0; }
|
||||
|
||||
button.jsoneditor-sort-desc span.jsoneditor-icon {
|
||||
background-position: -192px -24px; }
|
||||
|
||||
button.jsoneditor-sort-desc:hover span.jsoneditor-icon,
|
||||
button.jsoneditor-sort-desc:focus span.jsoneditor-icon {
|
||||
background-position: -192px 0; }
|
||||
|
||||
div.jsoneditor-submenu {
|
||||
visibility: hidden;
|
||||
max-height: 0;
|
||||
overflow: hidden;
|
||||
transition: max-height 0.3s ease-out;
|
||||
box-shadow: inset 0 10px 10px -10px rgba(128, 128, 128, 0.5), inset 0 -10px 10px -10px rgba(128, 128, 128, 0.5); }
|
||||
|
||||
div.jsoneditor-submenu.jsoneditor-expanded {
|
||||
visibility: visible;
|
||||
max-height: 104px;
|
||||
/* 4 * 24px + 2 * 5px */
|
||||
/* FIXME: shouldn't rely on max-height equal to 4 items, should be flexible */ }
|
||||
|
||||
div.jsoneditor-submenu.jsoneditor-collapsing {
|
||||
visibility: visible;
|
||||
max-height: 0; }
|
||||
|
||||
div.jsoneditor-submenu button {
|
||||
padding-left: 24px; }
|
||||
|
||||
div.jsoneditor-submenu div.jsoneditor-menu-item:first-child {
|
||||
margin-top: 5px; }
|
||||
|
||||
div.jsoneditor-submenu div.jsoneditor-menu-item:last-child {
|
||||
margin-bottom: 5px; }
|
||||
|
||||
button.jsoneditor-type-string span.jsoneditor-icon {
|
||||
background-position: -144px -24px; }
|
||||
|
||||
button.jsoneditor-type-string:hover span.jsoneditor-icon,
|
||||
button.jsoneditor-type-string:focus span.jsoneditor-icon,
|
||||
button.jsoneditor-type-string.jsoneditor-selected span.jsoneditor-icon {
|
||||
background-position: -144px 0; }
|
||||
|
||||
button.jsoneditor-type-value span.jsoneditor-icon {
|
||||
background-position: -120px -24px; }
|
||||
|
||||
button.jsoneditor-type-value:hover span.jsoneditor-icon,
|
||||
button.jsoneditor-type-value:focus span.jsoneditor-icon,
|
||||
button.jsoneditor-type-value.jsoneditor-selected span.jsoneditor-icon {
|
||||
background-position: -120px 0; }
|
||||
|
||||
button.jsoneditor-type-Object span.jsoneditor-icon {
|
||||
background-position: -72px -24px; }
|
||||
|
||||
button.jsoneditor-type-Object:hover span.jsoneditor-icon,
|
||||
button.jsoneditor-type-Object:focus span.jsoneditor-icon,
|
||||
button.jsoneditor-type-Object.jsoneditor-selected span.jsoneditor-icon {
|
||||
background-position: -72px 0; }
|
||||
|
||||
button.jsoneditor-type-Array span.jsoneditor-icon {
|
||||
background-position: -96px -24px; }
|
||||
|
||||
button.jsoneditor-type-Array:hover span.jsoneditor-icon,
|
||||
button.jsoneditor-type-Array:focus span.jsoneditor-icon,
|
||||
button.jsoneditor-type-Array.jsoneditor-selected span.jsoneditor-icon {
|
||||
background-position: -96px 0; }
|
||||
|
||||
/******************************* Floatting Menu **********************************/
|
||||
div.jsoneditor-node-container {
|
||||
position: relative;
|
||||
transition: background-color 100ms ease-in; }
|
||||
div.jsoneditor-node-container.jsoneditor-selected {
|
||||
background-color: #ffed99; }
|
||||
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-hover {
|
||||
background-color: #ffdb80; }
|
||||
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-hover.jsoneditor-hover-insert-area {
|
||||
background-color: #ffed99; }
|
||||
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-hover.jsoneditor-hover-insert-area > div.jsoneditor-insert-area {
|
||||
border: 1px dashed gray;
|
||||
background-color: #f2f2f2; }
|
||||
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-hover.jsoneditor-hover-insert-area.jsoneditor-selected-insert-area > div.jsoneditor-insert-area {
|
||||
border: 1px dashed #f4af41;
|
||||
background-color: #ffdb80; }
|
||||
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-selected-insert-area {
|
||||
background-color: inherit; }
|
||||
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-selected-insert-area.jsoneditor-hover {
|
||||
background-color: #f2f2f2; }
|
||||
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-selected-insert-area.jsoneditor-hover.jsoneditor-hover-insert-area {
|
||||
background-color: inherit; }
|
||||
div.jsoneditor-node-container.jsoneditor-selected.jsoneditor-selected-insert-area > div.jsoneditor-insert-area {
|
||||
border: 1px dashed #f4af41;
|
||||
background: #ffed99; }
|
||||
div.jsoneditor-node-container.jsoneditor-selected div.jsoneditor-hover {
|
||||
background-color: #ffdb80; }
|
||||
div.jsoneditor-node-container.jsoneditor-selected div.jsoneditor-hover.jsoneditor-hover-insert-area {
|
||||
background-color: inherit; }
|
||||
div.jsoneditor-node-container.jsoneditor-selected div.jsoneditor-hover.jsoneditor-hover-insert-area > div.jsoneditor-insert-area {
|
||||
border: 1px dashed #f4af41;
|
||||
background: #ffdb80; }
|
||||
div.jsoneditor-node-container.jsoneditor-hover {
|
||||
background-color: #f2f2f2; }
|
||||
div.jsoneditor-node-container.jsoneditor-hover.jsoneditor-hover-insert-area {
|
||||
background-color: inherit; }
|
||||
div.jsoneditor-node-container.jsoneditor-hover.jsoneditor-hover-insert-area > div.jsoneditor-insert-area {
|
||||
border: 1px dashed gray;
|
||||
background-color: #f2f2f2; }
|
||||
div.jsoneditor-node-container div.jsoneditor-insert-area {
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 8px;
|
||||
left: 0;
|
||||
top: -4px;
|
||||
border: 1px transparent;
|
||||
box-sizing: border-box;
|
||||
z-index: 1; }
|
||||
div.jsoneditor-node-container div.jsoneditor-floating-menu {
|
||||
position: absolute;
|
||||
bottom: 100%;
|
||||
right: 0;
|
||||
z-index: 999;
|
||||
margin: 10px;
|
||||
white-space: nowrap;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, 0.24); }
|
||||
div.jsoneditor-node-container div.jsoneditor-floating-menu:after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 100%;
|
||||
left: 35px;
|
||||
margin-left: -10px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: solid 10px #4d4d4d;
|
||||
border-left: solid 10px transparent;
|
||||
border-right: solid 10px transparent; }
|
||||
div.jsoneditor-node-container div.jsoneditor-floating-menu button.jsoneditor-floating-menu-item {
|
||||
color: #fff;
|
||||
background: #4d4d4d;
|
||||
border: none;
|
||||
border-right: 1px solid #676767;
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
outline: none; }
|
||||
div.jsoneditor-node-container div.jsoneditor-floating-menu button.jsoneditor-floating-menu-item:focus, div.jsoneditor-node-container div.jsoneditor-floating-menu button.jsoneditor-floating-menu-item:hover {
|
||||
background: #676767; }
|
||||
div.jsoneditor-node-container div.jsoneditor-floating-menu button.jsoneditor-floating-menu-item:first-child {
|
||||
border-top-left-radius: 5px;
|
||||
border-bottom-left-radius: 5px; }
|
||||
div.jsoneditor-node-container div.jsoneditor-floating-menu button.jsoneditor-floating-menu-item:last-child {
|
||||
border-top-right-radius: 5px;
|
||||
border-bottom-right-radius: 5px;
|
||||
border-right: none; }
|
||||
|
||||
/******************************* **********************************/
|
||||
div.jsoneditor-modes {
|
||||
position: relative;
|
||||
display: inline-block;
|
||||
vertical-align: top; }
|
||||
div.jsoneditor-modes button {
|
||||
background: none;
|
||||
width: auto;
|
||||
padding: 2px 6px; }
|
||||
div.jsoneditor-modes button.jsoneditor-type-modes {
|
||||
width: 120px;
|
||||
height: auto;
|
||||
padding: 2px 6px;
|
||||
border-radius: 0;
|
||||
opacity: 1; }
|
||||
div.jsoneditor-modes button.jsoneditor-type-modes:hover {
|
||||
border: none; }
|
||||
|
||||
textarea.jsoneditor-text {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 150px;
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
outline-width: 0;
|
||||
border: none;
|
||||
background-color: #fff;
|
||||
resize: none;
|
||||
font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif;
|
||||
font-size: 10pt;
|
||||
color: #1A1A1A; }
|
||||
|
||||
div.jsoneditor-code {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 150px; }
|
||||
|
||||
/* JSON schema errors displayed at the bottom of the editor in mode text and code */
|
||||
.jsoneditor-errors {
|
||||
width: 100%;
|
||||
background-color: #ffef8b;
|
||||
border-top: 1px solid #ffd700; }
|
||||
.jsoneditor-errors table {
|
||||
border-collapse: collapse;
|
||||
font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif;
|
||||
font-size: 10pt; }
|
||||
.jsoneditor-errors table td {
|
||||
padding: 3px 6px;
|
||||
vertical-align: middle; }
|
||||
.jsoneditor-errors table td code {
|
||||
display: block;
|
||||
white-space: pre-wrap; }
|
||||
|
||||
.jsoneditor-schema-error {
|
||||
outline: none;
|
||||
border: none;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
padding: 0;
|
||||
margin: 0 4px;
|
||||
background: url("img/jsoneditor-icons.svg") -171px -49px; }
|
|
@ -1,19 +1,21 @@
|
|||
@import url('./popover.less');
|
||||
@import './popover.scss';
|
||||
|
||||
@fontFamily: droid sans mono, consolas, monospace, courier new, courier, sans-serif;
|
||||
@fontSize: 10pt;
|
||||
@black: #1A1A1A;
|
||||
@contentsMinHeight: 150px;
|
||||
@theme-color: #3883fa;
|
||||
@floating-menu-background: #4d4d4d;
|
||||
@floating-menu-color: #fff;
|
||||
// @selectedColor: #e5e5e5;
|
||||
@selectedColor: #ffed99;
|
||||
@hoverColor: #f2f2f2;
|
||||
@hoverAndSelectedColor: #ffdb80;
|
||||
$fontFamily: droid sans mono, consolas, monospace, courier new, courier, sans-serif;
|
||||
$fontSize: 10pt;
|
||||
$black: #1A1A1A;
|
||||
$contentsMinHeight: 150px;
|
||||
$theme-color: #3883fa; // TODO: create a central file with the theme colors
|
||||
$floating-menu-background: #4d4d4d;
|
||||
$floating-menu-color: #fff;
|
||||
// $selectedColor: #e5e5e5;
|
||||
$selectedColor: #ffed99;
|
||||
$hoverColor: #f2f2f2;
|
||||
$hoverAndSelectedColor: #ffdb80;
|
||||
|
||||
// TODO: split this scss file into separate files per React component
|
||||
|
||||
.jsoneditor {
|
||||
border: 1px solid @theme-color;
|
||||
border: 1px solid $theme-color;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
|
@ -28,7 +30,7 @@
|
|||
box-sizing: border-box;
|
||||
|
||||
color: white;
|
||||
background-color: @theme-color;
|
||||
background-color: $theme-color;
|
||||
flex: 0 0 auto;
|
||||
|
||||
button {
|
||||
|
@ -94,7 +96,7 @@
|
|||
.jsoneditor-contents {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: @contentsMinHeight;
|
||||
min-height: $contentsMinHeight;
|
||||
|
||||
overflow: hidden;
|
||||
padding: 0;
|
||||
|
@ -139,19 +141,19 @@ div.jsoneditor-list {
|
|||
.jsoneditor-separator {
|
||||
line-height: 20px;
|
||||
|
||||
font-family: @fontFamily;
|
||||
font-size: @fontSize;
|
||||
font-family: $fontFamily;
|
||||
font-size: $fontSize;
|
||||
}
|
||||
|
||||
.jsoneditor-property,
|
||||
.jsoneditor-value,
|
||||
.jsoneditor-readonly {
|
||||
min-width: 24px;
|
||||
word-break: break-word;
|
||||
word-break: normal;
|
||||
|
||||
padding: 0 5px;
|
||||
|
||||
color: @black;
|
||||
color: $black;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
|
@ -387,7 +389,7 @@ button.jsoneditor-menu-button {
|
|||
|
||||
button.jsoneditor-menu-button:hover,
|
||||
button.jsoneditor-menu-button:focus {
|
||||
color: @black;
|
||||
color: $black;
|
||||
background-color: #f5f5f5;
|
||||
outline: none;
|
||||
}
|
||||
|
@ -568,23 +570,23 @@ div.jsoneditor-node-container {
|
|||
// TODO: can the hover/select css be simplified?
|
||||
|
||||
&.jsoneditor-selected {
|
||||
background-color: @selectedColor;
|
||||
background-color: $selectedColor;
|
||||
|
||||
&.jsoneditor-hover {
|
||||
background-color: @hoverAndSelectedColor;
|
||||
background-color: $hoverAndSelectedColor;
|
||||
|
||||
&.jsoneditor-hover-insert-area {
|
||||
background-color: @selectedColor;
|
||||
background-color: $selectedColor;
|
||||
|
||||
> div.jsoneditor-insert-area {
|
||||
border: 1px dashed gray;
|
||||
background-color: @hoverColor;
|
||||
background-color: $hoverColor;
|
||||
}
|
||||
|
||||
&.jsoneditor-selected-insert-area {
|
||||
> div.jsoneditor-insert-area {
|
||||
border: 1px dashed #f4af41;
|
||||
background-color: @hoverAndSelectedColor;
|
||||
background-color: $hoverAndSelectedColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -594,7 +596,7 @@ div.jsoneditor-node-container {
|
|||
background-color: inherit;
|
||||
|
||||
&.jsoneditor-hover {
|
||||
background-color: @hoverColor;
|
||||
background-color: $hoverColor;
|
||||
|
||||
&.jsoneditor-hover-insert-area {
|
||||
background-color: inherit;
|
||||
|
@ -603,46 +605,46 @@ div.jsoneditor-node-container {
|
|||
|
||||
> div.jsoneditor-insert-area {
|
||||
border: 1px dashed #f4af41;
|
||||
background: @selectedColor;
|
||||
background: $selectedColor;
|
||||
}
|
||||
}
|
||||
|
||||
// hovering nested elements
|
||||
div.jsoneditor-hover {
|
||||
background-color: @hoverAndSelectedColor;
|
||||
background-color: $hoverAndSelectedColor;
|
||||
|
||||
&.jsoneditor-hover-insert-area {
|
||||
background-color: inherit;
|
||||
|
||||
> div.jsoneditor-insert-area {
|
||||
border: 1px dashed #f4af41;
|
||||
background: @hoverAndSelectedColor;
|
||||
background: $hoverAndSelectedColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
&.jsoneditor-hover {
|
||||
background-color: @hoverColor;
|
||||
background-color: $hoverColor;
|
||||
|
||||
&.jsoneditor-hover-insert-area {
|
||||
background-color: inherit;
|
||||
|
||||
> div.jsoneditor-insert-area {
|
||||
border: 1px dashed gray;
|
||||
background-color: @hoverColor;
|
||||
background-color: $hoverColor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.jsoneditor-insert-area {
|
||||
@height: 8px;
|
||||
$height: 8px;
|
||||
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: @height;
|
||||
height: $height;
|
||||
left: 0;
|
||||
top: -@height/2;
|
||||
top: -$height/2;
|
||||
border: 1px transparent;
|
||||
box-sizing: border-box;
|
||||
z-index: 1; // must be on top of next node, it overlaps a bit
|
||||
|
@ -667,23 +669,23 @@ div.jsoneditor-node-container {
|
|||
margin-left: -10px;
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-top: solid 10px @floating-menu-background;
|
||||
border-top: solid 10px $floating-menu-background;
|
||||
border-left: solid 10px transparent;
|
||||
border-right: solid 10px transparent;
|
||||
}
|
||||
|
||||
button.jsoneditor-floating-menu-item {
|
||||
color: @floating-menu-color;
|
||||
background: @floating-menu-background;
|
||||
color: $floating-menu-color;
|
||||
background: $floating-menu-background;
|
||||
border: none;
|
||||
border-right: 1px solid lighten(@floating-menu-background, 10%);
|
||||
border-right: 1px solid lighten($floating-menu-background, 10%);
|
||||
padding: 10px;
|
||||
cursor: pointer;
|
||||
outline: none;
|
||||
|
||||
&:focus,
|
||||
&:hover {
|
||||
background: lighten(@floating-menu-background, 10%);
|
||||
background: lighten($floating-menu-background, 10%);
|
||||
}
|
||||
|
||||
&:first-child {
|
||||
|
@ -728,7 +730,7 @@ div.jsoneditor-modes {
|
|||
textarea.jsoneditor-text {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: @contentsMinHeight;
|
||||
min-height: $contentsMinHeight;
|
||||
|
||||
margin: 0;
|
||||
box-sizing: border-box;
|
||||
|
@ -737,15 +739,15 @@ textarea.jsoneditor-text {
|
|||
background-color: #fff;
|
||||
resize: none;
|
||||
|
||||
font-family: @fontFamily;
|
||||
font-size: @fontSize;
|
||||
color: @black;
|
||||
font-family: $fontFamily;
|
||||
font-size: $fontSize;
|
||||
color: $black;
|
||||
}
|
||||
|
||||
div.jsoneditor-code {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: @contentsMinHeight;
|
||||
min-height: $contentsMinHeight;
|
||||
}
|
||||
|
||||
/* JSON schema errors displayed at the bottom of the editor in mode text and code */
|
||||
|
@ -758,8 +760,8 @@ div.jsoneditor-code {
|
|||
table {
|
||||
border-collapse: collapse;
|
||||
|
||||
font-family: @fontFamily;
|
||||
font-size: @fontSize;
|
||||
font-family: $fontFamily;
|
||||
font-size: $fontSize;
|
||||
|
||||
td {
|
||||
padding: 3px 6px;
|
|
@ -1,7 +1,4 @@
|
|||
// @flow weak
|
||||
|
||||
import { createElement as h, PureComponent } from 'react'
|
||||
import { keyComboFromEvent } from '../../utils/keyBindings'
|
||||
|
||||
const MENU_CLASS_NAME = 'jsoneditor-floating-menu'
|
||||
const MENU_ITEM_CLASS_NAME = 'jsoneditor-floating-menu-item'
|
|
@ -0,0 +1,57 @@
|
|||
div.jsoneditor-search {
|
||||
font-family: arial, sans-serif;
|
||||
font-size: 10pt; }
|
||||
div.jsoneditor-search div.jsoneditor-results {
|
||||
display: inline-block;
|
||||
margin-right: 5px; }
|
||||
div.jsoneditor-search form.jsoneditor-search-box {
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
max-width: 100%;
|
||||
background-color: white;
|
||||
border: 2px solid #3883fa;
|
||||
box-sizing: border-box; }
|
||||
div.jsoneditor-search form.jsoneditor-search-box::before {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
width: 22px;
|
||||
height: 100%;
|
||||
background: transparent url("../img/jsoneditor-icons.svg") -97px -71px;
|
||||
content: ''; }
|
||||
div.jsoneditor-search form.jsoneditor-search-box input.jsoneditor-search-text {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
border: none;
|
||||
outline: none;
|
||||
width: 120px;
|
||||
max-width: 100%;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
padding: 2px 2px 2px 22px;
|
||||
background: transparent; }
|
||||
div.jsoneditor-search form.jsoneditor-search-box input[type=button] {
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 16px;
|
||||
height: 100%;
|
||||
line-height: 22px;
|
||||
margin: 2px 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: transparent url("../img/jsoneditor-icons.svg");
|
||||
opacity: 0.8;
|
||||
font-family: arial, sans-serif;
|
||||
font-size: 10pt; }
|
||||
div.jsoneditor-search form.jsoneditor-search-box input[type=button]:hover {
|
||||
background-color: transparent; }
|
||||
div.jsoneditor-search form.jsoneditor-search-box input.jsoneditor-search-next {
|
||||
cursor: pointer;
|
||||
background-position: -124px -73px; }
|
||||
div.jsoneditor-search form.jsoneditor-search-box input.jsoneditor-search-next:hover {
|
||||
background-position: -124px -49px; }
|
||||
div.jsoneditor-search form.jsoneditor-search-box input.jsoneditor-search-previous {
|
||||
cursor: pointer;
|
||||
background-position: -148px -73px;
|
||||
margin-right: 2px; }
|
||||
div.jsoneditor-search form.jsoneditor-search-box input.jsoneditor-search-previous:hover {
|
||||
background-position: -148px -49px; }
|
|
@ -1,17 +1,11 @@
|
|||
// @flow weak
|
||||
|
||||
import { createElement as h, Component } from 'react'
|
||||
import PropTypes from 'prop-types'
|
||||
import { keyComboFromEvent } from '../../utils/keyBindings'
|
||||
import { findEditorContainer, setSelection } from '../utils/domSelector'
|
||||
|
||||
import '!style!css!less!./Search.less'
|
||||
import './Search.css'
|
||||
|
||||
export default class Search extends Component {
|
||||
state: {
|
||||
text: string
|
||||
}
|
||||
|
||||
constructor (props) {
|
||||
super (props)
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
@theme-color: #3883fa;
|
||||
$theme-color: #3883fa;
|
||||
|
||||
div.jsoneditor-search {
|
||||
font-family: arial, sans-serif;
|
||||
|
@ -15,17 +15,17 @@ div.jsoneditor-search {
|
|||
max-width: 100%;
|
||||
|
||||
background-color: white;
|
||||
border: 2px solid @theme-color;
|
||||
border: 2px solid $theme-color;
|
||||
box-sizing: border-box;
|
||||
|
||||
@search-icon-width: 22px;
|
||||
$search-icon-width: 22px;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
width: @search-icon-width;
|
||||
width: $search-icon-width;
|
||||
height: 100%;
|
||||
background: transparent url('../../img/jsoneditor-icons.svg') -97px -71px;
|
||||
background: transparent url('../img/jsoneditor-icons.svg') -97px -71px;
|
||||
content: '';
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ div.jsoneditor-search {
|
|||
max-width: 100%;
|
||||
height: 22px;
|
||||
line-height: 22px;
|
||||
padding: 2px 2px 2px @search-icon-width;
|
||||
padding: 2px 2px 2px $search-icon-width;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ div.jsoneditor-search {
|
|||
margin: 2px 0;
|
||||
padding: 0;
|
||||
border: none;
|
||||
background: transparent url('../../img/jsoneditor-icons.svg');
|
||||
background: transparent url('../img/jsoneditor-icons.svg');
|
||||
opacity: 0.8;
|
||||
|
||||
font-family: arial, sans-serif;
|
|
@ -0,0 +1,96 @@
|
|||
/* schema error popover */
|
||||
.jsoneditor-schema-error {
|
||||
position: relative;
|
||||
/*@-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; }*/
|
||||
/*}*/ }
|
||||
.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: -10px;
|
||||
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: -10px;
|
||||
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 {
|
||||
.jsoneditor-schema-error from {
|
||||
opacity: 0; }
|
||||
.jsoneditor-schema-error to {
|
||||
opacity: 1; } }
|
|
@ -64,7 +64,7 @@
|
|||
right: -14px;
|
||||
left: inherit;
|
||||
margin-left: inherit;
|
||||
margin-top: -7px;
|
||||
margin-top: -10px;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
@ -76,7 +76,7 @@
|
|||
top: 19px;
|
||||
left: -14px;
|
||||
margin-left: inherit;
|
||||
margin-top: -7px;
|
||||
margin-top: -10px;
|
||||
position: absolute;
|
||||
}
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
// @flow weak
|
||||
|
||||
/**
|
||||
* This file contains functions to act on a ESON object.
|
||||
* All functions are pure and don't mutate the ESON.
|
||||
|
@ -14,12 +12,6 @@ import times from 'lodash/times'
|
|||
import initial from 'lodash/initial'
|
||||
import last from 'lodash/last'
|
||||
|
||||
import type {
|
||||
ESON, ESONPointer, Selection,
|
||||
Path,
|
||||
JSONType
|
||||
} from './types'
|
||||
|
||||
export const SELECTED = 1
|
||||
export const SELECTED_END = 2
|
||||
export const SELECTED_BEFORE = 3
|
||||
|
@ -38,8 +30,8 @@ export function expandAll (path) {
|
|||
|
||||
/**
|
||||
*
|
||||
* @param {JSONType} json
|
||||
* @param {JSONPath} path
|
||||
* @param {JSON} json
|
||||
* @param {Path} path
|
||||
* @return {ESON}
|
||||
*/
|
||||
export function jsonToEson (json, path = []) {
|
||||
|
@ -69,7 +61,7 @@ export function jsonToEson (json, path = []) {
|
|||
* @param {ESON} eson
|
||||
* @return {Object | Array | string | number | boolean | null} json
|
||||
*/
|
||||
export function esonToJson (eson: ESON) {
|
||||
export function esonToJson (eson) {
|
||||
switch (eson[META].type) {
|
||||
case 'Array':
|
||||
return eson.map(item => esonToJson(item))
|
||||
|
@ -154,6 +146,7 @@ export function updatePaths(eson, path = []) {
|
|||
* @return {ESON}
|
||||
*/
|
||||
export function expand (eson, filterCallback, expanded = true) {
|
||||
// TODO: adjust expand to have a filterCallback which can return true, false, or undefined. In the latter case, the expanded state is left as is.
|
||||
return transform(eson, function (value, path) {
|
||||
return ((value[META].type === 'Array' || value[META].type === 'Object') && filterCallback(path))
|
||||
? expandOne(value, [], expanded)
|
||||
|
@ -215,7 +208,7 @@ export function applyErrors (eson, errors = []) {
|
|||
* Cleanup meta data from an eson object
|
||||
* @param {ESON} eson Object to be cleaned up
|
||||
* @param {String} field Field name, for example 'error' or 'selected'
|
||||
* @param {String[] | JSONPath[]} [ignorePaths=[]] An optional array with paths to be ignored
|
||||
* @param {Path[]} [ignorePaths=[]] An optional array with paths to be ignored
|
||||
* @return {ESON}
|
||||
*/
|
||||
export function cleanupMetaData(eson, field, ignorePaths = []) {
|
||||
|
@ -395,8 +388,8 @@ export function applySelection (eson, selection) {
|
|||
return updatedObj
|
||||
}
|
||||
else { // root[META].type === 'Array'
|
||||
const startIndex = parseInt(start)
|
||||
const endIndex = parseInt(end)
|
||||
const startIndex = parseInt(start, 10)
|
||||
const endIndex = parseInt(end, 10)
|
||||
|
||||
const minIndex = Math.min(startIndex, endIndex)
|
||||
const maxIndex = Math.max(startIndex, endIndex) + 1 // include max index itself
|
||||
|
@ -434,8 +427,8 @@ export function findSelectionIndices (root, rootPath, selection) {
|
|||
const end = (selection.after || selection.before || selection.end)[rootPath.length]
|
||||
|
||||
// if no object we assume it's an Array
|
||||
const startIndex = root[META].type === 'Object' ? root[META].props.indexOf(start) : parseInt(start)
|
||||
const endIndex = root[META].type === 'Object' ? root[META].props.indexOf(end) : parseInt(end)
|
||||
const startIndex = root[META].type === 'Object' ? root[META].props.indexOf(start) : parseInt(start, 10)
|
||||
const endIndex = root[META].type === 'Object' ? root[META].props.indexOf(end) : parseInt(end, 10)
|
||||
|
||||
const minIndex = Math.min(startIndex, endIndex)
|
||||
const maxIndex = Math.max(startIndex, endIndex) +
|
||||
|
@ -446,8 +439,11 @@ export function findSelectionIndices (root, rootPath, selection) {
|
|||
|
||||
/**
|
||||
* Get the JSON paths from a selection, sorted from first to last
|
||||
* @param {ESON} eson
|
||||
* @param {Selection} selection
|
||||
* @return {Path[]}
|
||||
*/
|
||||
export function pathsFromSelection (eson, selection: Selection): Path[] {
|
||||
export function pathsFromSelection (eson, selection) {
|
||||
// find the parent node shared by both start and end of the selection
|
||||
const rootPath = findRootPath(selection)
|
||||
const root = getIn(eson, rootPath)
|
||||
|
@ -468,7 +464,7 @@ export function pathsFromSelection (eson, selection: Selection): Path[] {
|
|||
* @param {Path[]} paths
|
||||
* @return {Array.<{name: string, value: JSONType}>}
|
||||
*/
|
||||
export function contentsFromPaths (data: ESON, paths: Path[]) {
|
||||
export function contentsFromPaths (data, paths) {
|
||||
return paths.map(path => {
|
||||
return {
|
||||
name: last(path),
|
||||
|
@ -508,8 +504,11 @@ export function findRootPath(selection) {
|
|||
/**
|
||||
* Find the common path of two paths.
|
||||
* For example findCommonRoot(['arr', '1', 'name'], ['arr', '1', 'address', 'contact']) returns ['arr', '1']
|
||||
* @param {Path} path1
|
||||
* @param {Path} path2
|
||||
* @return {Path}
|
||||
*/
|
||||
function findSharedPath (path1: Path, path2: Path): Path {
|
||||
function findSharedPath (path1, path2) {
|
||||
let i = 0;
|
||||
while (i < path1.length && path1[i] === path2[i]) {
|
||||
i++;
|
||||
|
@ -536,7 +535,7 @@ export function pathExists (eson, path) {
|
|||
|
||||
if (Array.isArray(eson)) {
|
||||
// index of an array
|
||||
return pathExists(eson[parseInt(path[0])], path.slice(1))
|
||||
return pathExists(eson[parseInt(path[0], 10)], path.slice(1))
|
||||
}
|
||||
else { // Object
|
||||
// object property. find the index of this property
|
||||
|
@ -583,9 +582,9 @@ export function findNextProp (parent, prop) {
|
|||
* Parse a JSON Pointer
|
||||
* WARNING: this is not a complete implementation
|
||||
* @param {string} pointer
|
||||
* @return {Array}
|
||||
* @return {Path}
|
||||
*/
|
||||
export function parseJSONPointer (pointer: string) {
|
||||
export function parseJSONPointer (pointer) {
|
||||
const path = pointer.split('/')
|
||||
path.shift() // remove the first empty entry
|
||||
|
||||
|
@ -598,7 +597,7 @@ export function parseJSONPointer (pointer: string) {
|
|||
* @param {Path} path
|
||||
* @return {string}
|
||||
*/
|
||||
export function compileJSONPointer (path: Path) {
|
||||
export function compileJSONPointer (path) {
|
||||
return path
|
||||
.map(p => '/' + String(p).replace(/~/g, '~0').replace(/\//g, '~1'))
|
||||
.join('')
|
||||
|
@ -612,7 +611,7 @@ export function compileJSONPointer (path: Path) {
|
|||
* @param {String} search
|
||||
* @return {boolean} Returns true if `search` is found in `text`
|
||||
*/
|
||||
export function containsCaseInsensitive (text: string, search: string): boolean {
|
||||
export function containsCaseInsensitive (text, search) {
|
||||
return String(text).toLowerCase().indexOf(search.toLowerCase()) !== -1
|
||||
}
|
||||
|
||||
|
@ -620,7 +619,7 @@ export function containsCaseInsensitive (text: string, search: string): boolean
|
|||
* Get a new "unique" id. Id's are created from an incremental counter.
|
||||
* @return {number}
|
||||
*/
|
||||
export function createId () : number {
|
||||
export function createId () {
|
||||
_id++
|
||||
return _id
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
'use strict'
|
||||
|
||||
import { readFileSync } from 'fs'
|
||||
import test from 'ava'
|
||||
import { setIn, getIn, deleteIn } from '../src/utils/immutabilityHelpers'
|
||||
import { setIn, getIn, deleteIn } from './utils/immutabilityHelpers'
|
||||
import {
|
||||
META,
|
||||
esonToJson, pathExists, transform,
|
||||
|
@ -12,17 +11,17 @@ import {
|
|||
previousSearchResult,
|
||||
applySelection, pathsFromSelection,
|
||||
SELECTED, SELECTED_END
|
||||
} from '../src/eson'
|
||||
} from './eson'
|
||||
import 'console.table'
|
||||
import repeat from 'lodash/repeat'
|
||||
import { assertDeepEqualEson } from './utils/assertDeepEqualEson'
|
||||
|
||||
test('jsonToEson', t => {
|
||||
assertDeepEqualEson(t, jsonToEson(1), {[META]: {id: '[ID]', path: [], type: 'value', value: 1}})
|
||||
assertDeepEqualEson(t, jsonToEson("foo"), {[META]: {id: '[ID]', path: [], type: 'value', value: "foo"}})
|
||||
assertDeepEqualEson(t, jsonToEson(null), {[META]: {id: '[ID]', path: [], type: 'value', value: null}})
|
||||
assertDeepEqualEson(t, jsonToEson(false), {[META]: {id: '[ID]', path: [], type: 'value', value: false}})
|
||||
assertDeepEqualEson(t, jsonToEson({a:1, b: 2}), {
|
||||
test('jsonToEson', () => {
|
||||
assertDeepEqualEson(jsonToEson(1), {[META]: {id: '[ID]', path: [], type: 'value', value: 1}})
|
||||
assertDeepEqualEson(jsonToEson("foo"), {[META]: {id: '[ID]', path: [], type: 'value', value: "foo"}})
|
||||
assertDeepEqualEson(jsonToEson(null), {[META]: {id: '[ID]', path: [], type: 'value', value: null}})
|
||||
assertDeepEqualEson(jsonToEson(false), {[META]: {id: '[ID]', path: [], type: 'value', value: false}})
|
||||
assertDeepEqualEson(jsonToEson({a:1, b: 2}), {
|
||||
[META]: {id: '[ID]', path: [], type: 'Object', props: ['a', 'b']},
|
||||
a: {[META]: {id: '[ID]', path: ['a'], type: 'value', value: 1}},
|
||||
b: {[META]: {id: '[ID]', path: ['b'], type: 'value', value: 2}}
|
||||
|
@ -34,10 +33,10 @@ test('jsonToEson', t => {
|
|||
{[META]: {id: '[ID]', path: ['1'], type: 'value', value: 2}}
|
||||
]
|
||||
expected[META] = {id: '[ID]', path: [], type: 'Array'}
|
||||
assertDeepEqualEson(t, actual, expected)
|
||||
assertDeepEqualEson(actual, expected)
|
||||
})
|
||||
|
||||
test('esonToJson', t => {
|
||||
test('esonToJson', () => {
|
||||
const json = {
|
||||
"obj": {
|
||||
"arr": [1,2, {"first":3,"last":4}]
|
||||
|
@ -47,10 +46,10 @@ test('esonToJson', t => {
|
|||
"bool": false
|
||||
}
|
||||
const eson = jsonToEson(json)
|
||||
t.deepEqual(esonToJson(eson), json)
|
||||
expect(esonToJson(eson)).toEqual(json)
|
||||
})
|
||||
|
||||
test('expand a single path', t => {
|
||||
test('expand a single path', () => {
|
||||
const eson = jsonToEson({
|
||||
"obj": {
|
||||
"arr": [1,2, {"first":3,"last":4}]
|
||||
|
@ -62,15 +61,15 @@ test('expand a single path', t => {
|
|||
|
||||
const path = ['obj', 'arr', 2]
|
||||
const collapsed = expandOne(eson, path, false)
|
||||
t.is(collapsed.obj.arr[2][META].expanded, false)
|
||||
assertDeepEqualEson(t, deleteIn(collapsed, path.concat([META, 'expanded'])), eson)
|
||||
expect(collapsed.obj.arr[2][META].expanded).toEqual(false)
|
||||
assertDeepEqualEson(deleteIn(collapsed, path.concat([META, 'expanded'])), eson)
|
||||
|
||||
const expanded = expandOne(eson, path, true)
|
||||
t.is(expanded.obj.arr[2][META].expanded, true)
|
||||
assertDeepEqualEson(t, deleteIn(expanded, path.concat([META, 'expanded'])), eson)
|
||||
expect(expanded.obj.arr[2][META].expanded).toEqual(true)
|
||||
assertDeepEqualEson(deleteIn(expanded, path.concat([META, 'expanded'])), eson)
|
||||
})
|
||||
|
||||
test('expand all objects/arrays on a path', t => {
|
||||
test('expand all objects/arrays on a path', () => {
|
||||
const eson = jsonToEson({
|
||||
"obj": {
|
||||
"arr": [1,2, {"first":3,"last":4}]
|
||||
|
@ -83,16 +82,16 @@ test('expand all objects/arrays on a path', t => {
|
|||
const path = ['obj', 'arr', 2]
|
||||
|
||||
const collapsed = expandPath(eson, path, false)
|
||||
t.is(collapsed[META].expanded, false)
|
||||
t.is(collapsed.obj[META].expanded, false)
|
||||
t.is(collapsed.obj.arr[META].expanded, false)
|
||||
t.is(collapsed.obj.arr[2][META].expanded, false)
|
||||
expect(collapsed[META].expanded).toEqual(false)
|
||||
expect(collapsed.obj[META].expanded).toEqual(false)
|
||||
expect(collapsed.obj.arr[META].expanded).toEqual(false)
|
||||
expect(collapsed.obj.arr[2][META].expanded).toEqual(false)
|
||||
|
||||
const expanded = expandPath(eson, path, true)
|
||||
t.is(expanded[META].expanded, true)
|
||||
t.is(expanded.obj[META].expanded, true)
|
||||
t.is(expanded.obj.arr[META].expanded, true)
|
||||
t.is(expanded.obj.arr[2][META].expanded, true)
|
||||
expect(expanded[META].expanded).toEqual(true)
|
||||
expect(expanded.obj[META].expanded).toEqual(true)
|
||||
expect(expanded.obj.arr[META].expanded).toEqual(true)
|
||||
expect(expanded.obj.arr[2][META].expanded).toEqual(true)
|
||||
|
||||
let orig = expanded
|
||||
orig = deleteIn(orig, [].concat([META, 'expanded']))
|
||||
|
@ -100,10 +99,10 @@ test('expand all objects/arrays on a path', t => {
|
|||
orig = deleteIn(orig, ['obj', 'arr'].concat([META, 'expanded']))
|
||||
orig = deleteIn(orig, ['obj', 'arr', 2].concat([META, 'expanded']))
|
||||
|
||||
assertDeepEqualEson(t, orig, eson)
|
||||
assertDeepEqualEson(orig, eson)
|
||||
})
|
||||
|
||||
test('expand a callback', t => {
|
||||
test('expand a callback', () => {
|
||||
const eson = jsonToEson({
|
||||
"obj": {
|
||||
"arr": [1,2, {"first":3,"last":4}]
|
||||
|
@ -118,19 +117,19 @@ test('expand a callback', t => {
|
|||
}
|
||||
const expandedValue = false
|
||||
const collapsed = expand(eson, filterCallback, expandedValue)
|
||||
t.is(collapsed[META].expanded, undefined)
|
||||
t.is(collapsed.obj[META].expanded, expandedValue)
|
||||
t.is(collapsed.obj.arr[META].expanded, expandedValue)
|
||||
t.is(collapsed.obj.arr[2][META].expanded, expandedValue)
|
||||
expect(collapsed[META].expanded).toEqual(undefined)
|
||||
expect(collapsed.obj[META].expanded).toEqual(expandedValue)
|
||||
expect(collapsed.obj.arr[META].expanded).toEqual(expandedValue)
|
||||
expect(collapsed.obj.arr[2][META].expanded).toEqual(expandedValue)
|
||||
|
||||
let orig = collapsed
|
||||
orig = deleteIn(orig, ['obj'].concat([META, 'expanded']))
|
||||
orig = deleteIn(orig, ['obj', 'arr'].concat([META, 'expanded']))
|
||||
orig = deleteIn(orig, ['obj', 'arr', 2].concat([META, 'expanded']))
|
||||
assertDeepEqualEson(t, orig, eson)
|
||||
assertDeepEqualEson(orig, eson)
|
||||
})
|
||||
|
||||
test('expand a callback should not change the object when nothing happens', t => {
|
||||
test('expand a callback should not change the object when nothing happens', () => {
|
||||
const eson = jsonToEson({a: [1,2,3], b: {c: 4}})
|
||||
function callback (path) {
|
||||
return false
|
||||
|
@ -138,39 +137,39 @@ test('expand a callback should not change the object when nothing happens', t =>
|
|||
const expanded = false
|
||||
const collapsed = expand(eson, callback, expanded)
|
||||
|
||||
t.is(collapsed, eson)
|
||||
expect(collapsed).toBe(eson)
|
||||
})
|
||||
|
||||
test('transform (no change)', t => {
|
||||
test('transform (no change)', () => {
|
||||
const eson = jsonToEson({a: [1,2,3], b: {c: 4}})
|
||||
const updated = transform(eson, (value, path) => value)
|
||||
assertDeepEqualEson(t, updated, eson)
|
||||
t.is(updated, eson)
|
||||
assertDeepEqualEson(updated, eson)
|
||||
expect(updated).toBe(eson)
|
||||
})
|
||||
|
||||
test('transform (change based on value)', t => {
|
||||
test('transform (change based on value)', () => {
|
||||
const eson = jsonToEson({a: [1,2,3], b: {c: 4}})
|
||||
|
||||
const updated = transform(eson,
|
||||
(value, path) => value[META].value === 2 ? jsonToEson(20, path) : value)
|
||||
const expected = jsonToEson({a: [1,20,3], b: {c: 4}})
|
||||
|
||||
assertDeepEqualEson(t, updated, expected)
|
||||
t.is(updated.b, eson.b) // should not have replaced b
|
||||
assertDeepEqualEson(updated, expected)
|
||||
expect(updated.b).toBe(eson.b) // should not have replaced b
|
||||
})
|
||||
|
||||
test('transform (change based on path)', t => {
|
||||
test('transform (change based on path)', () => {
|
||||
const eson = jsonToEson({a: [1,2,3], b: {c: 4}})
|
||||
|
||||
const updated = transform(eson,
|
||||
(value, path) => path.join('.') === 'a.1' ? jsonToEson(20, path) : value)
|
||||
const expected = jsonToEson({a: [1,20,3], b: {c: 4}})
|
||||
|
||||
assertDeepEqualEson(t, updated, expected)
|
||||
t.is(updated.b, eson.b) // should not have replaced b
|
||||
assertDeepEqualEson(updated, expected)
|
||||
expect(updated.b).toBe(eson.b) // should not have replaced b
|
||||
})
|
||||
|
||||
test('pathExists', t => {
|
||||
test('pathExists', () => {
|
||||
const eson = jsonToEson({
|
||||
"obj": {
|
||||
"arr": [1,2, {"first":3,"last":4}]
|
||||
|
@ -180,29 +179,29 @@ test('pathExists', t => {
|
|||
"bool": false
|
||||
})
|
||||
|
||||
t.is(pathExists(eson, ['obj', 'arr', 2, 'first']), true)
|
||||
t.is(pathExists(eson, ['obj', 'foo']), false)
|
||||
t.is(pathExists(eson, ['obj', 'foo', 'bar']), false)
|
||||
t.is(pathExists(eson, []), true)
|
||||
expect(pathExists(eson, ['obj', 'arr', 2, 'first'])).toEqual(true)
|
||||
expect(pathExists(eson, ['obj', 'foo'])).toEqual(false)
|
||||
expect(pathExists(eson, ['obj', 'foo', 'bar'])).toEqual(false)
|
||||
expect(pathExists(eson, [])).toEqual(true)
|
||||
})
|
||||
|
||||
test('parseJSONPointer', t => {
|
||||
t.deepEqual(parseJSONPointer('/obj/a'), ['obj', 'a'])
|
||||
t.deepEqual(parseJSONPointer('/arr/-'), ['arr', '-'])
|
||||
t.deepEqual(parseJSONPointer('/foo/~1~0 ~0~1'), ['foo', '/~ ~/'])
|
||||
t.deepEqual(parseJSONPointer('/obj'), ['obj'])
|
||||
t.deepEqual(parseJSONPointer('/'), [''])
|
||||
t.deepEqual(parseJSONPointer(''), [])
|
||||
test('parseJSONPointer', () => {
|
||||
expect(parseJSONPointer('/obj/a')).toEqual(['obj', 'a'])
|
||||
expect(parseJSONPointer('/arr/-')).toEqual(['arr', '-'])
|
||||
expect(parseJSONPointer('/foo/~1~0 ~0~1')).toEqual(['foo', '/~ ~/'])
|
||||
expect(parseJSONPointer('/obj')).toEqual(['obj'])
|
||||
expect(parseJSONPointer('/')).toEqual([''])
|
||||
expect(parseJSONPointer('')).toEqual([])
|
||||
})
|
||||
|
||||
test('compileJSONPointer', t => {
|
||||
t.deepEqual(compileJSONPointer(['foo', 'bar']), '/foo/bar')
|
||||
t.deepEqual(compileJSONPointer(['foo', '/~ ~/']), '/foo/~1~0 ~0~1')
|
||||
t.deepEqual(compileJSONPointer(['']), '/')
|
||||
t.deepEqual(compileJSONPointer([]), '')
|
||||
test('compileJSONPointer', () => {
|
||||
expect(compileJSONPointer(['foo', 'bar'])).toEqual('/foo/bar')
|
||||
expect(compileJSONPointer(['foo', '/~ ~/'])).toEqual('/foo/~1~0 ~0~1')
|
||||
expect(compileJSONPointer([''])).toEqual('/')
|
||||
expect(compileJSONPointer([])).toEqual('')
|
||||
})
|
||||
|
||||
test('add and remove errors', t => {
|
||||
test('add and remove errors', () => {
|
||||
const eson = jsonToEson({
|
||||
"obj": {
|
||||
"arr": [1,2, {"first":3,"last":4}]
|
||||
|
@ -222,19 +221,19 @@ test('add and remove errors', t => {
|
|||
let expected = eson
|
||||
expected = setIn(expected, ['obj', 'arr', '2', 'last', META, 'error'], jsonSchemaErrors[0])
|
||||
expected = setIn(expected, ['nill', META, 'error'], jsonSchemaErrors[1])
|
||||
assertDeepEqualEson(t, actual1, expected)
|
||||
assertDeepEqualEson(actual1, expected)
|
||||
|
||||
// re-applying the same errors should not change eson
|
||||
const actual2 = applyErrors(actual1, jsonSchemaErrors)
|
||||
t.is(actual2, actual1)
|
||||
expect(actual2).toBe(actual1)
|
||||
|
||||
// clear errors
|
||||
const actual3 = applyErrors(actual2, [])
|
||||
assertDeepEqualEson(t, actual3, eson)
|
||||
t.is(actual3.str, eson.str) // shouldn't have touched values not affected by the errors
|
||||
assertDeepEqualEson(actual3, eson)
|
||||
expect(actual3.str).toEqual(eson.str) // shouldn't have touched values not affected by the errors
|
||||
})
|
||||
|
||||
test('search', t => {
|
||||
test('search', () => {
|
||||
const eson = jsonToEson({
|
||||
"obj": {
|
||||
"arr": [1,2, {"first":3,"last":4}]
|
||||
|
@ -248,7 +247,7 @@ test('search', t => {
|
|||
const matches = result.searchResult.matches
|
||||
const active = result.searchResult.active
|
||||
|
||||
t.deepEqual(matches, [
|
||||
expect(matches).toEqual([
|
||||
{path: ['obj', 'arr', '2', 'last'], area: 'property'},
|
||||
{path: ['str'], area: 'value'},
|
||||
{path: ['nill'], area: 'property'},
|
||||
|
@ -256,7 +255,7 @@ test('search', t => {
|
|||
{path: ['bool'], area: 'property'},
|
||||
{path: ['bool'], area: 'value'}
|
||||
])
|
||||
t.deepEqual(active, {path: ['obj', 'arr', '2', 'last'], area: 'property'})
|
||||
expect(active).toEqual({path: ['obj', 'arr', '2', 'last'], area: 'property'})
|
||||
|
||||
let expected = esonWithSearch
|
||||
expected = setIn(expected, ['obj', 'arr', '2', 'last', META, 'searchProperty'], 'active')
|
||||
|
@ -266,10 +265,10 @@ test('search', t => {
|
|||
expected = setIn(expected, ['bool', META, 'searchProperty'], 'normal')
|
||||
expected = setIn(expected, ['bool', META, 'searchValue'], 'normal')
|
||||
|
||||
assertDeepEqualEson(t, esonWithSearch, expected)
|
||||
assertDeepEqualEson(esonWithSearch, expected)
|
||||
})
|
||||
|
||||
test('nextSearchResult', t => {
|
||||
test('nextSearchResult', () => {
|
||||
const eson = jsonToEson({
|
||||
"obj": {
|
||||
"arr": [1,2, {"first":3,"last":4}]
|
||||
|
@ -280,37 +279,37 @@ test('nextSearchResult', t => {
|
|||
})
|
||||
const first = search(eson, 'A')
|
||||
|
||||
t.deepEqual(first.searchResult.matches, [
|
||||
expect(first.searchResult.matches).toEqual([
|
||||
{path: ['obj', 'arr'], area: 'property'},
|
||||
{path: ['obj', 'arr', '2', 'last'], area: 'property'},
|
||||
{path: ['bool'], area: 'value'}
|
||||
])
|
||||
|
||||
t.deepEqual(first.searchResult.active, {path: ['obj', 'arr'], area: 'property'})
|
||||
t.is(getIn(first.eson, ['obj', 'arr', META, 'searchProperty']), 'active')
|
||||
t.is(getIn(first.eson, ['obj', 'arr', '2', 'last', META, 'searchProperty']), 'normal')
|
||||
t.is(getIn(first.eson, ['bool', META, 'searchValue']), 'normal')
|
||||
expect(first.searchResult.active).toEqual({path: ['obj', 'arr'], area: 'property'})
|
||||
expect(getIn(first.eson, ['obj', 'arr', META, 'searchProperty'])).toEqual('active')
|
||||
expect(getIn(first.eson, ['obj', 'arr', '2', 'last', META, 'searchProperty'])).toEqual('normal')
|
||||
expect(getIn(first.eson, ['bool', META, 'searchValue'])).toEqual('normal')
|
||||
|
||||
const second = nextSearchResult(first.eson, first.searchResult)
|
||||
t.deepEqual(second.searchResult.active, {path: ['obj', 'arr', '2', 'last'], area: 'property'})
|
||||
t.is(getIn(second.eson, ['obj', 'arr', META, 'searchProperty']), 'normal')
|
||||
t.is(getIn(second.eson, ['obj', 'arr', '2', 'last', META, 'searchProperty']), 'active')
|
||||
t.is(getIn(second.eson, ['bool', META, 'searchValue']), 'normal')
|
||||
expect(second.searchResult.active).toEqual({path: ['obj', 'arr', '2', 'last'], area: 'property'})
|
||||
expect(getIn(second.eson, ['obj', 'arr', META, 'searchProperty'])).toEqual('normal')
|
||||
expect(getIn(second.eson, ['obj', 'arr', '2', 'last', META, 'searchProperty'])).toEqual('active')
|
||||
expect(getIn(second.eson, ['bool', META, 'searchValue'])).toEqual('normal')
|
||||
|
||||
const third = nextSearchResult(second.eson, second.searchResult)
|
||||
t.deepEqual(third.searchResult.active, {path: ['bool'], area: 'value'})
|
||||
t.is(getIn(third.eson, ['obj', 'arr', META, 'searchProperty']), 'normal')
|
||||
t.is(getIn(third.eson, ['obj', 'arr', '2', 'last', META, 'searchProperty']), 'normal')
|
||||
t.is(getIn(third.eson, ['bool', META, 'searchValue']), 'active')
|
||||
expect(third.searchResult.active).toEqual({path: ['bool'], area: 'value'})
|
||||
expect(getIn(third.eson, ['obj', 'arr', META, 'searchProperty'])).toEqual('normal')
|
||||
expect(getIn(third.eson, ['obj', 'arr', '2', 'last', META, 'searchProperty'])).toEqual('normal')
|
||||
expect(getIn(third.eson, ['bool', META, 'searchValue'])).toEqual('active')
|
||||
|
||||
const wrappedAround = nextSearchResult(third.eson, third.searchResult)
|
||||
t.deepEqual(wrappedAround.searchResult.active, {path: ['obj', 'arr'], area: 'property'})
|
||||
t.is(getIn(wrappedAround.eson, ['obj', 'arr', META, 'searchProperty']), 'active')
|
||||
t.is(getIn(wrappedAround.eson, ['obj', 'arr', '2', 'last', META, 'searchProperty']), 'normal')
|
||||
t.is(getIn(wrappedAround.eson, ['bool', META, 'searchValue']), 'normal')
|
||||
expect(wrappedAround.searchResult.active).toEqual({path: ['obj', 'arr'], area: 'property'})
|
||||
expect(getIn(wrappedAround.eson, ['obj', 'arr', META, 'searchProperty'])).toEqual('active')
|
||||
expect(getIn(wrappedAround.eson, ['obj', 'arr', '2', 'last', META, 'searchProperty'])).toEqual('normal')
|
||||
expect(getIn(wrappedAround.eson, ['bool', META, 'searchValue'])).toEqual('normal')
|
||||
})
|
||||
|
||||
test('previousSearchResult', t => {
|
||||
test('previousSearchResult', () => {
|
||||
const eson = jsonToEson({
|
||||
"obj": {
|
||||
"arr": [1,2, {"first":3,"last":4}]
|
||||
|
@ -321,37 +320,37 @@ test('previousSearchResult', t => {
|
|||
})
|
||||
const init = search(eson, 'A')
|
||||
|
||||
t.deepEqual(init.searchResult.matches, [
|
||||
expect(init.searchResult.matches).toEqual([
|
||||
{path: ['obj', 'arr'], area: 'property'},
|
||||
{path: ['obj', 'arr', '2', 'last'], area: 'property'},
|
||||
{path: ['bool'], area: 'value'}
|
||||
])
|
||||
|
||||
t.deepEqual(init.searchResult.active, {path: ['obj', 'arr'], area: 'property'})
|
||||
t.is(getIn(init.eson, ['obj', 'arr', META, 'searchProperty']), 'active')
|
||||
t.is(getIn(init.eson, ['obj', 'arr', '2', 'last', META, 'searchProperty']), 'normal')
|
||||
t.is(getIn(init.eson, ['bool', META, 'searchValue']), 'normal')
|
||||
expect(init.searchResult.active).toEqual({path: ['obj', 'arr'], area: 'property'})
|
||||
expect(getIn(init.eson, ['obj', 'arr', META, 'searchProperty'])).toEqual('active')
|
||||
expect(getIn(init.eson, ['obj', 'arr', '2', 'last', META, 'searchProperty'])).toEqual('normal')
|
||||
expect(getIn(init.eson, ['bool', META, 'searchValue'])).toEqual('normal')
|
||||
|
||||
const third = previousSearchResult(init.eson, init.searchResult)
|
||||
t.deepEqual(third.searchResult.active, {path: ['bool'], area: 'value'})
|
||||
t.is(getIn(third.eson, ['obj', 'arr', META, 'searchProperty']), 'normal')
|
||||
t.is(getIn(third.eson, ['obj', 'arr', '2', 'last', META, 'searchProperty']), 'normal')
|
||||
t.is(getIn(third.eson, ['bool', META, 'searchValue']), 'active')
|
||||
expect(third.searchResult.active).toEqual({path: ['bool'], area: 'value'})
|
||||
expect(getIn(third.eson, ['obj', 'arr', META, 'searchProperty'])).toEqual('normal')
|
||||
expect(getIn(third.eson, ['obj', 'arr', '2', 'last', META, 'searchProperty'])).toEqual('normal')
|
||||
expect(getIn(third.eson, ['bool', META, 'searchValue'])).toEqual('active')
|
||||
|
||||
const second = previousSearchResult(third.eson, third.searchResult)
|
||||
t.deepEqual(second.searchResult.active, {path: ['obj', 'arr', '2', 'last'], area: 'property'})
|
||||
t.is(getIn(second.eson, ['obj', 'arr', META, 'searchProperty']), 'normal')
|
||||
t.is(getIn(second.eson, ['obj', 'arr', '2', 'last', META, 'searchProperty']), 'active')
|
||||
t.is(getIn(second.eson, ['bool', META, 'searchValue']), 'normal')
|
||||
expect(second.searchResult.active).toEqual({path: ['obj', 'arr', '2', 'last'], area: 'property'})
|
||||
expect(getIn(second.eson, ['obj', 'arr', META, 'searchProperty'])).toEqual('normal')
|
||||
expect(getIn(second.eson, ['obj', 'arr', '2', 'last', META, 'searchProperty'])).toEqual('active')
|
||||
expect(getIn(second.eson, ['bool', META, 'searchValue'])).toEqual('normal')
|
||||
|
||||
const first = previousSearchResult(second.eson, second.searchResult)
|
||||
t.deepEqual(first.searchResult.active, {path: ['obj', 'arr'], area: 'property'})
|
||||
t.is(getIn(first.eson, ['obj', 'arr', META, 'searchProperty']), 'active')
|
||||
t.is(getIn(first.eson, ['obj', 'arr', '2', 'last', META, 'searchProperty']), 'normal')
|
||||
t.is(getIn(first.eson, ['bool', META, 'searchValue']), 'normal')
|
||||
expect(first.searchResult.active).toEqual({path: ['obj', 'arr'], area: 'property'})
|
||||
expect(getIn(first.eson, ['obj', 'arr', META, 'searchProperty'])).toEqual('active')
|
||||
expect(getIn(first.eson, ['obj', 'arr', '2', 'last', META, 'searchProperty'])).toEqual('normal')
|
||||
expect(getIn(first.eson, ['bool', META, 'searchValue'])).toEqual('normal')
|
||||
})
|
||||
|
||||
test('selection (object)', t => {
|
||||
test('selection (object)', () => {
|
||||
const eson = jsonToEson({
|
||||
"obj": {
|
||||
"arr": [1,2, {"first":3,"last":4}]
|
||||
|
@ -371,7 +370,7 @@ test('selection (object)', t => {
|
|||
expected = setIn(expected, ['obj', META, 'selected'], SELECTED)
|
||||
expected = setIn(expected, ['str', META, 'selected'], SELECTED)
|
||||
expected = setIn(expected, ['nill', META, 'selected'], SELECTED_END)
|
||||
assertDeepEqualEson(t, actual, expected)
|
||||
assertDeepEqualEson(actual, expected)
|
||||
|
||||
// test whether old selection results are cleaned up
|
||||
const selection2 = {
|
||||
|
@ -382,10 +381,10 @@ test('selection (object)', t => {
|
|||
let expected2 = eson
|
||||
expected2 = setIn(expected2, ['nill', META, 'selected'], SELECTED)
|
||||
expected2 = setIn(expected2, ['bool', META, 'selected'], SELECTED_END)
|
||||
assertDeepEqualEson(t, actual2, expected2)
|
||||
assertDeepEqualEson(actual2, expected2)
|
||||
})
|
||||
|
||||
test('selection (array)', t => {
|
||||
test('selection (array)', () => {
|
||||
const eson = jsonToEson({
|
||||
"obj": {
|
||||
"arr": [1,2, {"first":3,"last":4}]
|
||||
|
@ -405,10 +404,10 @@ test('selection (array)', t => {
|
|||
expected = setIn(expected, ['obj', 'arr', '0', META, 'selected'], SELECTED_END)
|
||||
expected = setIn(expected, ['obj', 'arr', '1', META, 'selected'], SELECTED)
|
||||
|
||||
assertDeepEqualEson(t, actual, expected)
|
||||
assertDeepEqualEson(actual, expected)
|
||||
})
|
||||
|
||||
test('selection (value)', t => {
|
||||
test('selection (value)', () => {
|
||||
const eson = jsonToEson({
|
||||
"obj": {
|
||||
"arr": [1,2, {"first":3,"last":4}]
|
||||
|
@ -424,10 +423,10 @@ test('selection (value)', t => {
|
|||
|
||||
const actual = applySelection(eson, selection)
|
||||
const expected = setIn(eson, ['obj', 'arr', '2', 'first', META, 'selected'], SELECTED_END)
|
||||
assertDeepEqualEson(t, actual, expected)
|
||||
assertDeepEqualEson(actual, expected)
|
||||
})
|
||||
|
||||
test('selection (node)', t => {
|
||||
test('selection (node)', () => {
|
||||
const eson = jsonToEson({
|
||||
"obj": {
|
||||
"arr": [1,2, {"first":3,"last":4}]
|
||||
|
@ -443,10 +442,10 @@ test('selection (node)', t => {
|
|||
|
||||
const actual = applySelection(eson, selection)
|
||||
const expected = setIn(eson, ['obj', 'arr', META, 'selected'], SELECTED_END)
|
||||
assertDeepEqualEson(t, actual, expected)
|
||||
assertDeepEqualEson(actual, expected)
|
||||
})
|
||||
|
||||
test('pathsFromSelection (object)', t => {
|
||||
test('pathsFromSelection (object)', () => {
|
||||
const eson = jsonToEson({
|
||||
"obj": {
|
||||
"arr": [1,2, {"first":3,"last":4}]
|
||||
|
@ -460,14 +459,14 @@ test('pathsFromSelection (object)', t => {
|
|||
end: ['nill']
|
||||
}
|
||||
|
||||
t.deepEqual(pathsFromSelection(eson, selection), [
|
||||
expect(pathsFromSelection(eson, selection)).toEqual([
|
||||
['obj'],
|
||||
['str'],
|
||||
['nill']
|
||||
])
|
||||
})
|
||||
|
||||
test('pathsFromSelection (array)', t => {
|
||||
test('pathsFromSelection (array)', () => {
|
||||
const eson = jsonToEson({
|
||||
"obj": {
|
||||
"arr": [1,2, {"first":3,"last":4}]
|
||||
|
@ -481,13 +480,13 @@ test('pathsFromSelection (array)', t => {
|
|||
end: ['obj', 'arr', '0'] // note the "wrong" order of start and end
|
||||
}
|
||||
|
||||
t.deepEqual(pathsFromSelection(eson, selection), [
|
||||
expect(pathsFromSelection(eson, selection)).toEqual([
|
||||
['obj', 'arr', '0'],
|
||||
['obj', 'arr', '1']
|
||||
])
|
||||
})
|
||||
|
||||
test('pathsFromSelection (value)', t => {
|
||||
test('pathsFromSelection (value)', () => {
|
||||
const eson = jsonToEson({
|
||||
"obj": {
|
||||
"arr": [1,2, {"first":3,"last":4}]
|
||||
|
@ -501,12 +500,12 @@ test('pathsFromSelection (value)', t => {
|
|||
end: ['obj', 'arr', '2', 'first']
|
||||
}
|
||||
|
||||
t.deepEqual(pathsFromSelection(eson, selection), [
|
||||
expect(pathsFromSelection(eson, selection)).toEqual([
|
||||
['obj', 'arr', '2', 'first'],
|
||||
])
|
||||
})
|
||||
|
||||
test('pathsFromSelection (before)', t => {
|
||||
test('pathsFromSelection (before)', () => {
|
||||
const eson = jsonToEson({
|
||||
"obj": {
|
||||
"arr": [1,2, {"first":3,"last":4}]
|
||||
|
@ -519,10 +518,10 @@ test('pathsFromSelection (before)', t => {
|
|||
before: ['obj', 'arr', '2', 'first']
|
||||
}
|
||||
|
||||
t.deepEqual(pathsFromSelection(eson, selection), [])
|
||||
expect(pathsFromSelection(eson, selection)).toEqual([])
|
||||
})
|
||||
|
||||
test('pathsFromSelection (after)', t => {
|
||||
test('pathsFromSelection (after)', () => {
|
||||
const eson = jsonToEson({
|
||||
"obj": {
|
||||
"arr": [1,2, {"first":3,"last":4}]
|
||||
|
@ -535,7 +534,7 @@ test('pathsFromSelection (after)', t => {
|
|||
after: ['obj', 'arr', '2', 'first']
|
||||
}
|
||||
|
||||
t.deepEqual(pathsFromSelection(eson, selection), [])
|
||||
expect(pathsFromSelection(eson, selection)).toEqual([])
|
||||
})
|
||||
|
||||
// helper function to print JSON in the console
|
|
@ -0,0 +1,7 @@
|
|||
import _JSONEditor from './components/JSONEditor'
|
||||
|
||||
export const JSONEditor = _JSONEditor
|
||||
|
||||
export default JSONEditor
|
||||
|
||||
// TODO: export util functions like immutability helpers
|
|
@ -0,0 +1,275 @@
|
|||
import React, { createElement as h, Component } from 'react'
|
||||
import * as ReactDOM from 'react-dom'
|
||||
import JSONEditor from './components/JSONEditor'
|
||||
import CodeMode from './components/CodeMode'
|
||||
import TextMode from './components/TextMode'
|
||||
import TreeMode from './components/TreeMode'
|
||||
import { compileJSONPointer, parseJSONPointer } from './eson'
|
||||
|
||||
const modes = {
|
||||
code: CodeMode,
|
||||
form: TreeMode,
|
||||
text: TextMode,
|
||||
tree: TreeMode,
|
||||
view: TreeMode
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new json editor
|
||||
* @param {HTMLElement} container
|
||||
* @param {Options} options
|
||||
* @return {Object}
|
||||
* @constructor
|
||||
*/
|
||||
function jsoneditor (container, options = {}) {
|
||||
if (arguments.length > 2) {
|
||||
throw new Error ('Passing JSON via the constructor has been deprecated. ' +
|
||||
'Please pass JSON via editor.set(json).')
|
||||
}
|
||||
|
||||
const editor = {
|
||||
isJSONEditor: true,
|
||||
|
||||
_container: container,
|
||||
_options: options,
|
||||
_schema: null,
|
||||
_modes: modes,
|
||||
_mode: null,
|
||||
_component: null
|
||||
}
|
||||
|
||||
/**
|
||||
* Set JSON object in editor
|
||||
* @param {Object | Array | string | number | boolean | null} json JSON data
|
||||
* @param {Options} [options]
|
||||
*/
|
||||
editor.set = function (json, options = {}) {
|
||||
// TODO: remove options from editor.set, move them to global options instead
|
||||
editor._component.set(json, options)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get JSON from the editor
|
||||
* @returns {Object | Array | string | number | boolean | null} json
|
||||
*/
|
||||
editor.get = function () {
|
||||
return editor._component.get()
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a string containing a JSON document
|
||||
* @param {string} text
|
||||
*/
|
||||
editor.setText = function (text) {
|
||||
editor._component.setText(text)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the JSON document as text
|
||||
* @return {string} text
|
||||
*/
|
||||
editor.getText = function () {
|
||||
return editor._component.getText()
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the json.
|
||||
* Only applicable for mode 'text' and 'code' (in other modes nothing will
|
||||
* happen)
|
||||
*/
|
||||
editor.format = function () {
|
||||
const formatted = TextMode.format(editor._component.getText(), TextMode.getIndentation(this.props))
|
||||
editor._component.setText(formatted)
|
||||
|
||||
// TODO: test whether this doesn't destroy the current state
|
||||
}
|
||||
|
||||
/**
|
||||
* Compact the json.
|
||||
* Only applicable for mode 'text' and 'code' (in other modes nothing will
|
||||
* happen)
|
||||
*/
|
||||
editor.compact = function () {
|
||||
const compacted = TextMode.compact(editor._component.getText())
|
||||
editor._component.setText(compacted)
|
||||
|
||||
// TODO: test whether this doesn't destroy the current state
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a JSON schema for validation of the JSON object.
|
||||
* To remove the schema, call JSONEditor.setSchema(null)
|
||||
* @param {Object | null} schema
|
||||
*/
|
||||
editor.setSchema = function (schema) {
|
||||
editor._schema = schema || null
|
||||
editor._component.setSchema(schema)
|
||||
}
|
||||
|
||||
/**
|
||||
* Expand one or multiple objects or arrays.
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* // expand one item at a specific path
|
||||
* editor.expand(['foo', 1, 'bar'])
|
||||
*
|
||||
* // expand all items nested at a maximum depth of 2
|
||||
* editor.expand(function (path) {
|
||||
* return path.length <= 2
|
||||
* })
|
||||
*
|
||||
* @param {Path | function (path: Path) : boolean} callback
|
||||
*/
|
||||
editor.expand = function (callback) {
|
||||
editor._component.expand(callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse one or multiple objects or arrays
|
||||
*
|
||||
* Example usage:
|
||||
*
|
||||
* // collapse one item at a specific path
|
||||
* editor.collapse(['foo', 1, 'bar'])
|
||||
*
|
||||
* // collapse all items nested deeper than 2
|
||||
* editor.collapse(function (path) {
|
||||
* return path.length > 2
|
||||
* })
|
||||
*
|
||||
* @param {Path | function (path: Path) : boolean} callback
|
||||
*/
|
||||
editor.collapse = function (callback) {
|
||||
editor._component.collapse(callback)
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a JSONPatch to the current JSON document
|
||||
* @param {Array} actions JSONPatch actions
|
||||
* @return {Array} Returns a JSONPatch to revert the applied patch
|
||||
*/
|
||||
editor.patch = function (actions) {
|
||||
return editor._component.patch(actions)
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the mode of the editor
|
||||
* @param {'tree' | 'text'} mode
|
||||
*/
|
||||
editor.setMode = function (mode) {
|
||||
// TODO: strongly simplify .setMode, no error handling or logic here
|
||||
|
||||
if (mode === editor._mode) {
|
||||
// mode stays the same. do nothing
|
||||
return
|
||||
}
|
||||
|
||||
let success = false
|
||||
let initialChildCount = editor._container.children.length
|
||||
let component = null
|
||||
try {
|
||||
// find the constructor for the selected mode
|
||||
const constructor = editor._modes[mode]
|
||||
if (!constructor) {
|
||||
throw new Error('Unknown mode "' + mode + '". ' +
|
||||
'Choose from: ' + Object.keys(modes).join(', '))
|
||||
}
|
||||
|
||||
function handleChangeMode (mode) {
|
||||
// we execute editor.setMode on the next tick, after the click event
|
||||
// has been finished. This is a workaround for preact which does not
|
||||
// neatly replace a rendered app whilst the event is still being handled.
|
||||
setTimeout(() => {
|
||||
const prevMode = editor._mode
|
||||
|
||||
editor.setMode(mode)
|
||||
|
||||
if (editor._options.onChangeMode) {
|
||||
editor._options.onChangeMode(mode, prevMode)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function handleError (err) {
|
||||
if (editor._options && editor._options.onError) {
|
||||
editor._options.onError(err)
|
||||
}
|
||||
else {
|
||||
console.error(err)
|
||||
}
|
||||
}
|
||||
|
||||
// create new component
|
||||
component = ReactDOM.render(
|
||||
h(constructor, {
|
||||
...options,
|
||||
mode,
|
||||
onChangeMode: handleChangeMode,
|
||||
onError: handleError
|
||||
}),
|
||||
editor._container)
|
||||
|
||||
// apply JSON schema (if any)
|
||||
try {
|
||||
component.setSchema(editor._schema)
|
||||
}
|
||||
catch (err) {
|
||||
handleError(err)
|
||||
}
|
||||
|
||||
// set JSON (this can throw an error)
|
||||
const text = editor._component ? editor._component.getText() : '{}'
|
||||
component.setText(text)
|
||||
|
||||
// when setText didn't fail, we will reach this point
|
||||
success = true
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err)
|
||||
}
|
||||
finally {
|
||||
if (success) {
|
||||
editor._mode = mode
|
||||
editor._component = component
|
||||
}
|
||||
else {
|
||||
// TODO: fall back to text mode when loading code mode failed?
|
||||
|
||||
// remove the just created component if an error occurred during construction
|
||||
// (for example when construction or setText failed)
|
||||
const childCount = editor._container.children.length
|
||||
if (childCount !== initialChildCount) {
|
||||
editor._container.removeChild(editor._container.lastChild)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the editor from the DOM and clean up workers
|
||||
*/
|
||||
editor.destroy = function () {
|
||||
ReactDOM.unmountComponentAtNode(editor._container)
|
||||
}
|
||||
|
||||
const mode = options && options.mode || (options.modes && options.modes[0]) || 'tree';
|
||||
editor.setMode(mode)
|
||||
|
||||
return editor
|
||||
}
|
||||
|
||||
// expose util functions
|
||||
jsoneditor.utils = {
|
||||
compileJSONPointer,
|
||||
parseJSONPointer
|
||||
}
|
||||
|
||||
// expose React component
|
||||
jsoneditor.JSONEditor = JSONEditor
|
||||
|
||||
// expose React itself
|
||||
jsoneditor.React = React
|
||||
jsoneditor.ReactDOM = ReactDOM
|
||||
|
||||
module.exports = jsoneditor
|
|
@ -2,7 +2,6 @@ import isEqual from 'lodash/isEqual'
|
|||
import initial from 'lodash/initial'
|
||||
import last from 'lodash/last'
|
||||
|
||||
import type { ESON, Path, ESONPatch } from './types'
|
||||
import {
|
||||
setIn, updateIn, getIn, deleteIn, insertAt,
|
||||
cloneWithSymbols
|
|
@ -1,10 +1,11 @@
|
|||
'use strict'
|
||||
|
||||
import { readFileSync } from 'fs'
|
||||
import test from 'ava'
|
||||
import { META, jsonToEson, esonToJson } from '../src/eson'
|
||||
import { patchEson } from '../src/patchEson'
|
||||
import { META, jsonToEson, esonToJson } from './eson'
|
||||
import { patchEson } from './patchEson'
|
||||
import { assertDeepEqualEson } from './utils/assertDeepEqualEson'
|
||||
|
||||
test('jsonpatch add', t => {
|
||||
test('jsonpatch add', () => {
|
||||
const json = {
|
||||
arr: [1,2,3],
|
||||
obj: {a : 2}
|
||||
|
@ -19,16 +20,16 @@ test('jsonpatch add', t => {
|
|||
const patchedData = result.data
|
||||
const revert = result.revert
|
||||
|
||||
assertDeepEqualEson(t, patchedData, jsonToEson({
|
||||
assertDeepEqualEson(patchedData, jsonToEson({
|
||||
arr: [1,2,3],
|
||||
obj: {a : 2, b: {foo: 'bar'}}
|
||||
}))
|
||||
t.deepEqual(revert, [
|
||||
expect(revert).toEqual([
|
||||
{op: 'remove', path: '/obj/b'}
|
||||
])
|
||||
})
|
||||
|
||||
test('jsonpatch add: insert in matrix', t => {
|
||||
test('jsonpatch add: insert in matrix', () => {
|
||||
const json = {
|
||||
arr: [1,2,3],
|
||||
obj: {a : 2}
|
||||
|
@ -43,16 +44,16 @@ test('jsonpatch add: insert in matrix', t => {
|
|||
const patchedData = result.data
|
||||
const revert = result.revert
|
||||
|
||||
assertDeepEqualEson(t, patchedData, jsonToEson({
|
||||
assertDeepEqualEson(patchedData, jsonToEson({
|
||||
arr: [1,4,2,3],
|
||||
obj: {a : 2}
|
||||
}))
|
||||
t.deepEqual(revert, [
|
||||
expect(revert).toEqual([
|
||||
{op: 'remove', path: '/arr/1'}
|
||||
])
|
||||
})
|
||||
|
||||
test('jsonpatch add: append to matrix', t => {
|
||||
test('jsonpatch add: append to matrix', () => {
|
||||
const json = {
|
||||
arr: [1,2,3],
|
||||
obj: {a : 2}
|
||||
|
@ -67,16 +68,16 @@ test('jsonpatch add: append to matrix', t => {
|
|||
const patchedData = result.data
|
||||
const revert = result.revert
|
||||
|
||||
assertDeepEqualEson(t, patchedData, jsonToEson({
|
||||
assertDeepEqualEson(patchedData, jsonToEson({
|
||||
arr: [1,2,3,4],
|
||||
obj: {a : 2}
|
||||
}))
|
||||
t.deepEqual(revert, [
|
||||
expect(revert).toEqual([
|
||||
{op: 'remove', path: '/arr/3'}
|
||||
])
|
||||
})
|
||||
|
||||
test('jsonpatch remove', t => {
|
||||
test('jsonpatch remove', () => {
|
||||
const json = {
|
||||
arr: [1,2,3],
|
||||
obj: {a : 4}
|
||||
|
@ -93,11 +94,11 @@ test('jsonpatch remove', t => {
|
|||
const revert = result.revert
|
||||
const patchedJson = esonToJson(patchedData)
|
||||
|
||||
assertDeepEqualEson(t, patchedData, jsonToEson({
|
||||
assertDeepEqualEson(patchedData, jsonToEson({
|
||||
arr: [1,3],
|
||||
obj: {}
|
||||
}))
|
||||
t.deepEqual(revert, [
|
||||
expect(revert).toEqual([
|
||||
{op: 'add', path: '/arr/1', value: 2, meta: {type: 'value'}},
|
||||
{op: 'add', path: '/obj/a', value: 4, meta: {type: 'value', before: null}}
|
||||
])
|
||||
|
@ -109,11 +110,11 @@ test('jsonpatch remove', t => {
|
|||
const revert2 = result2.revert
|
||||
const patchedJson2 = esonToJson(patchedData2)
|
||||
|
||||
t.deepEqual(patchedJson2, json)
|
||||
t.deepEqual(revert2, patch)
|
||||
expect(patchedJson2).toEqual(json)
|
||||
expect(revert2).toEqual(patch)
|
||||
})
|
||||
|
||||
test('jsonpatch replace', t => {
|
||||
test('jsonpatch replace', () => {
|
||||
const json = {
|
||||
arr: [1,2,3],
|
||||
obj: {a : 4}
|
||||
|
@ -130,11 +131,11 @@ test('jsonpatch replace', t => {
|
|||
const revert = result.revert
|
||||
const patchedJson = esonToJson(patchedData)
|
||||
|
||||
assertDeepEqualEson(t, patchedData, jsonToEson({
|
||||
assertDeepEqualEson(patchedData, jsonToEson({
|
||||
arr: [1,200,3],
|
||||
obj: {a: 400}
|
||||
}))
|
||||
t.deepEqual(revert, [
|
||||
expect(revert).toEqual([
|
||||
{op: 'replace', path: '/arr/1', value: 2, meta: {type: 'value'}},
|
||||
{op: 'replace', path: '/obj/a', value: 4, meta: {type: 'value'}}
|
||||
])
|
||||
|
@ -146,14 +147,14 @@ test('jsonpatch replace', t => {
|
|||
const revert2 = result2.revert
|
||||
const patchedJson2 = esonToJson(patchedData2)
|
||||
|
||||
t.deepEqual(patchedJson2, json)
|
||||
t.deepEqual(revert2, [
|
||||
expect(patchedJson2).toEqual(json)
|
||||
expect(revert2).toEqual([
|
||||
{op: 'replace', path: '/obj/a', value: 400, meta: {type: 'value'}},
|
||||
{op: 'replace', path: '/arr/1', value: 200, meta: {type: 'value'}}
|
||||
])
|
||||
})
|
||||
|
||||
test('jsonpatch replace (keep ids intact)', t => {
|
||||
test('jsonpatch replace (keep ids intact)', () => {
|
||||
const json = { value: 42 }
|
||||
const patch = [
|
||||
{op: 'replace', path: '/value', value: 100}
|
||||
|
@ -165,10 +166,10 @@ test('jsonpatch replace (keep ids intact)', t => {
|
|||
const patchedData = patchEson(data, patch).data
|
||||
const patchedValueId = patchedData.value[META].id
|
||||
|
||||
t.is(patchedValueId, valueId)
|
||||
expect(patchedValueId).toEqual(valueId)
|
||||
})
|
||||
|
||||
test('jsonpatch copy', t => {
|
||||
test('jsonpatch copy', () => {
|
||||
const json = {
|
||||
arr: [1,2,3],
|
||||
obj: {a : 4}
|
||||
|
@ -184,11 +185,11 @@ test('jsonpatch copy', t => {
|
|||
const revert = result.revert
|
||||
const patchedJson = esonToJson(patchedData)
|
||||
|
||||
t.deepEqual(patchedJson, {
|
||||
expect(patchedJson).toEqual({
|
||||
arr: [1, 2, {a:4}, 3],
|
||||
obj: {a: 4}
|
||||
})
|
||||
t.deepEqual(revert, [
|
||||
expect(revert).toEqual([
|
||||
{op: 'remove', path: '/arr/2'}
|
||||
])
|
||||
|
||||
|
@ -199,13 +200,13 @@ test('jsonpatch copy', t => {
|
|||
const revert2 = result2.revert
|
||||
const patchedJson2 = esonToJson(patchedData2)
|
||||
|
||||
t.deepEqual(patchedJson2, json)
|
||||
t.deepEqual(revert2, [
|
||||
expect(patchedJson2).toEqual(json)
|
||||
expect(revert2).toEqual([
|
||||
{op: 'add', path: '/arr/2', value: {a: 4}, meta: {type: 'Object'}}
|
||||
])
|
||||
})
|
||||
|
||||
test('jsonpatch copy (keeps the same ids)', t => {
|
||||
test('jsonpatch copy (keeps the same ids)', () => {
|
||||
const json = { foo: { bar: 42 } }
|
||||
const patch = [
|
||||
{op: 'copy', from: '/foo', path: '/copied'}
|
||||
|
@ -221,16 +222,16 @@ test('jsonpatch copy (keeps the same ids)', t => {
|
|||
const copiedId = patchedData.copied[META].id
|
||||
const patchedCopiedBarId = patchedData.copied.bar[META].id
|
||||
|
||||
t.is(patchedFooId, fooId, 'same foo id')
|
||||
t.is(patchedBarId, barId, 'same bar id')
|
||||
expect(patchedFooId).toEqual(fooId)
|
||||
expect(patchedBarId).toEqual(barId)
|
||||
|
||||
t.not(copiedId, fooId, 'different id of property copied')
|
||||
expect(copiedId).not.toEqual(fooId)
|
||||
|
||||
// The id's of the copied childs are the same, that's okish, they will not bite each other
|
||||
t.is(patchedCopiedBarId, patchedBarId, 'same copied bar id')
|
||||
expect(patchedCopiedBarId).toEqual(patchedBarId)
|
||||
})
|
||||
|
||||
test('jsonpatch move', t => {
|
||||
test('jsonpatch move', () => {
|
||||
const json = {
|
||||
arr: [1,2,3],
|
||||
obj: {a : 4}
|
||||
|
@ -246,11 +247,11 @@ test('jsonpatch move', t => {
|
|||
const revert = result.revert
|
||||
const patchedJson = esonToJson(patchedData)
|
||||
|
||||
t.is(result.error, null)
|
||||
t.deepEqual(patchedJson, {
|
||||
expect(result.error).toEqual(null)
|
||||
expect(patchedJson).toEqual({
|
||||
arr: [1, 2, {a:4}, 3]
|
||||
})
|
||||
t.deepEqual(revert, [
|
||||
expect(revert).toEqual([
|
||||
{op: 'move', from: '/arr/2', path: '/obj'}
|
||||
])
|
||||
|
||||
|
@ -261,11 +262,11 @@ test('jsonpatch move', t => {
|
|||
const revert2 = result2.revert
|
||||
const patchedJson2 = esonToJson(patchedData2)
|
||||
|
||||
t.deepEqual(patchedJson2, json)
|
||||
t.deepEqual(revert2, patch)
|
||||
expect(patchedJson2).toEqual(json)
|
||||
expect(revert2).toEqual(patch)
|
||||
})
|
||||
|
||||
test('jsonpatch move before', t => {
|
||||
test('jsonpatch move before', () => {
|
||||
const json = {
|
||||
arr: [1,2,3],
|
||||
obj: {a : 4},
|
||||
|
@ -282,12 +283,12 @@ test('jsonpatch move before', t => {
|
|||
const revert = result.revert
|
||||
const patchedJson = esonToJson(patchedData)
|
||||
|
||||
t.is(result.error, null)
|
||||
t.deepEqual(patchedJson, {
|
||||
expect(result.error).toEqual(null)
|
||||
expect(patchedJson).toEqual({
|
||||
arr: [1, 2, {a:4}, 3],
|
||||
zzz: 'zzz'
|
||||
})
|
||||
t.deepEqual(revert, [
|
||||
expect(revert).toEqual([
|
||||
{op: 'move', from: '/arr/2', path: '/obj', meta: {before: 'zzz'}}
|
||||
])
|
||||
|
||||
|
@ -298,11 +299,11 @@ test('jsonpatch move before', t => {
|
|||
const revert2 = result2.revert
|
||||
const patchedJson2 = esonToJson(patchedData2)
|
||||
|
||||
t.deepEqual(patchedJson2, json)
|
||||
t.deepEqual(revert2, patch)
|
||||
expect(patchedJson2).toEqual(json)
|
||||
expect(revert2).toEqual(patch)
|
||||
})
|
||||
|
||||
test('jsonpatch move and replace', t => {
|
||||
test('jsonpatch move and replace', () => {
|
||||
const json = { a: 2, b: 3 }
|
||||
|
||||
const patch = [
|
||||
|
@ -317,11 +318,11 @@ test('jsonpatch move and replace', t => {
|
|||
const patchedJson = esonToJson(patchedData)
|
||||
|
||||
// id of the replaced B must be kept intact
|
||||
t.is(patchedData.b[META].id, data.b[META].id)
|
||||
expect(patchedData.b[META].id).toEqual(data.b[META].id)
|
||||
|
||||
assertDeepEqualEson(t, patchedData, jsonToEson({b: 2}))
|
||||
t.deepEqual(patchedJson, { b : 2 })
|
||||
t.deepEqual(revert, [
|
||||
assertDeepEqualEson(patchedData, jsonToEson({b: 2}))
|
||||
expect(patchedJson).toEqual({ b : 2 })
|
||||
expect(revert).toEqual([
|
||||
{op:'move', from: '/b', path: '/a'},
|
||||
{op:'add', path:'/b', value: 3, meta: {type: 'value', before: 'b'}}
|
||||
])
|
||||
|
@ -333,14 +334,14 @@ test('jsonpatch move and replace', t => {
|
|||
const revert2 = result2.revert
|
||||
const patchedJson2 = esonToJson(patchedData2)
|
||||
|
||||
t.deepEqual(patchedJson2, json)
|
||||
t.deepEqual(revert2, [
|
||||
expect(patchedJson2).toEqual(json)
|
||||
expect(revert2).toEqual([
|
||||
{op: 'remove', path: '/b'},
|
||||
{op: 'move', from: '/a', path: '/b'}
|
||||
])
|
||||
})
|
||||
|
||||
test('jsonpatch move and replace (nested)', t => {
|
||||
test('jsonpatch move and replace (nested)', () => {
|
||||
const json = {
|
||||
arr: [1,2,3],
|
||||
obj: {a : 4}
|
||||
|
@ -356,10 +357,10 @@ test('jsonpatch move and replace (nested)', t => {
|
|||
const revert = result.revert
|
||||
const patchedJson = esonToJson(patchedData)
|
||||
|
||||
t.deepEqual(patchedJson, {
|
||||
expect(patchedJson).toEqual({
|
||||
arr: {a:4}
|
||||
})
|
||||
t.deepEqual(revert, [
|
||||
expect(revert).toEqual([
|
||||
{op:'move', from: '/arr', path: '/obj'},
|
||||
{op:'add', path:'/arr', value: [1,2,3], meta: {type: 'Array'}}
|
||||
])
|
||||
|
@ -371,14 +372,14 @@ test('jsonpatch move and replace (nested)', t => {
|
|||
const revert2 = result2.revert
|
||||
const patchedJson2 = esonToJson(patchedData2)
|
||||
|
||||
t.deepEqual(patchedJson2, json)
|
||||
t.deepEqual(revert2, [
|
||||
expect(patchedJson2).toEqual(json)
|
||||
expect(revert2).toEqual([
|
||||
{op: 'remove', path: '/arr'},
|
||||
{op: 'move', from: '/obj', path: '/arr'}
|
||||
])
|
||||
})
|
||||
|
||||
test('jsonpatch move (keep id intact)', t => {
|
||||
test('jsonpatch move (keep id intact)', () => {
|
||||
const json = { value: 42 }
|
||||
const patch = [
|
||||
{op: 'move', from: '/value', path: '/moved'}
|
||||
|
@ -390,10 +391,10 @@ test('jsonpatch move (keep id intact)', t => {
|
|||
const patchedData = patchEson(data, patch).data
|
||||
const patchedValueId = patchedData.moved[META].id
|
||||
|
||||
t.is(patchedValueId, valueId)
|
||||
expect(patchedValueId).toEqual(valueId)
|
||||
})
|
||||
|
||||
test('jsonpatch move and replace (keep ids intact)', t => {
|
||||
test('jsonpatch move and replace (keep ids intact)', () => {
|
||||
const json = { a: 2, b: 3 }
|
||||
const patch = [
|
||||
{op: 'move', from: '/a', path: '/b'}
|
||||
|
@ -402,15 +403,15 @@ test('jsonpatch move and replace (keep ids intact)', t => {
|
|||
const data = jsonToEson(json)
|
||||
const bId = data.b[META].id
|
||||
|
||||
t.deepEqual(data[META].props, ['a', 'b'])
|
||||
expect(data[META].props).toEqual(['a', 'b'])
|
||||
|
||||
const patchedData = patchEson(data, patch).data
|
||||
|
||||
t.is(patchedData.b[META].id, bId)
|
||||
t.deepEqual(patchedData[META].props, ['b'])
|
||||
expect(patchedData.b[META].id).toEqual(bId)
|
||||
expect(patchedData[META].props).toEqual(['b'])
|
||||
})
|
||||
|
||||
test('jsonpatch test (ok)', t => {
|
||||
test('jsonpatch test (ok)', () => {
|
||||
const json = {
|
||||
arr: [1,2,3],
|
||||
obj: {a : 4}
|
||||
|
@ -427,18 +428,18 @@ test('jsonpatch test (ok)', t => {
|
|||
const revert = result.revert
|
||||
const patchedJson = esonToJson(patchedData)
|
||||
|
||||
t.deepEqual(patchedJson, {
|
||||
expect(patchedJson).toEqual({
|
||||
arr: [1,2,3],
|
||||
obj: {a : 4},
|
||||
added: 'ok'
|
||||
})
|
||||
t.deepEqual(revert, [
|
||||
expect(revert).toEqual([
|
||||
{op: 'remove', path: '/added'}
|
||||
])
|
||||
|
||||
})
|
||||
|
||||
test('jsonpatch test (fail: path not found)', t => {
|
||||
test('jsonpatch test (fail: path not found)', () => {
|
||||
const json = {
|
||||
arr: [1,2,3],
|
||||
obj: {a : 4}
|
||||
|
@ -456,15 +457,15 @@ test('jsonpatch test (fail: path not found)', t => {
|
|||
const patchedJson = esonToJson(patchedData)
|
||||
|
||||
// patch shouldn't be applied
|
||||
t.deepEqual(patchedJson, {
|
||||
expect(patchedJson).toEqual({
|
||||
arr: [1,2,3],
|
||||
obj: {a : 4}
|
||||
})
|
||||
t.deepEqual(revert, [])
|
||||
t.is(result.error.toString(), 'Error: Test failed, path not found')
|
||||
expect(revert).toEqual([])
|
||||
expect(result.error.toString()).toEqual('Error: Test failed, path not found')
|
||||
})
|
||||
|
||||
test('jsonpatch test (fail: value not equal)', t => {
|
||||
test('jsonpatch test (fail: value not equal)', () => {
|
||||
const json = {
|
||||
arr: [1,2,3],
|
||||
obj: {a : 4}
|
||||
|
@ -482,12 +483,12 @@ test('jsonpatch test (fail: value not equal)', t => {
|
|||
const patchedJson = esonToJson(patchedData)
|
||||
|
||||
// patch shouldn't be applied
|
||||
t.deepEqual(patchedJson, {
|
||||
expect(patchedJson).toEqual({
|
||||
arr: [1,2,3],
|
||||
obj: {a : 4}
|
||||
})
|
||||
t.deepEqual(revert, [])
|
||||
t.is(result.error.toString(), 'Error: Test failed, value differs')
|
||||
expect(revert).toEqual([])
|
||||
expect(result.error.toString()).toEqual('Error: Test failed, value differs')
|
||||
})
|
||||
|
||||
// helper function to print JSON in the console
|
|
@ -0,0 +1,104 @@
|
|||
/** JSDoc type definitions */
|
||||
|
||||
/**
|
||||
* @typedef {{} | [] | string | number | boolean | null} JSON
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* name: string?,
|
||||
* mode: 'code' | 'form' | 'text' | 'tree' | 'view'?,
|
||||
* modes: string[]?,
|
||||
* history: boolean?,
|
||||
* indentation: number | string?,
|
||||
* onChange: function (patch: ESONPatch, revert: ESONPatch)?,
|
||||
* onChangeText: function ()?,
|
||||
* onChangeMode: function (mode: string, prevMode: string)?,
|
||||
* onError: function (err: Error)?,
|
||||
* isPropertyEditable: function (Path)?
|
||||
* isValueEditable: function (Path)?,
|
||||
* escapeUnicode: boolean?,
|
||||
* expand: function(path: Path) : boolean?,
|
||||
* ajv: Object?,
|
||||
* ace: Object?
|
||||
* }} Options
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {string[]} Path
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* start?: Path,
|
||||
* end?: Path,
|
||||
* before?: Path,
|
||||
* after?: Path,
|
||||
* }} Selection
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{matches: ESONPointer[], active: ESONPointer, text: String}} SearchResult
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {'value' | 'property'} ESONPointerArea
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* path: Path,
|
||||
* area?: ESONPointerArea
|
||||
* }} ESONPointer
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {'normal' | 'active'} SearchResultStatus
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {'Object' | 'Array' | 'value' | 'string'} ESONType
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* op: 'add' | 'remove' | 'replace' | 'copy' | 'move' | 'test',
|
||||
* path: string,
|
||||
* from?: string,
|
||||
* value?: *,
|
||||
* meta?: ESONPatchOptions
|
||||
* }} ESONPatchAction
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {ESONPatchAction[]} ESONPatch
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {{
|
||||
* id: string,
|
||||
* path: Path,
|
||||
* type: ESONType,
|
||||
* before?: string
|
||||
* props?: string[],
|
||||
* expanded?: boolean,
|
||||
* selected?: boolean,
|
||||
* searchProperty?: SearchResultStatus,
|
||||
* searchValue?: SearchResultStatus
|
||||
* }} ESONPatchOptions
|
||||
*
|
||||
* // TODO: describe search results and selection
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object | Array} ESON
|
||||
*/
|
||||
|
||||
/**
|
||||
* TODO: change type of dataPath to Path? ESONPointer.path is an array, JSONSchemaError.path is a string -> make this consistent
|
||||
*
|
||||
* @typedef {{
|
||||
* dataPath: string,
|
||||
* message: string
|
||||
* }} JSONSchemaError
|
||||
*/
|
|
@ -0,0 +1,39 @@
|
|||
import {META} from "../eson"
|
||||
import lodashTransform from "lodash/transform"
|
||||
|
||||
export function assertDeepEqualEson (actual, expected, path = [], ignoreIds = true) {
|
||||
if (expected === undefined) {
|
||||
throw new Error('Argument "expected" is undefined')
|
||||
}
|
||||
|
||||
// console.log('assertDeepEqualEson', actual, expected)
|
||||
|
||||
const actualMeta = ignoreIds ? normalizeMetaIds(actual[META]) : actual[META]
|
||||
const expectedMeta = ignoreIds ? normalizeMetaIds(expected[META]) : expected[META]
|
||||
|
||||
expect(actualMeta).toEqual(expectedMeta) // `Meta data not equal, path=[${path.join(', ')}], actual[META]=${JSON.stringify(actualMeta)}, expected[META]=${JSON.stringify(expectedMeta)}`
|
||||
|
||||
if (actualMeta.type === 'Array') {
|
||||
expect(actual.length).toEqual(expected.length) // 'Actual lengths of arrays should be equal, path=[${path.join(\', \')}]'
|
||||
actual.forEach((item, index) => assertDeepEqualEson(actual[index], expected[index], path.concat(index)), ignoreIds)
|
||||
}
|
||||
else if (actualMeta.type === 'Object') {
|
||||
expect(Object.keys(actual).sort()).toEqual(Object.keys(expected).sort()) // 'Actual properties should be equal, path=[${path.join(\', \')}]'
|
||||
actualMeta.props.forEach(key => assertDeepEqualEson(actual[key], expected[key], path.concat(key)), ignoreIds)
|
||||
}
|
||||
else { // actual[META].type === 'value'
|
||||
expect(Object.keys(actual)).toEqual([]) // 'Value should not contain additional properties, path=[${path.join(\', \')}]'
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeMetaIds (meta) {
|
||||
return lodashTransform(meta, (result, value, key) => {
|
||||
if (key === 'id') {
|
||||
result[key] = '[ID]'
|
||||
}
|
||||
else {
|
||||
result[key] = value
|
||||
}
|
||||
}, {})
|
||||
}
|
||||
|
|
@ -188,7 +188,7 @@ export function getInternetExplorerVersion() {
|
|||
if (navigator.appName === 'Microsoft Internet Explorer')
|
||||
{
|
||||
const ua = navigator.userAgent
|
||||
const re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})")
|
||||
const re = new RegExp("MSIE ([0-9]{1,}[.0-9]{0,})")
|
||||
if (re.exec(ua) !== null) {
|
||||
rv = parseFloat( RegExp.$1 )
|
||||
}
|
|
@ -1,6 +1,4 @@
|
|||
'use strict';
|
||||
|
||||
import { isObjectOrArray, isObject } from './typeUtils'
|
||||
import { isObjectOrArray } from './typeUtils'
|
||||
|
||||
/**
|
||||
* Immutability helpers
|
|
@ -1,8 +1,6 @@
|
|||
import test from 'ava';
|
||||
import { getIn, setIn, updateIn, deleteIn, insertAt, transform } from '../src/utils/immutabilityHelpers'
|
||||
import { getIn, setIn, updateIn, deleteIn, insertAt } from './immutabilityHelpers'
|
||||
|
||||
|
||||
test('getIn', t => {
|
||||
test('getIn', () => {
|
||||
const obj = {
|
||||
a: {
|
||||
b: {
|
||||
|
@ -19,13 +17,13 @@ test('getIn', t => {
|
|||
]
|
||||
}
|
||||
|
||||
t.deepEqual(getIn(obj, ['a', 'b']), {c: 2})
|
||||
t.is(getIn(obj, ['e', '1', 'f']), 5)
|
||||
t.is(getIn(obj, ['e', '999', 'f']), undefined)
|
||||
t.is(getIn(obj, ['non', 'existing', 'path']), undefined)
|
||||
expect(getIn(obj, ['a', 'b'])).toEqual({c: 2})
|
||||
expect(getIn(obj, ['e', '1', 'f'])).toEqual(5)
|
||||
expect(getIn(obj, ['e', '999', 'f'])).toBeUndefined()
|
||||
expect(getIn(obj, ['non', 'existing', 'path'])).toBeUndefined()
|
||||
})
|
||||
|
||||
test('setIn basic', t => {
|
||||
test('setIn basic', () => {
|
||||
const obj = {
|
||||
a: {
|
||||
b: {
|
||||
|
@ -36,7 +34,7 @@ test('setIn basic', t => {
|
|||
}
|
||||
|
||||
const updated = setIn(obj, ['a', 'b', 'c'], 4)
|
||||
t.deepEqual (updated, {
|
||||
expect(updated).toEqual({
|
||||
a: {
|
||||
b: {
|
||||
c: 4
|
||||
|
@ -46,7 +44,7 @@ test('setIn basic', t => {
|
|||
})
|
||||
|
||||
// original should be unchanged
|
||||
t.deepEqual (obj, {
|
||||
expect(obj).toEqual({
|
||||
a: {
|
||||
b: {
|
||||
c: 2
|
||||
|
@ -55,25 +53,25 @@ test('setIn basic', t => {
|
|||
d: 3
|
||||
})
|
||||
|
||||
t.truthy (obj !== updated)
|
||||
expect(obj).not.toBe(updated)
|
||||
})
|
||||
|
||||
test('setIn non existing path', t => {
|
||||
test('setIn non existing path', () => {
|
||||
const obj = {}
|
||||
|
||||
t.throws(() => setIn(obj, ['a', 'b', 'c'], 4), /Path does not exist/)
|
||||
expect(() => setIn(obj, ['a', 'b', 'c'], 4)).toThrow(/Path does not exist/)
|
||||
})
|
||||
|
||||
test('setIn replace value with object should throw an exception', t => {
|
||||
test('setIn replace value with object should throw an exception', () => {
|
||||
const obj = {
|
||||
a: 42,
|
||||
d: 3
|
||||
}
|
||||
|
||||
t.throws(() => setIn(obj, ['a', 'b', 'c'], 4), /Path does not exist/)
|
||||
expect(() => setIn(obj, ['a', 'b', 'c'], 4)).toThrow(/Path does not exist/)
|
||||
})
|
||||
|
||||
test('setIn replace value inside nested array', t => {
|
||||
test('setIn replace value inside nested array', () => {
|
||||
const obj = {
|
||||
a: [
|
||||
1,
|
||||
|
@ -88,7 +86,7 @@ test('setIn replace value inside nested array', t => {
|
|||
|
||||
const updated = setIn(obj, ['a', '2', 'c'], 8)
|
||||
|
||||
t.deepEqual (updated, {
|
||||
expect(updated).toEqual({
|
||||
a: [
|
||||
1,
|
||||
2,
|
||||
|
@ -101,23 +99,23 @@ test('setIn replace value inside nested array', t => {
|
|||
})
|
||||
})
|
||||
|
||||
test('setIn identical value should return the original object', t => {
|
||||
test('setIn identical value should return the original object', () => {
|
||||
const obj = {a:1, b:2}
|
||||
|
||||
const updated = setIn(obj, ['b'], 2)
|
||||
|
||||
t.is(updated, obj) // strict equal
|
||||
expect(updated).toBe(obj) // strict equal
|
||||
})
|
||||
|
||||
test('setIn identical value should return the original object (2)', t => {
|
||||
test('setIn identical value should return the original object (2)', () => {
|
||||
const obj = {a:1, b: { c: 2}}
|
||||
|
||||
const updated = setIn(obj, ['b', 'c'], 2)
|
||||
|
||||
t.is(updated, obj) // strict equal
|
||||
expect(updated).toBe(obj) // strict equal
|
||||
})
|
||||
|
||||
test('updateIn', t => {
|
||||
test('updateIn', () => {
|
||||
const obj = {
|
||||
a: {
|
||||
b: {
|
||||
|
@ -128,7 +126,7 @@ test('updateIn', t => {
|
|||
}
|
||||
|
||||
const updated = updateIn(obj, ['a', 'b', 'c'], (value) => value + 100)
|
||||
t.deepEqual (updated, {
|
||||
expect(updated).toEqual({
|
||||
a: {
|
||||
b: {
|
||||
c: 102
|
||||
|
@ -138,7 +136,7 @@ test('updateIn', t => {
|
|||
})
|
||||
|
||||
// original should be unchanged
|
||||
t.deepEqual (obj, {
|
||||
expect(obj).toEqual({
|
||||
a: {
|
||||
b: {
|
||||
c: 2
|
||||
|
@ -147,10 +145,10 @@ test('updateIn', t => {
|
|||
d: 3
|
||||
})
|
||||
|
||||
t.truthy (obj !== updated)
|
||||
expect(obj).not.toBe(updated)
|
||||
})
|
||||
|
||||
test('updateIn (2)', t => {
|
||||
test('updateIn (2)', () => {
|
||||
const obj = {
|
||||
a: {
|
||||
b: {
|
||||
|
@ -161,7 +159,7 @@ test('updateIn (2)', t => {
|
|||
}
|
||||
|
||||
const updated = updateIn(obj, ['a', 'b' ], (obj) => [1,2,3])
|
||||
t.deepEqual (updated, {
|
||||
expect(updated).toEqual({
|
||||
a: {
|
||||
b: [1,2,3]
|
||||
},
|
||||
|
@ -169,7 +167,7 @@ test('updateIn (2)', t => {
|
|||
})
|
||||
})
|
||||
|
||||
test('updateIn (3)', t => {
|
||||
test('updateIn (3)', () => {
|
||||
const obj = {
|
||||
a: {
|
||||
b: {
|
||||
|
@ -180,7 +178,7 @@ test('updateIn (3)', t => {
|
|||
}
|
||||
|
||||
const updated = updateIn(obj, ['a', 'e' ], (value) => 'foo-' + value)
|
||||
t.deepEqual (updated, {
|
||||
expect(updated).toEqual({
|
||||
a: {
|
||||
b: {
|
||||
c: 2
|
||||
|
@ -191,17 +189,17 @@ test('updateIn (3)', t => {
|
|||
})
|
||||
})
|
||||
|
||||
test('updateIn return identical value should return the original object', t => {
|
||||
test('updateIn return identical value should return the original object', () => {
|
||||
const obj = {
|
||||
a: 2,
|
||||
b: 3
|
||||
}
|
||||
|
||||
const updated = updateIn(obj, ['b' ], (value) => 3)
|
||||
t.is(updated, obj)
|
||||
expect(updated).toBe(obj)
|
||||
})
|
||||
|
||||
test('deleteIn', t => {
|
||||
test('deleteIn', () => {
|
||||
const obj = {
|
||||
a: {
|
||||
b: {
|
||||
|
@ -213,7 +211,7 @@ test('deleteIn', t => {
|
|||
}
|
||||
|
||||
const updated = deleteIn(obj, ['a', 'b', 'c'])
|
||||
t.deepEqual (updated, {
|
||||
expect(updated).toEqual({
|
||||
a: {
|
||||
b: {
|
||||
d: 3
|
||||
|
@ -223,7 +221,7 @@ test('deleteIn', t => {
|
|||
})
|
||||
|
||||
// original should be unchanged
|
||||
t.deepEqual (obj, {
|
||||
expect(obj).toEqual({
|
||||
a: {
|
||||
b: {
|
||||
c: 2,
|
||||
|
@ -233,10 +231,10 @@ test('deleteIn', t => {
|
|||
e: 4
|
||||
})
|
||||
|
||||
t.truthy (obj !== updated)
|
||||
expect(obj).not.toBe(updated)
|
||||
})
|
||||
|
||||
test('deleteIn array', t => {
|
||||
test('deleteIn array', () => {
|
||||
const obj = {
|
||||
a: {
|
||||
b: [1, {c: 2, d: 3} , 4]
|
||||
|
@ -245,7 +243,7 @@ test('deleteIn array', t => {
|
|||
}
|
||||
|
||||
const updated = deleteIn(obj, ['a', 'b', '1', 'c'])
|
||||
t.deepEqual (updated, {
|
||||
expect(updated).toEqual({
|
||||
a: {
|
||||
b: [1, {d: 3} , 4]
|
||||
},
|
||||
|
@ -253,26 +251,26 @@ test('deleteIn array', t => {
|
|||
})
|
||||
|
||||
// original should be unchanged
|
||||
t.deepEqual (obj, {
|
||||
expect(obj).toEqual({
|
||||
a: {
|
||||
b: [1, {c: 2, d: 3} , 4]
|
||||
},
|
||||
e: 5
|
||||
})
|
||||
|
||||
t.truthy (obj !== updated)
|
||||
expect(obj).not.toBe(updated)
|
||||
})
|
||||
|
||||
test('deleteIn non existing path', t => {
|
||||
test('deleteIn non existing path', () => {
|
||||
const obj = { a: {}}
|
||||
|
||||
const updated = deleteIn(obj, ['a', 'b'])
|
||||
t.truthy (updated === obj)
|
||||
expect(updated).toBe(obj)
|
||||
})
|
||||
|
||||
test('insertAt', t => {
|
||||
test('insertAt', () => {
|
||||
const obj = { a: [1,2,3]}
|
||||
|
||||
const updated = insertAt(obj, ['a', '2'], 8)
|
||||
t.deepEqual(updated, {a: [1,2,8,3]})
|
||||
expect(updated).toEqual({a: [1,2,8,3]})
|
||||
})
|
|
@ -78,7 +78,7 @@ function normalizeKeyCombo (combo) {
|
|||
return upper
|
||||
}
|
||||
|
||||
const isMac = navigator.platform.toUpperCase().indexOf('MAC') >= 0
|
||||
const isMac = window.navigator.platform.toUpperCase().indexOf('MAC') >= 0
|
||||
|
||||
const metaCodes = {
|
||||
'Ctrl': true,
|
|
@ -18,7 +18,7 @@ export function escapeHTML (text, escapeUnicode = false) {
|
|||
}
|
||||
|
||||
htmlEscaped = htmlEscaped
|
||||
.replace(/ /g, ' \u00A0') // replace double space with an nbsp and space
|
||||
.replace(/ {2}/g, ' \u00A0') // replace double space with an nbsp and space
|
||||
.replace(/^ /, '\u00A0') // space at start
|
||||
.replace(/ $/, '\u00A0') // space at end
|
||||
|
||||
|
@ -48,8 +48,8 @@ export function escapeUnicodeChars (text) {
|
|||
* @return {String} text
|
||||
*/
|
||||
export function unescapeHTML (escapedText) {
|
||||
var json = '"' + escapeJSON(escapedText) + '"'
|
||||
var htmlEscaped = parseJSON(json)
|
||||
const json = '"' + escapeJSON(escapedText) + '"'
|
||||
const htmlEscaped = parseJSON(json)
|
||||
|
||||
return htmlEscaped.replace(/\u00A0/g, ' ') // nbsp character
|
||||
}
|
||||
|
@ -65,24 +65,24 @@ export function unescapeHTML (escapedText) {
|
|||
*/
|
||||
export function escapeJSON (text) {
|
||||
// TODO: replace with some smart regex (only when a new solution is faster!)
|
||||
var escaped = ''
|
||||
var i = 0
|
||||
let escaped = ''
|
||||
let i = 0
|
||||
while (i < text.length) {
|
||||
var c = text.charAt(i)
|
||||
if (c == '\n') {
|
||||
let c = text.charAt(i)
|
||||
if (c === '\n') {
|
||||
escaped += '\\n'
|
||||
}
|
||||
else if (c == '\\') {
|
||||
else if (c === '\\') {
|
||||
escaped += c
|
||||
i++
|
||||
|
||||
c = text.charAt(i)
|
||||
if (c === '' || '"\\/bfnrtu'.indexOf(c) == -1) {
|
||||
if (c === '' || '"\\/bfnrtu'.indexOf(c) === -1) {
|
||||
escaped += '\\' // no valid escape character
|
||||
}
|
||||
escaped += c
|
||||
}
|
||||
else if (c == '"') {
|
||||
else if (c === '"') {
|
||||
escaped += '\\"'
|
||||
}
|
||||
else {
|
|
@ -0,0 +1,25 @@
|
|||
import { escapeHTML, unescapeHTML, findUniqueName } from './stringUtils'
|
||||
|
||||
test('escapeHTML', () => {
|
||||
expect(escapeHTML(' hello ')).toEqual('\u00A0\u00A0 hello \u00A0')
|
||||
expect(escapeHTML('\u00A0 hello')).toEqual('\u00A0 hello')
|
||||
expect(escapeHTML('hello\nworld')).toEqual('hello\\nworld')
|
||||
|
||||
// TODO: test escapeHTML more thoroughly
|
||||
})
|
||||
|
||||
test('unescapeHTML', () => {
|
||||
expect(unescapeHTML(' \u00A0 hello \u00A0')).toEqual(' hello ')
|
||||
expect(unescapeHTML('\u00A0 hello')).toEqual(' hello')
|
||||
|
||||
expect(unescapeHTML('hello\\nworld')).toEqual('hello\nworld')
|
||||
|
||||
// TODO: test unescapeHTML more thoroughly
|
||||
})
|
||||
|
||||
test('findUniqueName', () => {
|
||||
expect(findUniqueName('other', ['a', 'b', 'c'])).toEqual('other')
|
||||
expect(findUniqueName('b', ['a', 'b', 'c'])).toEqual('b (copy)')
|
||||
expect(findUniqueName('b', ['a', 'b', 'c', 'b (copy)'])).toEqual('b (copy 2)')
|
||||
expect(findUniqueName('b', ['a', 'b', 'c', 'b (copy)', 'b (copy 2)'])).toEqual('b (copy 3)')
|
||||
})
|
114
src/types.js
114
src/types.js
|
@ -1,114 +0,0 @@
|
|||
// @flow
|
||||
|
||||
/**
|
||||
*
|
||||
* @typedef {{
|
||||
* name: string?,
|
||||
* mode: 'code' | 'form' | 'text' | 'tree' | 'view'?,
|
||||
* modes: string[]?,
|
||||
* history: boolean?,
|
||||
* indentation: number | string?,
|
||||
* onChange: function (patch: ESONPatch, revert: ESONPatch)?,
|
||||
* onChangeText: function ()?,
|
||||
* onChangeMode: function (mode: string, prevMode: string)?,
|
||||
* onError: function (err: Error)?,
|
||||
* isPropertyEditable: function (Path)?
|
||||
* isValueEditable: function (Path)?,
|
||||
* escapeUnicode: boolean?,
|
||||
* expand: function(path: Path) : boolean?,
|
||||
* ajv: Object?,
|
||||
* ace: Object?
|
||||
* }} Options
|
||||
*
|
||||
* @typedef {string[]} Path
|
||||
*
|
||||
* @typedef {{matches: ESONPointer[], active: ESONPointer, text: String}} SearchResult
|
||||
*
|
||||
*/
|
||||
|
||||
// FIXME: redefine all ESON related types
|
||||
|
||||
|
||||
/**************************** GENERIC JSON TYPES ******************************/
|
||||
|
||||
export type JSONType = | string | number | boolean | null | JSONObjectType | JSONArrayType
|
||||
export type JSONObjectType = { [key:string]: JSONType }
|
||||
export type JSONArrayType = JSONType[]
|
||||
|
||||
|
||||
/********************** TYPES FOR THE ESON OBJECT MODEL *************************/
|
||||
|
||||
export type SearchResultStatus = 'normal' | 'active'
|
||||
export type ESONPointerArea = 'value' | 'property'
|
||||
|
||||
export type ESONObject = {
|
||||
_meta: {
|
||||
type: 'Object',
|
||||
path: Path,
|
||||
expanded?: boolean,
|
||||
selected?: boolean,
|
||||
searchProperty?: SearchResultStatus,
|
||||
searchValue?: SearchResultStatus
|
||||
}
|
||||
}
|
||||
|
||||
export type ESONArray = {
|
||||
_meta: {
|
||||
type: 'Array',
|
||||
path: Path,
|
||||
length: number
|
||||
expanded?: boolean,
|
||||
selected?: boolean,
|
||||
searchProperty?: SearchResultStatus,
|
||||
searchValue?: SearchResultStatus
|
||||
}
|
||||
}
|
||||
|
||||
export type ESONValue = {
|
||||
_meta: {
|
||||
type: 'value' | 'string',
|
||||
path: Path,
|
||||
value: null | boolean | string | number,
|
||||
selected?: boolean,
|
||||
searchProperty?: SearchResultStatus,
|
||||
searchValue?: SearchResultStatus
|
||||
}
|
||||
}
|
||||
|
||||
export type ESON = ESONObject | ESONArray | ESONValue
|
||||
|
||||
export type ESONType = 'Object' | 'Array' | 'value' | 'string'
|
||||
|
||||
export type Path = string[]
|
||||
|
||||
export type ESONPointer = {
|
||||
path: Path,
|
||||
area?: ESONPointerArea
|
||||
}
|
||||
|
||||
export type Selection = {
|
||||
start?: Path,
|
||||
end?: Path,
|
||||
before?: Path,
|
||||
after?: Path
|
||||
}
|
||||
|
||||
export type ESONPatchAction = {
|
||||
op: string, // TODO: define allowed ops
|
||||
path: string,
|
||||
from?: string,
|
||||
value?: any,
|
||||
meta?: ESONPatchOptions
|
||||
}
|
||||
export type ESONPatch = ESONPatchAction[]
|
||||
|
||||
export type ESONPatchOptions = {
|
||||
type: ESONType,
|
||||
expand: (Path) => boolean
|
||||
}
|
||||
|
||||
// TODO: ESONPointer.path is an array, JSONSchemaError.path is a string -> make this consistent
|
||||
export type JSONSchemaError = {
|
||||
dataPath: string, // TODO: change type to Path
|
||||
message: string
|
||||
}
|
|
@ -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,14 +0,0 @@
|
|||
JSON Editor Icons
|
||||
|
||||
size: outer: 24x24 px
|
||||
inner: 16x16 px
|
||||
|
||||
blue background: RGBA 97b0f8ff
|
||||
gray background: RGBA 4d4d4dff
|
||||
grey background: RGBA d3d3d3ff
|
||||
|
||||
red foreground: RGBA ff3300ff
|
||||
green foreground: RGBA 13ae00ff
|
||||
|
||||
characters are based on the Arial font
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
|
@ -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
|
||||
|
|
@ -1,457 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var util = require('./util');
|
||||
|
||||
/**
|
||||
* A context menu
|
||||
* @param {Object[]} items Array containing the menu structure
|
||||
* TODO: describe structure
|
||||
* @param {Object} [options] Object with options. Available options:
|
||||
* {function} close Callback called when the
|
||||
* context menu is being closed.
|
||||
* @constructor
|
||||
*/
|
||||
function ContextMenu (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;
|
||||
|
||||
// create root element
|
||||
var 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 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 (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);
|
||||
|
||||
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 = {};
|
||||
|
||||
// create a menu item
|
||||
var 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;
|
||||
if (item.click) {
|
||||
// submenu and a button with a click handler
|
||||
button.className += ' jsoneditor-default';
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
buttonSubmenu = buttonExpand;
|
||||
}
|
||||
else {
|
||||
// submenu and a button without a click handler
|
||||
var divExpand = document.createElement('div');
|
||||
divExpand.className = 'jsoneditor-expand';
|
||||
button.appendChild(divExpand);
|
||||
|
||||
buttonSubmenu = button;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// 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(function (item) {
|
||||
var height = (items.length + (item.submenu ? item.submenu.length : 0)) * 24;
|
||||
me.maxHeight = Math.max(me.maxHeight, height);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently visible buttons
|
||||
* @return {Array.<HTMLElement>} buttons
|
||||
* @private
|
||||
*/
|
||||
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
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return buttons;
|
||||
};
|
||||
|
||||
// currently displayed context menu, a singleton. We may only have one visible context menu
|
||||
ContextMenu.visibleMenu = undefined;
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
// fits below -> show below
|
||||
}
|
||||
else if (anchorRect.top - this.maxHeight > contentRect.top) {
|
||||
// fits above -> show above
|
||||
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';
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
this.hide();
|
||||
|
||||
handled = true;
|
||||
}
|
||||
else if (keynum == 9) { // Tab
|
||||
if (!event.shiftKey) { // Tab
|
||||
buttons = this._getVisibleButtons();
|
||||
targetIndex = buttons.indexOf(target);
|
||||
if (targetIndex == buttons.length - 1) {
|
||||
// move to first button
|
||||
buttons[0].focus();
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
else { // Shift+Tab
|
||||
buttons = this._getVisibleButtons();
|
||||
targetIndex = buttons.indexOf(target);
|
||||
if (targetIndex == 0) {
|
||||
// move to last button
|
||||
buttons[buttons.length - 1].focus();
|
||||
handled = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (keynum == 37) { // Arrow Left
|
||||
if (target.className == 'jsoneditor-expand') {
|
||||
buttons = this._getVisibleButtons();
|
||||
targetIndex = buttons.indexOf(target);
|
||||
prevButton = buttons[targetIndex - 1];
|
||||
if (prevButton) {
|
||||
prevButton.focus();
|
||||
}
|
||||
}
|
||||
handled = true;
|
||||
}
|
||||
else if (keynum == 38) { // Arrow Up
|
||||
buttons = this._getVisibleButtons();
|
||||
targetIndex = buttons.indexOf(target);
|
||||
prevButton = buttons[targetIndex - 1];
|
||||
if (prevButton && prevButton.className == 'jsoneditor-expand') {
|
||||
// skip expand button
|
||||
prevButton = buttons[targetIndex - 2];
|
||||
}
|
||||
if (!prevButton) {
|
||||
// move to last button
|
||||
prevButton = buttons[buttons.length - 1];
|
||||
}
|
||||
if (prevButton) {
|
||||
prevButton.focus();
|
||||
}
|
||||
handled = true;
|
||||
}
|
||||
else if (keynum == 39) { // Arrow Right
|
||||
buttons = this._getVisibleButtons();
|
||||
targetIndex = buttons.indexOf(target);
|
||||
nextButton = buttons[targetIndex + 1];
|
||||
if (nextButton && nextButton.className == 'jsoneditor-expand') {
|
||||
nextButton.focus();
|
||||
}
|
||||
handled = true;
|
||||
}
|
||||
else if (keynum == 40) { // Arrow Down
|
||||
buttons = this._getVisibleButtons();
|
||||
targetIndex = buttons.indexOf(target);
|
||||
nextButton = buttons[targetIndex + 1];
|
||||
if (nextButton && nextButton.className == 'jsoneditor-expand') {
|
||||
// skip expand button
|
||||
nextButton = buttons[targetIndex + 2];
|
||||
}
|
||||
if (!nextButton) {
|
||||
// move to first button
|
||||
nextButton = buttons[0];
|
||||
}
|
||||
if (nextButton) {
|
||||
nextButton.focus();
|
||||
handled = true;
|
||||
}
|
||||
handled = true;
|
||||
}
|
||||
// TODO: arrow left and right
|
||||
|
||||
if (handled) {
|
||||
event.stopPropagation();
|
||||
event.preventDefault();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
e = e.parentNode;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
module.exports = ContextMenu;
|
|
@ -1,86 +0,0 @@
|
|||
'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;
|
||||
}
|
||||
|
||||
if (this.node != node) {
|
||||
// unhighlight current node
|
||||
if (this.node) {
|
||||
this.node.setHighlight(false);
|
||||
}
|
||||
|
||||
// highlight new node
|
||||
this.node = node;
|
||||
this.node.setHighlight(true);
|
||||
}
|
||||
|
||||
// cancel any current timeout
|
||||
this._cancelUnhighlight();
|
||||
};
|
||||
|
||||
/**
|
||||
* Unhighlight currently highlighted node.
|
||||
* Will be done after a delay
|
||||
*/
|
||||
Highlighter.prototype.unhighlight = function () {
|
||||
if (this.locked) {
|
||||
return;
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
Highlighter.prototype.lock = function () {
|
||||
this.locked = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Unlock highlighting or unhighlighting nodes
|
||||
*/
|
||||
Highlighter.prototype.unlock = function () {
|
||||
this.locked = false;
|
||||
};
|
||||
|
||||
module.exports = Highlighter;
|
|
@ -1,267 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var util = require('./util');
|
||||
|
||||
/**
|
||||
* @constructor History
|
||||
* Store action history, enables undo and redo
|
||||
* @param {JSONEditor} editor
|
||||
*/
|
||||
function History (editor) {
|
||||
this.editor = editor;
|
||||
this.history = [];
|
||||
this.index = -1;
|
||||
|
||||
this.clear();
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
*/
|
||||
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,385 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var Ajv;
|
||||
try {
|
||||
Ajv = require('ajv');
|
||||
}
|
||||
catch (err) {
|
||||
// no problem... when we need Ajv we will throw a neat exception
|
||||
}
|
||||
|
||||
var treemode = require('./treemode');
|
||||
var textmode = require('./textmode');
|
||||
var util = require('./util');
|
||||
|
||||
/**
|
||||
* @constructor JSONEditor
|
||||
* @param {Element} container Container element
|
||||
* @param {Object} [options] Object with options. available options:
|
||||
* {String} mode Editor mode. Available values:
|
||||
* 'tree' (default), 'view',
|
||||
* 'form', 'text', and 'code'.
|
||||
* {function} onChange Callback method, triggered
|
||||
* on change of contents
|
||||
* {function} onError Callback method, triggered
|
||||
* when an error occurs
|
||||
* {Boolean} search Enable search box.
|
||||
* True by default
|
||||
* Only applicable for modes
|
||||
* 'tree', 'view', and 'form'
|
||||
* {Boolean} history Enable history (undo/redo).
|
||||
* True by default
|
||||
* Only applicable for modes
|
||||
* 'tree', 'view', and 'form'
|
||||
* {String} name Field name for the root node.
|
||||
* Only applicable for modes
|
||||
* 'tree', 'view', and 'form'
|
||||
* {Number} indentation Number of indentation
|
||||
* spaces. 4 by default.
|
||||
* Only applicable for
|
||||
* modes 'text' and 'code'
|
||||
* {boolean} escapeUnicode If true, unicode
|
||||
* characters are escaped.
|
||||
* false by default.
|
||||
* {boolean} sortObjectKeys If true, object keys are
|
||||
* sorted before display.
|
||||
* false by default.
|
||||
* @param {Object | undefined} json JSON object
|
||||
*/
|
||||
function JSONEditor (container, options, json) {
|
||||
if (!(this instanceof JSONEditor)) {
|
||||
throw new Error('JSONEditor constructor called without "new".');
|
||||
}
|
||||
|
||||
// check for unsupported browser (IE8 and older)
|
||||
var ieVersion = util.getInternetExplorerVersion();
|
||||
if (ieVersion != -1 && ieVersion < 9) {
|
||||
throw new Error('Unsupported browser, IE9 or newer required. ' +
|
||||
'Please install the newest version of your browser.');
|
||||
}
|
||||
|
||||
if (options) {
|
||||
// check for deprecated options
|
||||
if (options.error) {
|
||||
console.warn('Option "error" has been renamed to "onError"');
|
||||
options.onError = options.error;
|
||||
delete options.error;
|
||||
}
|
||||
if (options.change) {
|
||||
console.warn('Option "change" has been renamed to "onChange"');
|
||||
options.onChange = options.change;
|
||||
delete options.change;
|
||||
}
|
||||
if (options.editable) {
|
||||
console.warn('Option "editable" has been renamed to "onEditable"');
|
||||
options.onEditable = options.editable;
|
||||
delete options.editable;
|
||||
}
|
||||
|
||||
// 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');
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (arguments.length) {
|
||||
this._create(container, options, json);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Configuration for all registered modes. Example:
|
||||
* {
|
||||
* tree: {
|
||||
* mixin: TreeEditor,
|
||||
* data: 'json'
|
||||
* },
|
||||
* text: {
|
||||
* mixin: TextEditor,
|
||||
* data: 'text'
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* @type { Object.<String, {mixin: Object, data: String} > }
|
||||
*/
|
||||
JSONEditor.modes = {};
|
||||
|
||||
// debounce interval for JSON schema vaidation in milliseconds
|
||||
JSONEditor.prototype.DEBOUNCE_INTERVAL = 150;
|
||||
|
||||
/**
|
||||
* Create the JSONEditor
|
||||
* @param {Element} container Container element
|
||||
* @param {Object} [options] See description in constructor
|
||||
* @param {Object | undefined} json JSON object
|
||||
* @private
|
||||
*/
|
||||
JSONEditor.prototype._create = function (container, options, json) {
|
||||
this.container = container;
|
||||
this.options = options || {};
|
||||
this.json = json || {};
|
||||
|
||||
var mode = this.options.mode || 'tree';
|
||||
this.setMode(mode);
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroy the editor. Clean up DOM, event listeners, and web workers.
|
||||
*/
|
||||
JSONEditor.prototype.destroy = function () {};
|
||||
|
||||
/**
|
||||
* Set JSON object in editor
|
||||
* @param {Object | undefined} json JSON data
|
||||
*/
|
||||
JSONEditor.prototype.set = function (json) {
|
||||
this.json = json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get JSON from the editor
|
||||
* @returns {Object} json
|
||||
*/
|
||||
JSONEditor.prototype.get = function () {
|
||||
return this.json;
|
||||
};
|
||||
|
||||
/**
|
||||
* Set string containing JSON for the editor
|
||||
* @param {String | undefined} jsonText
|
||||
*/
|
||||
JSONEditor.prototype.setText = function (jsonText) {
|
||||
this.json = util.parse(jsonText);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get stringified JSON contents from the editor
|
||||
* @returns {String} jsonText
|
||||
*/
|
||||
JSONEditor.prototype.getText = function () {
|
||||
return JSON.stringify(this.json);
|
||||
};
|
||||
|
||||
/**
|
||||
* Set a field name for the root node.
|
||||
* @param {String | undefined} name
|
||||
*/
|
||||
JSONEditor.prototype.setName = function (name) {
|
||||
if (!this.options) {
|
||||
this.options = {};
|
||||
}
|
||||
this.options.name = name;
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the field name for the root node.
|
||||
* @return {String | undefined} name
|
||||
*/
|
||||
JSONEditor.prototype.getName = function () {
|
||||
return this.options && this.options.name;
|
||||
};
|
||||
|
||||
/**
|
||||
* Change the mode of the editor.
|
||||
* JSONEditor will be extended with all methods needed for the chosen mode.
|
||||
* @param {String} mode Available modes: 'tree' (default), 'view', 'form',
|
||||
* 'text', and 'code'.
|
||||
*/
|
||||
JSONEditor.prototype.setMode = function (mode) {
|
||||
var container = this.container;
|
||||
var options = util.extend({}, this.options);
|
||||
var oldMode = options.mode;
|
||||
var data;
|
||||
var name;
|
||||
|
||||
options.mode = mode;
|
||||
var config = JSONEditor.modes[mode];
|
||||
if (config) {
|
||||
try {
|
||||
var 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.setName(name);
|
||||
this[asText ? 'setText' : 'set'](data); // set text or json
|
||||
|
||||
if (typeof config.load === 'function') {
|
||||
try {
|
||||
config.load.call(this);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
|
||||
if (typeof options.onModeChange === 'function' && mode !== oldMode) {
|
||||
try {
|
||||
options.onModeChange(mode, oldMode);
|
||||
}
|
||||
catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (err) {
|
||||
this._onError(err);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new Error('Unknown mode "' + options.mode + '"');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the current mode
|
||||
* @return {string}
|
||||
*/
|
||||
JSONEditor.prototype.getMode = function () {
|
||||
return this.options.mode;
|
||||
};
|
||||
|
||||
/**
|
||||
* Throw an error. If an error callback is configured in options.error, this
|
||||
* callback will be invoked. Else, a regular error is thrown.
|
||||
* @param {Error} err
|
||||
* @private
|
||||
*/
|
||||
JSONEditor.prototype._onError = function(err) {
|
||||
if (this.options && typeof this.options.onError === 'function') {
|
||||
this.options.onError(err);
|
||||
}
|
||||
else {
|
||||
throw err;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Set a JSON schema for validation of the JSON object.
|
||||
* To remove the schema, call JSONEditor.setSchema(null)
|
||||
* @param {Object | null} schema
|
||||
*/
|
||||
JSONEditor.prototype.setSchema = function (schema) {
|
||||
// compile a JSON schema validator if a JSON schema is provided
|
||||
if (schema) {
|
||||
var ajv;
|
||||
try {
|
||||
// grab ajv from options if provided, else create a new instance
|
||||
ajv = this.options.ajv || Ajv({ allErrors: true, verbose: 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`.');
|
||||
}
|
||||
|
||||
if (ajv) {
|
||||
this.validateSchema = ajv.compile(schema);
|
||||
|
||||
// add schema to the options, so that when switching to an other mode,
|
||||
// the set schema is not lost
|
||||
this.options.schema = schema;
|
||||
|
||||
// validate now
|
||||
this.validate();
|
||||
}
|
||||
|
||||
this.refresh(); // update DOM
|
||||
}
|
||||
else {
|
||||
// remove current schema
|
||||
this.validateSchema = null;
|
||||
this.options.schema = null;
|
||||
this.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 () {
|
||||
// must be implemented by treemode and textmode
|
||||
};
|
||||
|
||||
/**
|
||||
* Refresh the rendered contents
|
||||
*/
|
||||
JSONEditor.prototype.refresh = function () {
|
||||
// can be implemented by treemode and textmode
|
||||
};
|
||||
|
||||
/**
|
||||
* Register a plugin with one ore multiple modes for the JSON Editor.
|
||||
*
|
||||
* A mode is described as an object with properties:
|
||||
*
|
||||
* - `mode: String` The name of the mode.
|
||||
* - `mixin: Object` An object containing the mixin functions which
|
||||
* will be added to the JSONEditor. Must contain functions
|
||||
* create, get, getText, set, and setText. May have
|
||||
* additional functions.
|
||||
* When the JSONEditor switches to a mixin, all mixin
|
||||
* functions are added to the JSONEditor, and then
|
||||
* the function `create(container, options)` is executed.
|
||||
* - `data: 'text' | 'json'` The type of data that will be used to load the mixin.
|
||||
* - `[load: function]` An optional function called after the mixin
|
||||
* has been loaded.
|
||||
*
|
||||
* @param {Object | Array} mode A mode object or an array with multiple mode objects.
|
||||
*/
|
||||
JSONEditor.registerMode = function (mode) {
|
||||
var i, prop;
|
||||
|
||||
if (util.isArray(mode)) {
|
||||
// multiple modes
|
||||
for (i = 0; i < mode.length; i++) {
|
||||
JSONEditor.registerMode(mode[i]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
// validate the new mode
|
||||
if (!('mode' in mode)) throw new Error('Property "mode" missing');
|
||||
if (!('mixin' in mode)) throw new Error('Property "mixin" missing');
|
||||
if (!('data' in mode)) throw new Error('Property "data" missing');
|
||||
var name = mode.mode;
|
||||
if (name in JSONEditor.modes) {
|
||||
throw new Error('Mode "' + name + '" already registered');
|
||||
}
|
||||
|
||||
// validate the mixin
|
||||
if (typeof mode.mixin.create !== 'function') {
|
||||
throw new Error('Required function "create" missing on mixin');
|
||||
}
|
||||
var reserved = ['setMode', 'registerMode', 'modes'];
|
||||
for (i = 0; i < reserved.length; i++) {
|
||||
prop = reserved[i];
|
||||
if (prop in mode.mixin) {
|
||||
throw new Error('Reserved property "' + prop + '" not allowed in mixin');
|
||||
}
|
||||
}
|
||||
|
||||
JSONEditor.modes[name] = mode;
|
||||
}
|
||||
};
|
||||
|
||||
// register tree and text modes
|
||||
JSONEditor.registerMode(treemode);
|
||||
JSONEditor.registerMode(textmode);
|
||||
|
||||
module.exports = JSONEditor;
|
|
@ -1,114 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var ContextMenu = require('./ContextMenu');
|
||||
|
||||
/**
|
||||
* 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 {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');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 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 + '"');
|
||||
}
|
||||
|
||||
item.className = 'jsoneditor-type-modes' + ((current == mode) ? ' jsoneditor-selected' : '');
|
||||
items.push(item);
|
||||
}
|
||||
|
||||
// retrieve the title of current mode
|
||||
var currentMode = availableModes[current];
|
||||
if (!currentMode) {
|
||||
throw new Error('Unknown mode "' + current + '"');
|
||||
}
|
||||
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
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
3526
src_old/js/Node.js
3526
src_old/js/Node.js
File diff suppressed because it is too large
Load Diff
|
@ -1,312 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
/**
|
||||
* @constructor SearchBox
|
||||
* Create a search box in given HTML container
|
||||
* @param {JSONEditor} editor The JSON Editor to attach to
|
||||
* @param {Element} container HTML container element of where to
|
||||
* create the search box
|
||||
*/
|
||||
function SearchBox (editor, container) {
|
||||
var searchBox = this;
|
||||
|
||||
this.editor = editor;
|
||||
this.timeout = undefined;
|
||||
this.delay = 200; // ms
|
||||
this.lastText = undefined;
|
||||
|
||||
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);
|
||||
|
||||
var td = document.createElement('td');
|
||||
tr.appendChild(td);
|
||||
var results = document.createElement('div');
|
||||
this.dom.results = results;
|
||||
results.className = 'jsoneditor-results';
|
||||
td.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);
|
||||
|
||||
// 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);
|
||||
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
else {
|
||||
delete prevNode.searchValueActive;
|
||||
}
|
||||
prevNode.updateDom();
|
||||
}
|
||||
|
||||
if (!this.results || !this.results[index]) {
|
||||
// out of range, set to undefined
|
||||
this.resultIndex = undefined;
|
||||
this.activeResult = undefined;
|
||||
return;
|
||||
}
|
||||
|
||||
this.resultIndex = index;
|
||||
|
||||
// set new node active
|
||||
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);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Cancel any running onDelayedSearch.
|
||||
* @private
|
||||
*/
|
||||
SearchBox.prototype._clearDelay = function() {
|
||||
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
|
||||
*/
|
||||
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);
|
||||
};
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
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);
|
||||
|
||||
// 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;
|
||||
}
|
||||
}
|
||||
else {
|
||||
this.dom.results.innerHTML = '';
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
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
|
||||
*/
|
||||
SearchBox.prototype.clear = function () {
|
||||
this.dom.search.value = '';
|
||||
this._onSearch();
|
||||
};
|
||||
|
||||
/**
|
||||
* Destroy the search box
|
||||
*/
|
||||
SearchBox.prototype.destroy = function () {
|
||||
this.editor = null;
|
||||
this.dom.container.removeChild(this.dom.table);
|
||||
this.dom = null;
|
||||
|
||||
this.results = null;
|
||||
this.activeResult = null;
|
||||
|
||||
this._clearDelay();
|
||||
|
||||
};
|
||||
|
||||
module.exports = SearchBox;
|
|
@ -1,9 +0,0 @@
|
|||
// load brace
|
||||
var ace = require('brace');
|
||||
|
||||
// load required ace modules
|
||||
require('brace/mode/json');
|
||||
require('brace/ext/searchbox');
|
||||
require('./theme-jsoneditor');
|
||||
|
||||
module.exports = ace;
|
|
@ -1,144 +0,0 @@
|
|||
/* ***** BEGIN LICENSE BLOCK *****
|
||||
* Distributed under the BSD license:
|
||||
*
|
||||
* Copyright (c) 2010, Ajax.org B.V.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Ajax.org B.V. nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL AJAX.ORG B.V. BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ***** END LICENSE BLOCK ***** */
|
||||
|
||||
ace.define('ace/theme/jsoneditor', ['require', 'exports', 'module', 'ace/lib/dom'], function(acequire, exports, module) {
|
||||
|
||||
exports.isDark = false;
|
||||
exports.cssClass = "ace-jsoneditor";
|
||||
exports.cssText = ".ace-jsoneditor .ace_gutter {\
|
||||
background: #ebebeb;\
|
||||
color: #333\
|
||||
}\
|
||||
\
|
||||
.ace-jsoneditor.ace_editor {\
|
||||
font-family: droid sans mono, consolas, monospace, courier new, courier, sans-serif;\
|
||||
line-height: 1.3;\
|
||||
}\
|
||||
.ace-jsoneditor .ace_print-margin {\
|
||||
width: 1px;\
|
||||
background: #e8e8e8\
|
||||
}\
|
||||
.ace-jsoneditor .ace_scroller {\
|
||||
background-color: #FFFFFF\
|
||||
}\
|
||||
.ace-jsoneditor .ace_text-layer {\
|
||||
color: gray\
|
||||
}\
|
||||
.ace-jsoneditor .ace_variable {\
|
||||
color: #1a1a1a\
|
||||
}\
|
||||
.ace-jsoneditor .ace_cursor {\
|
||||
border-left: 2px solid #000000\
|
||||
}\
|
||||
.ace-jsoneditor .ace_overwrite-cursors .ace_cursor {\
|
||||
border-left: 0px;\
|
||||
border-bottom: 1px solid #000000\
|
||||
}\
|
||||
.ace-jsoneditor .ace_marker-layer .ace_selection {\
|
||||
background: lightgray\
|
||||
}\
|
||||
.ace-jsoneditor.ace_multiselect .ace_selection.ace_start {\
|
||||
box-shadow: 0 0 3px 0px #FFFFFF;\
|
||||
border-radius: 2px\
|
||||
}\
|
||||
.ace-jsoneditor .ace_marker-layer .ace_step {\
|
||||
background: rgb(255, 255, 0)\
|
||||
}\
|
||||
.ace-jsoneditor .ace_marker-layer .ace_bracket {\
|
||||
margin: -1px 0 0 -1px;\
|
||||
border: 1px solid #BFBFBF\
|
||||
}\
|
||||
.ace-jsoneditor .ace_marker-layer .ace_active-line {\
|
||||
background: #FFFBD1\
|
||||
}\
|
||||
.ace-jsoneditor .ace_gutter-active-line {\
|
||||
background-color : #dcdcdc\
|
||||
}\
|
||||
.ace-jsoneditor .ace_marker-layer .ace_selected-word {\
|
||||
border: 1px solid lightgray\
|
||||
}\
|
||||
.ace-jsoneditor .ace_invisible {\
|
||||
color: #BFBFBF\
|
||||
}\
|
||||
.ace-jsoneditor .ace_keyword,\
|
||||
.ace-jsoneditor .ace_meta,\
|
||||
.ace-jsoneditor .ace_support.ace_constant.ace_property-value {\
|
||||
color: #AF956F\
|
||||
}\
|
||||
.ace-jsoneditor .ace_keyword.ace_operator {\
|
||||
color: #484848\
|
||||
}\
|
||||
.ace-jsoneditor .ace_keyword.ace_other.ace_unit {\
|
||||
color: #96DC5F\
|
||||
}\
|
||||
.ace-jsoneditor .ace_constant.ace_language {\
|
||||
color: darkorange\
|
||||
}\
|
||||
.ace-jsoneditor .ace_constant.ace_numeric {\
|
||||
color: red\
|
||||
}\
|
||||
.ace-jsoneditor .ace_constant.ace_character.ace_entity {\
|
||||
color: #BF78CC\
|
||||
}\
|
||||
.ace-jsoneditor .ace_invalid {\
|
||||
color: #FFFFFF;\
|
||||
background-color: #FF002A;\
|
||||
}\
|
||||
.ace-jsoneditor .ace_fold {\
|
||||
background-color: #AF956F;\
|
||||
border-color: #000000\
|
||||
}\
|
||||
.ace-jsoneditor .ace_storage,\
|
||||
.ace-jsoneditor .ace_support.ace_class,\
|
||||
.ace-jsoneditor .ace_support.ace_function,\
|
||||
.ace-jsoneditor .ace_support.ace_other,\
|
||||
.ace-jsoneditor .ace_support.ace_type {\
|
||||
color: #C52727\
|
||||
}\
|
||||
.ace-jsoneditor .ace_string {\
|
||||
color: green\
|
||||
}\
|
||||
.ace-jsoneditor .ace_comment {\
|
||||
color: #BCC8BA\
|
||||
}\
|
||||
.ace-jsoneditor .ace_entity.ace_name.ace_tag,\
|
||||
.ace-jsoneditor .ace_entity.ace_other.ace_attribute-name {\
|
||||
color: #606060\
|
||||
}\
|
||||
.ace-jsoneditor .ace_markup.ace_underline {\
|
||||
text-decoration: underline\
|
||||
}\
|
||||
.ace-jsoneditor .ace_indent-guide {\
|
||||
background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y\
|
||||
}";
|
||||
|
||||
var dom = acequire("../lib/dom");
|
||||
dom.importCssString(exports.cssText, exports.cssClass);
|
||||
});
|
|
@ -1,228 +0,0 @@
|
|||
'use strict';
|
||||
|
||||
var util = require('./util');
|
||||
var ContextMenu = require('./ContextMenu');
|
||||
|
||||
/**
|
||||
* A factory function to create an AppendNode, which depends on a Node
|
||||
* @param {Node} Node
|
||||
*/
|
||||
function appendNodeFactory(Node) {
|
||||
/**
|
||||
* @constructor AppendNode
|
||||
* @extends Node
|
||||
* @param {TreeEditor} editor
|
||||
* Create a new AppendNode. This is a special node which is created at the
|
||||
* end of the list with childs for an object or array
|
||||
*/
|
||||
function AppendNode (editor) {
|
||||
/** @type {TreeEditor} */
|
||||
this.editor = editor;
|
||||
this.dom = {};
|
||||
}
|
||||
|
||||
AppendNode.prototype = new Node();
|
||||
|
||||
/**
|
||||
* Return a table row with an append button.
|
||||
* @return {Element} dom TR element
|
||||
*/
|
||||
AppendNode.prototype.getDom = function () {
|
||||
// TODO: implement a new solution for the append node
|
||||
var dom = this.dom;
|
||||
|
||||
if (dom.tr) {
|
||||
return dom.tr;
|
||||
}
|
||||
|
||||
this._updateEditability();
|
||||
|
||||
// a row for the append button
|
||||
var trAppend = document.createElement('tr');
|
||||
trAppend.node = this;
|
||||
dom.tr = trAppend;
|
||||
|
||||
// TODO: consistent naming
|
||||
|
||||
if (this.editor.options.mode === 'tree') {
|
||||
// a cell for the dragarea column
|
||||
dom.tdDrag = document.createElement('td');
|
||||
|
||||
// create context menu
|
||||
var tdMenu = document.createElement('td');
|
||||
dom.tdMenu = tdMenu;
|
||||
var menu = document.createElement('button');
|
||||
menu.className = 'jsoneditor-contextmenu';
|
||||
menu.title = 'Click to open the actions menu (Ctrl+M)';
|
||||
dom.menu = menu;
|
||||
tdMenu.appendChild(dom.menu);
|
||||
}
|
||||
|
||||
// a cell for the contents (showing text 'empty')
|
||||
var tdAppend = document.createElement('td');
|
||||
var domText = document.createElement('div');
|
||||
domText.innerHTML = '(empty)';
|
||||
domText.className = 'jsoneditor-readonly';
|
||||
tdAppend.appendChild(domText);
|
||||
dom.td = tdAppend;
|
||||
dom.text = domText;
|
||||
|
||||
this.updateDom();
|
||||
|
||||
return trAppend;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the HTML dom of the Node
|
||||
*/
|
||||
AppendNode.prototype.updateDom = function () {
|
||||
var dom = this.dom;
|
||||
var tdAppend = dom.td;
|
||||
if (tdAppend) {
|
||||
tdAppend.style.paddingLeft = (this.getLevel() * 24 + 26) + 'px';
|
||||
// TODO: not so nice hard coded offset
|
||||
}
|
||||
|
||||
var domText = dom.text;
|
||||
if (domText) {
|
||||
domText.innerHTML = '(empty ' + this.parent.type + ')';
|
||||
}
|
||||
|
||||
// attach or detach the contents of the append node:
|
||||
// hide when the parent has childs, show when the parent has no childs
|
||||
var trAppend = dom.tr;
|
||||
if (!this.isVisible()) {
|
||||
if (dom.tr.firstChild) {
|
||||
if (dom.tdDrag) {
|
||||
trAppend.removeChild(dom.tdDrag);
|
||||
}
|
||||
if (dom.tdMenu) {
|
||||
trAppend.removeChild(dom.tdMenu);
|
||||
}
|
||||
trAppend.removeChild(tdAppend);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (!dom.tr.firstChild) {
|
||||
if (dom.tdDrag) {
|
||||
trAppend.appendChild(dom.tdDrag);
|
||||
}
|
||||
if (dom.tdMenu) {
|
||||
trAppend.appendChild(dom.tdMenu);
|
||||
}
|
||||
trAppend.appendChild(tdAppend);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Check whether the AppendNode is currently visible.
|
||||
* the AppendNode is visible when its parent has no childs (i.e. is empty).
|
||||
* @return {boolean} isVisible
|
||||
*/
|
||||
AppendNode.prototype.isVisible = function () {
|
||||
return (this.parent.childs.length == 0);
|
||||
};
|
||||
|
||||
/**
|
||||
* Show a contextmenu for this node
|
||||
* @param {HTMLElement} anchor The element to attach the menu to.
|
||||
* @param {function} [onClose] Callback method called when the context menu
|
||||
* is being closed.
|
||||
*/
|
||||
AppendNode.prototype.showContextMenu = function (anchor, onClose) {
|
||||
var node = this;
|
||||
var titles = Node.TYPE_TITLES;
|
||||
var items = [
|
||||
// create append button
|
||||
{
|
||||
'text': 'Append',
|
||||
'title': 'Append a new field with type \'auto\' (Ctrl+Shift+Ins)',
|
||||
'submenuTitle': 'Select the type of the field to be appended',
|
||||
'className': 'jsoneditor-insert',
|
||||
'click': function () {
|
||||
node._onAppend('', '', 'auto');
|
||||
},
|
||||
'submenu': [
|
||||
{
|
||||
'text': 'Auto',
|
||||
'className': 'jsoneditor-type-auto',
|
||||
'title': titles.auto,
|
||||
'click': function () {
|
||||
node._onAppend('', '', 'auto');
|
||||
}
|
||||
},
|
||||
{
|
||||
'text': 'Array',
|
||||
'className': 'jsoneditor-type-array',
|
||||
'title': titles.array,
|
||||
'click': function () {
|
||||
node._onAppend('', []);
|
||||
}
|
||||
},
|
||||
{
|
||||
'text': 'Object',
|
||||
'className': 'jsoneditor-type-object',
|
||||
'title': titles.object,
|
||||
'click': function () {
|
||||
node._onAppend('', {});
|
||||
}
|
||||
},
|
||||
{
|
||||
'text': 'String',
|
||||
'className': 'jsoneditor-type-string',
|
||||
'title': titles.string,
|
||||
'click': function () {
|
||||
node._onAppend('', '', 'string');
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
|
||||
var menu = new ContextMenu(items, {close: onClose});
|
||||
menu.show(anchor, this.editor.content);
|
||||
};
|
||||
|
||||
/**
|
||||
* Handle an event. The event is catched centrally by the editor
|
||||
* @param {Event} event
|
||||
*/
|
||||
AppendNode.prototype.onEvent = function (event) {
|
||||
var type = event.type;
|
||||
var target = event.target || event.srcElement;
|
||||
var dom = this.dom;
|
||||
|
||||
// highlight the append nodes parent
|
||||
var menu = dom.menu;
|
||||
if (target == menu) {
|
||||
if (type == 'mouseover') {
|
||||
this.editor.highlighter.highlight(this.parent);
|
||||
}
|
||||
else if (type == 'mouseout') {
|
||||
this.editor.highlighter.unhighlight();
|
||||
}
|
||||
}
|
||||
|
||||
// context menu events
|
||||
if (type == 'click' && target == dom.menu) {
|
||||
var highlighter = this.editor.highlighter;
|
||||
highlighter.highlight(this.parent);
|
||||
highlighter.lock();
|
||||
util.addClassName(dom.menu, 'jsoneditor-selected');
|
||||
this.showContextMenu(dom.menu, function () {
|
||||
util.removeClassName(dom.menu, 'jsoneditor-selected');
|
||||
highlighter.unlock();
|
||||
highlighter.unhighlight();
|
||||
});
|
||||
}
|
||||
|
||||
if (type == 'keydown') {
|
||||
this.onKeyDown(event);
|
||||
}
|
||||
};
|
||||
|
||||
return AppendNode;
|
||||
}
|
||||
|
||||
module.exports = appendNodeFactory;
|
|
@ -1,15 +0,0 @@
|
|||
The file jsonlint.js is copied from the following project:
|
||||
|
||||
https://github.com/josdejong/jsonlint at 85a19d7
|
||||
|
||||
which is a fork of the (currently not maintained) project:
|
||||
|
||||
https://github.com/zaach/jsonlint
|
||||
|
||||
The forked project contains some fixes to allow the file to be bundled with
|
||||
browserify. The file is copied in this project to prevent issues with linking
|
||||
to a github project from package.json, which is for example not supported
|
||||
by jspm.
|
||||
|
||||
As soon as zaach/jsonlint is being maintained again we can push the fix
|
||||
to the original library and use it as dependency again.
|
|
@ -1,418 +0,0 @@
|
|||
/* Jison generated parser */
|
||||
var jsonlint = (function(){
|
||||
var parser = {trace: function trace() { },
|
||||
yy: {},
|
||||
symbols_: {"error":2,"JSONString":3,"STRING":4,"JSONNumber":5,"NUMBER":6,"JSONNullLiteral":7,"NULL":8,"JSONBooleanLiteral":9,"TRUE":10,"FALSE":11,"JSONText":12,"JSONValue":13,"EOF":14,"JSONObject":15,"JSONArray":16,"{":17,"}":18,"JSONMemberList":19,"JSONMember":20,":":21,",":22,"[":23,"]":24,"JSONElementList":25,"$accept":0,"$end":1},
|
||||
terminals_: {2:"error",4:"STRING",6:"NUMBER",8:"NULL",10:"TRUE",11:"FALSE",14:"EOF",17:"{",18:"}",21:":",22:",",23:"[",24:"]"},
|
||||
productions_: [0,[3,1],[5,1],[7,1],[9,1],[9,1],[12,2],[13,1],[13,1],[13,1],[13,1],[13,1],[13,1],[15,2],[15,3],[20,3],[19,1],[19,3],[16,2],[16,3],[25,1],[25,3]],
|
||||
performAction: function anonymous(yytext,yyleng,yylineno,yy,yystate,$$,_$) {
|
||||
|
||||
var $0 = $$.length - 1;
|
||||
switch (yystate) {
|
||||
case 1: // replace escaped characters with actual character
|
||||
this.$ = yytext.replace(/\\(\\|")/g, "$"+"1")
|
||||
.replace(/\\n/g,'\n')
|
||||
.replace(/\\r/g,'\r')
|
||||
.replace(/\\t/g,'\t')
|
||||
.replace(/\\v/g,'\v')
|
||||
.replace(/\\f/g,'\f')
|
||||
.replace(/\\b/g,'\b');
|
||||
|
||||
break;
|
||||
case 2:this.$ = Number(yytext);
|
||||
break;
|
||||
case 3:this.$ = null;
|
||||
break;
|
||||
case 4:this.$ = true;
|
||||
break;
|
||||
case 5:this.$ = false;
|
||||
break;
|
||||
case 6:return this.$ = $$[$0-1];
|
||||
break;
|
||||
case 13:this.$ = {};
|
||||
break;
|
||||
case 14:this.$ = $$[$0-1];
|
||||
break;
|
||||
case 15:this.$ = [$$[$0-2], $$[$0]];
|
||||
break;
|
||||
case 16:this.$ = {}; this.$[$$[$0][0]] = $$[$0][1];
|
||||
break;
|
||||
case 17:this.$ = $$[$0-2]; $$[$0-2][$$[$0][0]] = $$[$0][1];
|
||||
break;
|
||||
case 18:this.$ = [];
|
||||
break;
|
||||
case 19:this.$ = $$[$0-1];
|
||||
break;
|
||||
case 20:this.$ = [$$[$0]];
|
||||
break;
|
||||
case 21:this.$ = $$[$0-2]; $$[$0-2].push($$[$0]);
|
||||
break;
|
||||
}
|
||||
},
|
||||
table: [{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],12:1,13:2,15:7,16:8,17:[1,14],23:[1,15]},{1:[3]},{14:[1,16]},{14:[2,7],18:[2,7],22:[2,7],24:[2,7]},{14:[2,8],18:[2,8],22:[2,8],24:[2,8]},{14:[2,9],18:[2,9],22:[2,9],24:[2,9]},{14:[2,10],18:[2,10],22:[2,10],24:[2,10]},{14:[2,11],18:[2,11],22:[2,11],24:[2,11]},{14:[2,12],18:[2,12],22:[2,12],24:[2,12]},{14:[2,3],18:[2,3],22:[2,3],24:[2,3]},{14:[2,4],18:[2,4],22:[2,4],24:[2,4]},{14:[2,5],18:[2,5],22:[2,5],24:[2,5]},{14:[2,1],18:[2,1],21:[2,1],22:[2,1],24:[2,1]},{14:[2,2],18:[2,2],22:[2,2],24:[2,2]},{3:20,4:[1,12],18:[1,17],19:18,20:19},{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],13:23,15:7,16:8,17:[1,14],23:[1,15],24:[1,21],25:22},{1:[2,6]},{14:[2,13],18:[2,13],22:[2,13],24:[2,13]},{18:[1,24],22:[1,25]},{18:[2,16],22:[2,16]},{21:[1,26]},{14:[2,18],18:[2,18],22:[2,18],24:[2,18]},{22:[1,28],24:[1,27]},{22:[2,20],24:[2,20]},{14:[2,14],18:[2,14],22:[2,14],24:[2,14]},{3:20,4:[1,12],20:29},{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],13:30,15:7,16:8,17:[1,14],23:[1,15]},{14:[2,19],18:[2,19],22:[2,19],24:[2,19]},{3:5,4:[1,12],5:6,6:[1,13],7:3,8:[1,9],9:4,10:[1,10],11:[1,11],13:31,15:7,16:8,17:[1,14],23:[1,15]},{18:[2,17],22:[2,17]},{18:[2,15],22:[2,15]},{22:[2,21],24:[2,21]}],
|
||||
defaultActions: {16:[2,6]},
|
||||
parseError: function parseError(str, hash) {
|
||||
throw new Error(str);
|
||||
},
|
||||
parse: function parse(input) {
|
||||
var self = this,
|
||||
stack = [0],
|
||||
vstack = [null], // semantic value stack
|
||||
lstack = [], // location stack
|
||||
table = this.table,
|
||||
yytext = '',
|
||||
yylineno = 0,
|
||||
yyleng = 0,
|
||||
recovering = 0,
|
||||
TERROR = 2,
|
||||
EOF = 1;
|
||||
|
||||
//this.reductionCount = this.shiftCount = 0;
|
||||
|
||||
this.lexer.setInput(input);
|
||||
this.lexer.yy = this.yy;
|
||||
this.yy.lexer = this.lexer;
|
||||
if (typeof this.lexer.yylloc == 'undefined')
|
||||
this.lexer.yylloc = {};
|
||||
var yyloc = this.lexer.yylloc;
|
||||
lstack.push(yyloc);
|
||||
|
||||
if (typeof this.yy.parseError === 'function')
|
||||
this.parseError = this.yy.parseError;
|
||||
|
||||
function popStack (n) {
|
||||
stack.length = stack.length - 2*n;
|
||||
vstack.length = vstack.length - n;
|
||||
lstack.length = lstack.length - n;
|
||||
}
|
||||
|
||||
function lex() {
|
||||
var token;
|
||||
token = self.lexer.lex() || 1; // $end = 1
|
||||
// if token isn't its numeric value, convert
|
||||
if (typeof token !== 'number') {
|
||||
token = self.symbols_[token] || token;
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
var symbol, preErrorSymbol, state, action, a, r, yyval={},p,len,newState, expected;
|
||||
while (true) {
|
||||
// retreive state number from top of stack
|
||||
state = stack[stack.length-1];
|
||||
|
||||
// use default actions if available
|
||||
if (this.defaultActions[state]) {
|
||||
action = this.defaultActions[state];
|
||||
} else {
|
||||
if (symbol == null)
|
||||
symbol = lex();
|
||||
// read action for current state and first input
|
||||
action = table[state] && table[state][symbol];
|
||||
}
|
||||
|
||||
// handle parse error
|
||||
_handle_error:
|
||||
if (typeof action === 'undefined' || !action.length || !action[0]) {
|
||||
|
||||
if (!recovering) {
|
||||
// Report error
|
||||
expected = [];
|
||||
for (p in table[state]) if (this.terminals_[p] && p > 2) {
|
||||
expected.push("'"+this.terminals_[p]+"'");
|
||||
}
|
||||
var errStr = '';
|
||||
if (this.lexer.showPosition) {
|
||||
errStr = 'Parse error on line '+(yylineno+1)+":\n"+this.lexer.showPosition()+"\nExpecting "+expected.join(', ') + ", got '" + this.terminals_[symbol]+ "'";
|
||||
} else {
|
||||
errStr = 'Parse error on line '+(yylineno+1)+": Unexpected " +
|
||||
(symbol == 1 /*EOF*/ ? "end of input" :
|
||||
("'"+(this.terminals_[symbol] || symbol)+"'"));
|
||||
}
|
||||
this.parseError(errStr,
|
||||
{text: this.lexer.match, token: this.terminals_[symbol] || symbol, line: this.lexer.yylineno, loc: yyloc, expected: expected});
|
||||
}
|
||||
|
||||
// just recovered from another error
|
||||
if (recovering == 3) {
|
||||
if (symbol == EOF) {
|
||||
throw new Error(errStr || 'Parsing halted.');
|
||||
}
|
||||
|
||||
// discard current lookahead and grab another
|
||||
yyleng = this.lexer.yyleng;
|
||||
yytext = this.lexer.yytext;
|
||||
yylineno = this.lexer.yylineno;
|
||||
yyloc = this.lexer.yylloc;
|
||||
symbol = lex();
|
||||
}
|
||||
|
||||
// try to recover from error
|
||||
while (1) {
|
||||
// check for error recovery rule in this state
|
||||
if ((TERROR.toString()) in table[state]) {
|
||||
break;
|
||||
}
|
||||
if (state == 0) {
|
||||
throw new Error(errStr || 'Parsing halted.');
|
||||
}
|
||||
popStack(1);
|
||||
state = stack[stack.length-1];
|
||||
}
|
||||
|
||||
preErrorSymbol = symbol; // save the lookahead token
|
||||
symbol = TERROR; // insert generic error symbol as new lookahead
|
||||
state = stack[stack.length-1];
|
||||
action = table[state] && table[state][TERROR];
|
||||
recovering = 3; // allow 3 real symbols to be shifted before reporting a new error
|
||||
}
|
||||
|
||||
// this shouldn't happen, unless resolve defaults are off
|
||||
if (action[0] instanceof Array && action.length > 1) {
|
||||
throw new Error('Parse Error: multiple actions possible at state: '+state+', token: '+symbol);
|
||||
}
|
||||
|
||||
switch (action[0]) {
|
||||
|
||||
case 1: // shift
|
||||
//this.shiftCount++;
|
||||
|
||||
stack.push(symbol);
|
||||
vstack.push(this.lexer.yytext);
|
||||
lstack.push(this.lexer.yylloc);
|
||||
stack.push(action[1]); // push state
|
||||
symbol = null;
|
||||
if (!preErrorSymbol) { // normal execution/no error
|
||||
yyleng = this.lexer.yyleng;
|
||||
yytext = this.lexer.yytext;
|
||||
yylineno = this.lexer.yylineno;
|
||||
yyloc = this.lexer.yylloc;
|
||||
if (recovering > 0)
|
||||
recovering--;
|
||||
} else { // error just occurred, resume old lookahead f/ before error
|
||||
symbol = preErrorSymbol;
|
||||
preErrorSymbol = null;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: // reduce
|
||||
//this.reductionCount++;
|
||||
|
||||
len = this.productions_[action[1]][1];
|
||||
|
||||
// perform semantic action
|
||||
yyval.$ = vstack[vstack.length-len]; // default to $$ = $1
|
||||
// default location, uses first token for firsts, last for lasts
|
||||
yyval._$ = {
|
||||
first_line: lstack[lstack.length-(len||1)].first_line,
|
||||
last_line: lstack[lstack.length-1].last_line,
|
||||
first_column: lstack[lstack.length-(len||1)].first_column,
|
||||
last_column: lstack[lstack.length-1].last_column
|
||||
};
|
||||
r = this.performAction.call(yyval, yytext, yyleng, yylineno, this.yy, action[1], vstack, lstack);
|
||||
|
||||
if (typeof r !== 'undefined') {
|
||||
return r;
|
||||
}
|
||||
|
||||
// pop off stack
|
||||
if (len) {
|
||||
stack = stack.slice(0,-1*len*2);
|
||||
vstack = vstack.slice(0, -1*len);
|
||||
lstack = lstack.slice(0, -1*len);
|
||||
}
|
||||
|
||||
stack.push(this.productions_[action[1]][0]); // push nonterminal (reduce)
|
||||
vstack.push(yyval.$);
|
||||
lstack.push(yyval._$);
|
||||
// goto new state = table[STATE][NONTERMINAL]
|
||||
newState = table[stack[stack.length-2]][stack[stack.length-1]];
|
||||
stack.push(newState);
|
||||
break;
|
||||
|
||||
case 3: // accept
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}};
|
||||
/* Jison generated lexer */
|
||||
var lexer = (function(){
|
||||
var lexer = ({EOF:1,
|
||||
parseError:function parseError(str, hash) {
|
||||
if (this.yy.parseError) {
|
||||
this.yy.parseError(str, hash);
|
||||
} else {
|
||||
throw new Error(str);
|
||||
}
|
||||
},
|
||||
setInput:function (input) {
|
||||
this._input = input;
|
||||
this._more = this._less = this.done = false;
|
||||
this.yylineno = this.yyleng = 0;
|
||||
this.yytext = this.matched = this.match = '';
|
||||
this.conditionStack = ['INITIAL'];
|
||||
this.yylloc = {first_line:1,first_column:0,last_line:1,last_column:0};
|
||||
return this;
|
||||
},
|
||||
input:function () {
|
||||
var ch = this._input[0];
|
||||
this.yytext+=ch;
|
||||
this.yyleng++;
|
||||
this.match+=ch;
|
||||
this.matched+=ch;
|
||||
var lines = ch.match(/\n/);
|
||||
if (lines) this.yylineno++;
|
||||
this._input = this._input.slice(1);
|
||||
return ch;
|
||||
},
|
||||
unput:function (ch) {
|
||||
this._input = ch + this._input;
|
||||
return this;
|
||||
},
|
||||
more:function () {
|
||||
this._more = true;
|
||||
return this;
|
||||
},
|
||||
less:function (n) {
|
||||
this._input = this.match.slice(n) + this._input;
|
||||
},
|
||||
pastInput:function () {
|
||||
var past = this.matched.substr(0, this.matched.length - this.match.length);
|
||||
return (past.length > 20 ? '...':'') + past.substr(-20).replace(/\n/g, "");
|
||||
},
|
||||
upcomingInput:function () {
|
||||
var next = this.match;
|
||||
if (next.length < 20) {
|
||||
next += this._input.substr(0, 20-next.length);
|
||||
}
|
||||
return (next.substr(0,20)+(next.length > 20 ? '...':'')).replace(/\n/g, "");
|
||||
},
|
||||
showPosition:function () {
|
||||
var pre = this.pastInput();
|
||||
var c = new Array(pre.length + 1).join("-");
|
||||
return pre + this.upcomingInput() + "\n" + c+"^";
|
||||
},
|
||||
next:function () {
|
||||
if (this.done) {
|
||||
return this.EOF;
|
||||
}
|
||||
if (!this._input) this.done = true;
|
||||
|
||||
var token,
|
||||
match,
|
||||
tempMatch,
|
||||
index,
|
||||
col,
|
||||
lines;
|
||||
if (!this._more) {
|
||||
this.yytext = '';
|
||||
this.match = '';
|
||||
}
|
||||
var rules = this._currentRules();
|
||||
for (var i=0;i < rules.length; i++) {
|
||||
tempMatch = this._input.match(this.rules[rules[i]]);
|
||||
if (tempMatch && (!match || tempMatch[0].length > match[0].length)) {
|
||||
match = tempMatch;
|
||||
index = i;
|
||||
if (!this.options.flex) break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
lines = match[0].match(/\n.*/g);
|
||||
if (lines) this.yylineno += lines.length;
|
||||
this.yylloc = {first_line: this.yylloc.last_line,
|
||||
last_line: this.yylineno+1,
|
||||
first_column: this.yylloc.last_column,
|
||||
last_column: lines ? lines[lines.length-1].length-1 : this.yylloc.last_column + match[0].length}
|
||||
this.yytext += match[0];
|
||||
this.match += match[0];
|
||||
this.yyleng = this.yytext.length;
|
||||
this._more = false;
|
||||
this._input = this._input.slice(match[0].length);
|
||||
this.matched += match[0];
|
||||
token = this.performAction.call(this, this.yy, this, rules[index],this.conditionStack[this.conditionStack.length-1]);
|
||||
if (this.done && this._input) this.done = false;
|
||||
if (token) return token;
|
||||
else return;
|
||||
}
|
||||
if (this._input === "") {
|
||||
return this.EOF;
|
||||
} else {
|
||||
this.parseError('Lexical error on line '+(this.yylineno+1)+'. Unrecognized text.\n'+this.showPosition(),
|
||||
{text: "", token: null, line: this.yylineno});
|
||||
}
|
||||
},
|
||||
lex:function lex() {
|
||||
var r = this.next();
|
||||
if (typeof r !== 'undefined') {
|
||||
return r;
|
||||
} else {
|
||||
return this.lex();
|
||||
}
|
||||
},
|
||||
begin:function begin(condition) {
|
||||
this.conditionStack.push(condition);
|
||||
},
|
||||
popState:function popState() {
|
||||
return this.conditionStack.pop();
|
||||
},
|
||||
_currentRules:function _currentRules() {
|
||||
return this.conditions[this.conditionStack[this.conditionStack.length-1]].rules;
|
||||
},
|
||||
topState:function () {
|
||||
return this.conditionStack[this.conditionStack.length-2];
|
||||
},
|
||||
pushState:function begin(condition) {
|
||||
this.begin(condition);
|
||||
}});
|
||||
lexer.options = {};
|
||||
lexer.performAction = function anonymous(yy,yy_,$avoiding_name_collisions,YY_START) {
|
||||
|
||||
var YYSTATE=YY_START
|
||||
switch($avoiding_name_collisions) {
|
||||
case 0:/* skip whitespace */
|
||||
break;
|
||||
case 1:return 6
|
||||
break;
|
||||
case 2:yy_.yytext = yy_.yytext.substr(1,yy_.yyleng-2); return 4
|
||||
break;
|
||||
case 3:return 17
|
||||
break;
|
||||
case 4:return 18
|
||||
break;
|
||||
case 5:return 23
|
||||
break;
|
||||
case 6:return 24
|
||||
break;
|
||||
case 7:return 22
|
||||
break;
|
||||
case 8:return 21
|
||||
break;
|
||||
case 9:return 10
|
||||
break;
|
||||
case 10:return 11
|
||||
break;
|
||||
case 11:return 8
|
||||
break;
|
||||
case 12:return 14
|
||||
break;
|
||||
case 13:return 'INVALID'
|
||||
break;
|
||||
}
|
||||
};
|
||||
lexer.rules = [/^(?:\s+)/,/^(?:(-?([0-9]|[1-9][0-9]+))(\.[0-9]+)?([eE][-+]?[0-9]+)?\b)/,/^(?:"(?:\\[\\"bfnrt/]|\\u[a-fA-F0-9]{4}|[^\\\0-\x09\x0a-\x1f"])*")/,/^(?:\{)/,/^(?:\})/,/^(?:\[)/,/^(?:\])/,/^(?:,)/,/^(?::)/,/^(?:true\b)/,/^(?:false\b)/,/^(?:null\b)/,/^(?:$)/,/^(?:.)/];
|
||||
lexer.conditions = {"INITIAL":{"rules":[0,1,2,3,4,5,6,7,8,9,10,11,12,13],"inclusive":true}};
|
||||
|
||||
|
||||
;
|
||||
return lexer;})()
|
||||
parser.lexer = lexer;
|
||||
return parser;
|
||||
})();
|
||||
if (typeof require !== 'undefined' && typeof exports !== 'undefined') {
|
||||
exports.parser = jsonlint;
|
||||
exports.parse = jsonlint.parse.bind(jsonlint);
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
/*!
|
||||
* jsoneditor.js
|
||||
*
|
||||
* @brief
|
||||
* JSONEditor 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.
|
||||
*
|
||||
* Supported browsers: Chrome, Firefox, Safari, Opera, Internet Explorer 8+
|
||||
*
|
||||
* @license
|
||||
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
|
||||
* use this file except in compliance with the License. You may obtain a copy
|
||||
* of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
* License for the specific language governing permissions and limitations under
|
||||
* the License.
|
||||
*
|
||||
* Copyright (c) 2011-2016 Jos de Jong, http://jsoneditoronline.org
|
||||
*
|
||||
* @author Jos de Jong, <wjosdejong@gmail.com>
|
||||
* @version @@version
|
||||
* @date @@date
|
||||
*/
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue