Set up code style linting with standardjs
This commit is contained in:
parent
8e2a7de17c
commit
a5d6b8a65b
|
@ -1,3 +1,10 @@
|
||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- "lts/*"
|
- "lts/*"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
include:
|
||||||
|
- name: Lint
|
||||||
|
stage: other
|
||||||
|
script: npm run lint
|
||||||
|
node_js: lts/*
|
||||||
|
|
|
@ -6,10 +6,18 @@ up with ideas and suggestions, and contribute to the code.
|
||||||
|
|
||||||
There are a few preferences regarding code contributions:
|
There are a few preferences regarding code contributions:
|
||||||
|
|
||||||
- `jsoneditor` follows the node.js code style as described
|
- Send pull requests to the `develop` branch, not the `master` branch.
|
||||||
[here](http://nodeguide.com/style.html).
|
- You can use modern JavaScript features, the code is transpiled using Babel.
|
||||||
- Send pull requests to the `develop` branch, not the `master` branch.
|
- `jsoneditor` follows the https://standardjs.com/ code style. To test:
|
||||||
- Only commit changes done in the source files under `./src`, not to the builds
|
|
||||||
which are located under the `./dist` folder.
|
```
|
||||||
|
npm run lint
|
||||||
|
```
|
||||||
|
|
||||||
|
- If possible, create a unit test for any new functionality. To run tests:
|
||||||
|
|
||||||
|
```
|
||||||
|
npm test
|
||||||
|
```
|
||||||
|
|
||||||
Thanks!
|
Thanks!
|
||||||
|
|
12
README.md
12
README.md
|
@ -96,9 +96,9 @@ with npm (recommended):
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// create the editor
|
// create the editor
|
||||||
var container = document.getElementById("jsoneditor");
|
var container = document.getElementById("jsoneditor")
|
||||||
var options = {};
|
var options = {}
|
||||||
var editor = new JSONEditor(container, options);
|
var editor = new JSONEditor(container, options)
|
||||||
|
|
||||||
// set json
|
// set json
|
||||||
var json = {
|
var json = {
|
||||||
|
@ -108,11 +108,11 @@ with npm (recommended):
|
||||||
"Number": 123,
|
"Number": 123,
|
||||||
"Object": {"a": "b", "c": "d"},
|
"Object": {"a": "b", "c": "d"},
|
||||||
"String": "Hello World"
|
"String": "Hello World"
|
||||||
};
|
}
|
||||||
editor.set(json);
|
editor.set(json)
|
||||||
|
|
||||||
// get json
|
// get json
|
||||||
var json = editor.get();
|
var json = editor.get()
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
<link rel="stylesheet" type="text/css" href="../../dist/jsoneditor.css">
|
<link rel="stylesheet" type="text/css" href="../../dist/jsoneditor.css">
|
||||||
<script data-main="scripts/main" src="scripts/require.js"></script>
|
<script data-main="scripts/main" src="https://requirejs.org/docs/release/2.3.6/minified/require.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -1,25 +1,25 @@
|
||||||
var module = '../../../dist/jsoneditor';
|
var module = '../../../dist/jsoneditor'
|
||||||
require([module], function (JSONEditor) {
|
require([module], function (JSONEditor) {
|
||||||
// create the editor
|
// create the editor
|
||||||
var container = document.getElementById('jsoneditor');
|
var container = document.getElementById('jsoneditor')
|
||||||
var editor = new JSONEditor(container);
|
var editor = new JSONEditor(container)
|
||||||
|
|
||||||
// set json
|
// set json
|
||||||
document.getElementById('setJSON').onclick = function () {
|
document.getElementById('setJSON').onclick = function () {
|
||||||
var json = {
|
var json = {
|
||||||
'array': [1, 2, 3],
|
array: [1, 2, 3],
|
||||||
'boolean': true,
|
boolean: true,
|
||||||
'null': null,
|
null: null,
|
||||||
'number': 123,
|
number: 123,
|
||||||
'object': {'a': 'b', 'c': 'd'},
|
object: { a: 'b', c: 'd' },
|
||||||
'string': 'Hello World'
|
string: 'Hello World'
|
||||||
};
|
}
|
||||||
editor.set(json);
|
editor.set(json)
|
||||||
};
|
}
|
||||||
|
|
||||||
// get json
|
// get json
|
||||||
document.getElementById('getJSON').onclick = function () {
|
document.getElementById('getJSON').onclick = function () {
|
||||||
var json = editor.get();
|
var json = editor.get()
|
||||||
alert(JSON.stringify(json, null, 2));
|
window.alert(JSON.stringify(json, null, 2))
|
||||||
};
|
}
|
||||||
});
|
})
|
||||||
|
|
|
@ -1,36 +0,0 @@
|
||||||
/*
|
|
||||||
RequireJS 2.1.13 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
|
|
||||||
Available via the MIT or new BSD license.
|
|
||||||
see: http://github.com/jrburke/requirejs for details
|
|
||||||
*/
|
|
||||||
var requirejs,require,define;
|
|
||||||
(function(ba){function G(b){return"[object Function]"===K.call(b)}function H(b){return"[object Array]"===K.call(b)}function v(b,c){if(b){var d;for(d=0;d<b.length&&(!b[d]||!c(b[d],d,b));d+=1);}}function T(b,c){if(b){var d;for(d=b.length-1;-1<d&&(!b[d]||!c(b[d],d,b));d-=1);}}function t(b,c){return fa.call(b,c)}function m(b,c){return t(b,c)&&b[c]}function B(b,c){for(var d in b)if(t(b,d)&&c(b[d],d))break}function U(b,c,d,e){c&&B(c,function(c,g){if(d||!t(b,g))e&&"object"===typeof c&&c&&!H(c)&&!G(c)&&!(c instanceof
|
|
||||||
RegExp)?(b[g]||(b[g]={}),U(b[g],c,d,e)):b[g]=c});return b}function u(b,c){return function(){return c.apply(b,arguments)}}function ca(b){throw b;}function da(b){if(!b)return b;var c=ba;v(b.split("."),function(b){c=c[b]});return c}function C(b,c,d,e){c=Error(c+"\nhttp://requirejs.org/docs/errors.html#"+b);c.requireType=b;c.requireModules=e;d&&(c.originalError=d);return c}function ga(b){function c(a,k,b){var f,l,c,d,e,g,i,p,k=k&&k.split("/"),h=j.map,n=h&&h["*"];if(a){a=a.split("/");l=a.length-1;j.nodeIdCompat&&
|
|
||||||
Q.test(a[l])&&(a[l]=a[l].replace(Q,""));"."===a[0].charAt(0)&&k&&(l=k.slice(0,k.length-1),a=l.concat(a));l=a;for(c=0;c<l.length;c++)if(d=l[c],"."===d)l.splice(c,1),c-=1;else if(".."===d&&!(0===c||1==c&&".."===l[2]||".."===l[c-1])&&0<c)l.splice(c-1,2),c-=2;a=a.join("/")}if(b&&h&&(k||n)){l=a.split("/");c=l.length;a:for(;0<c;c-=1){e=l.slice(0,c).join("/");if(k)for(d=k.length;0<d;d-=1)if(b=m(h,k.slice(0,d).join("/")))if(b=m(b,e)){f=b;g=c;break a}!i&&(n&&m(n,e))&&(i=m(n,e),p=c)}!f&&i&&(f=i,g=p);f&&(l.splice(0,
|
|
||||||
g,f),a=l.join("/"))}return(f=m(j.pkgs,a))?f:a}function d(a){z&&v(document.getElementsByTagName("script"),function(k){if(k.getAttribute("data-requiremodule")===a&&k.getAttribute("data-requirecontext")===i.contextName)return k.parentNode.removeChild(k),!0})}function e(a){var k=m(j.paths,a);if(k&&H(k)&&1<k.length)return k.shift(),i.require.undef(a),i.makeRequire(null,{skipMap:!0})([a]),!0}function n(a){var k,c=a?a.indexOf("!"):-1;-1<c&&(k=a.substring(0,c),a=a.substring(c+1,a.length));return[k,a]}function p(a,
|
|
||||||
k,b,f){var l,d,e=null,g=k?k.name:null,j=a,p=!0,h="";a||(p=!1,a="_@r"+(K+=1));a=n(a);e=a[0];a=a[1];e&&(e=c(e,g,f),d=m(r,e));a&&(e?h=d&&d.normalize?d.normalize(a,function(a){return c(a,g,f)}):c(a,g,f):(h=c(a,g,f),a=n(h),e=a[0],h=a[1],b=!0,l=i.nameToUrl(h)));b=e&&!d&&!b?"_unnormalized"+(O+=1):"";return{prefix:e,name:h,parentMap:k,unnormalized:!!b,url:l,originalName:j,isDefine:p,id:(e?e+"!"+h:h)+b}}function s(a){var k=a.id,b=m(h,k);b||(b=h[k]=new i.Module(a));return b}function q(a,k,b){var f=a.id,c=m(h,
|
|
||||||
f);if(t(r,f)&&(!c||c.defineEmitComplete))"defined"===k&&b(r[f]);else if(c=s(a),c.error&&"error"===k)b(c.error);else c.on(k,b)}function w(a,b){var c=a.requireModules,f=!1;if(b)b(a);else if(v(c,function(b){if(b=m(h,b))b.error=a,b.events.error&&(f=!0,b.emit("error",a))}),!f)g.onError(a)}function x(){R.length&&(ha.apply(A,[A.length,0].concat(R)),R=[])}function y(a){delete h[a];delete V[a]}function F(a,b,c){var f=a.map.id;a.error?a.emit("error",a.error):(b[f]=!0,v(a.depMaps,function(f,d){var e=f.id,g=
|
|
||||||
m(h,e);g&&(!a.depMatched[d]&&!c[e])&&(m(b,e)?(a.defineDep(d,r[e]),a.check()):F(g,b,c))}),c[f]=!0)}function D(){var a,b,c=(a=1E3*j.waitSeconds)&&i.startTime+a<(new Date).getTime(),f=[],l=[],g=!1,h=!0;if(!W){W=!0;B(V,function(a){var i=a.map,j=i.id;if(a.enabled&&(i.isDefine||l.push(a),!a.error))if(!a.inited&&c)e(j)?g=b=!0:(f.push(j),d(j));else if(!a.inited&&(a.fetched&&i.isDefine)&&(g=!0,!i.prefix))return h=!1});if(c&&f.length)return a=C("timeout","Load timeout for modules: "+f,null,f),a.contextName=
|
|
||||||
i.contextName,w(a);h&&v(l,function(a){F(a,{},{})});if((!c||b)&&g)if((z||ea)&&!X)X=setTimeout(function(){X=0;D()},50);W=!1}}function E(a){t(r,a[0])||s(p(a[0],null,!0)).init(a[1],a[2])}function I(a){var a=a.currentTarget||a.srcElement,b=i.onScriptLoad;a.detachEvent&&!Y?a.detachEvent("onreadystatechange",b):a.removeEventListener("load",b,!1);b=i.onScriptError;(!a.detachEvent||Y)&&a.removeEventListener("error",b,!1);return{node:a,id:a&&a.getAttribute("data-requiremodule")}}function J(){var a;for(x();A.length;){a=
|
|
||||||
A.shift();if(null===a[0])return w(C("mismatch","Mismatched anonymous define() module: "+a[a.length-1]));E(a)}}var W,Z,i,L,X,j={waitSeconds:7,baseUrl:"./",paths:{},bundles:{},pkgs:{},shim:{},config:{}},h={},V={},$={},A=[],r={},S={},aa={},K=1,O=1;L={require:function(a){return a.require?a.require:a.require=i.makeRequire(a.map)},exports:function(a){a.usingExports=!0;if(a.map.isDefine)return a.exports?r[a.map.id]=a.exports:a.exports=r[a.map.id]={}},module:function(a){return a.module?a.module:a.module=
|
|
||||||
{id:a.map.id,uri:a.map.url,config:function(){return m(j.config,a.map.id)||{}},exports:a.exports||(a.exports={})}}};Z=function(a){this.events=m($,a.id)||{};this.map=a;this.shim=m(j.shim,a.id);this.depExports=[];this.depMaps=[];this.depMatched=[];this.pluginMaps={};this.depCount=0};Z.prototype={init:function(a,b,c,f){f=f||{};if(!this.inited){this.factory=b;if(c)this.on("error",c);else this.events.error&&(c=u(this,function(a){this.emit("error",a)}));this.depMaps=a&&a.slice(0);this.errback=c;this.inited=
|
|
||||||
!0;this.ignore=f.ignore;f.enabled||this.enabled?this.enable():this.check()}},defineDep:function(a,b){this.depMatched[a]||(this.depMatched[a]=!0,this.depCount-=1,this.depExports[a]=b)},fetch:function(){if(!this.fetched){this.fetched=!0;i.startTime=(new Date).getTime();var a=this.map;if(this.shim)i.makeRequire(this.map,{enableBuildCallback:!0})(this.shim.deps||[],u(this,function(){return a.prefix?this.callPlugin():this.load()}));else return a.prefix?this.callPlugin():this.load()}},load:function(){var a=
|
|
||||||
this.map.url;S[a]||(S[a]=!0,i.load(this.map.id,a))},check:function(){if(this.enabled&&!this.enabling){var a,b,c=this.map.id;b=this.depExports;var f=this.exports,l=this.factory;if(this.inited)if(this.error)this.emit("error",this.error);else{if(!this.defining){this.defining=!0;if(1>this.depCount&&!this.defined){if(G(l)){if(this.events.error&&this.map.isDefine||g.onError!==ca)try{f=i.execCb(c,l,b,f)}catch(d){a=d}else f=i.execCb(c,l,b,f);this.map.isDefine&&void 0===f&&((b=this.module)?f=b.exports:this.usingExports&&
|
|
||||||
(f=this.exports));if(a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",w(this.error=a)}else f=l;this.exports=f;if(this.map.isDefine&&!this.ignore&&(r[c]=f,g.onResourceLoad))g.onResourceLoad(i,this.map,this.depMaps);y(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=
|
|
||||||
this.map,b=a.id,d=p(a.prefix);this.depMaps.push(d);q(d,"defined",u(this,function(f){var l,d;d=m(aa,this.map.id);var e=this.map.name,P=this.map.parentMap?this.map.parentMap.name:null,n=i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(f.normalize&&(e=f.normalize(e,function(a){return c(a,P,!0)})||""),f=p(a.prefix+"!"+e,this.map.parentMap),q(f,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(h,f.id)){this.depMaps.push(f);
|
|
||||||
if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else d?(this.map.url=i.nameToUrl(d),this.load()):(l=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),l.error=u(this,function(a){this.inited=!0;this.error=a;a.requireModules=[b];B(h,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&y(a.map.id)});w(a)}),l.fromText=u(this,function(f,c){var d=a.name,e=p(d),P=M;c&&(f=c);P&&(M=!1);s(e);t(j.config,b)&&(j.config[d]=j.config[b]);try{g.exec(f)}catch(h){return w(C("fromtexteval",
|
|
||||||
"fromText eval for "+b+" failed: "+h,h,[b]))}P&&(M=!0);this.depMaps.push(e);i.completeLoad(d);n([d],l)}),f.load(a.name,n,l,j))}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=this;this.enabling=this.enabled=!0;v(this.depMaps,u(this,function(a,b){var c,f;if("string"===typeof a){a=p(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(L,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;q(a,"defined",u(this,function(a){this.defineDep(b,
|
|
||||||
a);this.check()}));this.errback&&q(a,"error",u(this,this.errback))}c=a.id;f=h[c];!t(L,c)&&(f&&!f.enabled)&&i.enable(a,this)}));B(this.pluginMaps,u(this,function(a){var b=m(h,a.id);b&&!b.enabled&&i.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){v(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:j,contextName:b,registry:h,defined:r,urlFetched:S,defQueue:A,Module:Z,makeModuleMap:p,
|
|
||||||
nextTick:g.nextTick,onError:w,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=j.shim,c={paths:!0,bundles:!0,config:!0,map:!0};B(a,function(a,b){c[b]?(j[b]||(j[b]={}),U(j[b],a,!0,!0)):j[b]=a});a.bundles&&B(a.bundles,function(a,b){v(a,function(a){a!==b&&(aa[a]=b)})});a.shim&&(B(a.shim,function(a,c){H(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);b[c]=a}),j.shim=b);a.packages&&v(a.packages,function(a){var b,
|
|
||||||
a="string"===typeof a?{name:a}:a;b=a.name;a.location&&(j.paths[b]=a.location);j.pkgs[b]=a.name+"/"+(a.main||"main").replace(ia,"").replace(Q,"")});B(h,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=p(b))});if(a.deps||a.callback)i.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(ba,arguments));return b||a.exports&&da(a.exports)}},makeRequire:function(a,e){function j(c,d,m){var n,q;e.enableBuildCallback&&(d&&G(d))&&(d.__requireJsBuild=
|
|
||||||
!0);if("string"===typeof c){if(G(d))return w(C("requireargs","Invalid require call"),m);if(a&&t(L,c))return L[c](h[a.id]);if(g.get)return g.get(i,c,a,j);n=p(c,a,!1,!0);n=n.id;return!t(r,n)?w(C("notloaded",'Module name "'+n+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):r[n]}J();i.nextTick(function(){J();q=s(p(null,a));q.skipMap=e.skipMap;q.init(c,d,m,{enabled:!0});D()});return j}e=e||{};U(j,{isBrowser:z,toUrl:function(b){var d,e=b.lastIndexOf("."),k=b.split("/")[0];if(-1!==
|
|
||||||
e&&(!("."===k||".."===k)||1<e))d=b.substring(e,b.length),b=b.substring(0,e);return i.nameToUrl(c(b,a&&a.id,!0),d,!0)},defined:function(b){return t(r,p(b,a,!1,!0).id)},specified:function(b){b=p(b,a,!1,!0).id;return t(r,b)||t(h,b)}});a||(j.undef=function(b){x();var c=p(b,a,!0),e=m(h,b);d(b);delete r[b];delete S[c.url];delete $[b];T(A,function(a,c){a[0]===b&&A.splice(c,1)});e&&(e.events.defined&&($[b]=e.events),y(b))});return j},enable:function(a){m(h,a.id)&&s(a).enable()},completeLoad:function(a){var b,
|
|
||||||
c,d=m(j.shim,a)||{},g=d.exports;for(x();A.length;){c=A.shift();if(null===c[0]){c[0]=a;if(b)break;b=!0}else c[0]===a&&(b=!0);E(c)}c=m(h,a);if(!b&&!t(r,a)&&c&&!c.inited){if(j.enforceDefine&&(!g||!da(g)))return e(a)?void 0:w(C("nodefine","No define call for "+a,null,[a]));E([a,d.deps||[],d.exportsFn])}D()},nameToUrl:function(a,b,c){var d,e,h;(d=m(j.pkgs,a))&&(a=d);if(d=m(aa,a))return i.nameToUrl(d,b,c);if(g.jsExtRegExp.test(a))d=a+(b||"");else{d=j.paths;a=a.split("/");for(e=a.length;0<e;e-=1)if(h=a.slice(0,
|
|
||||||
e).join("/"),h=m(d,h)){H(h)&&(h=h[0]);a.splice(0,e,h);break}d=a.join("/");d+=b||(/^data\:|\?/.test(d)||c?"":".js");d=("/"===d.charAt(0)||d.match(/^[\w\+\.\-]+:/)?"":j.baseUrl)+d}return j.urlArgs?d+((-1===d.indexOf("?")?"?":"&")+j.urlArgs):d},load:function(a,b){g.load(i,a,b)},execCb:function(a,b,c,d){return b.apply(d,c)},onScriptLoad:function(a){if("load"===a.type||ja.test((a.currentTarget||a.srcElement).readyState))N=null,a=I(a),i.completeLoad(a.id)},onScriptError:function(a){var b=I(a);if(!e(b.id))return w(C("scripterror",
|
|
||||||
"Script error for: "+b.id,a,[b.id]))}};i.require=i.makeRequire();return i}var g,x,y,D,I,E,N,J,s,O,ka=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,la=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,Q=/\.js$/,ia=/^\.\//;x=Object.prototype;var K=x.toString,fa=x.hasOwnProperty,ha=Array.prototype.splice,z=!!("undefined"!==typeof window&&"undefined"!==typeof navigator&&window.document),ea=!z&&"undefined"!==typeof importScripts,ja=z&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,
|
|
||||||
Y="undefined"!==typeof opera&&"[object Opera]"===opera.toString(),F={},q={},R=[],M=!1;if("undefined"===typeof define){if("undefined"!==typeof requirejs){if(G(requirejs))return;q=requirejs;requirejs=void 0}"undefined"!==typeof require&&!G(require)&&(q=require,require=void 0);g=requirejs=function(b,c,d,e){var n,p="_";!H(b)&&"string"!==typeof b&&(n=b,H(c)?(b=c,c=d,d=e):b=[]);n&&n.context&&(p=n.context);(e=m(F,p))||(e=F[p]=g.s.newContext(p));n&&e.configure(n);return e.require(b,c,d)};g.config=function(b){return g(b)};
|
|
||||||
g.nextTick="undefined"!==typeof setTimeout?function(b){setTimeout(b,4)}:function(b){b()};require||(require=g);g.version="2.1.13";g.jsExtRegExp=/^\/|:|\?|\.js$/;g.isBrowser=z;x=g.s={contexts:F,newContext:ga};g({});v(["toUrl","undef","defined","specified"],function(b){g[b]=function(){var c=F._;return c.require[b].apply(c,arguments)}});if(z&&(y=x.head=document.getElementsByTagName("head")[0],D=document.getElementsByTagName("base")[0]))y=x.head=D.parentNode;g.onError=ca;g.createNode=function(b){var c=
|
|
||||||
b.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script");c.type=b.scriptType||"text/javascript";c.charset="utf-8";c.async=!0;return c};g.load=function(b,c,d){var e=b&&b.config||{};if(z)return e=g.createNode(e,c,d),e.setAttribute("data-requirecontext",b.contextName),e.setAttribute("data-requiremodule",c),e.attachEvent&&!(e.attachEvent.toString&&0>e.attachEvent.toString().indexOf("[native code"))&&!Y?(M=!0,e.attachEvent("onreadystatechange",b.onScriptLoad)):
|
|
||||||
(e.addEventListener("load",b.onScriptLoad,!1),e.addEventListener("error",b.onScriptError,!1)),e.src=d,J=e,D?y.insertBefore(e,D):y.appendChild(e),J=null,e;if(ea)try{importScripts(d),b.completeLoad(c)}catch(m){b.onError(C("importscripts","importScripts failed for "+c+" at "+d,m,[c]))}};z&&!q.skipDataMain&&T(document.getElementsByTagName("script"),function(b){y||(y=b.parentNode);if(I=b.getAttribute("data-main"))return s=I,q.baseUrl||(E=s.split("/"),s=E.pop(),O=E.length?E.join("/")+"/":"./",q.baseUrl=
|
|
||||||
O),s=s.replace(Q,""),g.jsExtRegExp.test(s)&&(s=I),q.deps=q.deps?q.deps.concat(s):[s],!0});define=function(b,c,d){var e,g;"string"!==typeof b&&(d=c,c=b,b=null);H(c)||(d=c,c=null);!c&&G(d)&&(c=[],d.length&&(d.toString().replace(ka,"").replace(la,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c)));if(M){if(!(e=J))N&&"interactive"===N.readyState||T(document.getElementsByTagName("script"),function(b){if("interactive"===b.readyState)return N=b}),e=N;e&&(b||
|
|
||||||
(b=e.getAttribute("data-requiremodule")),g=F[e.getAttribute("data-requirecontext")])}(g?g.defQueue:R).push([b,c,d])};define.amd={jQuery:!0};g.exec=function(b){return eval(b)};g(q)}})(this);
|
|
202
gulpfile.js
202
gulpfile.js
|
@ -1,38 +1,38 @@
|
||||||
var fs = require('fs');
|
var fs = require('fs')
|
||||||
var path = require('path');
|
var path = require('path')
|
||||||
var gulp = require('gulp');
|
var gulp = require('gulp')
|
||||||
var log = require('fancy-log');
|
var log = require('fancy-log')
|
||||||
var format = require('date-format');
|
var format = require('date-format')
|
||||||
var concatCss = require('gulp-concat-css');
|
var concatCss = require('gulp-concat-css')
|
||||||
var minifyCSS = require('gulp-clean-css');
|
var minifyCSS = require('gulp-clean-css')
|
||||||
var sass = require('gulp-sass')
|
var sass = require('gulp-sass')
|
||||||
var mkdirp = require('mkdirp');
|
var mkdirp = require('mkdirp')
|
||||||
var webpack = require('webpack');
|
var webpack = require('webpack')
|
||||||
var uglify = require('uglify-js');
|
var uglify = require('uglify-js')
|
||||||
|
|
||||||
var NAME = 'jsoneditor';
|
var NAME = 'jsoneditor'
|
||||||
var NAME_MINIMALIST = 'jsoneditor-minimalist';
|
var NAME_MINIMALIST = 'jsoneditor-minimalist'
|
||||||
var ENTRY = './src/js/JSONEditor.js';
|
var ENTRY = './src/js/JSONEditor.js'
|
||||||
var HEADER = './src/js/header.js';
|
var HEADER = './src/js/header.js'
|
||||||
var IMAGE = './src/scss/img/jsoneditor-icons.svg';
|
var IMAGE = './src/scss/img/jsoneditor-icons.svg'
|
||||||
var DOCS = './src/docs/*';
|
var DOCS = './src/docs/*'
|
||||||
var DIST = path.join(__dirname, 'dist');
|
var DIST = path.join(__dirname, 'dist')
|
||||||
|
|
||||||
// generate banner with today's date and correct version
|
// generate banner with today's date and correct version
|
||||||
function createBanner() {
|
function createBanner () {
|
||||||
var today = format.asString('yyyy-MM-dd', new Date()); // today, formatted as yyyy-MM-dd
|
var today = format.asString('yyyy-MM-dd', new Date()) // today, formatted as yyyy-MM-dd
|
||||||
var version = require('./package.json').version; // math.js version
|
var version = require('./package.json').version // math.js version
|
||||||
|
|
||||||
return String(fs.readFileSync(HEADER))
|
return String(fs.readFileSync(HEADER))
|
||||||
.replace('@@date', today)
|
.replace('@@date', today)
|
||||||
.replace('@@version', version);
|
.replace('@@version', version)
|
||||||
}
|
}
|
||||||
|
|
||||||
var bannerPlugin = new webpack.BannerPlugin({
|
var bannerPlugin = new webpack.BannerPlugin({
|
||||||
banner: createBanner(),
|
banner: createBanner(),
|
||||||
entryOnly: true,
|
entryOnly: true,
|
||||||
raw: true
|
raw: true
|
||||||
});
|
})
|
||||||
|
|
||||||
var webpackConfigModule = {
|
var webpackConfigModule = {
|
||||||
rules: [
|
rules: [
|
||||||
|
@ -47,7 +47,7 @@ var webpackConfigModule = {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
};
|
}
|
||||||
|
|
||||||
// create a single instance of the compiler to allow caching
|
// create a single instance of the compiler to allow caching
|
||||||
var compiler = webpack({
|
var compiler = webpack({
|
||||||
|
@ -66,10 +66,10 @@ var compiler = webpack({
|
||||||
module: webpackConfigModule,
|
module: webpackConfigModule,
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['.js'],
|
extensions: ['.js'],
|
||||||
mainFields: [ 'main' ], // pick ES5 version of vanilla-picker
|
mainFields: ['main'] // pick ES5 version of vanilla-picker
|
||||||
},
|
},
|
||||||
cache: true
|
cache: true
|
||||||
});
|
})
|
||||||
|
|
||||||
// create a single instance of the compiler to allow caching
|
// create a single instance of the compiler to allow caching
|
||||||
var compilerMinimalist = webpack({
|
var compilerMinimalist = webpack({
|
||||||
|
@ -92,10 +92,10 @@ var compilerMinimalist = webpack({
|
||||||
minimize: false
|
minimize: false
|
||||||
},
|
},
|
||||||
cache: true
|
cache: true
|
||||||
});
|
})
|
||||||
|
|
||||||
function minify(name) {
|
function minify (name) {
|
||||||
var code = String(fs.readFileSync(DIST + '/' + name + '.js'));
|
var code = String(fs.readFileSync(DIST + '/' + name + '.js'))
|
||||||
var result = uglify.minify(code, {
|
var result = uglify.minify(code, {
|
||||||
sourceMap: {
|
sourceMap: {
|
||||||
url: name + '.map'
|
url: name + '.map'
|
||||||
|
@ -104,80 +104,80 @@ function minify(name) {
|
||||||
comments: /@license/,
|
comments: /@license/,
|
||||||
max_line_len: 64000 // extra large because we have embedded code for workers
|
max_line_len: 64000 // extra large because we have embedded code for workers
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
throw result.error;
|
throw result.error
|
||||||
}
|
}
|
||||||
|
|
||||||
var fileMin = DIST + '/' + name + '.min.js';
|
var fileMin = DIST + '/' + name + '.min.js'
|
||||||
var fileMap = DIST + '/' + name + '.map';
|
var fileMap = DIST + '/' + name + '.map'
|
||||||
|
|
||||||
fs.writeFileSync(fileMin, result.code);
|
fs.writeFileSync(fileMin, result.code)
|
||||||
fs.writeFileSync(fileMap, result.map);
|
fs.writeFileSync(fileMap, result.map)
|
||||||
|
|
||||||
log('Minified ' + fileMin);
|
log('Minified ' + fileMin)
|
||||||
log('Mapped ' + fileMap);
|
log('Mapped ' + fileMap)
|
||||||
}
|
}
|
||||||
|
|
||||||
// make dist folder structure
|
// make dist folder structure
|
||||||
gulp.task('mkdir', function(done) {
|
gulp.task('mkdir', function (done) {
|
||||||
mkdirp.sync(DIST);
|
mkdirp.sync(DIST)
|
||||||
mkdirp.sync(DIST + '/img');
|
mkdirp.sync(DIST + '/img')
|
||||||
|
|
||||||
done();
|
done()
|
||||||
});
|
})
|
||||||
|
|
||||||
// bundle javascript
|
// bundle javascript
|
||||||
gulp.task('bundle', function(done) {
|
gulp.task('bundle', function (done) {
|
||||||
// update the banner contents (has a date in it which should stay up to date)
|
// update the banner contents (has a date in it which should stay up to date)
|
||||||
bannerPlugin.banner = createBanner();
|
bannerPlugin.banner = createBanner()
|
||||||
|
|
||||||
compiler.run(function(err, stats) {
|
compiler.run(function (err, stats) {
|
||||||
if (err) {
|
if (err) {
|
||||||
log(err);
|
log(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log('bundled ' + NAME + '.js');
|
log('bundled ' + NAME + '.js')
|
||||||
|
|
||||||
done();
|
done()
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
// bundle minimalist version of javascript
|
// bundle minimalist version of javascript
|
||||||
gulp.task('bundle-minimalist', function(done) {
|
gulp.task('bundle-minimalist', function (done) {
|
||||||
// update the banner contents (has a date in it which should stay up to date)
|
// update the banner contents (has a date in it which should stay up to date)
|
||||||
bannerPlugin.banner = createBanner();
|
bannerPlugin.banner = createBanner()
|
||||||
|
|
||||||
compilerMinimalist.run(function(err, stats) {
|
compilerMinimalist.run(function (err, stats) {
|
||||||
if (err) {
|
if (err) {
|
||||||
log(err);
|
log(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
log('bundled ' + NAME_MINIMALIST + '.js');
|
log('bundled ' + NAME_MINIMALIST + '.js')
|
||||||
|
|
||||||
done();
|
done()
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
// bundle css
|
// bundle css
|
||||||
gulp.task('bundle-css', function(done) {
|
gulp.task('bundle-css', function (done) {
|
||||||
gulp
|
gulp
|
||||||
.src([
|
.src([
|
||||||
'src/scss/reset.scss',
|
'src/scss/reset.scss',
|
||||||
'src/scss/jsoneditor.scss',
|
'src/scss/jsoneditor.scss',
|
||||||
'src/scss/contextmenu.scss',
|
'src/scss/contextmenu.scss',
|
||||||
'src/scss/menu.scss',
|
'src/scss/menu.scss',
|
||||||
'src/scss/searchbox.scss',
|
'src/scss/searchbox.scss',
|
||||||
'src/scss/autocomplete.scss',
|
'src/scss/autocomplete.scss',
|
||||||
'src/scss/treepath.scss',
|
'src/scss/treepath.scss',
|
||||||
'src/scss/statusbar.scss',
|
'src/scss/statusbar.scss',
|
||||||
'src/scss/navigationbar.scss',
|
'src/scss/navigationbar.scss',
|
||||||
'src/js/assets/selectr/selectr.scss',
|
'src/js/assets/selectr/selectr.scss'
|
||||||
])
|
])
|
||||||
.pipe(
|
.pipe(
|
||||||
sass({
|
sass({
|
||||||
// importer: tildeImporter
|
// importer: tildeImporter
|
||||||
})
|
})
|
||||||
)
|
)
|
||||||
.pipe(concatCss(NAME + '.css'))
|
.pipe(concatCss(NAME + '.css'))
|
||||||
|
@ -189,48 +189,48 @@ gulp.task('bundle-css', function(done) {
|
||||||
})
|
})
|
||||||
|
|
||||||
// create a folder img and copy the icons
|
// create a folder img and copy the icons
|
||||||
gulp.task('copy-img', function(done) {
|
gulp.task('copy-img', function (done) {
|
||||||
gulp.src(IMAGE).pipe(gulp.dest(DIST + '/img'));
|
gulp.src(IMAGE).pipe(gulp.dest(DIST + '/img'))
|
||||||
log('Copied images');
|
log('Copied images')
|
||||||
|
|
||||||
done();
|
done()
|
||||||
});
|
})
|
||||||
|
|
||||||
// create a folder img and copy the icons
|
// create a folder img and copy the icons
|
||||||
gulp.task('copy-docs', function(done) {
|
gulp.task('copy-docs', function (done) {
|
||||||
gulp.src(DOCS).pipe(gulp.dest(DIST));
|
gulp.src(DOCS).pipe(gulp.dest(DIST))
|
||||||
log('Copied doc');
|
log('Copied doc')
|
||||||
|
|
||||||
done();
|
done()
|
||||||
});
|
})
|
||||||
|
|
||||||
gulp.task('minify', function(done) {
|
gulp.task('minify', function (done) {
|
||||||
minify(NAME);
|
minify(NAME)
|
||||||
|
|
||||||
done();
|
done()
|
||||||
});
|
})
|
||||||
|
|
||||||
gulp.task('minify-minimalist', function(done) {
|
gulp.task('minify-minimalist', function (done) {
|
||||||
minify(NAME_MINIMALIST);
|
minify(NAME_MINIMALIST)
|
||||||
|
|
||||||
done();
|
done()
|
||||||
});
|
})
|
||||||
|
|
||||||
// The watch task (to automatically rebuild when the source code changes)
|
// The watch task (to automatically rebuild when the source code changes)
|
||||||
// Does only generate jsoneditor.js and jsoneditor.css, and copy the image
|
// Does only generate jsoneditor.js and jsoneditor.css, and copy the image
|
||||||
// Does NOT minify the code and does NOT generate the minimalist version
|
// Does NOT minify the code and does NOT generate the minimalist version
|
||||||
gulp.task('watch', gulp.series('bundle', 'bundle-css', 'copy-img', function() {
|
gulp.task('watch', gulp.series('bundle', 'bundle-css', 'copy-img', function () {
|
||||||
gulp.watch(['src/**/*'], gulp.series('bundle', 'bundle-css', 'copy-img'));
|
gulp.watch(['src/**/*'], gulp.series('bundle', 'bundle-css', 'copy-img'))
|
||||||
}));
|
}))
|
||||||
|
|
||||||
// The default task (called when you run `gulp`)
|
// The default task (called when you run `gulp`)
|
||||||
gulp.task('default', gulp.series(
|
gulp.task('default', gulp.series(
|
||||||
'mkdir',
|
'mkdir',
|
||||||
gulp.parallel(
|
gulp.parallel(
|
||||||
'copy-img',
|
'copy-img',
|
||||||
'copy-docs',
|
'copy-docs',
|
||||||
'bundle-css',
|
'bundle-css',
|
||||||
gulp.series('bundle', 'minify'),
|
gulp.series('bundle', 'minify'),
|
||||||
gulp.series('bundle-minimalist', 'minify-minimalist')
|
gulp.series('bundle-minimalist', 'minify-minimalist')
|
||||||
)
|
)
|
||||||
));
|
))
|
||||||
|
|
2
index.js
2
index.js
|
@ -1 +1 @@
|
||||||
module.exports = require('./src/js/JSONEditor');
|
module.exports = require('./src/js/JSONEditor')
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
|
@ -21,7 +21,8 @@
|
||||||
"build": "gulp",
|
"build": "gulp",
|
||||||
"minify": "gulp minify",
|
"minify": "gulp minify",
|
||||||
"start": "gulp watch",
|
"start": "gulp watch",
|
||||||
"test": "mocha test"
|
"test": "mocha test",
|
||||||
|
"lint": "standard --env=mocha"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ajv": "6.10.2",
|
"ajv": "6.10.2",
|
||||||
|
@ -47,7 +48,14 @@
|
||||||
"json-loader": "0.5.7",
|
"json-loader": "0.5.7",
|
||||||
"mkdirp": "0.5.1",
|
"mkdirp": "0.5.1",
|
||||||
"mocha": "6.2.0",
|
"mocha": "6.2.0",
|
||||||
|
"standard": "14.0.2",
|
||||||
"uglify-js": "3.6.0",
|
"uglify-js": "3.6.0",
|
||||||
"webpack": "4.39.3"
|
"webpack": "4.39.3"
|
||||||
|
},
|
||||||
|
"standard": {
|
||||||
|
"ignore": [
|
||||||
|
"src/js/assets",
|
||||||
|
"examples/react*"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,8 @@
|
||||||
'use strict';
|
'use strict'
|
||||||
|
|
||||||
var createAbsoluteAnchor = require('./createAbsoluteAnchor').createAbsoluteAnchor;
|
var createAbsoluteAnchor = require('./createAbsoluteAnchor').createAbsoluteAnchor
|
||||||
var util = require('./util');
|
var util = require('./util')
|
||||||
var translate = require('./i18n').translate;
|
var translate = require('./i18n').translate
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A context menu
|
* A context menu
|
||||||
|
@ -14,153 +14,150 @@ var translate = require('./i18n').translate;
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function ContextMenu (items, options) {
|
function ContextMenu (items, options) {
|
||||||
this.dom = {};
|
this.dom = {}
|
||||||
|
|
||||||
var me = this;
|
var me = this
|
||||||
var dom = this.dom;
|
var dom = this.dom
|
||||||
this.anchor = undefined;
|
this.anchor = undefined
|
||||||
this.items = items;
|
this.items = items
|
||||||
this.eventListeners = {};
|
this.eventListeners = {}
|
||||||
this.selection = undefined; // holds the selection before the menu was opened
|
this.selection = undefined // holds the selection before the menu was opened
|
||||||
this.onClose = options ? options.close : undefined;
|
this.onClose = options ? options.close : undefined
|
||||||
|
|
||||||
// create root element
|
// create root element
|
||||||
var root = document.createElement('div');
|
var root = document.createElement('div')
|
||||||
root.className = 'jsoneditor-contextmenu-root';
|
root.className = 'jsoneditor-contextmenu-root'
|
||||||
dom.root = root;
|
dom.root = root
|
||||||
|
|
||||||
// create a container element
|
// create a container element
|
||||||
var menu = document.createElement('div');
|
var menu = document.createElement('div')
|
||||||
menu.className = 'jsoneditor-contextmenu';
|
menu.className = 'jsoneditor-contextmenu'
|
||||||
dom.menu = menu;
|
dom.menu = menu
|
||||||
root.appendChild(menu);
|
root.appendChild(menu)
|
||||||
|
|
||||||
// create a list to hold the menu items
|
// create a list to hold the menu items
|
||||||
var list = document.createElement('ul');
|
var list = document.createElement('ul')
|
||||||
list.className = 'jsoneditor-menu';
|
list.className = 'jsoneditor-menu'
|
||||||
menu.appendChild(list);
|
menu.appendChild(list)
|
||||||
dom.list = list;
|
dom.list = list
|
||||||
dom.items = []; // list with all buttons
|
dom.items = [] // list with all buttons
|
||||||
|
|
||||||
// create a (non-visible) button to set the focus to the menu
|
// create a (non-visible) button to set the focus to the menu
|
||||||
var focusButton = document.createElement('button');
|
var focusButton = document.createElement('button')
|
||||||
focusButton.type = 'button';
|
focusButton.type = 'button'
|
||||||
dom.focusButton = focusButton;
|
dom.focusButton = focusButton
|
||||||
var li = document.createElement('li');
|
var li = document.createElement('li')
|
||||||
li.style.overflow = 'hidden';
|
li.style.overflow = 'hidden'
|
||||||
li.style.height = '0';
|
li.style.height = '0'
|
||||||
li.appendChild(focusButton);
|
li.appendChild(focusButton)
|
||||||
list.appendChild(li);
|
list.appendChild(li)
|
||||||
|
|
||||||
function createMenuItems (list, domItems, items) {
|
function createMenuItems (list, domItems, items) {
|
||||||
items.forEach(function (item) {
|
items.forEach(function (item) {
|
||||||
if (item.type == 'separator') {
|
if (item.type === 'separator') {
|
||||||
// create a separator
|
// create a separator
|
||||||
var separator = document.createElement('div');
|
var separator = document.createElement('div')
|
||||||
separator.className = 'jsoneditor-separator';
|
separator.className = 'jsoneditor-separator'
|
||||||
li = document.createElement('li');
|
const li = document.createElement('li')
|
||||||
li.appendChild(separator);
|
li.appendChild(separator)
|
||||||
list.appendChild(li);
|
list.appendChild(li)
|
||||||
}
|
} else {
|
||||||
else {
|
var domItem = {}
|
||||||
var domItem = {};
|
|
||||||
|
|
||||||
// create a menu item
|
// create a menu item
|
||||||
var li = document.createElement('li');
|
const li = document.createElement('li')
|
||||||
list.appendChild(li);
|
list.appendChild(li)
|
||||||
|
|
||||||
// create a button in the menu item
|
// create a button in the menu item
|
||||||
var button = document.createElement('button');
|
var button = document.createElement('button')
|
||||||
button.type = 'button';
|
button.type = 'button'
|
||||||
button.className = item.className;
|
button.className = item.className
|
||||||
domItem.button = button;
|
domItem.button = button
|
||||||
if (item.title) {
|
if (item.title) {
|
||||||
button.title = item.title;
|
button.title = item.title
|
||||||
}
|
}
|
||||||
if (item.click) {
|
if (item.click) {
|
||||||
button.onclick = function (event) {
|
button.onclick = function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault()
|
||||||
me.hide();
|
me.hide()
|
||||||
item.click();
|
item.click()
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
li.appendChild(button);
|
li.appendChild(button)
|
||||||
|
|
||||||
// create the contents of the button
|
// create the contents of the button
|
||||||
if (item.submenu) {
|
if (item.submenu) {
|
||||||
// add the icon to the button
|
// add the icon to the button
|
||||||
var divIcon = document.createElement('div');
|
var divIcon = document.createElement('div')
|
||||||
divIcon.className = 'jsoneditor-icon';
|
divIcon.className = 'jsoneditor-icon'
|
||||||
button.appendChild(divIcon);
|
button.appendChild(divIcon)
|
||||||
var divText = document.createElement('div');
|
var divText = document.createElement('div')
|
||||||
divText.className = 'jsoneditor-text' +
|
divText.className = 'jsoneditor-text' +
|
||||||
(item.click ? '' : ' jsoneditor-right-margin');
|
(item.click ? '' : ' jsoneditor-right-margin')
|
||||||
divText.appendChild(document.createTextNode(item.text));
|
divText.appendChild(document.createTextNode(item.text))
|
||||||
button.appendChild(divText);
|
button.appendChild(divText)
|
||||||
|
|
||||||
var buttonSubmenu;
|
var buttonSubmenu
|
||||||
if (item.click) {
|
if (item.click) {
|
||||||
// submenu and a button with a click handler
|
// submenu and a button with a click handler
|
||||||
button.className += ' jsoneditor-default';
|
button.className += ' jsoneditor-default'
|
||||||
|
|
||||||
var buttonExpand = document.createElement('button');
|
var buttonExpand = document.createElement('button')
|
||||||
buttonExpand.type = 'button';
|
buttonExpand.type = 'button'
|
||||||
domItem.buttonExpand = buttonExpand;
|
domItem.buttonExpand = buttonExpand
|
||||||
buttonExpand.className = 'jsoneditor-expand';
|
buttonExpand.className = 'jsoneditor-expand'
|
||||||
buttonExpand.innerHTML = '<div class="jsoneditor-expand"></div>';
|
buttonExpand.innerHTML = '<div class="jsoneditor-expand"></div>'
|
||||||
li.appendChild(buttonExpand);
|
li.appendChild(buttonExpand)
|
||||||
if (item.submenuTitle) {
|
if (item.submenuTitle) {
|
||||||
buttonExpand.title = item.submenuTitle;
|
buttonExpand.title = item.submenuTitle
|
||||||
}
|
}
|
||||||
|
|
||||||
buttonSubmenu = buttonExpand;
|
buttonSubmenu = buttonExpand
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// submenu and a button without a click handler
|
// submenu and a button without a click handler
|
||||||
var divExpand = document.createElement('div');
|
var divExpand = document.createElement('div')
|
||||||
divExpand.className = 'jsoneditor-expand';
|
divExpand.className = 'jsoneditor-expand'
|
||||||
button.appendChild(divExpand);
|
button.appendChild(divExpand)
|
||||||
|
|
||||||
buttonSubmenu = button;
|
buttonSubmenu = button
|
||||||
}
|
}
|
||||||
|
|
||||||
// attach a handler to expand/collapse the submenu
|
// attach a handler to expand/collapse the submenu
|
||||||
buttonSubmenu.onclick = function (event) {
|
buttonSubmenu.onclick = function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault()
|
||||||
me._onExpandItem(domItem);
|
me._onExpandItem(domItem)
|
||||||
buttonSubmenu.focus();
|
buttonSubmenu.focus()
|
||||||
};
|
}
|
||||||
|
|
||||||
// create the submenu
|
// create the submenu
|
||||||
var domSubItems = [];
|
var domSubItems = []
|
||||||
domItem.subItems = domSubItems;
|
domItem.subItems = domSubItems
|
||||||
var ul = document.createElement('ul');
|
var ul = document.createElement('ul')
|
||||||
domItem.ul = ul;
|
domItem.ul = ul
|
||||||
ul.className = 'jsoneditor-menu';
|
ul.className = 'jsoneditor-menu'
|
||||||
ul.style.height = '0';
|
ul.style.height = '0'
|
||||||
li.appendChild(ul);
|
li.appendChild(ul)
|
||||||
createMenuItems(ul, domSubItems, item.submenu);
|
createMenuItems(ul, domSubItems, item.submenu)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// no submenu, just a button with clickhandler
|
// no submenu, just a button with clickhandler
|
||||||
button.innerHTML = '<div class="jsoneditor-icon"></div>' +
|
button.innerHTML = '<div class="jsoneditor-icon"></div>' +
|
||||||
'<div class="jsoneditor-text">' + translate(item.text) + '</div>';
|
'<div class="jsoneditor-text">' + translate(item.text) + '</div>'
|
||||||
}
|
}
|
||||||
|
|
||||||
domItems.push(domItem);
|
domItems.push(domItem)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
createMenuItems(list, this.dom.items, items);
|
createMenuItems(list, this.dom.items, items)
|
||||||
|
|
||||||
// TODO: when the editor is small, show the submenu on the right instead of inline?
|
// 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
|
// calculate the max height of the menu with one submenu expanded
|
||||||
this.maxHeight = 0; // height in pixels
|
this.maxHeight = 0 // height in pixels
|
||||||
items.forEach(function (item) {
|
items.forEach(function (item) {
|
||||||
var height = (items.length + (item.submenu ? item.submenu.length : 0)) * 24;
|
var height = (items.length + (item.submenu ? item.submenu.length : 0)) * 24
|
||||||
me.maxHeight = Math.max(me.maxHeight, height);
|
me.maxHeight = Math.max(me.maxHeight, height)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -169,29 +166,29 @@ function ContextMenu (items, options) {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
ContextMenu.prototype._getVisibleButtons = function () {
|
ContextMenu.prototype._getVisibleButtons = function () {
|
||||||
var buttons = [];
|
var buttons = []
|
||||||
var me = this;
|
var me = this
|
||||||
this.dom.items.forEach(function (item) {
|
this.dom.items.forEach(function (item) {
|
||||||
buttons.push(item.button);
|
buttons.push(item.button)
|
||||||
if (item.buttonExpand) {
|
if (item.buttonExpand) {
|
||||||
buttons.push(item.buttonExpand);
|
buttons.push(item.buttonExpand)
|
||||||
}
|
}
|
||||||
if (item.subItems && item == me.expandedItem) {
|
if (item.subItems && item === me.expandedItem) {
|
||||||
item.subItems.forEach(function (subItem) {
|
item.subItems.forEach(function (subItem) {
|
||||||
buttons.push(subItem.button);
|
buttons.push(subItem.button)
|
||||||
if (subItem.buttonExpand) {
|
if (subItem.buttonExpand) {
|
||||||
buttons.push(subItem.buttonExpand);
|
buttons.push(subItem.buttonExpand)
|
||||||
}
|
}
|
||||||
// TODO: change to fully recursive method
|
// TODO: change to fully recursive method
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
return buttons;
|
return buttons
|
||||||
};
|
}
|
||||||
|
|
||||||
// currently displayed context menu, a singleton. We may only have one visible context menu
|
// currently displayed context menu, a singleton. We may only have one visible context menu
|
||||||
ContextMenu.visibleMenu = undefined;
|
ContextMenu.visibleMenu = undefined
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attach the menu to an anchor
|
* Attach the menu to an anchor
|
||||||
|
@ -200,64 +197,61 @@ ContextMenu.visibleMenu = undefined;
|
||||||
* @param {Boolean=} ignoreParent ignore anchor parent in regard to the calculation of the position, needed when the parent position is absolute
|
* @param {Boolean=} ignoreParent ignore anchor parent in regard to the calculation of the position, needed when the parent position is absolute
|
||||||
*/
|
*/
|
||||||
ContextMenu.prototype.show = function (anchor, frame, ignoreParent) {
|
ContextMenu.prototype.show = function (anchor, frame, ignoreParent) {
|
||||||
this.hide();
|
this.hide()
|
||||||
|
|
||||||
// determine whether to display the menu below or above the anchor
|
// determine whether to display the menu below or above the anchor
|
||||||
var showBelow = true;
|
var showBelow = true
|
||||||
var parent = anchor.parentNode;
|
var parent = anchor.parentNode
|
||||||
var anchorRect = anchor.getBoundingClientRect();
|
var anchorRect = anchor.getBoundingClientRect()
|
||||||
var parentRect = parent.getBoundingClientRect();
|
var parentRect = parent.getBoundingClientRect()
|
||||||
var frameRect = frame.getBoundingClientRect();
|
var frameRect = frame.getBoundingClientRect()
|
||||||
|
|
||||||
var me = this;
|
var me = this
|
||||||
this.dom.absoluteAnchor = createAbsoluteAnchor(anchor, frame, function () {
|
this.dom.absoluteAnchor = createAbsoluteAnchor(anchor, frame, function () {
|
||||||
me.hide()
|
me.hide()
|
||||||
});
|
})
|
||||||
|
|
||||||
if (anchorRect.bottom + this.maxHeight < frameRect.bottom) {
|
if (anchorRect.bottom + this.maxHeight < frameRect.bottom) {
|
||||||
// fits below -> show below
|
// fits below -> show below
|
||||||
}
|
} else if (anchorRect.top - this.maxHeight > frameRect.top) {
|
||||||
else if (anchorRect.top - this.maxHeight > frameRect.top) {
|
|
||||||
// fits above -> show above
|
// fits above -> show above
|
||||||
showBelow = false;
|
showBelow = false
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// doesn't fit above nor below -> show below
|
// doesn't fit above nor below -> show below
|
||||||
}
|
}
|
||||||
|
|
||||||
var topGap = ignoreParent ? 0 : (anchorRect.top - parentRect.top);
|
var topGap = ignoreParent ? 0 : (anchorRect.top - parentRect.top)
|
||||||
|
|
||||||
// position the menu
|
// position the menu
|
||||||
if (showBelow) {
|
if (showBelow) {
|
||||||
// display the menu below the anchor
|
// display the menu below the anchor
|
||||||
var anchorHeight = anchor.offsetHeight;
|
var anchorHeight = anchor.offsetHeight
|
||||||
this.dom.menu.style.left = '0';
|
this.dom.menu.style.left = '0'
|
||||||
this.dom.menu.style.top = topGap + anchorHeight + 'px';
|
this.dom.menu.style.top = topGap + anchorHeight + 'px'
|
||||||
this.dom.menu.style.bottom = '';
|
this.dom.menu.style.bottom = ''
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// display the menu above the anchor
|
// display the menu above the anchor
|
||||||
this.dom.menu.style.left = '0';
|
this.dom.menu.style.left = '0'
|
||||||
this.dom.menu.style.top = '';
|
this.dom.menu.style.top = ''
|
||||||
this.dom.menu.style.bottom = '0px';
|
this.dom.menu.style.bottom = '0px'
|
||||||
}
|
}
|
||||||
|
|
||||||
// attach the menu to the temporary, absolute anchor
|
// attach the menu to the temporary, absolute anchor
|
||||||
// parent.insertBefore(this.dom.root, anchor);
|
// parent.insertBefore(this.dom.root, anchor);
|
||||||
this.dom.absoluteAnchor.appendChild(this.dom.root);
|
this.dom.absoluteAnchor.appendChild(this.dom.root)
|
||||||
|
|
||||||
// move focus to the first button in the context menu
|
// move focus to the first button in the context menu
|
||||||
this.selection = util.getSelection();
|
this.selection = util.getSelection()
|
||||||
this.anchor = anchor;
|
this.anchor = anchor
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
me.dom.focusButton.focus();
|
me.dom.focusButton.focus()
|
||||||
}, 0);
|
}, 0)
|
||||||
|
|
||||||
if (ContextMenu.visibleMenu) {
|
if (ContextMenu.visibleMenu) {
|
||||||
ContextMenu.visibleMenu.hide();
|
ContextMenu.visibleMenu.hide()
|
||||||
}
|
}
|
||||||
ContextMenu.visibleMenu = this;
|
ContextMenu.visibleMenu = this
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Hide the context menu if visible
|
* Hide the context menu if visible
|
||||||
|
@ -265,22 +259,22 @@ ContextMenu.prototype.show = function (anchor, frame, ignoreParent) {
|
||||||
ContextMenu.prototype.hide = function () {
|
ContextMenu.prototype.hide = function () {
|
||||||
// remove temporary absolutely positioned anchor
|
// remove temporary absolutely positioned anchor
|
||||||
if (this.dom.absoluteAnchor) {
|
if (this.dom.absoluteAnchor) {
|
||||||
this.dom.absoluteAnchor.destroy();
|
this.dom.absoluteAnchor.destroy()
|
||||||
delete this.dom.absoluteAnchor;
|
delete this.dom.absoluteAnchor
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove the menu from the DOM
|
// remove the menu from the DOM
|
||||||
if (this.dom.root.parentNode) {
|
if (this.dom.root.parentNode) {
|
||||||
this.dom.root.parentNode.removeChild(this.dom.root);
|
this.dom.root.parentNode.removeChild(this.dom.root)
|
||||||
if (this.onClose) {
|
if (this.onClose) {
|
||||||
this.onClose();
|
this.onClose()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ContextMenu.visibleMenu == this) {
|
if (ContextMenu.visibleMenu === this) {
|
||||||
ContextMenu.visibleMenu = undefined;
|
ContextMenu.visibleMenu = undefined
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Expand a submenu
|
* Expand a submenu
|
||||||
|
@ -289,42 +283,43 @@ ContextMenu.prototype.hide = function () {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
ContextMenu.prototype._onExpandItem = function (domItem) {
|
ContextMenu.prototype._onExpandItem = function (domItem) {
|
||||||
var me = this;
|
var me = this
|
||||||
var alreadyVisible = (domItem == this.expandedItem);
|
var alreadyVisible = (domItem === this.expandedItem)
|
||||||
|
|
||||||
// hide the currently visible submenu
|
// hide the currently visible submenu
|
||||||
var expandedItem = this.expandedItem;
|
var expandedItem = this.expandedItem
|
||||||
if (expandedItem) {
|
if (expandedItem) {
|
||||||
//var ul = expandedItem.ul;
|
// var ul = expandedItem.ul;
|
||||||
expandedItem.ul.style.height = '0';
|
expandedItem.ul.style.height = '0'
|
||||||
expandedItem.ul.style.padding = '';
|
expandedItem.ul.style.padding = ''
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
if (me.expandedItem != expandedItem) {
|
if (me.expandedItem !== expandedItem) {
|
||||||
expandedItem.ul.style.display = '';
|
expandedItem.ul.style.display = ''
|
||||||
util.removeClassName(expandedItem.ul.parentNode, 'jsoneditor-selected');
|
util.removeClassName(expandedItem.ul.parentNode, 'jsoneditor-selected')
|
||||||
}
|
}
|
||||||
}, 300); // timeout duration must match the css transition duration
|
}, 300) // timeout duration must match the css transition duration
|
||||||
this.expandedItem = undefined;
|
this.expandedItem = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!alreadyVisible) {
|
if (!alreadyVisible) {
|
||||||
var ul = domItem.ul;
|
var ul = domItem.ul
|
||||||
ul.style.display = 'block';
|
ul.style.display = 'block'
|
||||||
var height = ul.clientHeight; // force a reflow in Firefox
|
// eslint-disable-next-line no-unused-expressions
|
||||||
|
ul.clientHeight // force a reflow in Firefox
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
if (me.expandedItem == domItem) {
|
if (me.expandedItem === domItem) {
|
||||||
var childsHeight = 0;
|
var childsHeight = 0
|
||||||
for (var i = 0; i < ul.childNodes.length; i++) {
|
for (var i = 0; i < ul.childNodes.length; i++) {
|
||||||
childsHeight += ul.childNodes[i].clientHeight;
|
childsHeight += ul.childNodes[i].clientHeight
|
||||||
}
|
}
|
||||||
ul.style.height = childsHeight + 'px';
|
ul.style.height = childsHeight + 'px'
|
||||||
ul.style.padding = '5px 10px';
|
ul.style.padding = '5px 10px'
|
||||||
}
|
}
|
||||||
}, 0);
|
}, 0)
|
||||||
util.addClassName(ul.parentNode, 'jsoneditor-selected');
|
util.addClassName(ul.parentNode, 'jsoneditor-selected')
|
||||||
this.expandedItem = domItem;
|
this.expandedItem = domItem
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle onkeydown event
|
* Handle onkeydown event
|
||||||
|
@ -332,107 +327,101 @@ ContextMenu.prototype._onExpandItem = function (domItem) {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
ContextMenu.prototype._onKeyDown = function (event) {
|
ContextMenu.prototype._onKeyDown = function (event) {
|
||||||
var target = event.target;
|
var target = event.target
|
||||||
var keynum = event.which;
|
var keynum = event.which
|
||||||
var handled = false;
|
var handled = false
|
||||||
var buttons, targetIndex, prevButton, nextButton;
|
var buttons, targetIndex, prevButton, nextButton
|
||||||
|
|
||||||
if (keynum == 27) { // ESC
|
if (keynum === 27) { // ESC
|
||||||
// hide the menu on ESC key
|
// hide the menu on ESC key
|
||||||
|
|
||||||
// restore previous selection and focus
|
// restore previous selection and focus
|
||||||
if (this.selection) {
|
if (this.selection) {
|
||||||
util.setSelection(this.selection);
|
util.setSelection(this.selection)
|
||||||
}
|
}
|
||||||
if (this.anchor) {
|
if (this.anchor) {
|
||||||
this.anchor.focus();
|
this.anchor.focus()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.hide();
|
this.hide()
|
||||||
|
|
||||||
handled = true;
|
handled = true
|
||||||
}
|
} else if (keynum === 9) { // Tab
|
||||||
else if (keynum == 9) { // Tab
|
|
||||||
if (!event.shiftKey) { // Tab
|
if (!event.shiftKey) { // Tab
|
||||||
buttons = this._getVisibleButtons();
|
buttons = this._getVisibleButtons()
|
||||||
targetIndex = buttons.indexOf(target);
|
targetIndex = buttons.indexOf(target)
|
||||||
if (targetIndex == buttons.length - 1) {
|
if (targetIndex === buttons.length - 1) {
|
||||||
// move to first button
|
// move to first button
|
||||||
buttons[0].focus();
|
buttons[0].focus()
|
||||||
handled = true;
|
handled = true
|
||||||
}
|
}
|
||||||
}
|
} else { // Shift+Tab
|
||||||
else { // Shift+Tab
|
buttons = this._getVisibleButtons()
|
||||||
buttons = this._getVisibleButtons();
|
targetIndex = buttons.indexOf(target)
|
||||||
targetIndex = buttons.indexOf(target);
|
if (targetIndex === 0) {
|
||||||
if (targetIndex == 0) {
|
|
||||||
// move to last button
|
// move to last button
|
||||||
buttons[buttons.length - 1].focus();
|
buttons[buttons.length - 1].focus()
|
||||||
handled = true;
|
handled = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else if (keynum === 37) { // Arrow Left
|
||||||
else if (keynum == 37) { // Arrow Left
|
if (target.className === 'jsoneditor-expand') {
|
||||||
if (target.className == 'jsoneditor-expand') {
|
buttons = this._getVisibleButtons()
|
||||||
buttons = this._getVisibleButtons();
|
targetIndex = buttons.indexOf(target)
|
||||||
targetIndex = buttons.indexOf(target);
|
prevButton = buttons[targetIndex - 1]
|
||||||
prevButton = buttons[targetIndex - 1];
|
|
||||||
if (prevButton) {
|
if (prevButton) {
|
||||||
prevButton.focus();
|
prevButton.focus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
handled = true;
|
handled = true
|
||||||
}
|
} else if (keynum === 38) { // Arrow Up
|
||||||
else if (keynum == 38) { // Arrow Up
|
buttons = this._getVisibleButtons()
|
||||||
buttons = this._getVisibleButtons();
|
targetIndex = buttons.indexOf(target)
|
||||||
targetIndex = buttons.indexOf(target);
|
prevButton = buttons[targetIndex - 1]
|
||||||
prevButton = buttons[targetIndex - 1];
|
if (prevButton && prevButton.className === 'jsoneditor-expand') {
|
||||||
if (prevButton && prevButton.className == 'jsoneditor-expand') {
|
|
||||||
// skip expand button
|
// skip expand button
|
||||||
prevButton = buttons[targetIndex - 2];
|
prevButton = buttons[targetIndex - 2]
|
||||||
}
|
}
|
||||||
if (!prevButton) {
|
if (!prevButton) {
|
||||||
// move to last button
|
// move to last button
|
||||||
prevButton = buttons[buttons.length - 1];
|
prevButton = buttons[buttons.length - 1]
|
||||||
}
|
}
|
||||||
if (prevButton) {
|
if (prevButton) {
|
||||||
prevButton.focus();
|
prevButton.focus()
|
||||||
}
|
}
|
||||||
handled = true;
|
handled = true
|
||||||
}
|
} else if (keynum === 39) { // Arrow Right
|
||||||
else if (keynum == 39) { // Arrow Right
|
buttons = this._getVisibleButtons()
|
||||||
buttons = this._getVisibleButtons();
|
targetIndex = buttons.indexOf(target)
|
||||||
targetIndex = buttons.indexOf(target);
|
nextButton = buttons[targetIndex + 1]
|
||||||
nextButton = buttons[targetIndex + 1];
|
if (nextButton && nextButton.className === 'jsoneditor-expand') {
|
||||||
if (nextButton && nextButton.className == 'jsoneditor-expand') {
|
nextButton.focus()
|
||||||
nextButton.focus();
|
|
||||||
}
|
}
|
||||||
handled = true;
|
handled = true
|
||||||
}
|
} else if (keynum === 40) { // Arrow Down
|
||||||
else if (keynum == 40) { // Arrow Down
|
buttons = this._getVisibleButtons()
|
||||||
buttons = this._getVisibleButtons();
|
targetIndex = buttons.indexOf(target)
|
||||||
targetIndex = buttons.indexOf(target);
|
nextButton = buttons[targetIndex + 1]
|
||||||
nextButton = buttons[targetIndex + 1];
|
if (nextButton && nextButton.className === 'jsoneditor-expand') {
|
||||||
if (nextButton && nextButton.className == 'jsoneditor-expand') {
|
|
||||||
// skip expand button
|
// skip expand button
|
||||||
nextButton = buttons[targetIndex + 2];
|
nextButton = buttons[targetIndex + 2]
|
||||||
}
|
}
|
||||||
if (!nextButton) {
|
if (!nextButton) {
|
||||||
// move to first button
|
// move to first button
|
||||||
nextButton = buttons[0];
|
nextButton = buttons[0]
|
||||||
}
|
}
|
||||||
if (nextButton) {
|
if (nextButton) {
|
||||||
nextButton.focus();
|
nextButton.focus()
|
||||||
handled = true;
|
handled = true
|
||||||
}
|
}
|
||||||
handled = true;
|
handled = true
|
||||||
}
|
}
|
||||||
// TODO: arrow left and right
|
// TODO: arrow left and right
|
||||||
|
|
||||||
if (handled) {
|
if (handled) {
|
||||||
event.stopPropagation();
|
event.stopPropagation()
|
||||||
event.preventDefault();
|
event.preventDefault()
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
module.exports = ContextMenu;
|
module.exports = ContextMenu
|
||||||
|
|
|
@ -8,170 +8,167 @@
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function ErrorTable (config) {
|
function ErrorTable (config) {
|
||||||
this.errorTableVisible = config.errorTableVisible;
|
this.errorTableVisible = config.errorTableVisible
|
||||||
this.onToggleVisibility = config.onToggleVisibility;
|
this.onToggleVisibility = config.onToggleVisibility
|
||||||
this.onFocusLine = config.onFocusLine || function () {};
|
this.onFocusLine = config.onFocusLine || function () {}
|
||||||
this.onChangeHeight = config.onChangeHeight;
|
this.onChangeHeight = config.onChangeHeight
|
||||||
|
|
||||||
this.dom = {};
|
this.dom = {}
|
||||||
|
|
||||||
var validationErrorsContainer = document.createElement('div');
|
var validationErrorsContainer = document.createElement('div')
|
||||||
validationErrorsContainer.className = 'jsoneditor-validation-errors-container';
|
validationErrorsContainer.className = 'jsoneditor-validation-errors-container'
|
||||||
this.dom.validationErrorsContainer = validationErrorsContainer;
|
this.dom.validationErrorsContainer = validationErrorsContainer
|
||||||
|
|
||||||
var additionalErrorsIndication = document.createElement('div');
|
var additionalErrorsIndication = document.createElement('div')
|
||||||
additionalErrorsIndication.style.display = 'none';
|
additionalErrorsIndication.style.display = 'none'
|
||||||
additionalErrorsIndication.className = "jsoneditor-additional-errors fadein";
|
additionalErrorsIndication.className = 'jsoneditor-additional-errors fadein'
|
||||||
additionalErrorsIndication.innerHTML = "Scroll for more ▿";
|
additionalErrorsIndication.innerHTML = 'Scroll for more ▿'
|
||||||
this.dom.additionalErrorsIndication = additionalErrorsIndication;
|
this.dom.additionalErrorsIndication = additionalErrorsIndication
|
||||||
validationErrorsContainer.appendChild(additionalErrorsIndication);
|
validationErrorsContainer.appendChild(additionalErrorsIndication)
|
||||||
|
|
||||||
var validationErrorIcon = document.createElement('span');
|
var validationErrorIcon = document.createElement('span')
|
||||||
validationErrorIcon.className = 'jsoneditor-validation-error-icon';
|
validationErrorIcon.className = 'jsoneditor-validation-error-icon'
|
||||||
validationErrorIcon.style.display = 'none';
|
validationErrorIcon.style.display = 'none'
|
||||||
this.dom.validationErrorIcon = validationErrorIcon;
|
this.dom.validationErrorIcon = validationErrorIcon
|
||||||
|
|
||||||
var validationErrorCount = document.createElement('span');
|
var validationErrorCount = document.createElement('span')
|
||||||
validationErrorCount.className = 'jsoneditor-validation-error-count';
|
validationErrorCount.className = 'jsoneditor-validation-error-count'
|
||||||
validationErrorCount.style.display = 'none';
|
validationErrorCount.style.display = 'none'
|
||||||
this.dom.validationErrorCount = validationErrorCount;
|
this.dom.validationErrorCount = validationErrorCount
|
||||||
|
|
||||||
this.dom.parseErrorIndication = document.createElement('span');
|
this.dom.parseErrorIndication = document.createElement('span')
|
||||||
this.dom.parseErrorIndication.className = 'jsoneditor-parse-error-icon';
|
this.dom.parseErrorIndication.className = 'jsoneditor-parse-error-icon'
|
||||||
this.dom.parseErrorIndication.style.display = 'none';
|
this.dom.parseErrorIndication.style.display = 'none'
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorTable.prototype.getErrorTable = function () {
|
ErrorTable.prototype.getErrorTable = function () {
|
||||||
return this.dom.validationErrorsContainer;
|
return this.dom.validationErrorsContainer
|
||||||
};
|
}
|
||||||
|
|
||||||
ErrorTable.prototype.getErrorCounter = function () {
|
ErrorTable.prototype.getErrorCounter = function () {
|
||||||
return this.dom.validationErrorCount;
|
return this.dom.validationErrorCount
|
||||||
};
|
}
|
||||||
|
|
||||||
ErrorTable.prototype.getWarningIcon = function () {
|
ErrorTable.prototype.getWarningIcon = function () {
|
||||||
return this.dom.validationErrorIcon;
|
return this.dom.validationErrorIcon
|
||||||
};
|
}
|
||||||
|
|
||||||
ErrorTable.prototype.getErrorIcon = function () {
|
ErrorTable.prototype.getErrorIcon = function () {
|
||||||
return this.dom.parseErrorIndication;
|
return this.dom.parseErrorIndication
|
||||||
};
|
}
|
||||||
|
|
||||||
ErrorTable.prototype.toggleTableVisibility = function () {
|
ErrorTable.prototype.toggleTableVisibility = function () {
|
||||||
this.errorTableVisible = !this.errorTableVisible;
|
this.errorTableVisible = !this.errorTableVisible
|
||||||
this.onToggleVisibility(this.errorTableVisible);
|
this.onToggleVisibility(this.errorTableVisible)
|
||||||
}
|
}
|
||||||
|
|
||||||
ErrorTable.prototype.setErrors = function (errors, errorLocations) {
|
ErrorTable.prototype.setErrors = function (errors, errorLocations) {
|
||||||
var me = this;
|
var me = this
|
||||||
|
|
||||||
// clear any previous errors
|
// clear any previous errors
|
||||||
if (this.dom.validationErrors) {
|
if (this.dom.validationErrors) {
|
||||||
this.dom.validationErrors.parentNode.removeChild(this.dom.validationErrors);
|
this.dom.validationErrors.parentNode.removeChild(this.dom.validationErrors)
|
||||||
this.dom.validationErrors = null;
|
this.dom.validationErrors = null
|
||||||
this.dom.additionalErrorsIndication.style.display = 'none';
|
this.dom.additionalErrorsIndication.style.display = 'none'
|
||||||
}
|
}
|
||||||
|
|
||||||
// create the table with errors
|
// create the table with errors
|
||||||
// keep default behavior for parse errors
|
// keep default behavior for parse errors
|
||||||
if (this.errorTableVisible && errors.length > 0) {
|
if (this.errorTableVisible && errors.length > 0) {
|
||||||
var validationErrors = document.createElement('div');
|
var validationErrors = document.createElement('div')
|
||||||
validationErrors.className = 'jsoneditor-validation-errors';
|
validationErrors.className = 'jsoneditor-validation-errors'
|
||||||
validationErrors.innerHTML = '<table class="jsoneditor-text-errors"><tbody></tbody></table>';
|
validationErrors.innerHTML = '<table class="jsoneditor-text-errors"><tbody></tbody></table>'
|
||||||
var tbody = validationErrors.getElementsByTagName('tbody')[0];
|
var tbody = validationErrors.getElementsByTagName('tbody')[0]
|
||||||
|
|
||||||
errors.forEach(function (error) {
|
errors.forEach(function (error) {
|
||||||
var message;
|
var message
|
||||||
if (typeof error === 'string') {
|
if (typeof error === 'string') {
|
||||||
message = '<td colspan="2"><pre>' + error + '</pre></td>';
|
message = '<td colspan="2"><pre>' + error + '</pre></td>'
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
message =
|
message =
|
||||||
'<td>' + (error.dataPath || '') + '</td>' +
|
'<td>' + (error.dataPath || '') + '</td>' +
|
||||||
'<td><pre>' + error.message + '</pre></td>';
|
'<td><pre>' + error.message + '</pre></td>'
|
||||||
}
|
}
|
||||||
|
|
||||||
var line;
|
var line
|
||||||
|
|
||||||
if (!isNaN(error.line)) {
|
if (!isNaN(error.line)) {
|
||||||
line = error.line;
|
line = error.line
|
||||||
} else if (error.dataPath) {
|
} else if (error.dataPath) {
|
||||||
var errLoc = errorLocations.find(function(loc) { return loc.path === error.dataPath; });
|
var errLoc = errorLocations.find(function (loc) { return loc.path === error.dataPath })
|
||||||
if (errLoc) {
|
if (errLoc) {
|
||||||
line = errLoc.line + 1;
|
line = errLoc.line + 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var trEl = document.createElement('tr');
|
var trEl = document.createElement('tr')
|
||||||
trEl.className = !isNaN(line) ? 'jump-to-line' : '';
|
trEl.className = !isNaN(line) ? 'jump-to-line' : ''
|
||||||
if (error.type === 'error') {
|
if (error.type === 'error') {
|
||||||
trEl.className += ' parse-error';
|
trEl.className += ' parse-error'
|
||||||
} else {
|
} else {
|
||||||
trEl.className += ' validation-error';
|
trEl.className += ' validation-error'
|
||||||
}
|
}
|
||||||
|
|
||||||
trEl.innerHTML = ('<td><button class="jsoneditor-schema-error"></button></td><td style="white-space:nowrap;">'+ (!isNaN(line) ? ('Ln ' + line) : '') +'</td>' + message);
|
trEl.innerHTML = ('<td><button class="jsoneditor-schema-error"></button></td><td style="white-space:nowrap;">' + (!isNaN(line) ? ('Ln ' + line) : '') + '</td>' + message)
|
||||||
trEl.onclick = function() {
|
trEl.onclick = function () {
|
||||||
me.onFocusLine(line);
|
me.onFocusLine(line)
|
||||||
};
|
}
|
||||||
|
|
||||||
tbody.appendChild(trEl);
|
tbody.appendChild(trEl)
|
||||||
});
|
})
|
||||||
|
|
||||||
this.dom.validationErrors = validationErrors;
|
this.dom.validationErrors = validationErrors
|
||||||
this.dom.validationErrorsContainer.appendChild(validationErrors);
|
this.dom.validationErrorsContainer.appendChild(validationErrors)
|
||||||
this.dom.additionalErrorsIndication.title = errors.length + " errors total";
|
this.dom.additionalErrorsIndication.title = errors.length + ' errors total'
|
||||||
|
|
||||||
if (this.dom.validationErrorsContainer.clientHeight < this.dom.validationErrorsContainer.scrollHeight) {
|
if (this.dom.validationErrorsContainer.clientHeight < this.dom.validationErrorsContainer.scrollHeight) {
|
||||||
this.dom.additionalErrorsIndication.style.display = 'block';
|
this.dom.additionalErrorsIndication.style.display = 'block'
|
||||||
this.dom.validationErrorsContainer.onscroll = function () {
|
this.dom.validationErrorsContainer.onscroll = function () {
|
||||||
me.dom.additionalErrorsIndication.style.display =
|
me.dom.additionalErrorsIndication.style.display =
|
||||||
(me.dom.validationErrorsContainer.clientHeight > 0 && me.dom.validationErrorsContainer.scrollTop === 0) ? 'block' : 'none';
|
(me.dom.validationErrorsContainer.clientHeight > 0 && me.dom.validationErrorsContainer.scrollTop === 0) ? 'block' : 'none'
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.dom.validationErrorsContainer.onscroll = undefined;
|
this.dom.validationErrorsContainer.onscroll = undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
var height = this.dom.validationErrorsContainer.clientHeight + (this.dom.statusBar ? this.dom.statusBar.clientHeight : 0);
|
var height = this.dom.validationErrorsContainer.clientHeight + (this.dom.statusBar ? this.dom.statusBar.clientHeight : 0)
|
||||||
// this.content.style.marginBottom = (-height) + 'px';
|
// this.content.style.marginBottom = (-height) + 'px';
|
||||||
// this.content.style.paddingBottom = height + 'px';
|
// this.content.style.paddingBottom = height + 'px';
|
||||||
this.onChangeHeight(height);
|
this.onChangeHeight(height)
|
||||||
} else {
|
} else {
|
||||||
this.onChangeHeight(0);
|
this.onChangeHeight(0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the status bar
|
// update the status bar
|
||||||
var validationErrorsCount = errors.filter(function (error) {
|
var validationErrorsCount = errors.filter(function (error) {
|
||||||
return error.type !== 'error'
|
return error.type !== 'error'
|
||||||
}).length;
|
}).length
|
||||||
if (validationErrorsCount > 0) {
|
if (validationErrorsCount > 0) {
|
||||||
this.dom.validationErrorCount.style.display = 'inline';
|
this.dom.validationErrorCount.style.display = 'inline'
|
||||||
this.dom.validationErrorCount.innerText = validationErrorsCount;
|
this.dom.validationErrorCount.innerText = validationErrorsCount
|
||||||
this.dom.validationErrorCount.onclick = this.toggleTableVisibility.bind(this);
|
this.dom.validationErrorCount.onclick = this.toggleTableVisibility.bind(this)
|
||||||
|
|
||||||
this.dom.validationErrorIcon.style.display = 'inline';
|
this.dom.validationErrorIcon.style.display = 'inline'
|
||||||
this.dom.validationErrorIcon.title = validationErrorsCount + ' schema validation error(s) found';
|
this.dom.validationErrorIcon.title = validationErrorsCount + ' schema validation error(s) found'
|
||||||
this.dom.validationErrorIcon.onclick = this.toggleTableVisibility.bind(this);
|
this.dom.validationErrorIcon.onclick = this.toggleTableVisibility.bind(this)
|
||||||
}
|
} else {
|
||||||
else {
|
this.dom.validationErrorCount.style.display = 'none'
|
||||||
this.dom.validationErrorCount.style.display = 'none';
|
this.dom.validationErrorIcon.style.display = 'none'
|
||||||
this.dom.validationErrorIcon.style.display = 'none';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the parse error icon
|
// update the parse error icon
|
||||||
var hasParseErrors = errors.some(function (error) {
|
var hasParseErrors = errors.some(function (error) {
|
||||||
return error.type === 'error'
|
return error.type === 'error'
|
||||||
});
|
})
|
||||||
if (hasParseErrors) {
|
if (hasParseErrors) {
|
||||||
var line = errors[0].line
|
var line = errors[0].line
|
||||||
this.dom.parseErrorIndication.style.display = 'block';
|
this.dom.parseErrorIndication.style.display = 'block'
|
||||||
this.dom.parseErrorIndication.title = !isNaN(line)
|
this.dom.parseErrorIndication.title = !isNaN(line)
|
||||||
? ('parse error on line ' + line)
|
? ('parse error on line ' + line)
|
||||||
: 'parse error - check that the json is valid';
|
: 'parse error - check that the json is valid'
|
||||||
|
} else {
|
||||||
|
this.dom.parseErrorIndication.style.display = 'none'
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
this.dom.parseErrorIndication.style.display = 'none';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
module.exports = ErrorTable;
|
module.exports = ErrorTable
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
'use strict';
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The highlighter can highlight/unhighlight a node, and
|
* The highlighter can highlight/unhighlight a node, and
|
||||||
|
@ -6,7 +6,7 @@
|
||||||
* @constructor Highlighter
|
* @constructor Highlighter
|
||||||
*/
|
*/
|
||||||
function Highlighter () {
|
function Highlighter () {
|
||||||
this.locked = false;
|
this.locked = false
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -15,23 +15,23 @@ function Highlighter () {
|
||||||
*/
|
*/
|
||||||
Highlighter.prototype.highlight = function (node) {
|
Highlighter.prototype.highlight = function (node) {
|
||||||
if (this.locked) {
|
if (this.locked) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.node != node) {
|
if (this.node !== node) {
|
||||||
// unhighlight current node
|
// unhighlight current node
|
||||||
if (this.node) {
|
if (this.node) {
|
||||||
this.node.setHighlight(false);
|
this.node.setHighlight(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// highlight new node
|
// highlight new node
|
||||||
this.node = node;
|
this.node = node
|
||||||
this.node.setHighlight(true);
|
this.node.setHighlight(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// cancel any current timeout
|
// cancel any current timeout
|
||||||
this._cancelUnhighlight();
|
this._cancelUnhighlight()
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unhighlight currently highlighted node.
|
* Unhighlight currently highlighted node.
|
||||||
|
@ -39,23 +39,23 @@ Highlighter.prototype.highlight = function (node) {
|
||||||
*/
|
*/
|
||||||
Highlighter.prototype.unhighlight = function () {
|
Highlighter.prototype.unhighlight = function () {
|
||||||
if (this.locked) {
|
if (this.locked) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var me = this;
|
var me = this
|
||||||
if (this.node) {
|
if (this.node) {
|
||||||
this._cancelUnhighlight();
|
this._cancelUnhighlight()
|
||||||
|
|
||||||
// do the unhighlighting after a small delay, to prevent re-highlighting
|
// do the unhighlighting after a small delay, to prevent re-highlighting
|
||||||
// the same node when moving from the drag-icon to the contextmenu-icon
|
// the same node when moving from the drag-icon to the contextmenu-icon
|
||||||
// or vice versa.
|
// or vice versa.
|
||||||
this.unhighlightTimer = setTimeout(function () {
|
this.unhighlightTimer = setTimeout(function () {
|
||||||
me.node.setHighlight(false);
|
me.node.setHighlight(false)
|
||||||
me.node = undefined;
|
me.node = undefined
|
||||||
me.unhighlightTimer = undefined;
|
me.unhighlightTimer = undefined
|
||||||
}, 0);
|
}, 0)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel an unhighlight action (if before the timeout of the unhighlight action)
|
* Cancel an unhighlight action (if before the timeout of the unhighlight action)
|
||||||
|
@ -63,24 +63,24 @@ Highlighter.prototype.unhighlight = function () {
|
||||||
*/
|
*/
|
||||||
Highlighter.prototype._cancelUnhighlight = function () {
|
Highlighter.prototype._cancelUnhighlight = function () {
|
||||||
if (this.unhighlightTimer) {
|
if (this.unhighlightTimer) {
|
||||||
clearTimeout(this.unhighlightTimer);
|
clearTimeout(this.unhighlightTimer)
|
||||||
this.unhighlightTimer = undefined;
|
this.unhighlightTimer = undefined
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lock highlighting or unhighlighting nodes.
|
* Lock highlighting or unhighlighting nodes.
|
||||||
* methods highlight and unhighlight do not work while locked.
|
* methods highlight and unhighlight do not work while locked.
|
||||||
*/
|
*/
|
||||||
Highlighter.prototype.lock = function () {
|
Highlighter.prototype.lock = function () {
|
||||||
this.locked = true;
|
this.locked = true
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unlock highlighting or unhighlighting nodes
|
* Unlock highlighting or unhighlighting nodes
|
||||||
*/
|
*/
|
||||||
Highlighter.prototype.unlock = function () {
|
Highlighter.prototype.unlock = function () {
|
||||||
this.locked = false;
|
this.locked = false
|
||||||
};
|
}
|
||||||
|
|
||||||
module.exports = Highlighter;
|
module.exports = Highlighter
|
||||||
|
|
|
@ -7,82 +7,81 @@
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function History (onChange, calculateItemSize, limit) {
|
function History (onChange, calculateItemSize, limit) {
|
||||||
this.onChange = onChange;
|
this.onChange = onChange
|
||||||
this.calculateItemSize = calculateItemSize || function () {
|
this.calculateItemSize = calculateItemSize || function () {
|
||||||
return 1;
|
return 1
|
||||||
};
|
}
|
||||||
this.limit = limit;
|
this.limit = limit
|
||||||
|
|
||||||
this.items = [];
|
this.items = []
|
||||||
this.index = -1;
|
this.index = -1
|
||||||
}
|
}
|
||||||
|
|
||||||
History.prototype.add = function (item) {
|
History.prototype.add = function (item) {
|
||||||
// limit number of items in history so that the total size doesn't
|
// limit number of items in history so that the total size doesn't
|
||||||
// always keep at least one item in memory
|
// always keep at least one item in memory
|
||||||
while (this._calculateHistorySize() > this.limit && this.items.length > 1) {
|
while (this._calculateHistorySize() > this.limit && this.items.length > 1) {
|
||||||
this.items.shift();
|
this.items.shift()
|
||||||
this.index--;
|
this.index--
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanup any redo action that are not valid anymore
|
// cleanup any redo action that are not valid anymore
|
||||||
this.items = this.items.slice(0, this.index + 1);
|
this.items = this.items.slice(0, this.index + 1)
|
||||||
|
|
||||||
this.items.push(item);
|
this.items.push(item)
|
||||||
this.index++;
|
this.index++
|
||||||
|
|
||||||
this.onChange();
|
this.onChange()
|
||||||
};
|
}
|
||||||
|
|
||||||
History.prototype._calculateHistorySize = function () {
|
History.prototype._calculateHistorySize = function () {
|
||||||
var calculateItemSize = this.calculateItemSize;
|
var calculateItemSize = this.calculateItemSize
|
||||||
var totalSize = 0;
|
var totalSize = 0
|
||||||
|
|
||||||
this.items.forEach(function (item) {
|
this.items.forEach(function (item) {
|
||||||
totalSize += calculateItemSize(item);
|
totalSize += calculateItemSize(item)
|
||||||
});
|
})
|
||||||
|
|
||||||
return totalSize;
|
return totalSize
|
||||||
}
|
}
|
||||||
|
|
||||||
History.prototype.undo = function () {
|
History.prototype.undo = function () {
|
||||||
if (!this.canUndo()) {
|
if (!this.canUndo()) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.index--;
|
this.index--
|
||||||
|
|
||||||
this.onChange();
|
this.onChange()
|
||||||
|
|
||||||
return this.items[this.index];
|
return this.items[this.index]
|
||||||
};
|
}
|
||||||
|
|
||||||
History.prototype.redo = function () {
|
History.prototype.redo = function () {
|
||||||
if (!this.canRedo()) {
|
if (!this.canRedo()) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.index++;
|
this.index++
|
||||||
|
|
||||||
this.onChange();
|
this.onChange()
|
||||||
|
|
||||||
return this.items[this.index];
|
return this.items[this.index]
|
||||||
};
|
}
|
||||||
|
|
||||||
History.prototype.canUndo = function () {
|
History.prototype.canUndo = function () {
|
||||||
return this.index > 0;
|
return this.index > 0
|
||||||
};
|
}
|
||||||
|
|
||||||
History.prototype.canRedo = function () {
|
History.prototype.canRedo = function () {
|
||||||
return this.index < this.items.length - 1;
|
return this.index < this.items.length - 1
|
||||||
};
|
}
|
||||||
|
|
||||||
History.prototype.clear = function () {
|
History.prototype.clear = function () {
|
||||||
this.items = [];
|
this.items = []
|
||||||
this.index = -1;
|
this.index = -1
|
||||||
|
|
||||||
this.onChange();
|
this.onChange()
|
||||||
};
|
}
|
||||||
|
|
||||||
|
module.exports = History
|
||||||
module.exports = History;
|
|
||||||
|
|
|
@ -1,23 +1,22 @@
|
||||||
'use strict';
|
'use strict'
|
||||||
|
|
||||||
var Ajv;
|
var Ajv
|
||||||
try {
|
try {
|
||||||
Ajv = require('ajv');
|
Ajv = require('ajv')
|
||||||
}
|
} catch (err) {
|
||||||
catch (err) {
|
|
||||||
// no problem... when we need Ajv we will throw a neat exception
|
// no problem... when we need Ajv we will throw a neat exception
|
||||||
}
|
}
|
||||||
|
|
||||||
var ace = require('./ace'); // may be undefined in case of minimalist bundle
|
var ace = require('./ace') // may be undefined in case of minimalist bundle
|
||||||
var VanillaPicker = require('./vanilla-picker'); // may be undefined in case of minimalist bundle
|
var VanillaPicker = require('./vanilla-picker') // may be undefined in case of minimalist bundle
|
||||||
|
|
||||||
var treemode = require('./treemode');
|
var treemode = require('./treemode')
|
||||||
var textmode = require('./textmode');
|
var textmode = require('./textmode')
|
||||||
var previewmode = require('./previewmode');
|
var previewmode = require('./previewmode')
|
||||||
var util = require('./util');
|
var util = require('./util')
|
||||||
|
|
||||||
if (typeof Promise === 'undefined') {
|
if (typeof Promise === 'undefined') {
|
||||||
console.error('Promise undefined. Please load a Promise polyfill in the browser in order to use JSONEditor');
|
console.error('Promise undefined. Please load a Promise polyfill in the browser in order to use JSONEditor')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -89,41 +88,41 @@ if (typeof Promise === 'undefined') {
|
||||||
* Only applicable for
|
* Only applicable for
|
||||||
* modes 'form', 'tree' and
|
* modes 'form', 'tree' and
|
||||||
* 'view'
|
* 'view'
|
||||||
* {Number} maxVisibleChilds Number of children allowed for a node
|
* {Number} maxVisibleChilds Number of children allowed for a node
|
||||||
* in 'tree', 'view', or 'form' mode before
|
* in 'tree', 'view', or 'form' mode before
|
||||||
* the "show more/show all" buttons appear.
|
* the "show more/show all" buttons appear.
|
||||||
* 100 by default.
|
* 100 by default.
|
||||||
*
|
*
|
||||||
* @param {Object | undefined} json JSON object
|
* @param {Object | undefined} json JSON object
|
||||||
*/
|
*/
|
||||||
function JSONEditor (container, options, json) {
|
function JSONEditor (container, options, json) {
|
||||||
if (!(this instanceof JSONEditor)) {
|
if (!(this instanceof JSONEditor)) {
|
||||||
throw new Error('JSONEditor constructor called without "new".');
|
throw new Error('JSONEditor constructor called without "new".')
|
||||||
}
|
}
|
||||||
|
|
||||||
// check for unsupported browser (IE8 and older)
|
// check for unsupported browser (IE8 and older)
|
||||||
var ieVersion = util.getInternetExplorerVersion();
|
var ieVersion = util.getInternetExplorerVersion()
|
||||||
if (ieVersion != -1 && ieVersion < 9) {
|
if (ieVersion !== -1 && ieVersion < 9) {
|
||||||
throw new Error('Unsupported browser, IE9 or newer required. ' +
|
throw new Error('Unsupported browser, IE9 or newer required. ' +
|
||||||
'Please install the newest version of your browser.');
|
'Please install the newest version of your browser.')
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options) {
|
if (options) {
|
||||||
// check for deprecated options
|
// check for deprecated options
|
||||||
if (options.error) {
|
if (options.error) {
|
||||||
console.warn('Option "error" has been renamed to "onError"');
|
console.warn('Option "error" has been renamed to "onError"')
|
||||||
options.onError = options.error;
|
options.onError = options.error
|
||||||
delete options.error;
|
delete options.error
|
||||||
}
|
}
|
||||||
if (options.change) {
|
if (options.change) {
|
||||||
console.warn('Option "change" has been renamed to "onChange"');
|
console.warn('Option "change" has been renamed to "onChange"')
|
||||||
options.onChange = options.change;
|
options.onChange = options.change
|
||||||
delete options.change;
|
delete options.change
|
||||||
}
|
}
|
||||||
if (options.editable) {
|
if (options.editable) {
|
||||||
console.warn('Option "editable" has been renamed to "onEditable"');
|
console.warn('Option "editable" has been renamed to "onEditable"')
|
||||||
options.onEditable = options.editable;
|
options.onEditable = options.editable
|
||||||
delete options.editable;
|
delete options.editable
|
||||||
}
|
}
|
||||||
|
|
||||||
// warn if onChangeJSON is used when mode can be `text` or `code`
|
// warn if onChangeJSON is used when mode can be `text` or `code`
|
||||||
|
@ -131,7 +130,7 @@ function JSONEditor (container, options, json) {
|
||||||
if (options.mode === 'text' || options.mode === 'code' ||
|
if (options.mode === 'text' || options.mode === 'code' ||
|
||||||
(options.modes && (options.modes.indexOf('text') !== -1 || options.modes.indexOf('code') !== -1))) {
|
(options.modes && (options.modes.indexOf('text') !== -1 || options.modes.indexOf('code') !== -1))) {
|
||||||
console.warn('Option "onChangeJSON" is not applicable to modes "text" and "code". ' +
|
console.warn('Option "onChangeJSON" is not applicable to modes "text" and "code". ' +
|
||||||
'Use "onChangeText" or "onChange" instead.');
|
'Use "onChangeText" or "onChange" instead.')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -139,14 +138,14 @@ function JSONEditor (container, options, json) {
|
||||||
if (options) {
|
if (options) {
|
||||||
Object.keys(options).forEach(function (option) {
|
Object.keys(options).forEach(function (option) {
|
||||||
if (JSONEditor.VALID_OPTIONS.indexOf(option) === -1) {
|
if (JSONEditor.VALID_OPTIONS.indexOf(option) === -1) {
|
||||||
console.warn('Unknown option "' + option + '". This option will be ignored');
|
console.warn('Unknown option "' + option + '". This option will be ignored')
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (arguments.length) {
|
if (arguments.length) {
|
||||||
this._create(container, options, json);
|
this._create(container, options, json)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -165,13 +164,13 @@ function JSONEditor (container, options, json) {
|
||||||
*
|
*
|
||||||
* @type { Object.<String, {mixin: Object, data: String} > }
|
* @type { Object.<String, {mixin: Object, data: String} > }
|
||||||
*/
|
*/
|
||||||
JSONEditor.modes = {};
|
JSONEditor.modes = {}
|
||||||
|
|
||||||
// debounce interval for JSON schema vaidation in milliseconds
|
// debounce interval for JSON schema vaidation in milliseconds
|
||||||
JSONEditor.prototype.DEBOUNCE_INTERVAL = 150;
|
JSONEditor.prototype.DEBOUNCE_INTERVAL = 150
|
||||||
|
|
||||||
JSONEditor.VALID_OPTIONS = [
|
JSONEditor.VALID_OPTIONS = [
|
||||||
'ajv', 'schema', 'schemaRefs','templates',
|
'ajv', 'schema', 'schemaRefs', 'templates',
|
||||||
'ace', 'theme', 'autocomplete',
|
'ace', 'theme', 'autocomplete',
|
||||||
'onChange', 'onChangeJSON', 'onChangeText',
|
'onChange', 'onChangeJSON', 'onChangeText',
|
||||||
'onEditable', 'onError', 'onEvent', 'onModeChange', 'onNodeName', 'onValidate', 'onCreateMenu',
|
'onEditable', 'onError', 'onEvent', 'onModeChange', 'onNodeName', 'onValidate', 'onCreateMenu',
|
||||||
|
@ -181,7 +180,7 @@ JSONEditor.VALID_OPTIONS = [
|
||||||
'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation',
|
'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation',
|
||||||
'sortObjectKeys', 'navigationBar', 'statusBar', 'mainMenuBar', 'languages', 'language', 'enableSort', 'enableTransform',
|
'sortObjectKeys', 'navigationBar', 'statusBar', 'mainMenuBar', 'languages', 'language', 'enableSort', 'enableTransform',
|
||||||
'maxVisibleChilds'
|
'maxVisibleChilds'
|
||||||
];
|
]
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the JSONEditor
|
* Create the JSONEditor
|
||||||
|
@ -191,50 +190,50 @@ JSONEditor.VALID_OPTIONS = [
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
JSONEditor.prototype._create = function (container, options, json) {
|
JSONEditor.prototype._create = function (container, options, json) {
|
||||||
this.container = container;
|
this.container = container
|
||||||
this.options = options || {};
|
this.options = options || {}
|
||||||
this.json = json || {};
|
this.json = json || {}
|
||||||
|
|
||||||
var mode = this.options.mode || (this.options.modes && this.options.modes[0]) || 'tree';
|
var mode = this.options.mode || (this.options.modes && this.options.modes[0]) || 'tree'
|
||||||
this.setMode(mode);
|
this.setMode(mode)
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy the editor. Clean up DOM, event listeners, and web workers.
|
* Destroy the editor. Clean up DOM, event listeners, and web workers.
|
||||||
*/
|
*/
|
||||||
JSONEditor.prototype.destroy = function () {};
|
JSONEditor.prototype.destroy = function () {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set JSON object in editor
|
* Set JSON object in editor
|
||||||
* @param {Object | undefined} json JSON data
|
* @param {Object | undefined} json JSON data
|
||||||
*/
|
*/
|
||||||
JSONEditor.prototype.set = function (json) {
|
JSONEditor.prototype.set = function (json) {
|
||||||
this.json = json;
|
this.json = json
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get JSON from the editor
|
* Get JSON from the editor
|
||||||
* @returns {Object} json
|
* @returns {Object} json
|
||||||
*/
|
*/
|
||||||
JSONEditor.prototype.get = function () {
|
JSONEditor.prototype.get = function () {
|
||||||
return this.json;
|
return this.json
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set string containing JSON for the editor
|
* Set string containing JSON for the editor
|
||||||
* @param {String | undefined} jsonText
|
* @param {String | undefined} jsonText
|
||||||
*/
|
*/
|
||||||
JSONEditor.prototype.setText = function (jsonText) {
|
JSONEditor.prototype.setText = function (jsonText) {
|
||||||
this.json = util.parse(jsonText);
|
this.json = util.parse(jsonText)
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get stringified JSON contents from the editor
|
* Get stringified JSON contents from the editor
|
||||||
* @returns {String} jsonText
|
* @returns {String} jsonText
|
||||||
*/
|
*/
|
||||||
JSONEditor.prototype.getText = function () {
|
JSONEditor.prototype.getText = function () {
|
||||||
return JSON.stringify(this.json);
|
return JSON.stringify(this.json)
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a field name for the root node.
|
* Set a field name for the root node.
|
||||||
|
@ -242,18 +241,18 @@ JSONEditor.prototype.getText = function () {
|
||||||
*/
|
*/
|
||||||
JSONEditor.prototype.setName = function (name) {
|
JSONEditor.prototype.setName = function (name) {
|
||||||
if (!this.options) {
|
if (!this.options) {
|
||||||
this.options = {};
|
this.options = {}
|
||||||
}
|
}
|
||||||
this.options.name = name;
|
this.options.name = name
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the field name for the root node.
|
* Get the field name for the root node.
|
||||||
* @return {String | undefined} name
|
* @return {String | undefined} name
|
||||||
*/
|
*/
|
||||||
JSONEditor.prototype.getName = function () {
|
JSONEditor.prototype.getName = function () {
|
||||||
return this.options && this.options.name;
|
return this.options && this.options.name
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the mode of the editor.
|
* Change the mode of the editor.
|
||||||
|
@ -264,65 +263,61 @@ JSONEditor.prototype.getName = function () {
|
||||||
JSONEditor.prototype.setMode = function (mode) {
|
JSONEditor.prototype.setMode = function (mode) {
|
||||||
// if the mode is the same as current mode (and it's not the first time), do nothing.
|
// if the mode is the same as current mode (and it's not the first time), do nothing.
|
||||||
if (mode === this.options.mode && this.create) {
|
if (mode === this.options.mode && this.create) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var container = this.container;
|
var container = this.container
|
||||||
var options = util.extend({}, this.options);
|
var options = util.extend({}, this.options)
|
||||||
var oldMode = options.mode;
|
var oldMode = options.mode
|
||||||
var data;
|
var data
|
||||||
var name;
|
var name
|
||||||
|
|
||||||
options.mode = mode;
|
options.mode = mode
|
||||||
var config = JSONEditor.modes[mode];
|
var config = JSONEditor.modes[mode]
|
||||||
if (config) {
|
if (config) {
|
||||||
try {
|
try {
|
||||||
var asText = (config.data == 'text');
|
var asText = (config.data === 'text')
|
||||||
name = this.getName();
|
name = this.getName()
|
||||||
data = this[asText ? 'getText' : 'get'](); // get text or json
|
data = this[asText ? 'getText' : 'get']() // get text or json
|
||||||
|
|
||||||
this.destroy();
|
this.destroy()
|
||||||
util.clear(this);
|
util.clear(this)
|
||||||
util.extend(this, config.mixin);
|
util.extend(this, config.mixin)
|
||||||
this.create(container, options);
|
this.create(container, options)
|
||||||
|
|
||||||
this.setName(name);
|
this.setName(name)
|
||||||
this[asText ? 'setText' : 'set'](data); // set text or json
|
this[asText ? 'setText' : 'set'](data) // set text or json
|
||||||
|
|
||||||
if (typeof config.load === 'function') {
|
if (typeof config.load === 'function') {
|
||||||
try {
|
try {
|
||||||
config.load.call(this);
|
config.load.call(this)
|
||||||
}
|
} catch (err) {
|
||||||
catch (err) {
|
console.error(err)
|
||||||
console.error(err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof options.onModeChange === 'function' && mode !== oldMode) {
|
if (typeof options.onModeChange === 'function' && mode !== oldMode) {
|
||||||
try {
|
try {
|
||||||
options.onModeChange(mode, oldMode);
|
options.onModeChange(mode, oldMode)
|
||||||
}
|
} catch (err) {
|
||||||
catch (err) {
|
console.error(err)
|
||||||
console.error(err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} catch (err) {
|
||||||
|
this._onError(err)
|
||||||
}
|
}
|
||||||
catch (err) {
|
} else {
|
||||||
this._onError(err);
|
throw new Error('Unknown mode "' + options.mode + '"')
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
throw new Error('Unknown mode "' + options.mode + '"');
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the current mode
|
* Get the current mode
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
JSONEditor.prototype.getMode = function () {
|
JSONEditor.prototype.getMode = function () {
|
||||||
return this.options.mode;
|
return this.options.mode
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Throw an error. If an error callback is configured in options.error, this
|
* Throw an error. If an error callback is configured in options.error, this
|
||||||
|
@ -330,14 +325,13 @@ JSONEditor.prototype.getMode = function () {
|
||||||
* @param {Error} err
|
* @param {Error} err
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
JSONEditor.prototype._onError = function(err) {
|
JSONEditor.prototype._onError = function (err) {
|
||||||
if (this.options && typeof this.options.onError === 'function') {
|
if (this.options && typeof this.options.onError === 'function') {
|
||||||
this.options.onError(err);
|
this.options.onError(err)
|
||||||
|
} else {
|
||||||
|
throw err
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
throw err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set a JSON schema for validation of the JSON object.
|
* Set a JSON schema for validation of the JSON object.
|
||||||
|
@ -349,60 +343,57 @@ JSONEditor.prototype._onError = function(err) {
|
||||||
JSONEditor.prototype.setSchema = function (schema, schemaRefs) {
|
JSONEditor.prototype.setSchema = function (schema, schemaRefs) {
|
||||||
// compile a JSON schema validator if a JSON schema is provided
|
// compile a JSON schema validator if a JSON schema is provided
|
||||||
if (schema) {
|
if (schema) {
|
||||||
var ajv;
|
var ajv
|
||||||
try {
|
try {
|
||||||
// grab ajv from options if provided, else create a new instance
|
// grab ajv from options if provided, else create a new instance
|
||||||
if (this.options.ajv) {
|
if (this.options.ajv) {
|
||||||
ajv = this.options.ajv
|
ajv = this.options.ajv
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
ajv = Ajv({
|
ajv = Ajv({
|
||||||
allErrors: true,
|
allErrors: true,
|
||||||
verbose: true,
|
verbose: true,
|
||||||
schemaId: 'auto',
|
schemaId: 'auto',
|
||||||
$data: true
|
$data: true
|
||||||
});
|
})
|
||||||
|
|
||||||
// support both draft-04 and draft-06 alongside the latest draft-07
|
// support both draft-04 and draft-06 alongside the latest draft-07
|
||||||
ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-04.json'));
|
ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-04.json'))
|
||||||
ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-06.json'));
|
ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-06.json'))
|
||||||
}
|
}
|
||||||
}
|
} catch (err) {
|
||||||
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`.')
|
||||||
console.warn('Failed to create an instance of Ajv, JSON Schema validation is not available. Please use a JSONEditor bundle including Ajv, or pass an instance of Ajv as via the configuration option `ajv`.');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ajv) {
|
if (ajv) {
|
||||||
if(schemaRefs) {
|
if (schemaRefs) {
|
||||||
for (var ref in schemaRefs) {
|
for (var ref in schemaRefs) {
|
||||||
ajv.removeSchema(ref); // When updating a schema - old refs has to be removed first
|
ajv.removeSchema(ref) // When updating a schema - old refs has to be removed first
|
||||||
if(schemaRefs[ref]) {
|
if (schemaRefs[ref]) {
|
||||||
ajv.addSchema(schemaRefs[ref], ref);
|
ajv.addSchema(schemaRefs[ref], ref)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.options.schemaRefs = schemaRefs;
|
this.options.schemaRefs = schemaRefs
|
||||||
}
|
}
|
||||||
this.validateSchema = ajv.compile(schema);
|
this.validateSchema = ajv.compile(schema)
|
||||||
|
|
||||||
// add schema to the options, so that when switching to an other mode,
|
// add schema to the options, so that when switching to an other mode,
|
||||||
// the set schema is not lost
|
// the set schema is not lost
|
||||||
this.options.schema = schema;
|
this.options.schema = schema
|
||||||
|
|
||||||
// validate now
|
// validate now
|
||||||
this.validate();
|
this.validate()
|
||||||
}
|
}
|
||||||
|
|
||||||
this.refresh(); // update DOM
|
this.refresh() // update DOM
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// remove current schema
|
// remove current schema
|
||||||
this.validateSchema = null;
|
this.validateSchema = null
|
||||||
this.options.schema = null;
|
this.options.schema = null
|
||||||
this.options.schemaRefs = null;
|
this.options.schemaRefs = null
|
||||||
this.validate(); // to clear current error messages
|
this.validate() // to clear current error messages
|
||||||
this.refresh(); // update DOM
|
this.refresh() // update DOM
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate current JSON object against the configured JSON schema
|
* Validate current JSON object against the configured JSON schema
|
||||||
|
@ -410,14 +401,14 @@ JSONEditor.prototype.setSchema = function (schema, schemaRefs) {
|
||||||
*/
|
*/
|
||||||
JSONEditor.prototype.validate = function () {
|
JSONEditor.prototype.validate = function () {
|
||||||
// must be implemented by treemode and textmode
|
// must be implemented by treemode and textmode
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh the rendered contents
|
* Refresh the rendered contents
|
||||||
*/
|
*/
|
||||||
JSONEditor.prototype.refresh = function () {
|
JSONEditor.prototype.refresh = function () {
|
||||||
// can be implemented by treemode and textmode
|
// can be implemented by treemode and textmode
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register a plugin with one ore multiple modes for the JSON Editor.
|
* Register a plugin with one ore multiple modes for the JSON Editor.
|
||||||
|
@ -439,51 +430,50 @@ JSONEditor.prototype.refresh = function () {
|
||||||
* @param {Object | Array} mode A mode object or an array with multiple mode objects.
|
* @param {Object | Array} mode A mode object or an array with multiple mode objects.
|
||||||
*/
|
*/
|
||||||
JSONEditor.registerMode = function (mode) {
|
JSONEditor.registerMode = function (mode) {
|
||||||
var i, prop;
|
var i, prop
|
||||||
|
|
||||||
if (util.isArray(mode)) {
|
if (util.isArray(mode)) {
|
||||||
// multiple modes
|
// multiple modes
|
||||||
for (i = 0; i < mode.length; i++) {
|
for (i = 0; i < mode.length; i++) {
|
||||||
JSONEditor.registerMode(mode[i]);
|
JSONEditor.registerMode(mode[i])
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
// validate the new mode
|
// validate the new mode
|
||||||
if (!('mode' in mode)) throw new Error('Property "mode" missing');
|
if (!('mode' in mode)) throw new Error('Property "mode" missing')
|
||||||
if (!('mixin' in mode)) throw new Error('Property "mixin" missing');
|
if (!('mixin' in mode)) throw new Error('Property "mixin" missing')
|
||||||
if (!('data' in mode)) throw new Error('Property "data" missing');
|
if (!('data' in mode)) throw new Error('Property "data" missing')
|
||||||
var name = mode.mode;
|
var name = mode.mode
|
||||||
if (name in JSONEditor.modes) {
|
if (name in JSONEditor.modes) {
|
||||||
throw new Error('Mode "' + name + '" already registered');
|
throw new Error('Mode "' + name + '" already registered')
|
||||||
}
|
}
|
||||||
|
|
||||||
// validate the mixin
|
// validate the mixin
|
||||||
if (typeof mode.mixin.create !== 'function') {
|
if (typeof mode.mixin.create !== 'function') {
|
||||||
throw new Error('Required function "create" missing on mixin');
|
throw new Error('Required function "create" missing on mixin')
|
||||||
}
|
}
|
||||||
var reserved = ['setMode', 'registerMode', 'modes'];
|
var reserved = ['setMode', 'registerMode', 'modes']
|
||||||
for (i = 0; i < reserved.length; i++) {
|
for (i = 0; i < reserved.length; i++) {
|
||||||
prop = reserved[i];
|
prop = reserved[i]
|
||||||
if (prop in mode.mixin) {
|
if (prop in mode.mixin) {
|
||||||
throw new Error('Reserved property "' + prop + '" not allowed in mixin');
|
throw new Error('Reserved property "' + prop + '" not allowed in mixin')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONEditor.modes[name] = mode;
|
JSONEditor.modes[name] = mode
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// register tree, text, and preview modes
|
// register tree, text, and preview modes
|
||||||
JSONEditor.registerMode(treemode);
|
JSONEditor.registerMode(treemode)
|
||||||
JSONEditor.registerMode(textmode);
|
JSONEditor.registerMode(textmode)
|
||||||
JSONEditor.registerMode(previewmode);
|
JSONEditor.registerMode(previewmode)
|
||||||
|
|
||||||
// expose some of the libraries that can be used customized
|
// expose some of the libraries that can be used customized
|
||||||
JSONEditor.ace = ace;
|
JSONEditor.ace = ace
|
||||||
JSONEditor.Ajv = Ajv;
|
JSONEditor.Ajv = Ajv
|
||||||
JSONEditor.VanillaPicker = VanillaPicker;
|
JSONEditor.VanillaPicker = VanillaPicker
|
||||||
|
|
||||||
// default export for TypeScript ES6 projects
|
// default export for TypeScript ES6 projects
|
||||||
JSONEditor.default = JSONEditor;
|
JSONEditor.default = JSONEditor
|
||||||
|
|
||||||
module.exports = JSONEditor;
|
module.exports = JSONEditor
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
'use strict';
|
'use strict'
|
||||||
|
|
||||||
var ContextMenu = require('./ContextMenu');
|
var ContextMenu = require('./ContextMenu')
|
||||||
var translate = require('./i18n').translate;
|
var translate = require('./i18n').translate
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a select box to be used in the editor menu's, which allows to switch mode
|
* Create a select box to be used in the editor menu's, which allows to switch mode
|
||||||
|
@ -11,113 +11,113 @@ var translate = require('./i18n').translate;
|
||||||
* @param {function(mode: string)} onSwitch Callback invoked on switch
|
* @param {function(mode: string)} onSwitch Callback invoked on switch
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function ModeSwitcher(container, modes, current, onSwitch) {
|
function ModeSwitcher (container, modes, current, onSwitch) {
|
||||||
// available modes
|
// available modes
|
||||||
var availableModes = {
|
var availableModes = {
|
||||||
code: {
|
code: {
|
||||||
'text': translate('modeCodeText'),
|
text: translate('modeCodeText'),
|
||||||
'title': translate('modeCodeTitle'),
|
title: translate('modeCodeTitle'),
|
||||||
'click': function () {
|
click: function () {
|
||||||
onSwitch('code')
|
onSwitch('code')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
form: {
|
form: {
|
||||||
'text': translate('modeFormText'),
|
text: translate('modeFormText'),
|
||||||
'title': translate('modeFormTitle'),
|
title: translate('modeFormTitle'),
|
||||||
'click': function () {
|
click: function () {
|
||||||
onSwitch('form');
|
onSwitch('form')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
text: {
|
text: {
|
||||||
'text': translate('modeTextText'),
|
text: translate('modeTextText'),
|
||||||
'title': translate('modeTextTitle'),
|
title: translate('modeTextTitle'),
|
||||||
'click': function () {
|
click: function () {
|
||||||
onSwitch('text');
|
onSwitch('text')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
tree: {
|
tree: {
|
||||||
'text': translate('modeTreeText'),
|
text: translate('modeTreeText'),
|
||||||
'title': translate('modeTreeTitle'),
|
title: translate('modeTreeTitle'),
|
||||||
'click': function () {
|
click: function () {
|
||||||
onSwitch('tree');
|
onSwitch('tree')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
view: {
|
view: {
|
||||||
'text': translate('modeViewText'),
|
text: translate('modeViewText'),
|
||||||
'title': translate('modeViewTitle'),
|
title: translate('modeViewTitle'),
|
||||||
'click': function () {
|
click: function () {
|
||||||
onSwitch('view');
|
onSwitch('view')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
preview: {
|
preview: {
|
||||||
'text': translate('modePreviewText'),
|
text: translate('modePreviewText'),
|
||||||
'title': translate('modePreviewTitle'),
|
title: translate('modePreviewTitle'),
|
||||||
'click': function () {
|
click: function () {
|
||||||
onSwitch('preview');
|
onSwitch('preview')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// list the selected modes
|
// list the selected modes
|
||||||
var items = [];
|
var items = []
|
||||||
for (var i = 0; i < modes.length; i++) {
|
for (var i = 0; i < modes.length; i++) {
|
||||||
var mode = modes[i];
|
var mode = modes[i]
|
||||||
var item = availableModes[mode];
|
var item = availableModes[mode]
|
||||||
if (!item) {
|
if (!item) {
|
||||||
throw new Error('Unknown mode "' + mode + '"');
|
throw new Error('Unknown mode "' + mode + '"')
|
||||||
}
|
}
|
||||||
|
|
||||||
item.className = 'jsoneditor-type-modes' + ((current == mode) ? ' jsoneditor-selected' : '');
|
item.className = 'jsoneditor-type-modes' + ((current === mode) ? ' jsoneditor-selected' : '')
|
||||||
items.push(item);
|
items.push(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
// retrieve the title of current mode
|
// retrieve the title of current mode
|
||||||
var currentMode = availableModes[current];
|
var currentMode = availableModes[current]
|
||||||
if (!currentMode) {
|
if (!currentMode) {
|
||||||
throw new Error('Unknown mode "' + current + '"');
|
throw new Error('Unknown mode "' + current + '"')
|
||||||
}
|
}
|
||||||
var currentTitle = currentMode.text;
|
var currentTitle = currentMode.text
|
||||||
|
|
||||||
// create the html element
|
// create the html element
|
||||||
var box = document.createElement('button');
|
var box = document.createElement('button')
|
||||||
box.type = 'button';
|
box.type = 'button'
|
||||||
box.className = 'jsoneditor-modes jsoneditor-separator';
|
box.className = 'jsoneditor-modes jsoneditor-separator'
|
||||||
box.innerHTML = currentTitle + ' ▾';
|
box.innerHTML = currentTitle + ' ▾'
|
||||||
box.title = 'Switch editor mode';
|
box.title = 'Switch editor mode'
|
||||||
box.onclick = function () {
|
box.onclick = function () {
|
||||||
var menu = new ContextMenu(items);
|
var menu = new ContextMenu(items)
|
||||||
menu.show(box, container);
|
menu.show(box, container)
|
||||||
};
|
}
|
||||||
|
|
||||||
var frame = document.createElement('div');
|
var frame = document.createElement('div')
|
||||||
frame.className = 'jsoneditor-modes';
|
frame.className = 'jsoneditor-modes'
|
||||||
frame.style.position = 'relative';
|
frame.style.position = 'relative'
|
||||||
frame.appendChild(box);
|
frame.appendChild(box)
|
||||||
|
|
||||||
container.appendChild(frame);
|
container.appendChild(frame)
|
||||||
|
|
||||||
this.dom = {
|
this.dom = {
|
||||||
container: container,
|
container: container,
|
||||||
box: box,
|
box: box,
|
||||||
frame: frame
|
frame: frame
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set focus to switcher
|
* Set focus to switcher
|
||||||
*/
|
*/
|
||||||
ModeSwitcher.prototype.focus = function () {
|
ModeSwitcher.prototype.focus = function () {
|
||||||
this.dom.box.focus();
|
this.dom.box.focus()
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy the ModeSwitcher, remove from DOM
|
* Destroy the ModeSwitcher, remove from DOM
|
||||||
*/
|
*/
|
||||||
ModeSwitcher.prototype.destroy = function () {
|
ModeSwitcher.prototype.destroy = function () {
|
||||||
if (this.dom && this.dom.frame && this.dom.frame.parentNode) {
|
if (this.dom && this.dom.frame && this.dom.frame.parentNode) {
|
||||||
this.dom.frame.parentNode.removeChild(this.dom.frame);
|
this.dom.frame.parentNode.removeChild(this.dom.frame)
|
||||||
}
|
}
|
||||||
this.dom = null;
|
this.dom = null
|
||||||
};
|
}
|
||||||
|
|
||||||
module.exports = ModeSwitcher;
|
module.exports = ModeSwitcher
|
||||||
|
|
3907
src/js/Node.js
3907
src/js/Node.js
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
||||||
'use strict';
|
'use strict'
|
||||||
|
|
||||||
var util = require('./util');
|
var util = require('./util')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor History
|
* @constructor History
|
||||||
|
@ -8,190 +8,190 @@ var util = require('./util');
|
||||||
* @param {JSONEditor} editor
|
* @param {JSONEditor} editor
|
||||||
*/
|
*/
|
||||||
function NodeHistory (editor) {
|
function NodeHistory (editor) {
|
||||||
this.editor = editor;
|
this.editor = editor
|
||||||
this.history = [];
|
this.history = []
|
||||||
this.index = -1;
|
this.index = -1
|
||||||
|
|
||||||
this.clear();
|
this.clear()
|
||||||
|
|
||||||
// helper function to find a Node from a path
|
// helper function to find a Node from a path
|
||||||
function findNode(path) {
|
function findNode (path) {
|
||||||
return editor.node.findNodeByInternalPath(path)
|
return editor.node.findNodeByInternalPath(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
// map with all supported actions
|
// map with all supported actions
|
||||||
this.actions = {
|
this.actions = {
|
||||||
'editField': {
|
editField: {
|
||||||
'undo': function (params) {
|
undo: function (params) {
|
||||||
var parentNode = findNode(params.parentPath);
|
var parentNode = findNode(params.parentPath)
|
||||||
var node = parentNode.childs[params.index];
|
var node = parentNode.childs[params.index]
|
||||||
node.updateField(params.oldValue);
|
node.updateField(params.oldValue)
|
||||||
},
|
},
|
||||||
'redo': function (params) {
|
redo: function (params) {
|
||||||
var parentNode = findNode(params.parentPath);
|
var parentNode = findNode(params.parentPath)
|
||||||
var node = parentNode.childs[params.index];
|
var node = parentNode.childs[params.index]
|
||||||
node.updateField(params.newValue);
|
node.updateField(params.newValue)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'editValue': {
|
editValue: {
|
||||||
'undo': function (params) {
|
undo: function (params) {
|
||||||
findNode(params.path).updateValue(params.oldValue);
|
findNode(params.path).updateValue(params.oldValue)
|
||||||
},
|
},
|
||||||
'redo': function (params) {
|
redo: function (params) {
|
||||||
findNode(params.path).updateValue(params.newValue);
|
findNode(params.path).updateValue(params.newValue)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'changeType': {
|
changeType: {
|
||||||
'undo': function (params) {
|
undo: function (params) {
|
||||||
findNode(params.path).changeType(params.oldType);
|
findNode(params.path).changeType(params.oldType)
|
||||||
},
|
},
|
||||||
'redo': function (params) {
|
redo: function (params) {
|
||||||
findNode(params.path).changeType(params.newType);
|
findNode(params.path).changeType(params.newType)
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
'appendNodes': {
|
appendNodes: {
|
||||||
'undo': function (params) {
|
undo: function (params) {
|
||||||
var parentNode = findNode(params.parentPath);
|
var parentNode = findNode(params.parentPath)
|
||||||
params.paths.map(findNode).forEach(function (node) {
|
params.paths.map(findNode).forEach(function (node) {
|
||||||
parentNode.removeChild(node);
|
parentNode.removeChild(node)
|
||||||
});
|
})
|
||||||
},
|
|
||||||
'redo': function (params) {
|
|
||||||
var parentNode = findNode(params.parentPath);
|
|
||||||
params.nodes.forEach(function (node) {
|
|
||||||
parentNode.appendChild(node);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'insertBeforeNodes': {
|
|
||||||
'undo': function (params) {
|
|
||||||
var parentNode = findNode(params.parentPath);
|
|
||||||
params.paths.map(findNode).forEach(function (node) {
|
|
||||||
parentNode.removeChild(node);
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
'redo': function (params) {
|
redo: function (params) {
|
||||||
var parentNode = findNode(params.parentPath);
|
var parentNode = findNode(params.parentPath)
|
||||||
var beforeNode = findNode(params.beforePath);
|
|
||||||
params.nodes.forEach(function (node) {
|
params.nodes.forEach(function (node) {
|
||||||
parentNode.insertBefore(node, beforeNode);
|
parentNode.appendChild(node)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'insertAfterNodes': {
|
insertBeforeNodes: {
|
||||||
'undo': function (params) {
|
undo: function (params) {
|
||||||
var parentNode = findNode(params.parentPath);
|
var parentNode = findNode(params.parentPath)
|
||||||
params.paths.map(findNode).forEach(function (node) {
|
params.paths.map(findNode).forEach(function (node) {
|
||||||
parentNode.removeChild(node);
|
parentNode.removeChild(node)
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
'redo': function (params) {
|
redo: function (params) {
|
||||||
var parentNode = findNode(params.parentPath);
|
var parentNode = findNode(params.parentPath)
|
||||||
var afterNode = findNode(params.afterPath);
|
var beforeNode = findNode(params.beforePath)
|
||||||
params.nodes.forEach(function (node) {
|
params.nodes.forEach(function (node) {
|
||||||
parentNode.insertAfter(node, afterNode);
|
parentNode.insertBefore(node, beforeNode)
|
||||||
afterNode = node;
|
})
|
||||||
});
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'removeNodes': {
|
insertAfterNodes: {
|
||||||
'undo': function (params) {
|
undo: function (params) {
|
||||||
var parentNode = findNode(params.parentPath);
|
var parentNode = findNode(params.parentPath)
|
||||||
var beforeNode = parentNode.childs[params.index] || parentNode.append;
|
|
||||||
params.nodes.forEach(function (node) {
|
|
||||||
parentNode.insertBefore(node, beforeNode);
|
|
||||||
});
|
|
||||||
},
|
|
||||||
'redo': function (params) {
|
|
||||||
var parentNode = findNode(params.parentPath);
|
|
||||||
params.paths.map(findNode).forEach(function (node) {
|
params.paths.map(findNode).forEach(function (node) {
|
||||||
parentNode.removeChild(node);
|
parentNode.removeChild(node)
|
||||||
});
|
})
|
||||||
|
},
|
||||||
|
redo: function (params) {
|
||||||
|
var parentNode = findNode(params.parentPath)
|
||||||
|
var afterNode = findNode(params.afterPath)
|
||||||
|
params.nodes.forEach(function (node) {
|
||||||
|
parentNode.insertAfter(node, afterNode)
|
||||||
|
afterNode = node
|
||||||
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'duplicateNodes': {
|
removeNodes: {
|
||||||
'undo': function (params) {
|
undo: function (params) {
|
||||||
var parentNode = findNode(params.parentPath);
|
var parentNode = findNode(params.parentPath)
|
||||||
|
var beforeNode = parentNode.childs[params.index] || parentNode.append
|
||||||
|
params.nodes.forEach(function (node) {
|
||||||
|
parentNode.insertBefore(node, beforeNode)
|
||||||
|
})
|
||||||
|
},
|
||||||
|
redo: function (params) {
|
||||||
|
var parentNode = findNode(params.parentPath)
|
||||||
|
params.paths.map(findNode).forEach(function (node) {
|
||||||
|
parentNode.removeChild(node)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
duplicateNodes: {
|
||||||
|
undo: function (params) {
|
||||||
|
var parentNode = findNode(params.parentPath)
|
||||||
params.clonePaths.map(findNode).forEach(function (node) {
|
params.clonePaths.map(findNode).forEach(function (node) {
|
||||||
parentNode.removeChild(node);
|
parentNode.removeChild(node)
|
||||||
});
|
})
|
||||||
},
|
},
|
||||||
'redo': function (params) {
|
redo: function (params) {
|
||||||
var parentNode = findNode(params.parentPath);
|
var parentNode = findNode(params.parentPath)
|
||||||
var afterNode = findNode(params.afterPath);
|
var afterNode = findNode(params.afterPath)
|
||||||
var nodes = params.paths.map(findNode);
|
var nodes = params.paths.map(findNode)
|
||||||
nodes.forEach(function (node) {
|
nodes.forEach(function (node) {
|
||||||
var clone = node.clone();
|
var clone = node.clone()
|
||||||
if (parentNode.type === 'object') {
|
if (parentNode.type === 'object') {
|
||||||
var existingFieldNames = parentNode.getFieldNames();
|
var existingFieldNames = parentNode.getFieldNames()
|
||||||
clone.field = util.findUniqueName(node.field, existingFieldNames);
|
clone.field = util.findUniqueName(node.field, existingFieldNames)
|
||||||
}
|
}
|
||||||
parentNode.insertAfter(clone, afterNode);
|
parentNode.insertAfter(clone, afterNode)
|
||||||
afterNode = clone;
|
afterNode = clone
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'moveNodes': {
|
moveNodes: {
|
||||||
'undo': function (params) {
|
undo: function (params) {
|
||||||
var oldParentNode = findNode(params.oldParentPath);
|
var oldParentNode = findNode(params.oldParentPath)
|
||||||
var newParentNode = findNode(params.newParentPath);
|
var newParentNode = findNode(params.newParentPath)
|
||||||
var oldBeforeNode = oldParentNode.childs[params.oldIndex] || oldParentNode.append;
|
var oldBeforeNode = oldParentNode.childs[params.oldIndex] || oldParentNode.append
|
||||||
|
|
||||||
// first copy the nodes, then move them
|
// first copy the nodes, then move them
|
||||||
var nodes = newParentNode.childs.slice(params.newIndex, params.newIndex + params.count);
|
var nodes = newParentNode.childs.slice(params.newIndex, params.newIndex + params.count)
|
||||||
|
|
||||||
nodes.forEach(function (node, index) {
|
nodes.forEach(function (node, index) {
|
||||||
node.field = params.fieldNames[index];
|
node.field = params.fieldNames[index]
|
||||||
oldParentNode.moveBefore(node, oldBeforeNode);
|
oldParentNode.moveBefore(node, oldBeforeNode)
|
||||||
});
|
})
|
||||||
|
|
||||||
// This is a hack to work around an issue that we don't know tha original
|
// This is a hack to work around an issue that we don't know tha original
|
||||||
// path of the new parent after dragging, as the node is already moved at that time.
|
// path of the new parent after dragging, as the node is already moved at that time.
|
||||||
if (params.newParentPathRedo === null) {
|
if (params.newParentPathRedo === null) {
|
||||||
params.newParentPathRedo = newParentNode.getInternalPath();
|
params.newParentPathRedo = newParentNode.getInternalPath()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'redo': function (params) {
|
redo: function (params) {
|
||||||
var oldParentNode = findNode(params.oldParentPathRedo);
|
var oldParentNode = findNode(params.oldParentPathRedo)
|
||||||
var newParentNode = findNode(params.newParentPathRedo);
|
var newParentNode = findNode(params.newParentPathRedo)
|
||||||
var newBeforeNode = newParentNode.childs[params.newIndexRedo] || newParentNode.append;
|
var newBeforeNode = newParentNode.childs[params.newIndexRedo] || newParentNode.append
|
||||||
|
|
||||||
// first copy the nodes, then move them
|
// first copy the nodes, then move them
|
||||||
var nodes = oldParentNode.childs.slice(params.oldIndexRedo, params.oldIndexRedo + params.count);
|
var nodes = oldParentNode.childs.slice(params.oldIndexRedo, params.oldIndexRedo + params.count)
|
||||||
|
|
||||||
nodes.forEach(function (node, index) {
|
nodes.forEach(function (node, index) {
|
||||||
node.field = params.fieldNames[index];
|
node.field = params.fieldNames[index]
|
||||||
newParentNode.moveBefore(node, newBeforeNode);
|
newParentNode.moveBefore(node, newBeforeNode)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
'sort': {
|
sort: {
|
||||||
'undo': function (params) {
|
undo: function (params) {
|
||||||
var node = findNode(params.path);
|
var node = findNode(params.path)
|
||||||
node.hideChilds();
|
node.hideChilds()
|
||||||
node.childs = params.oldChilds;
|
node.childs = params.oldChilds
|
||||||
node.updateDom({updateIndexes: true});
|
node.updateDom({ updateIndexes: true })
|
||||||
node.showChilds();
|
node.showChilds()
|
||||||
},
|
},
|
||||||
'redo': function (params) {
|
redo: function (params) {
|
||||||
var node = findNode(params.path);
|
var node = findNode(params.path)
|
||||||
node.hideChilds();
|
node.hideChilds()
|
||||||
node.childs = params.newChilds;
|
node.childs = params.newChilds
|
||||||
node.updateDom({updateIndexes: true});
|
node.updateDom({ updateIndexes: true })
|
||||||
node.showChilds();
|
node.showChilds()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
'transform': {
|
transform: {
|
||||||
'undo': function (params) {
|
undo: function (params) {
|
||||||
findNode(params.path).setInternalValue(params.oldValue);
|
findNode(params.path).setInternalValue(params.oldValue)
|
||||||
|
|
||||||
// TODO: would be nice to restore the state of the node and childs
|
// TODO: would be nice to restore the state of the node and childs
|
||||||
},
|
},
|
||||||
'redo': function (params) {
|
redo: function (params) {
|
||||||
findNode(params.path).setInternalValue(params.newValue);
|
findNode(params.path).setInternalValue(params.newValue)
|
||||||
|
|
||||||
// TODO: would be nice to restore the state of the node and childs
|
// TODO: would be nice to restore the state of the node and childs
|
||||||
}
|
}
|
||||||
|
@ -199,14 +199,14 @@ function NodeHistory (editor) {
|
||||||
|
|
||||||
// TODO: restore the original caret position and selection with each undo
|
// TODO: restore the original caret position and selection with each undo
|
||||||
// TODO: implement history for actions "expand", "collapse", "scroll", "setDocument"
|
// TODO: implement history for actions "expand", "collapse", "scroll", "setDocument"
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The method onChange is executed when the History is changed, and can
|
* The method onChange is executed when the History is changed, and can
|
||||||
* be overloaded.
|
* be overloaded.
|
||||||
*/
|
*/
|
||||||
NodeHistory.prototype.onChange = function () {};
|
NodeHistory.prototype.onChange = function () {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new action to the history
|
* Add a new action to the history
|
||||||
|
@ -220,118 +220,114 @@ NodeHistory.prototype.onChange = function () {};
|
||||||
* needed to undo or redo the action.
|
* needed to undo or redo the action.
|
||||||
*/
|
*/
|
||||||
NodeHistory.prototype.add = function (action, params) {
|
NodeHistory.prototype.add = function (action, params) {
|
||||||
this.index++;
|
this.index++
|
||||||
this.history[this.index] = {
|
this.history[this.index] = {
|
||||||
'action': action,
|
action: action,
|
||||||
'params': params,
|
params: params,
|
||||||
'timestamp': new Date()
|
timestamp: new Date()
|
||||||
};
|
}
|
||||||
|
|
||||||
// remove redo actions which are invalid now
|
// remove redo actions which are invalid now
|
||||||
if (this.index < this.history.length - 1) {
|
if (this.index < this.history.length - 1) {
|
||||||
this.history.splice(this.index + 1, this.history.length - this.index - 1);
|
this.history.splice(this.index + 1, this.history.length - this.index - 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
// fire onchange event
|
// fire onchange event
|
||||||
this.onChange();
|
this.onChange()
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear history
|
* Clear history
|
||||||
*/
|
*/
|
||||||
NodeHistory.prototype.clear = function () {
|
NodeHistory.prototype.clear = function () {
|
||||||
this.history = [];
|
this.history = []
|
||||||
this.index = -1;
|
this.index = -1
|
||||||
|
|
||||||
// fire onchange event
|
// fire onchange event
|
||||||
this.onChange();
|
this.onChange()
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if there is an action available for undo
|
* Check if there is an action available for undo
|
||||||
* @return {Boolean} canUndo
|
* @return {Boolean} canUndo
|
||||||
*/
|
*/
|
||||||
NodeHistory.prototype.canUndo = function () {
|
NodeHistory.prototype.canUndo = function () {
|
||||||
return (this.index >= 0);
|
return (this.index >= 0)
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if there is an action available for redo
|
* Check if there is an action available for redo
|
||||||
* @return {Boolean} canRedo
|
* @return {Boolean} canRedo
|
||||||
*/
|
*/
|
||||||
NodeHistory.prototype.canRedo = function () {
|
NodeHistory.prototype.canRedo = function () {
|
||||||
return (this.index < this.history.length - 1);
|
return (this.index < this.history.length - 1)
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Undo the last action
|
* Undo the last action
|
||||||
*/
|
*/
|
||||||
NodeHistory.prototype.undo = function () {
|
NodeHistory.prototype.undo = function () {
|
||||||
if (this.canUndo()) {
|
if (this.canUndo()) {
|
||||||
var obj = this.history[this.index];
|
var obj = this.history[this.index]
|
||||||
if (obj) {
|
if (obj) {
|
||||||
var action = this.actions[obj.action];
|
var action = this.actions[obj.action]
|
||||||
if (action && action.undo) {
|
if (action && action.undo) {
|
||||||
action.undo(obj.params);
|
action.undo(obj.params)
|
||||||
if (obj.params.oldSelection) {
|
if (obj.params.oldSelection) {
|
||||||
try {
|
try {
|
||||||
this.editor.setDomSelection(obj.params.oldSelection);
|
this.editor.setDomSelection(obj.params.oldSelection)
|
||||||
}
|
} catch (err) {
|
||||||
catch (err) {
|
console.error(err)
|
||||||
console.error(err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
console.error(new Error('unknown action "' + obj.action + '"'))
|
||||||
console.error(new Error('unknown action "' + obj.action + '"'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.index--;
|
this.index--
|
||||||
|
|
||||||
// fire onchange event
|
// fire onchange event
|
||||||
this.onChange();
|
this.onChange()
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redo the last action
|
* Redo the last action
|
||||||
*/
|
*/
|
||||||
NodeHistory.prototype.redo = function () {
|
NodeHistory.prototype.redo = function () {
|
||||||
if (this.canRedo()) {
|
if (this.canRedo()) {
|
||||||
this.index++;
|
this.index++
|
||||||
|
|
||||||
var obj = this.history[this.index];
|
var obj = this.history[this.index]
|
||||||
if (obj) {
|
if (obj) {
|
||||||
var action = this.actions[obj.action];
|
var action = this.actions[obj.action]
|
||||||
if (action && action.redo) {
|
if (action && action.redo) {
|
||||||
action.redo(obj.params);
|
action.redo(obj.params)
|
||||||
if (obj.params.newSelection) {
|
if (obj.params.newSelection) {
|
||||||
try {
|
try {
|
||||||
this.editor.setDomSelection(obj.params.newSelection);
|
this.editor.setDomSelection(obj.params.newSelection)
|
||||||
}
|
} catch (err) {
|
||||||
catch (err) {
|
console.error(err)
|
||||||
console.error(err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
console.error(new Error('unknown action "' + obj.action + '"'))
|
||||||
console.error(new Error('unknown action "' + obj.action + '"'));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// fire onchange event
|
// fire onchange event
|
||||||
this.onChange();
|
this.onChange()
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy history
|
* Destroy history
|
||||||
*/
|
*/
|
||||||
NodeHistory.prototype.destroy = function () {
|
NodeHistory.prototype.destroy = function () {
|
||||||
this.editor = null;
|
this.editor = null
|
||||||
|
|
||||||
this.history = [];
|
this.history = []
|
||||||
this.index = -1;
|
this.index = -1
|
||||||
};
|
}
|
||||||
|
|
||||||
module.exports = NodeHistory;
|
module.exports = NodeHistory
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
"use strict";
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @constructor SearchBox
|
* @constructor SearchBox
|
||||||
|
@ -7,80 +7,80 @@
|
||||||
* @param {Element} container HTML container element of where to
|
* @param {Element} container HTML container element of where to
|
||||||
* create the search box
|
* create the search box
|
||||||
*/
|
*/
|
||||||
function SearchBox(editor, container) {
|
function SearchBox (editor, container) {
|
||||||
var searchBox = this;
|
var searchBox = this
|
||||||
|
|
||||||
this.editor = editor;
|
this.editor = editor
|
||||||
this.timeout = undefined;
|
this.timeout = undefined
|
||||||
this.delay = 200; // ms
|
this.delay = 200 // ms
|
||||||
this.lastText = undefined;
|
this.lastText = undefined
|
||||||
|
|
||||||
this.dom = {};
|
this.dom = {}
|
||||||
this.dom.container = container;
|
this.dom.container = container
|
||||||
|
|
||||||
var wrapper = document.createElement("div");
|
var wrapper = document.createElement('div')
|
||||||
this.dom.wrapper = wrapper;
|
this.dom.wrapper = wrapper
|
||||||
wrapper.className = "jsoneditor-search";
|
wrapper.className = 'jsoneditor-search'
|
||||||
container.appendChild(wrapper);
|
container.appendChild(wrapper)
|
||||||
|
|
||||||
var results = document.createElement("div");
|
var results = document.createElement('div')
|
||||||
this.dom.results = results;
|
this.dom.results = results
|
||||||
results.className = "jsoneditor-results";
|
results.className = 'jsoneditor-results'
|
||||||
wrapper.appendChild(results);
|
wrapper.appendChild(results)
|
||||||
|
|
||||||
var divInput = document.createElement("div");
|
var divInput = document.createElement('div')
|
||||||
this.dom.input = divInput;
|
this.dom.input = divInput
|
||||||
divInput.className = "jsoneditor-frame";
|
divInput.className = 'jsoneditor-frame'
|
||||||
divInput.title = "Search fields and values";
|
divInput.title = 'Search fields and values'
|
||||||
wrapper.appendChild(divInput);
|
wrapper.appendChild(divInput)
|
||||||
|
|
||||||
var refreshSearch = document.createElement("button");
|
var refreshSearch = document.createElement('button')
|
||||||
refreshSearch.type = "button";
|
refreshSearch.type = 'button'
|
||||||
refreshSearch.className = "jsoneditor-refresh";
|
refreshSearch.className = 'jsoneditor-refresh'
|
||||||
divInput.appendChild(refreshSearch);
|
divInput.appendChild(refreshSearch)
|
||||||
|
|
||||||
var search = document.createElement("input");
|
var search = document.createElement('input')
|
||||||
search.type = "text";
|
search.type = 'text'
|
||||||
this.dom.search = search;
|
this.dom.search = search
|
||||||
search.oninput = function(event) {
|
search.oninput = function (event) {
|
||||||
searchBox._onDelayedSearch(event);
|
searchBox._onDelayedSearch(event)
|
||||||
};
|
}
|
||||||
search.onchange = function(event) {
|
search.onchange = function (event) {
|
||||||
// For IE 9
|
// For IE 9
|
||||||
searchBox._onSearch();
|
searchBox._onSearch()
|
||||||
};
|
}
|
||||||
search.onkeydown = function(event) {
|
search.onkeydown = function (event) {
|
||||||
searchBox._onKeyDown(event);
|
searchBox._onKeyDown(event)
|
||||||
};
|
}
|
||||||
search.onkeyup = function(event) {
|
search.onkeyup = function (event) {
|
||||||
searchBox._onKeyUp(event);
|
searchBox._onKeyUp(event)
|
||||||
};
|
}
|
||||||
refreshSearch.onclick = function(event) {
|
refreshSearch.onclick = function (event) {
|
||||||
search.select();
|
search.select()
|
||||||
};
|
}
|
||||||
|
|
||||||
// TODO: ESC in FF restores the last input, is a FF bug, https://bugzilla.mozilla.org/show_bug.cgi?id=598819
|
// TODO: ESC in FF restores the last input, is a FF bug, https://bugzilla.mozilla.org/show_bug.cgi?id=598819
|
||||||
divInput.appendChild(search);
|
divInput.appendChild(search)
|
||||||
|
|
||||||
var searchNext = document.createElement("button");
|
var searchNext = document.createElement('button')
|
||||||
searchNext.type = "button";
|
searchNext.type = 'button'
|
||||||
searchNext.title = "Next result (Enter)";
|
searchNext.title = 'Next result (Enter)'
|
||||||
searchNext.className = "jsoneditor-next";
|
searchNext.className = 'jsoneditor-next'
|
||||||
searchNext.onclick = function() {
|
searchNext.onclick = function () {
|
||||||
searchBox.next();
|
searchBox.next()
|
||||||
};
|
}
|
||||||
|
|
||||||
divInput.appendChild(searchNext);
|
divInput.appendChild(searchNext)
|
||||||
|
|
||||||
var searchPrevious = document.createElement("button");
|
var searchPrevious = document.createElement('button')
|
||||||
searchPrevious.type = "button";
|
searchPrevious.type = 'button'
|
||||||
searchPrevious.title = "Previous result (Shift+Enter)";
|
searchPrevious.title = 'Previous result (Shift+Enter)'
|
||||||
searchPrevious.className = "jsoneditor-previous";
|
searchPrevious.className = 'jsoneditor-previous'
|
||||||
searchPrevious.onclick = function() {
|
searchPrevious.onclick = function () {
|
||||||
searchBox.previous();
|
searchBox.previous()
|
||||||
};
|
}
|
||||||
|
|
||||||
divInput.appendChild(searchPrevious);
|
divInput.appendChild(searchPrevious)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -88,31 +88,31 @@ function SearchBox(editor, container) {
|
||||||
* @param {boolean} [focus] If true, focus will be set to the next result
|
* @param {boolean} [focus] If true, focus will be set to the next result
|
||||||
* focus is false by default.
|
* focus is false by default.
|
||||||
*/
|
*/
|
||||||
SearchBox.prototype.next = function(focus) {
|
SearchBox.prototype.next = function (focus) {
|
||||||
if (this.results != undefined) {
|
if (this.results !== null) {
|
||||||
var index = this.resultIndex != undefined ? this.resultIndex + 1 : 0;
|
var index = this.resultIndex !== null ? this.resultIndex + 1 : 0
|
||||||
if (index > this.results.length - 1) {
|
if (index > this.results.length - 1) {
|
||||||
index = 0;
|
index = 0
|
||||||
}
|
}
|
||||||
this._setActiveResult(index, focus);
|
this._setActiveResult(index, focus)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Go to the prevous search result
|
* Go to the prevous search result
|
||||||
* @param {boolean} [focus] If true, focus will be set to the next result
|
* @param {boolean} [focus] If true, focus will be set to the next result
|
||||||
* focus is false by default.
|
* focus is false by default.
|
||||||
*/
|
*/
|
||||||
SearchBox.prototype.previous = function(focus) {
|
SearchBox.prototype.previous = function (focus) {
|
||||||
if (this.results != undefined) {
|
if (this.results !== null) {
|
||||||
var max = this.results.length - 1;
|
var max = this.results.length - 1
|
||||||
var index = this.resultIndex != undefined ? this.resultIndex - 1 : max;
|
var index = this.resultIndex !== null ? this.resultIndex - 1 : max
|
||||||
if (index < 0) {
|
if (index < 0) {
|
||||||
index = max;
|
index = max
|
||||||
}
|
}
|
||||||
this._setActiveResult(index, focus);
|
this._setActiveResult(index, focus)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set new value for the current active result
|
* Set new value for the current active result
|
||||||
|
@ -121,57 +121,57 @@ SearchBox.prototype.previous = function(focus) {
|
||||||
* focus is false by default.
|
* focus is false by default.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
SearchBox.prototype._setActiveResult = function(index, focus) {
|
SearchBox.prototype._setActiveResult = function (index, focus) {
|
||||||
// de-activate current active result
|
// de-activate current active result
|
||||||
if (this.activeResult) {
|
if (this.activeResult) {
|
||||||
var prevNode = this.activeResult.node;
|
var prevNode = this.activeResult.node
|
||||||
var prevElem = this.activeResult.elem;
|
var prevElem = this.activeResult.elem
|
||||||
if (prevElem == "field") {
|
if (prevElem === 'field') {
|
||||||
delete prevNode.searchFieldActive;
|
delete prevNode.searchFieldActive
|
||||||
} else {
|
} else {
|
||||||
delete prevNode.searchValueActive;
|
delete prevNode.searchValueActive
|
||||||
}
|
}
|
||||||
prevNode.updateDom();
|
prevNode.updateDom()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.results || !this.results[index]) {
|
if (!this.results || !this.results[index]) {
|
||||||
// out of range, set to undefined
|
// out of range, set to undefined
|
||||||
this.resultIndex = undefined;
|
this.resultIndex = undefined
|
||||||
this.activeResult = undefined;
|
this.activeResult = undefined
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this.resultIndex = index;
|
this.resultIndex = index
|
||||||
|
|
||||||
// set new node active
|
// set new node active
|
||||||
var node = this.results[this.resultIndex].node;
|
var node = this.results[this.resultIndex].node
|
||||||
var elem = this.results[this.resultIndex].elem;
|
var elem = this.results[this.resultIndex].elem
|
||||||
if (elem == "field") {
|
if (elem === 'field') {
|
||||||
node.searchFieldActive = true;
|
node.searchFieldActive = true
|
||||||
} else {
|
} else {
|
||||||
node.searchValueActive = true;
|
node.searchValueActive = true
|
||||||
}
|
}
|
||||||
this.activeResult = this.results[this.resultIndex];
|
this.activeResult = this.results[this.resultIndex]
|
||||||
node.updateDom();
|
node.updateDom()
|
||||||
|
|
||||||
// TODO: not so nice that the focus is only set after the animation is finished
|
// TODO: not so nice that the focus is only set after the animation is finished
|
||||||
node.scrollTo(function() {
|
node.scrollTo(function () {
|
||||||
if (focus) {
|
if (focus) {
|
||||||
node.focus(elem);
|
node.focus(elem)
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancel any running onDelayedSearch.
|
* Cancel any running onDelayedSearch.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
SearchBox.prototype._clearDelay = function() {
|
SearchBox.prototype._clearDelay = function () {
|
||||||
if (this.timeout != undefined) {
|
if (this.timeout !== undefined) {
|
||||||
clearTimeout(this.timeout);
|
clearTimeout(this.timeout)
|
||||||
delete this.timeout;
|
delete this.timeout
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a timer to execute a search after a short delay.
|
* Start a timer to execute a search after a short delay.
|
||||||
|
@ -179,15 +179,15 @@ SearchBox.prototype._clearDelay = function() {
|
||||||
* @param {Event} event
|
* @param {Event} event
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
SearchBox.prototype._onDelayedSearch = function(event) {
|
SearchBox.prototype._onDelayedSearch = function (event) {
|
||||||
// execute the search after a short delay (reduces the number of
|
// execute the search after a short delay (reduces the number of
|
||||||
// search actions while typing in the search text box)
|
// search actions while typing in the search text box)
|
||||||
this._clearDelay();
|
this._clearDelay()
|
||||||
var searchBox = this;
|
var searchBox = this
|
||||||
this.timeout = setTimeout(function(event) {
|
this.timeout = setTimeout(function (event) {
|
||||||
searchBox._onSearch();
|
searchBox._onSearch()
|
||||||
}, this.delay);
|
}, this.delay)
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle onSearch event
|
* Handle onSearch event
|
||||||
|
@ -196,128 +196,128 @@ SearchBox.prototype._onDelayedSearch = function(event) {
|
||||||
* Default is false.
|
* Default is false.
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
SearchBox.prototype._onSearch = function(forceSearch) {
|
SearchBox.prototype._onSearch = function (forceSearch) {
|
||||||
this._clearDelay();
|
this._clearDelay()
|
||||||
|
|
||||||
var value = this.dom.search.value;
|
var value = this.dom.search.value
|
||||||
var text = value.length > 0 ? value : undefined;
|
var text = value.length > 0 ? value : undefined
|
||||||
if (text !== this.lastText || forceSearch) {
|
if (text !== this.lastText || forceSearch) {
|
||||||
// only search again when changed
|
// only search again when changed
|
||||||
this.lastText = text;
|
this.lastText = text
|
||||||
this.results = this.editor.search(text);
|
this.results = this.editor.search(text)
|
||||||
var MAX_SEARCH_RESULTS = this.results[0]
|
var MAX_SEARCH_RESULTS = this.results[0]
|
||||||
? this.results[0].node.MAX_SEARCH_RESULTS
|
? this.results[0].node.MAX_SEARCH_RESULTS
|
||||||
: Infinity;
|
: Infinity
|
||||||
|
|
||||||
// try to maintain the current active result if this is still part of the new search results
|
// try to maintain the current active result if this is still part of the new search results
|
||||||
var activeResultIndex = 0;
|
var activeResultIndex = 0
|
||||||
if (this.activeResult) {
|
if (this.activeResult) {
|
||||||
for (var i = 0; i < this.results.length; i++) {
|
for (var i = 0; i < this.results.length; i++) {
|
||||||
if (this.results[i].node === this.activeResult.node) {
|
if (this.results[i].node === this.activeResult.node) {
|
||||||
activeResultIndex = i;
|
activeResultIndex = i
|
||||||
break;
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this._setActiveResult(activeResultIndex, false);
|
this._setActiveResult(activeResultIndex, false)
|
||||||
|
|
||||||
// display search results
|
// display search results
|
||||||
if (text !== undefined) {
|
if (text !== undefined) {
|
||||||
var resultCount = this.results.length;
|
var resultCount = this.results.length
|
||||||
if (resultCount === 0) {
|
if (resultCount === 0) {
|
||||||
this.dom.results.innerHTML = "no results";
|
this.dom.results.innerHTML = 'no results'
|
||||||
} else if (resultCount === 1) {
|
} else if (resultCount === 1) {
|
||||||
this.dom.results.innerHTML = "1 result";
|
this.dom.results.innerHTML = '1 result'
|
||||||
} else if (resultCount > MAX_SEARCH_RESULTS) {
|
} else if (resultCount > MAX_SEARCH_RESULTS) {
|
||||||
this.dom.results.innerHTML = MAX_SEARCH_RESULTS + "+ results";
|
this.dom.results.innerHTML = MAX_SEARCH_RESULTS + '+ results'
|
||||||
} else {
|
} else {
|
||||||
this.dom.results.innerHTML = resultCount + " results";
|
this.dom.results.innerHTML = resultCount + ' results'
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this.dom.results.innerHTML = "";
|
this.dom.results.innerHTML = ''
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle onKeyDown event in the input box
|
* Handle onKeyDown event in the input box
|
||||||
* @param {Event} event
|
* @param {Event} event
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
SearchBox.prototype._onKeyDown = function(event) {
|
SearchBox.prototype._onKeyDown = function (event) {
|
||||||
var keynum = event.which;
|
var keynum = event.which
|
||||||
if (keynum == 27) {
|
if (keynum === 27) {
|
||||||
// ESC
|
// ESC
|
||||||
this.dom.search.value = ""; // clear search
|
this.dom.search.value = '' // clear search
|
||||||
this._onSearch();
|
this._onSearch()
|
||||||
event.preventDefault();
|
event.preventDefault()
|
||||||
event.stopPropagation();
|
event.stopPropagation()
|
||||||
} else if (keynum == 13) {
|
} else if (keynum === 13) {
|
||||||
// Enter
|
// Enter
|
||||||
if (event.ctrlKey) {
|
if (event.ctrlKey) {
|
||||||
// force to search again
|
// force to search again
|
||||||
this._onSearch(true);
|
this._onSearch(true)
|
||||||
} else if (event.shiftKey) {
|
} else if (event.shiftKey) {
|
||||||
// move to the previous search result
|
// move to the previous search result
|
||||||
this.previous();
|
this.previous()
|
||||||
} else {
|
} else {
|
||||||
// move to the next search result
|
// move to the next search result
|
||||||
this.next();
|
this.next()
|
||||||
}
|
}
|
||||||
event.preventDefault();
|
event.preventDefault()
|
||||||
event.stopPropagation();
|
event.stopPropagation()
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle onKeyUp event in the input box
|
* Handle onKeyUp event in the input box
|
||||||
* @param {Event} event
|
* @param {Event} event
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
SearchBox.prototype._onKeyUp = function(event) {
|
SearchBox.prototype._onKeyUp = function (event) {
|
||||||
var keynum = event.keyCode;
|
var keynum = event.keyCode
|
||||||
if (keynum != 27 && keynum != 13) {
|
if (keynum !== 27 && keynum !== 13) {
|
||||||
// !show and !Enter
|
// !show and !Enter
|
||||||
this._onDelayedSearch(event); // For IE 9
|
this._onDelayedSearch(event) // For IE 9
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear the search results
|
* Clear the search results
|
||||||
*/
|
*/
|
||||||
SearchBox.prototype.clear = function() {
|
SearchBox.prototype.clear = function () {
|
||||||
this.dom.search.value = "";
|
this.dom.search.value = ''
|
||||||
this._onSearch();
|
this._onSearch()
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Refresh searchResults if there is a search value
|
* Refresh searchResults if there is a search value
|
||||||
*/
|
*/
|
||||||
SearchBox.prototype.forceSearch = function() {
|
SearchBox.prototype.forceSearch = function () {
|
||||||
this._onSearch(true);
|
this._onSearch(true)
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test whether the search box value is empty
|
* Test whether the search box value is empty
|
||||||
* @returns {boolean} Returns true when empty.
|
* @returns {boolean} Returns true when empty.
|
||||||
*/
|
*/
|
||||||
SearchBox.prototype.isEmpty = function() {
|
SearchBox.prototype.isEmpty = function () {
|
||||||
return this.dom.search.value === "";
|
return this.dom.search.value === ''
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Destroy the search box
|
* Destroy the search box
|
||||||
*/
|
*/
|
||||||
SearchBox.prototype.destroy = function() {
|
SearchBox.prototype.destroy = function () {
|
||||||
this.editor = null;
|
this.editor = null
|
||||||
this.dom.container.removeChild(this.dom.wrapper);
|
this.dom.container.removeChild(this.dom.wrapper)
|
||||||
this.dom = null;
|
this.dom = null
|
||||||
|
|
||||||
this.results = null;
|
this.results = null
|
||||||
this.activeResult = null;
|
this.activeResult = null
|
||||||
|
|
||||||
this._clearDelay();
|
this._clearDelay()
|
||||||
};
|
}
|
||||||
|
|
||||||
module.exports = SearchBox;
|
module.exports = SearchBox
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
'use strict';
|
'use strict'
|
||||||
|
|
||||||
var ContextMenu = require('./ContextMenu');
|
var ContextMenu = require('./ContextMenu')
|
||||||
var translate = require('./i18n').translate;
|
var translate = require('./i18n').translate
|
||||||
var util = require('./util');
|
var util = require('./util')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a component that visualize path selection in tree based editors
|
* Creates a component that visualize path selection in tree based editors
|
||||||
* @param {HTMLElement} container
|
* @param {HTMLElement} container
|
||||||
* @param {HTMLElement} root
|
* @param {HTMLElement} root
|
||||||
* @constructor
|
* @constructor
|
||||||
*/
|
*/
|
||||||
function TreePath(container, root) {
|
function TreePath (container, root) {
|
||||||
if (container) {
|
if (container) {
|
||||||
this.root = root;
|
this.root = root
|
||||||
this.path = document.createElement('div');
|
this.path = document.createElement('div')
|
||||||
this.path.className = 'jsoneditor-treepath';
|
this.path.className = 'jsoneditor-treepath'
|
||||||
this.path.setAttribute('tabindex',0);
|
this.path.setAttribute('tabindex', 0)
|
||||||
this.contentMenuClicked;
|
this.contentMenuClicked = false
|
||||||
container.appendChild(this.path);
|
container.appendChild(this.path)
|
||||||
this.reset();
|
this.reset()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -26,98 +26,98 @@ function TreePath(container, root) {
|
||||||
* Reset component to initial status
|
* Reset component to initial status
|
||||||
*/
|
*/
|
||||||
TreePath.prototype.reset = function () {
|
TreePath.prototype.reset = function () {
|
||||||
this.path.innerHTML = translate('selectNode');
|
this.path.innerHTML = translate('selectNode')
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Renders the component UI according to a given path objects
|
* Renders the component UI according to a given path objects
|
||||||
* @param {Array<{name: String, childs: Array}>} pathObjs a list of path objects
|
* @param {Array<{name: String, childs: Array}>} pathObjs a list of path objects
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
TreePath.prototype.setPath = function (pathObjs) {
|
TreePath.prototype.setPath = function (pathObjs) {
|
||||||
var me = this;
|
var me = this
|
||||||
|
|
||||||
this.path.innerHTML = '';
|
this.path.innerHTML = ''
|
||||||
|
|
||||||
if (pathObjs && pathObjs.length) {
|
if (pathObjs && pathObjs.length) {
|
||||||
pathObjs.forEach(function (pathObj, idx) {
|
pathObjs.forEach(function (pathObj, idx) {
|
||||||
var pathEl = document.createElement('span');
|
var pathEl = document.createElement('span')
|
||||||
var sepEl;
|
var sepEl
|
||||||
pathEl.className = 'jsoneditor-treepath-element';
|
pathEl.className = 'jsoneditor-treepath-element'
|
||||||
pathEl.innerText = pathObj.name;
|
pathEl.innerText = pathObj.name
|
||||||
pathEl.onclick = _onSegmentClick.bind(me, pathObj);
|
pathEl.onclick = _onSegmentClick.bind(me, pathObj)
|
||||||
|
|
||||||
me.path.appendChild(pathEl);
|
me.path.appendChild(pathEl)
|
||||||
|
|
||||||
if (pathObj.children.length) {
|
if (pathObj.children.length) {
|
||||||
sepEl = document.createElement('span');
|
sepEl = document.createElement('span')
|
||||||
sepEl.className = 'jsoneditor-treepath-seperator';
|
sepEl.className = 'jsoneditor-treepath-seperator'
|
||||||
sepEl.innerHTML = '►';
|
sepEl.innerHTML = '►'
|
||||||
|
|
||||||
sepEl.onclick = function () {
|
sepEl.onclick = function () {
|
||||||
me.contentMenuClicked = true;
|
me.contentMenuClicked = true
|
||||||
var items = [];
|
var items = []
|
||||||
pathObj.children.forEach(function (child) {
|
pathObj.children.forEach(function (child) {
|
||||||
items.push({
|
items.push({
|
||||||
'text': child.name,
|
text: child.name,
|
||||||
'className': 'jsoneditor-type-modes' + (pathObjs[idx + 1] + 1 && pathObjs[idx + 1].name === child.name ? ' jsoneditor-selected' : ''),
|
className: 'jsoneditor-type-modes' + (pathObjs[idx + 1] + 1 && pathObjs[idx + 1].name === child.name ? ' jsoneditor-selected' : ''),
|
||||||
'click': _onContextMenuItemClick.bind(me, pathObj, child.name)
|
click: _onContextMenuItemClick.bind(me, pathObj, child.name)
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
var menu = new ContextMenu(items);
|
var menu = new ContextMenu(items)
|
||||||
menu.show(sepEl, me.root, true);
|
menu.show(sepEl, me.root, true)
|
||||||
};
|
}
|
||||||
|
|
||||||
me.path.appendChild(sepEl);
|
me.path.appendChild(sepEl)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(idx === pathObjs.length - 1) {
|
if (idx === pathObjs.length - 1) {
|
||||||
var leftRectPos = (sepEl || pathEl).getBoundingClientRect().right;
|
var leftRectPos = (sepEl || pathEl).getBoundingClientRect().right
|
||||||
if(me.path.offsetWidth < leftRectPos) {
|
if (me.path.offsetWidth < leftRectPos) {
|
||||||
me.path.scrollLeft = leftRectPos;
|
me.path.scrollLeft = leftRectPos
|
||||||
}
|
}
|
||||||
|
|
||||||
if (me.path.scrollLeft) {
|
if (me.path.scrollLeft) {
|
||||||
var showAllBtn = document.createElement('span');
|
var showAllBtn = document.createElement('span')
|
||||||
showAllBtn.className = 'jsoneditor-treepath-show-all-btn';
|
showAllBtn.className = 'jsoneditor-treepath-show-all-btn'
|
||||||
showAllBtn.title = 'show all path';
|
showAllBtn.title = 'show all path'
|
||||||
showAllBtn.innerHTML = '...';
|
showAllBtn.innerHTML = '...'
|
||||||
showAllBtn.onclick = _onShowAllClick.bind(me, pathObjs);
|
showAllBtn.onclick = _onShowAllClick.bind(me, pathObjs)
|
||||||
me.path.insertBefore(showAllBtn, me.path.firstChild);
|
me.path.insertBefore(showAllBtn, me.path.firstChild)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
function _onShowAllClick(pathObjs) {
|
function _onShowAllClick (pathObjs) {
|
||||||
me.contentMenuClicked = false;
|
me.contentMenuClicked = false
|
||||||
util.addClassName(me.path, 'show-all');
|
util.addClassName(me.path, 'show-all')
|
||||||
me.path.style.width = me.path.parentNode.getBoundingClientRect().width - 10 + 'px';
|
me.path.style.width = me.path.parentNode.getBoundingClientRect().width - 10 + 'px'
|
||||||
me.path.onblur = function() {
|
me.path.onblur = function () {
|
||||||
if (me.contentMenuClicked) {
|
if (me.contentMenuClicked) {
|
||||||
me.contentMenuClicked = false;
|
me.contentMenuClicked = false
|
||||||
me.path.focus();
|
me.path.focus()
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
util.removeClassName(me.path, 'show-all');
|
util.removeClassName(me.path, 'show-all')
|
||||||
me.path.onblur = undefined;
|
me.path.onblur = undefined
|
||||||
me.path.style.width = '';
|
me.path.style.width = ''
|
||||||
me.setPath(pathObjs);
|
me.setPath(pathObjs)
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _onSegmentClick(pathObj) {
|
function _onSegmentClick (pathObj) {
|
||||||
if (this.selectionCallback) {
|
if (this.selectionCallback) {
|
||||||
this.selectionCallback(pathObj);
|
this.selectionCallback(pathObj)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function _onContextMenuItemClick(pathObj, selection) {
|
function _onContextMenuItemClick (pathObj, selection) {
|
||||||
if (this.contextMenuCallback) {
|
if (this.contextMenuCallback) {
|
||||||
this.contextMenuCallback(pathObj, selection);
|
this.contextMenuCallback(pathObj, selection)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set a callback function for selection of path section
|
* set a callback function for selection of path section
|
||||||
|
@ -125,9 +125,9 @@ TreePath.prototype.setPath = function (pathObjs) {
|
||||||
*/
|
*/
|
||||||
TreePath.prototype.onSectionSelected = function (callback) {
|
TreePath.prototype.onSectionSelected = function (callback) {
|
||||||
if (typeof callback === 'function') {
|
if (typeof callback === 'function') {
|
||||||
this.selectionCallback = callback;
|
this.selectionCallback = callback
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* set a callback function for selection of path section
|
* set a callback function for selection of path section
|
||||||
|
@ -135,8 +135,8 @@ TreePath.prototype.onSectionSelected = function (callback) {
|
||||||
*/
|
*/
|
||||||
TreePath.prototype.onContextMenuItemSelected = function (callback) {
|
TreePath.prototype.onContextMenuItemSelected = function (callback) {
|
||||||
if (typeof callback === 'function') {
|
if (typeof callback === 'function') {
|
||||||
this.contextMenuCallback = callback;
|
this.contextMenuCallback = callback
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
module.exports = TreePath;
|
module.exports = TreePath
|
||||||
|
|
|
@ -2,20 +2,18 @@ var ace
|
||||||
if (window.ace) {
|
if (window.ace) {
|
||||||
// use the already loaded instance of Ace
|
// use the already loaded instance of Ace
|
||||||
ace = window.ace
|
ace = window.ace
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
try {
|
try {
|
||||||
// load brace
|
// load brace
|
||||||
ace = require('brace');
|
ace = require('brace')
|
||||||
|
|
||||||
// load required Ace plugins
|
// load required Ace plugins
|
||||||
require('brace/mode/json');
|
require('brace/mode/json')
|
||||||
require('brace/ext/searchbox');
|
require('brace/ext/searchbox')
|
||||||
}
|
} catch (err) {
|
||||||
catch (err) {
|
|
||||||
// failed to load brace (can be minimalist bundle).
|
// failed to load brace (can be minimalist bundle).
|
||||||
// No worries, the editor will fall back to plain text if needed.
|
// No worries, the editor will fall back to plain text if needed.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = ace;
|
module.exports = ace
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
*
|
*
|
||||||
* Copyright (c) 2010, Ajax.org B.V.
|
* Copyright (c) 2010, Ajax.org B.V.
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions are met:
|
* modification, are permitted provided that the following conditions are met:
|
||||||
* * Redistributions of source code must retain the above copyright
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
@ -14,7 +14,7 @@
|
||||||
* * Neither the name of Ajax.org B.V. nor the
|
* * Neither the name of Ajax.org B.V. nor the
|
||||||
* names of its contributors may be used to endorse or promote products
|
* names of its contributors may be used to endorse or promote products
|
||||||
* derived from this software without specific prior written permission.
|
* derived from this software without specific prior written permission.
|
||||||
*
|
*
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
* 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
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
@ -28,118 +28,117 @@
|
||||||
*
|
*
|
||||||
* ***** END LICENSE BLOCK ***** */
|
* ***** END LICENSE BLOCK ***** */
|
||||||
|
|
||||||
ace.define('ace/theme/jsoneditor', ['require', 'exports', 'module', 'ace/lib/dom'], function(acequire, exports, module) {
|
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
|
||||||
|
}
|
||||||
|
|
||||||
exports.isDark = false;
|
.ace-jsoneditor.ace_editor {
|
||||||
exports.cssClass = "ace-jsoneditor";
|
font-family: "dejavu sans mono", "droid sans mono", consolas, monaco, "lucida console", "courier new", courier, monospace, sans-serif;
|
||||||
exports.cssText = ".ace-jsoneditor .ace_gutter {\
|
line-height: 1.3;
|
||||||
background: #ebebeb;\
|
background-color: #fff;
|
||||||
color: #333\
|
}
|
||||||
}\
|
.ace-jsoneditor .ace_print-margin {
|
||||||
\
|
width: 1px;
|
||||||
.ace-jsoneditor.ace_editor {\
|
background: #e8e8e8
|
||||||
font-family: \"dejavu sans mono\", \"droid sans mono\", consolas, monaco, \"lucida console\", \"courier new\", courier, monospace, sans-serif;\
|
}
|
||||||
line-height: 1.3;\
|
.ace-jsoneditor .ace_scroller {
|
||||||
background-color: #fff;\
|
background-color: #FFFFFF
|
||||||
}\
|
}
|
||||||
.ace-jsoneditor .ace_print-margin {\
|
.ace-jsoneditor .ace_text-layer {
|
||||||
width: 1px;\
|
color: gray
|
||||||
background: #e8e8e8\
|
}
|
||||||
}\
|
.ace-jsoneditor .ace_variable {
|
||||||
.ace-jsoneditor .ace_scroller {\
|
color: #1a1a1a
|
||||||
background-color: #FFFFFF\
|
}
|
||||||
}\
|
.ace-jsoneditor .ace_cursor {
|
||||||
.ace-jsoneditor .ace_text-layer {\
|
border-left: 2px solid #000000
|
||||||
color: gray\
|
}
|
||||||
}\
|
.ace-jsoneditor .ace_overwrite-cursors .ace_cursor {
|
||||||
.ace-jsoneditor .ace_variable {\
|
border-left: 0px;
|
||||||
color: #1a1a1a\
|
border-bottom: 1px solid #000000
|
||||||
}\
|
}
|
||||||
.ace-jsoneditor .ace_cursor {\
|
.ace-jsoneditor .ace_marker-layer .ace_selection {
|
||||||
border-left: 2px solid #000000\
|
background: lightgray
|
||||||
}\
|
}
|
||||||
.ace-jsoneditor .ace_overwrite-cursors .ace_cursor {\
|
.ace-jsoneditor.ace_multiselect .ace_selection.ace_start {
|
||||||
border-left: 0px;\
|
box-shadow: 0 0 3px 0px #FFFFFF;
|
||||||
border-bottom: 1px solid #000000\
|
border-radius: 2px
|
||||||
}\
|
}
|
||||||
.ace-jsoneditor .ace_marker-layer .ace_selection {\
|
.ace-jsoneditor .ace_marker-layer .ace_step {
|
||||||
background: lightgray\
|
background: rgb(255, 255, 0)
|
||||||
}\
|
}
|
||||||
.ace-jsoneditor.ace_multiselect .ace_selection.ace_start {\
|
.ace-jsoneditor .ace_marker-layer .ace_bracket {
|
||||||
box-shadow: 0 0 3px 0px #FFFFFF;\
|
margin: -1px 0 0 -1px;
|
||||||
border-radius: 2px\
|
border: 1px solid #BFBFBF
|
||||||
}\
|
}
|
||||||
.ace-jsoneditor .ace_marker-layer .ace_step {\
|
.ace-jsoneditor .ace_marker-layer .ace_active-line {
|
||||||
background: rgb(255, 255, 0)\
|
background: #FFFBD1
|
||||||
}\
|
}
|
||||||
.ace-jsoneditor .ace_marker-layer .ace_bracket {\
|
.ace-jsoneditor .ace_gutter-active-line {
|
||||||
margin: -1px 0 0 -1px;\
|
background-color : #dcdcdc
|
||||||
border: 1px solid #BFBFBF\
|
}
|
||||||
}\
|
.ace-jsoneditor .ace_marker-layer .ace_selected-word {
|
||||||
.ace-jsoneditor .ace_marker-layer .ace_active-line {\
|
border: 1px solid lightgray
|
||||||
background: #FFFBD1\
|
}
|
||||||
}\
|
.ace-jsoneditor .ace_invisible {
|
||||||
.ace-jsoneditor .ace_gutter-active-line {\
|
color: #BFBFBF
|
||||||
background-color : #dcdcdc\
|
}
|
||||||
}\
|
.ace-jsoneditor .ace_keyword,
|
||||||
.ace-jsoneditor .ace_marker-layer .ace_selected-word {\
|
.ace-jsoneditor .ace_meta,
|
||||||
border: 1px solid lightgray\
|
.ace-jsoneditor .ace_support.ace_constant.ace_property-value {
|
||||||
}\
|
color: #AF956F
|
||||||
.ace-jsoneditor .ace_invisible {\
|
}
|
||||||
color: #BFBFBF\
|
.ace-jsoneditor .ace_keyword.ace_operator {
|
||||||
}\
|
color: #484848
|
||||||
.ace-jsoneditor .ace_keyword,\
|
}
|
||||||
.ace-jsoneditor .ace_meta,\
|
.ace-jsoneditor .ace_keyword.ace_other.ace_unit {
|
||||||
.ace-jsoneditor .ace_support.ace_constant.ace_property-value {\
|
color: #96DC5F
|
||||||
color: #AF956F\
|
}
|
||||||
}\
|
.ace-jsoneditor .ace_constant.ace_language {
|
||||||
.ace-jsoneditor .ace_keyword.ace_operator {\
|
color: darkorange
|
||||||
color: #484848\
|
}
|
||||||
}\
|
.ace-jsoneditor .ace_constant.ace_numeric {
|
||||||
.ace-jsoneditor .ace_keyword.ace_other.ace_unit {\
|
color: red
|
||||||
color: #96DC5F\
|
}
|
||||||
}\
|
.ace-jsoneditor .ace_constant.ace_character.ace_entity {
|
||||||
.ace-jsoneditor .ace_constant.ace_language {\
|
color: #BF78CC
|
||||||
color: darkorange\
|
}
|
||||||
}\
|
.ace-jsoneditor .ace_invalid {
|
||||||
.ace-jsoneditor .ace_constant.ace_numeric {\
|
color: #FFFFFF;
|
||||||
color: red\
|
background-color: #FF002A;
|
||||||
}\
|
}
|
||||||
.ace-jsoneditor .ace_constant.ace_character.ace_entity {\
|
.ace-jsoneditor .ace_fold {
|
||||||
color: #BF78CC\
|
background-color: #AF956F;
|
||||||
}\
|
border-color: #000000
|
||||||
.ace-jsoneditor .ace_invalid {\
|
}
|
||||||
color: #FFFFFF;\
|
.ace-jsoneditor .ace_storage,
|
||||||
background-color: #FF002A;\
|
.ace-jsoneditor .ace_support.ace_class,
|
||||||
}\
|
.ace-jsoneditor .ace_support.ace_function,
|
||||||
.ace-jsoneditor .ace_fold {\
|
.ace-jsoneditor .ace_support.ace_other,
|
||||||
background-color: #AF956F;\
|
.ace-jsoneditor .ace_support.ace_type {
|
||||||
border-color: #000000\
|
color: #C52727
|
||||||
}\
|
}
|
||||||
.ace-jsoneditor .ace_storage,\
|
.ace-jsoneditor .ace_string {
|
||||||
.ace-jsoneditor .ace_support.ace_class,\
|
color: green
|
||||||
.ace-jsoneditor .ace_support.ace_function,\
|
}
|
||||||
.ace-jsoneditor .ace_support.ace_other,\
|
.ace-jsoneditor .ace_comment {
|
||||||
.ace-jsoneditor .ace_support.ace_type {\
|
color: #BCC8BA
|
||||||
color: #C52727\
|
}
|
||||||
}\
|
.ace-jsoneditor .ace_entity.ace_name.ace_tag,
|
||||||
.ace-jsoneditor .ace_string {\
|
.ace-jsoneditor .ace_entity.ace_other.ace_attribute-name {
|
||||||
color: green\
|
color: #606060
|
||||||
}\
|
}
|
||||||
.ace-jsoneditor .ace_comment {\
|
.ace-jsoneditor .ace_markup.ace_underline {
|
||||||
color: #BCC8BA\
|
text-decoration: underline
|
||||||
}\
|
}
|
||||||
.ace-jsoneditor .ace_entity.ace_name.ace_tag,\
|
.ace-jsoneditor .ace_indent-guide {
|
||||||
.ace-jsoneditor .ace_entity.ace_other.ace_attribute-name {\
|
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y
|
||||||
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");
|
var dom = acequire('../lib/dom')
|
||||||
dom.importCssString(exports.cssText, exports.cssClass);
|
dom.importCssString(exports.cssText, exports.cssClass)
|
||||||
});
|
})
|
||||||
|
|
|
@ -1,14 +1,14 @@
|
||||||
'use strict';
|
'use strict'
|
||||||
|
|
||||||
var util = require('./util');
|
var util = require('./util')
|
||||||
var ContextMenu = require('./ContextMenu');
|
var ContextMenu = require('./ContextMenu')
|
||||||
var translate = require('./i18n').translate;
|
var translate = require('./i18n').translate
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A factory function to create an AppendNode, which depends on a Node
|
* A factory function to create an AppendNode, which depends on a Node
|
||||||
* @param {Node} Node
|
* @param {Node} Node
|
||||||
*/
|
*/
|
||||||
function appendNodeFactory(Node) {
|
function appendNodeFactory (Node) {
|
||||||
/**
|
/**
|
||||||
* @constructor AppendNode
|
* @constructor AppendNode
|
||||||
* @extends Node
|
* @extends Node
|
||||||
|
@ -18,11 +18,11 @@ function appendNodeFactory(Node) {
|
||||||
*/
|
*/
|
||||||
function AppendNode (editor) {
|
function AppendNode (editor) {
|
||||||
/** @type {TreeEditor} */
|
/** @type {TreeEditor} */
|
||||||
this.editor = editor;
|
this.editor = editor
|
||||||
this.dom = {};
|
this.dom = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
AppendNode.prototype = new Node();
|
AppendNode.prototype = new Node()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a table row with an append button.
|
* Return a table row with an append button.
|
||||||
|
@ -30,109 +30,108 @@ function appendNodeFactory(Node) {
|
||||||
*/
|
*/
|
||||||
AppendNode.prototype.getDom = function () {
|
AppendNode.prototype.getDom = function () {
|
||||||
// TODO: implement a new solution for the append node
|
// TODO: implement a new solution for the append node
|
||||||
var dom = this.dom;
|
var dom = this.dom
|
||||||
|
|
||||||
if (dom.tr) {
|
if (dom.tr) {
|
||||||
return dom.tr;
|
return dom.tr
|
||||||
}
|
}
|
||||||
|
|
||||||
this._updateEditability();
|
this._updateEditability()
|
||||||
|
|
||||||
// a row for the append button
|
// a row for the append button
|
||||||
var trAppend = document.createElement('tr');
|
var trAppend = document.createElement('tr')
|
||||||
trAppend.className = 'jsoneditor-append';
|
trAppend.className = 'jsoneditor-append'
|
||||||
trAppend.node = this;
|
trAppend.node = this
|
||||||
dom.tr = trAppend;
|
dom.tr = trAppend
|
||||||
|
|
||||||
// TODO: consistent naming
|
// TODO: consistent naming
|
||||||
|
|
||||||
if (this.editor.options.mode === 'tree') {
|
if (this.editor.options.mode === 'tree') {
|
||||||
// a cell for the dragarea column
|
// a cell for the dragarea column
|
||||||
dom.tdDrag = document.createElement('td');
|
dom.tdDrag = document.createElement('td')
|
||||||
|
|
||||||
// create context menu
|
// create context menu
|
||||||
var tdMenu = document.createElement('td');
|
var tdMenu = document.createElement('td')
|
||||||
dom.tdMenu = tdMenu;
|
dom.tdMenu = tdMenu
|
||||||
var menu = document.createElement('button');
|
var menu = document.createElement('button')
|
||||||
menu.type = 'button';
|
menu.type = 'button'
|
||||||
menu.className = 'jsoneditor-button jsoneditor-contextmenu';
|
menu.className = 'jsoneditor-button jsoneditor-contextmenu'
|
||||||
menu.title = 'Click to open the actions menu (Ctrl+M)';
|
menu.title = 'Click to open the actions menu (Ctrl+M)'
|
||||||
dom.menu = menu;
|
dom.menu = menu
|
||||||
tdMenu.appendChild(dom.menu);
|
tdMenu.appendChild(dom.menu)
|
||||||
}
|
}
|
||||||
|
|
||||||
// a cell for the contents (showing text 'empty')
|
// a cell for the contents (showing text 'empty')
|
||||||
var tdAppend = document.createElement('td');
|
var tdAppend = document.createElement('td')
|
||||||
var domText = document.createElement('div');
|
var domText = document.createElement('div')
|
||||||
domText.innerHTML = '(' + translate('empty') + ')';
|
domText.innerHTML = '(' + translate('empty') + ')'
|
||||||
domText.className = 'jsoneditor-readonly';
|
domText.className = 'jsoneditor-readonly'
|
||||||
tdAppend.appendChild(domText);
|
tdAppend.appendChild(domText)
|
||||||
dom.td = tdAppend;
|
dom.td = tdAppend
|
||||||
dom.text = domText;
|
dom.text = domText
|
||||||
|
|
||||||
this.updateDom();
|
this.updateDom()
|
||||||
|
|
||||||
return trAppend;
|
return trAppend
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append node doesn't have a path
|
* Append node doesn't have a path
|
||||||
* @returns {null}
|
* @returns {null}
|
||||||
*/
|
*/
|
||||||
AppendNode.prototype.getPath = function() {
|
AppendNode.prototype.getPath = function () {
|
||||||
return null;
|
return null
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Append node doesn't have an index
|
* Append node doesn't have an index
|
||||||
* @returns {null}
|
* @returns {null}
|
||||||
*/
|
*/
|
||||||
AppendNode.prototype.getIndex = function() {
|
AppendNode.prototype.getIndex = function () {
|
||||||
return null;
|
return null
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the HTML dom of the Node
|
* Update the HTML dom of the Node
|
||||||
*/
|
*/
|
||||||
AppendNode.prototype.updateDom = function(options) {
|
AppendNode.prototype.updateDom = function (options) {
|
||||||
var dom = this.dom;
|
var dom = this.dom
|
||||||
var tdAppend = dom.td;
|
var tdAppend = dom.td
|
||||||
if (tdAppend) {
|
if (tdAppend) {
|
||||||
tdAppend.style.paddingLeft = (this.getLevel() * 24 + 26) + 'px';
|
tdAppend.style.paddingLeft = (this.getLevel() * 24 + 26) + 'px'
|
||||||
// TODO: not so nice hard coded offset
|
// TODO: not so nice hard coded offset
|
||||||
}
|
}
|
||||||
|
|
||||||
var domText = dom.text;
|
var domText = dom.text
|
||||||
if (domText) {
|
if (domText) {
|
||||||
domText.innerHTML = '(' + translate('empty') + ' ' + this.parent.type + ')';
|
domText.innerHTML = '(' + translate('empty') + ' ' + this.parent.type + ')'
|
||||||
}
|
}
|
||||||
|
|
||||||
// attach or detach the contents of the append node:
|
// attach or detach the contents of the append node:
|
||||||
// hide when the parent has childs, show when the parent has no childs
|
// hide when the parent has childs, show when the parent has no childs
|
||||||
var trAppend = dom.tr;
|
var trAppend = dom.tr
|
||||||
if (!this.isVisible()) {
|
if (!this.isVisible()) {
|
||||||
if (dom.tr.firstChild) {
|
if (dom.tr.firstChild) {
|
||||||
if (dom.tdDrag) {
|
if (dom.tdDrag) {
|
||||||
trAppend.removeChild(dom.tdDrag);
|
trAppend.removeChild(dom.tdDrag)
|
||||||
}
|
}
|
||||||
if (dom.tdMenu) {
|
if (dom.tdMenu) {
|
||||||
trAppend.removeChild(dom.tdMenu);
|
trAppend.removeChild(dom.tdMenu)
|
||||||
}
|
}
|
||||||
trAppend.removeChild(tdAppend);
|
trAppend.removeChild(tdAppend)
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (!dom.tr.firstChild) {
|
if (!dom.tr.firstChild) {
|
||||||
if (dom.tdDrag) {
|
if (dom.tdDrag) {
|
||||||
trAppend.appendChild(dom.tdDrag);
|
trAppend.appendChild(dom.tdDrag)
|
||||||
}
|
}
|
||||||
if (dom.tdMenu) {
|
if (dom.tdMenu) {
|
||||||
trAppend.appendChild(dom.tdMenu);
|
trAppend.appendChild(dom.tdMenu)
|
||||||
}
|
}
|
||||||
trAppend.appendChild(tdAppend);
|
trAppend.appendChild(tdAppend)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether the AppendNode is currently visible.
|
* Check whether the AppendNode is currently visible.
|
||||||
|
@ -140,8 +139,8 @@ function appendNodeFactory(Node) {
|
||||||
* @return {boolean} isVisible
|
* @return {boolean} isVisible
|
||||||
*/
|
*/
|
||||||
AppendNode.prototype.isVisible = function () {
|
AppendNode.prototype.isVisible = function () {
|
||||||
return (this.parent.childs.length == 0);
|
return (this.parent.childs.length === 0)
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show a contextmenu for this node
|
* Show a contextmenu for this node
|
||||||
|
@ -150,110 +149,109 @@ function appendNodeFactory(Node) {
|
||||||
* is being closed.
|
* is being closed.
|
||||||
*/
|
*/
|
||||||
AppendNode.prototype.showContextMenu = function (anchor, onClose) {
|
AppendNode.prototype.showContextMenu = function (anchor, onClose) {
|
||||||
var node = this;
|
var node = this
|
||||||
var titles = Node.TYPE_TITLES;
|
var titles = Node.TYPE_TITLES
|
||||||
var appendSubmenu = [
|
var appendSubmenu = [
|
||||||
{
|
{
|
||||||
text: translate('auto'),
|
text: translate('auto'),
|
||||||
className: 'jsoneditor-type-auto',
|
className: 'jsoneditor-type-auto',
|
||||||
title: titles.auto,
|
title: titles.auto,
|
||||||
click: function () {
|
click: function () {
|
||||||
node._onAppend('', '', 'auto');
|
node._onAppend('', '', 'auto')
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: translate('array'),
|
|
||||||
className: 'jsoneditor-type-array',
|
|
||||||
title: titles.array,
|
|
||||||
click: function () {
|
|
||||||
node._onAppend('', []);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: translate('object'),
|
|
||||||
className: 'jsoneditor-type-object',
|
|
||||||
title: titles.object,
|
|
||||||
click: function () {
|
|
||||||
node._onAppend('', {});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
text: translate('string'),
|
|
||||||
className: 'jsoneditor-type-string',
|
|
||||||
title: titles.string,
|
|
||||||
click: function () {
|
|
||||||
node._onAppend('', '', 'string');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
];
|
},
|
||||||
node.addTemplates(appendSubmenu, true);
|
{
|
||||||
|
text: translate('array'),
|
||||||
|
className: 'jsoneditor-type-array',
|
||||||
|
title: titles.array,
|
||||||
|
click: function () {
|
||||||
|
node._onAppend('', [])
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: translate('object'),
|
||||||
|
className: 'jsoneditor-type-object',
|
||||||
|
title: titles.object,
|
||||||
|
click: function () {
|
||||||
|
node._onAppend('', {})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: translate('string'),
|
||||||
|
className: 'jsoneditor-type-string',
|
||||||
|
title: titles.string,
|
||||||
|
click: function () {
|
||||||
|
node._onAppend('', '', 'string')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
node.addTemplates(appendSubmenu, true)
|
||||||
var items = [
|
var items = [
|
||||||
// create append button
|
// create append button
|
||||||
{
|
{
|
||||||
'text': translate('appendText'),
|
text: translate('appendText'),
|
||||||
'title': translate('appendTitleAuto'),
|
title: translate('appendTitleAuto'),
|
||||||
'submenuTitle': translate('appendSubmenuTitle'),
|
submenuTitle: translate('appendSubmenuTitle'),
|
||||||
'className': 'jsoneditor-insert',
|
className: 'jsoneditor-insert',
|
||||||
'click': function () {
|
click: function () {
|
||||||
node._onAppend('', '', 'auto');
|
node._onAppend('', '', 'auto')
|
||||||
},
|
},
|
||||||
'submenu': appendSubmenu
|
submenu: appendSubmenu
|
||||||
}
|
}
|
||||||
];
|
]
|
||||||
|
|
||||||
if (this.editor.options.onCreateMenu) {
|
if (this.editor.options.onCreateMenu) {
|
||||||
var path = node.parent.getPath();
|
var path = node.parent.getPath()
|
||||||
|
|
||||||
items = this.editor.options.onCreateMenu(items, {
|
items = this.editor.options.onCreateMenu(items, {
|
||||||
type: 'append',
|
type: 'append',
|
||||||
path: path,
|
path: path,
|
||||||
paths: [path]
|
paths: [path]
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var menu = new ContextMenu(items, {close: onClose});
|
var menu = new ContextMenu(items, { close: onClose })
|
||||||
menu.show(anchor, this.editor.frame);
|
menu.show(anchor, this.editor.frame)
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle an event. The event is caught centrally by the editor
|
* Handle an event. The event is caught centrally by the editor
|
||||||
* @param {Event} event
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
AppendNode.prototype.onEvent = function (event) {
|
AppendNode.prototype.onEvent = function (event) {
|
||||||
var type = event.type;
|
var type = event.type
|
||||||
var target = event.target || event.srcElement;
|
var target = event.target || event.srcElement
|
||||||
var dom = this.dom;
|
var dom = this.dom
|
||||||
|
|
||||||
// highlight the append nodes parent
|
// highlight the append nodes parent
|
||||||
var menu = dom.menu;
|
var menu = dom.menu
|
||||||
if (target == menu) {
|
if (target === menu) {
|
||||||
if (type == 'mouseover') {
|
if (type === 'mouseover') {
|
||||||
this.editor.highlighter.highlight(this.parent);
|
this.editor.highlighter.highlight(this.parent)
|
||||||
}
|
} else if (type === 'mouseout') {
|
||||||
else if (type == 'mouseout') {
|
this.editor.highlighter.unhighlight()
|
||||||
this.editor.highlighter.unhighlight();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// context menu events
|
// context menu events
|
||||||
if (type == 'click' && target == dom.menu) {
|
if (type === 'click' && target === dom.menu) {
|
||||||
var highlighter = this.editor.highlighter;
|
var highlighter = this.editor.highlighter
|
||||||
highlighter.highlight(this.parent);
|
highlighter.highlight(this.parent)
|
||||||
highlighter.lock();
|
highlighter.lock()
|
||||||
util.addClassName(dom.menu, 'jsoneditor-selected');
|
util.addClassName(dom.menu, 'jsoneditor-selected')
|
||||||
this.showContextMenu(dom.menu, function () {
|
this.showContextMenu(dom.menu, function () {
|
||||||
util.removeClassName(dom.menu, 'jsoneditor-selected');
|
util.removeClassName(dom.menu, 'jsoneditor-selected')
|
||||||
highlighter.unlock();
|
highlighter.unlock()
|
||||||
highlighter.unhighlight();
|
highlighter.unhighlight()
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (type == 'keydown') {
|
if (type === 'keydown') {
|
||||||
this.onKeyDown(event);
|
this.onKeyDown(event)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
return AppendNode;
|
return AppendNode
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = appendNodeFactory;
|
module.exports = appendNodeFactory
|
||||||
|
|
|
@ -1,396 +1,384 @@
|
||||||
'use strict';
|
'use strict'
|
||||||
|
|
||||||
var defaultFilterFunction = {
|
var defaultFilterFunction = {
|
||||||
start: function (token, match, config) {
|
start: function (token, match, config) {
|
||||||
return match.indexOf(token) === 0;
|
return match.indexOf(token) === 0
|
||||||
},
|
},
|
||||||
contain: function (token, match, config) {
|
contain: function (token, match, config) {
|
||||||
return match.indexOf(token) > -1;
|
return match.indexOf(token) > -1
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
function completely(config) {
|
|
||||||
config = config || {};
|
|
||||||
config.filter = config.filter || 'start';
|
|
||||||
config.trigger = config.trigger || 'keydown';
|
|
||||||
config.confirmKeys = config.confirmKeys || [39, 35, 9] // right, end, tab
|
|
||||||
config.caseSensitive = config.caseSensitive || false // autocomplete case sensitive
|
|
||||||
|
|
||||||
var fontSize = '';
|
|
||||||
var fontFamily = '';
|
|
||||||
|
|
||||||
var wrapper = document.createElement('div');
|
|
||||||
wrapper.style.position = 'relative';
|
|
||||||
wrapper.style.outline = '0';
|
|
||||||
wrapper.style.border = '0';
|
|
||||||
wrapper.style.margin = '0';
|
|
||||||
wrapper.style.padding = '0';
|
|
||||||
|
|
||||||
var dropDown = document.createElement('div');
|
|
||||||
dropDown.className = 'autocomplete dropdown';
|
|
||||||
dropDown.style.position = 'absolute';
|
|
||||||
dropDown.style.visibility = 'hidden';
|
|
||||||
|
|
||||||
var spacer;
|
|
||||||
var leftSide; // <-- it will contain the leftSide part of the textfield (the bit that was already autocompleted)
|
|
||||||
var createDropDownController = function (elem, rs) {
|
|
||||||
var rows = [];
|
|
||||||
var ix = 0;
|
|
||||||
var oldIndex = -1;
|
|
||||||
|
|
||||||
var onMouseOver = function () { this.style.outline = '1px solid #ddd'; }
|
|
||||||
var onMouseOut = function () { this.style.outline = '0'; }
|
|
||||||
var onMouseDown = function () { p.hide(); p.onmouseselection(this.__hint, p.rs); }
|
|
||||||
|
|
||||||
var p = {
|
|
||||||
rs: rs,
|
|
||||||
hide: function () {
|
|
||||||
elem.style.visibility = 'hidden';
|
|
||||||
//rs.hideDropDown();
|
|
||||||
},
|
|
||||||
refresh: function (token, array) {
|
|
||||||
elem.style.visibility = 'hidden';
|
|
||||||
ix = 0;
|
|
||||||
elem.innerHTML = '';
|
|
||||||
var vph = (window.innerHeight || document.documentElement.clientHeight);
|
|
||||||
var rect = elem.parentNode.getBoundingClientRect();
|
|
||||||
var distanceToTop = rect.top - 6; // heuristic give 6px
|
|
||||||
var distanceToBottom = vph - rect.bottom - 6; // distance from the browser border.
|
|
||||||
|
|
||||||
rows = [];
|
|
||||||
var filterFn = typeof config.filter === 'function' ? config.filter : defaultFilterFunction[config.filter];
|
|
||||||
|
|
||||||
var filtered = !filterFn ? [] : array.filter(function (match) {
|
|
||||||
return filterFn(config.caseSensitive ? token : token.toLowerCase(), config.caseSensitive ? match : match.toLowerCase(), config);
|
|
||||||
});
|
|
||||||
|
|
||||||
rows = filtered.map(function (row) {
|
|
||||||
var divRow = document.createElement('div');
|
|
||||||
divRow.className = 'item';
|
|
||||||
//divRow.style.color = config.color;
|
|
||||||
divRow.onmouseover = onMouseOver;
|
|
||||||
divRow.onmouseout = onMouseOut;
|
|
||||||
divRow.onmousedown = onMouseDown;
|
|
||||||
divRow.__hint = row;
|
|
||||||
divRow.innerHTML = row.substring(0, token.length) + '<b>' + row.substring(token.length) + '</b>';
|
|
||||||
elem.appendChild(divRow);
|
|
||||||
return divRow;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (rows.length === 0) {
|
|
||||||
return; // nothing to show.
|
|
||||||
}
|
|
||||||
if (rows.length === 1 && ( (token.toLowerCase() === rows[0].__hint.toLowerCase() && !config.caseSensitive)
|
|
||||||
||(token === rows[0].__hint && config.caseSensitive))){
|
|
||||||
return; // do not show the dropDown if it has only one element which matches what we have just displayed.
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rows.length < 2) return;
|
|
||||||
p.highlight(0);
|
|
||||||
|
|
||||||
if (distanceToTop > distanceToBottom * 3) { // Heuristic (only when the distance to the to top is 4 times more than distance to the bottom
|
|
||||||
elem.style.maxHeight = distanceToTop + 'px'; // we display the dropDown on the top of the input text
|
|
||||||
elem.style.top = '';
|
|
||||||
elem.style.bottom = '100%';
|
|
||||||
} else {
|
|
||||||
elem.style.top = '100%';
|
|
||||||
elem.style.bottom = '';
|
|
||||||
elem.style.maxHeight = distanceToBottom + 'px';
|
|
||||||
}
|
|
||||||
elem.style.visibility = 'visible';
|
|
||||||
},
|
|
||||||
highlight: function (index) {
|
|
||||||
if (oldIndex != -1 && rows[oldIndex]) {
|
|
||||||
rows[oldIndex].className = "item";
|
|
||||||
}
|
|
||||||
rows[index].className = "item hover";
|
|
||||||
oldIndex = index;
|
|
||||||
},
|
|
||||||
move: function (step) { // moves the selection either up or down (unless it's not possible) step is either +1 or -1.
|
|
||||||
if (elem.style.visibility === 'hidden') return ''; // nothing to move if there is no dropDown. (this happens if the user hits escape and then down or up)
|
|
||||||
if (ix + step === -1 || ix + step === rows.length) return rows[ix].__hint; // NO CIRCULAR SCROLLING.
|
|
||||||
ix += step;
|
|
||||||
p.highlight(ix);
|
|
||||||
return rows[ix].__hint;//txtShadow.value = uRows[uIndex].__hint ;
|
|
||||||
},
|
|
||||||
onmouseselection: function () { } // it will be overwritten.
|
|
||||||
};
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
function setEndOfContenteditable(contentEditableElement) {
|
|
||||||
var range, selection;
|
|
||||||
if (document.createRange)//Firefox, Chrome, Opera, Safari, IE 9+
|
|
||||||
{
|
|
||||||
range = document.createRange();//Create a range (a range is a like the selection but invisible)
|
|
||||||
range.selectNodeContents(contentEditableElement);//Select the entire contents of the element with the range
|
|
||||||
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
|
|
||||||
selection = window.getSelection();//get the selection object (allows you to change selection)
|
|
||||||
selection.removeAllRanges();//remove any selections already made
|
|
||||||
selection.addRange(range);//make the range you have just created the visible selection
|
|
||||||
}
|
|
||||||
else if (document.selection)//IE 8 and lower
|
|
||||||
{
|
|
||||||
range = document.body.createTextRange();//Create a range (a range is a like the selection but invisible)
|
|
||||||
range.moveToElementText(contentEditableElement);//Select the entire contents of the element with the range
|
|
||||||
range.collapse(false);//collapse the range to the end point. false means collapse to end rather than the start
|
|
||||||
range.select();//Select the range (make it the visible selection
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function calculateWidthForText(text) {
|
|
||||||
if (spacer === undefined) { // on first call only.
|
|
||||||
spacer = document.createElement('span');
|
|
||||||
spacer.style.visibility = 'hidden';
|
|
||||||
spacer.style.position = 'fixed';
|
|
||||||
spacer.style.outline = '0';
|
|
||||||
spacer.style.margin = '0';
|
|
||||||
spacer.style.padding = '0';
|
|
||||||
spacer.style.border = '0';
|
|
||||||
spacer.style.left = '0';
|
|
||||||
spacer.style.whiteSpace = 'pre';
|
|
||||||
spacer.style.fontSize = fontSize;
|
|
||||||
spacer.style.fontFamily = fontFamily;
|
|
||||||
spacer.style.fontWeight = 'normal';
|
|
||||||
document.body.appendChild(spacer);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Used to encode an HTML string into a plain text.
|
|
||||||
// taken from http://stackoverflow.com/questions/1219860/javascript-jquery-html-encoding
|
|
||||||
spacer.innerHTML = String(text).replace(/&/g, '&')
|
|
||||||
.replace(/"/g, '"')
|
|
||||||
.replace(/'/g, ''')
|
|
||||||
.replace(/</g, '<')
|
|
||||||
.replace(/>/g, '>');
|
|
||||||
return spacer.getBoundingClientRect().right;
|
|
||||||
}
|
|
||||||
|
|
||||||
var rs = {
|
|
||||||
onArrowDown: function () { }, // defaults to no action.
|
|
||||||
onArrowUp: function () { }, // defaults to no action.
|
|
||||||
onEnter: function () { }, // defaults to no action.
|
|
||||||
onTab: function () { }, // defaults to no action.
|
|
||||||
startFrom: 0,
|
|
||||||
options: [],
|
|
||||||
element: null,
|
|
||||||
elementHint: null,
|
|
||||||
elementStyle: null,
|
|
||||||
wrapper: wrapper, // Only to allow easy access to the HTML elements to the final user (possibly for minor customizations)
|
|
||||||
show: function (element, startPos, options) {
|
|
||||||
this.startFrom = startPos;
|
|
||||||
this.wrapper.remove();
|
|
||||||
if (this.elementHint) {
|
|
||||||
this.elementHint.remove();
|
|
||||||
this.elementHint = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fontSize == '') {
|
|
||||||
fontSize = window.getComputedStyle(element).getPropertyValue('font-size');
|
|
||||||
}
|
|
||||||
if (fontFamily == '') {
|
|
||||||
fontFamily = window.getComputedStyle(element).getPropertyValue('font-family');
|
|
||||||
}
|
|
||||||
|
|
||||||
var w = element.getBoundingClientRect().right - element.getBoundingClientRect().left;
|
|
||||||
dropDown.style.marginLeft = '0';
|
|
||||||
dropDown.style.marginTop = element.getBoundingClientRect().height + 'px';
|
|
||||||
this.options = options;
|
|
||||||
|
|
||||||
if (this.element != element) {
|
|
||||||
this.element = element;
|
|
||||||
this.elementStyle = {
|
|
||||||
zIndex: this.element.style.zIndex,
|
|
||||||
position: this.element.style.position,
|
|
||||||
backgroundColor: this.element.style.backgroundColor,
|
|
||||||
borderColor: this.element.style.borderColor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
this.element.style.zIndex = 3;
|
|
||||||
this.element.style.position = 'relative';
|
|
||||||
this.element.style.backgroundColor = 'transparent';
|
|
||||||
this.element.style.borderColor = 'transparent';
|
|
||||||
|
|
||||||
this.elementHint = element.cloneNode();
|
|
||||||
this.elementHint.className = 'autocomplete hint';
|
|
||||||
this.elementHint.style.zIndex = 2;
|
|
||||||
this.elementHint.style.position = 'absolute';
|
|
||||||
this.elementHint.onfocus = function () { this.element.focus(); }.bind(this);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (this.element.addEventListener) {
|
|
||||||
this.element.removeEventListener("keydown", keyDownHandler);
|
|
||||||
this.element.addEventListener("keydown", keyDownHandler, false);
|
|
||||||
this.element.removeEventListener("blur", onBlurHandler);
|
|
||||||
this.element.addEventListener("blur", onBlurHandler, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
wrapper.appendChild(this.elementHint);
|
|
||||||
wrapper.appendChild(dropDown);
|
|
||||||
element.parentElement.appendChild(wrapper);
|
|
||||||
|
|
||||||
|
|
||||||
this.repaint(element);
|
|
||||||
},
|
|
||||||
setText: function (text) {
|
|
||||||
this.element.innerText = text;
|
|
||||||
},
|
|
||||||
getText: function () {
|
|
||||||
return this.element.innerText;
|
|
||||||
},
|
|
||||||
hideDropDown: function () {
|
|
||||||
this.wrapper.remove();
|
|
||||||
if (this.elementHint) {
|
|
||||||
this.elementHint.remove();
|
|
||||||
this.elementHint = null;
|
|
||||||
dropDownController.hide();
|
|
||||||
this.element.style.zIndex = this.elementStyle.zIndex;
|
|
||||||
this.element.style.position = this.elementStyle.position;
|
|
||||||
this.element.style.backgroundColor = this.elementStyle.backgroundColor;
|
|
||||||
this.element.style.borderColor = this.elementStyle.borderColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
},
|
|
||||||
repaint: function (element) {
|
|
||||||
var text = element.innerText;
|
|
||||||
text = text.replace('\n', '');
|
|
||||||
|
|
||||||
var startFrom = this.startFrom;
|
|
||||||
var options = this.options;
|
|
||||||
var optionsLength = this.options.length;
|
|
||||||
|
|
||||||
// breaking text in leftSide and token.
|
|
||||||
|
|
||||||
var token = text.substring(this.startFrom);
|
|
||||||
leftSide = text.substring(0, this.startFrom);
|
|
||||||
|
|
||||||
for (var i = 0; i < optionsLength; i++) {
|
|
||||||
var opt = this.options[i];
|
|
||||||
if ( (!config.caseSensitive && opt.toLowerCase().indexOf(token.toLowerCase()) === 0)
|
|
||||||
|| (config.caseSensitive && opt.indexOf(token) === 0)) { // <-- how about upperCase vs. lowercase
|
|
||||||
this.elementHint.innerText = leftSide + token + opt.substring(token.length);
|
|
||||||
this.elementHint.realInnerText = leftSide + opt;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// moving the dropDown and refreshing it.
|
|
||||||
dropDown.style.left = calculateWidthForText(leftSide) + 'px';
|
|
||||||
dropDownController.refresh(token, this.options);
|
|
||||||
this.elementHint.style.width = calculateWidthForText(this.elementHint.innerText) + 10 + 'px'
|
|
||||||
var wasDropDownHidden = (dropDown.style.visibility == 'hidden');
|
|
||||||
if (!wasDropDownHidden)
|
|
||||||
this.elementHint.style.width = calculateWidthForText(this.elementHint.innerText) + dropDown.clientWidth + 'px';
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
var dropDownController = createDropDownController(dropDown, rs);
|
|
||||||
|
|
||||||
var keyDownHandler = function (e) {
|
|
||||||
//console.log("Keydown:" + e.keyCode);
|
|
||||||
e = e || window.event;
|
|
||||||
var keyCode = e.keyCode;
|
|
||||||
|
|
||||||
if (this.elementHint == null) return;
|
|
||||||
|
|
||||||
if (keyCode == 33) { return; } // page up (do nothing)
|
|
||||||
if (keyCode == 34) { return; } // page down (do nothing);
|
|
||||||
|
|
||||||
if (keyCode == 27) { //escape
|
|
||||||
rs.hideDropDown();
|
|
||||||
rs.element.focus();
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var text = this.element.innerText;
|
|
||||||
text = text.replace('\n', '');
|
|
||||||
var startFrom = this.startFrom;
|
|
||||||
|
|
||||||
if (config.confirmKeys.indexOf(keyCode) >= 0) { // (autocomplete triggered)
|
|
||||||
if (keyCode == 9) {
|
|
||||||
if (this.elementHint.innerText.length == 0) {
|
|
||||||
rs.onTab();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (this.elementHint.innerText.length > 0) { // if there is a hint
|
|
||||||
if (this.element.innerText != this.elementHint.realInnerText) {
|
|
||||||
this.element.innerText = this.elementHint.realInnerText;
|
|
||||||
rs.hideDropDown();
|
|
||||||
setEndOfContenteditable(this.element);
|
|
||||||
if (keyCode == 9) {
|
|
||||||
rs.element.focus();
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyCode == 13) { // enter (autocomplete triggered)
|
|
||||||
if (this.elementHint.innerText.length == 0) { // if there is a hint
|
|
||||||
rs.onEnter();
|
|
||||||
} else {
|
|
||||||
var wasDropDownHidden = (dropDown.style.visibility == 'hidden');
|
|
||||||
dropDownController.hide();
|
|
||||||
|
|
||||||
if (wasDropDownHidden) {
|
|
||||||
rs.hideDropDown();
|
|
||||||
rs.element.focus();
|
|
||||||
rs.onEnter();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.element.innerText = this.elementHint.realInnerText;
|
|
||||||
rs.hideDropDown();
|
|
||||||
setEndOfContenteditable(this.element);
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyCode == 40) { // down
|
|
||||||
var token = text.substring(this.startFrom);
|
|
||||||
var m = dropDownController.move(+1);
|
|
||||||
if (m == '') { rs.onArrowDown(); }
|
|
||||||
this.elementHint.innerText = leftSide + token + m.substring(token.length);
|
|
||||||
this.elementHint.realInnerText = leftSide + m;
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (keyCode == 38) { // up
|
|
||||||
var token = text.substring(this.startFrom);
|
|
||||||
var m = dropDownController.move(-1);
|
|
||||||
if (m == '') { rs.onArrowUp(); }
|
|
||||||
this.elementHint.innerText = leftSide + token + m.substring(token.length);
|
|
||||||
this.elementHint.realInnerText = leftSide + m;
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
}.bind(rs);
|
|
||||||
|
|
||||||
var onBlurHandler = function (e) {
|
|
||||||
rs.hideDropDown();
|
|
||||||
//console.log("Lost focus.");
|
|
||||||
}.bind(rs);
|
|
||||||
|
|
||||||
dropDownController.onmouseselection = function (text, rs) {
|
|
||||||
rs.element.innerText = rs.elementHint.innerText = leftSide + text;
|
|
||||||
rs.hideDropDown();
|
|
||||||
window.setTimeout(function () {
|
|
||||||
rs.element.focus();
|
|
||||||
setEndOfContenteditable(rs.element);
|
|
||||||
}, 1);
|
|
||||||
};
|
|
||||||
|
|
||||||
return rs;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = completely;
|
function completely (config) {
|
||||||
|
config = config || {}
|
||||||
|
config.filter = config.filter || 'start'
|
||||||
|
config.trigger = config.trigger || 'keydown'
|
||||||
|
config.confirmKeys = config.confirmKeys || [39, 35, 9] // right, end, tab
|
||||||
|
config.caseSensitive = config.caseSensitive || false // autocomplete case sensitive
|
||||||
|
|
||||||
|
var fontSize = ''
|
||||||
|
var fontFamily = ''
|
||||||
|
|
||||||
|
var wrapper = document.createElement('div')
|
||||||
|
wrapper.style.position = 'relative'
|
||||||
|
wrapper.style.outline = '0'
|
||||||
|
wrapper.style.border = '0'
|
||||||
|
wrapper.style.margin = '0'
|
||||||
|
wrapper.style.padding = '0'
|
||||||
|
|
||||||
|
var dropDown = document.createElement('div')
|
||||||
|
dropDown.className = 'autocomplete dropdown'
|
||||||
|
dropDown.style.position = 'absolute'
|
||||||
|
dropDown.style.visibility = 'hidden'
|
||||||
|
|
||||||
|
var spacer
|
||||||
|
var leftSide // <-- it will contain the leftSide part of the textfield (the bit that was already autocompleted)
|
||||||
|
var createDropDownController = function (elem, rs) {
|
||||||
|
var rows = []
|
||||||
|
var ix = 0
|
||||||
|
var oldIndex = -1
|
||||||
|
|
||||||
|
var onMouseOver = function () { this.style.outline = '1px solid #ddd' }
|
||||||
|
var onMouseOut = function () { this.style.outline = '0' }
|
||||||
|
var onMouseDown = function () { p.hide(); p.onmouseselection(this.__hint, p.rs) }
|
||||||
|
|
||||||
|
var p = {
|
||||||
|
rs: rs,
|
||||||
|
hide: function () {
|
||||||
|
elem.style.visibility = 'hidden'
|
||||||
|
// rs.hideDropDown();
|
||||||
|
},
|
||||||
|
refresh: function (token, array) {
|
||||||
|
elem.style.visibility = 'hidden'
|
||||||
|
ix = 0
|
||||||
|
elem.innerHTML = ''
|
||||||
|
var vph = (window.innerHeight || document.documentElement.clientHeight)
|
||||||
|
var rect = elem.parentNode.getBoundingClientRect()
|
||||||
|
var distanceToTop = rect.top - 6 // heuristic give 6px
|
||||||
|
var distanceToBottom = vph - rect.bottom - 6 // distance from the browser border.
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
var filterFn = typeof config.filter === 'function' ? config.filter : defaultFilterFunction[config.filter]
|
||||||
|
|
||||||
|
var filtered = !filterFn ? [] : array.filter(function (match) {
|
||||||
|
return filterFn(config.caseSensitive ? token : token.toLowerCase(), config.caseSensitive ? match : match.toLowerCase(), config)
|
||||||
|
})
|
||||||
|
|
||||||
|
rows = filtered.map(function (row) {
|
||||||
|
var divRow = document.createElement('div')
|
||||||
|
divRow.className = 'item'
|
||||||
|
// divRow.style.color = config.color;
|
||||||
|
divRow.onmouseover = onMouseOver
|
||||||
|
divRow.onmouseout = onMouseOut
|
||||||
|
divRow.onmousedown = onMouseDown
|
||||||
|
divRow.__hint = row
|
||||||
|
divRow.innerHTML = row.substring(0, token.length) + '<b>' + row.substring(token.length) + '</b>'
|
||||||
|
elem.appendChild(divRow)
|
||||||
|
return divRow
|
||||||
|
})
|
||||||
|
|
||||||
|
if (rows.length === 0) {
|
||||||
|
return // nothing to show.
|
||||||
|
}
|
||||||
|
if (rows.length === 1 && ((token.toLowerCase() === rows[0].__hint.toLowerCase() && !config.caseSensitive) ||
|
||||||
|
(token === rows[0].__hint && config.caseSensitive))) {
|
||||||
|
return // do not show the dropDown if it has only one element which matches what we have just displayed.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rows.length < 2) return
|
||||||
|
p.highlight(0)
|
||||||
|
|
||||||
|
if (distanceToTop > distanceToBottom * 3) { // Heuristic (only when the distance to the to top is 4 times more than distance to the bottom
|
||||||
|
elem.style.maxHeight = distanceToTop + 'px' // we display the dropDown on the top of the input text
|
||||||
|
elem.style.top = ''
|
||||||
|
elem.style.bottom = '100%'
|
||||||
|
} else {
|
||||||
|
elem.style.top = '100%'
|
||||||
|
elem.style.bottom = ''
|
||||||
|
elem.style.maxHeight = distanceToBottom + 'px'
|
||||||
|
}
|
||||||
|
elem.style.visibility = 'visible'
|
||||||
|
},
|
||||||
|
highlight: function (index) {
|
||||||
|
if (oldIndex !== -1 && rows[oldIndex]) {
|
||||||
|
rows[oldIndex].className = 'item'
|
||||||
|
}
|
||||||
|
rows[index].className = 'item hover'
|
||||||
|
oldIndex = index
|
||||||
|
},
|
||||||
|
move: function (step) { // moves the selection either up or down (unless it's not possible) step is either +1 or -1.
|
||||||
|
if (elem.style.visibility === 'hidden') return '' // nothing to move if there is no dropDown. (this happens if the user hits escape and then down or up)
|
||||||
|
if (ix + step === -1 || ix + step === rows.length) return rows[ix].__hint // NO CIRCULAR SCROLLING.
|
||||||
|
ix += step
|
||||||
|
p.highlight(ix)
|
||||||
|
return rows[ix].__hint// txtShadow.value = uRows[uIndex].__hint ;
|
||||||
|
},
|
||||||
|
onmouseselection: function () { } // it will be overwritten.
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
function setEndOfContenteditable (contentEditableElement) {
|
||||||
|
var range, selection
|
||||||
|
if (document.createRange) {
|
||||||
|
// Firefox, Chrome, Opera, Safari, IE 9+
|
||||||
|
range = document.createRange()// Create a range (a range is a like the selection but invisible)
|
||||||
|
range.selectNodeContents(contentEditableElement)// Select the entire contents of the element with the range
|
||||||
|
range.collapse(false)// collapse the range to the end point. false means collapse to end rather than the start
|
||||||
|
selection = window.getSelection()// get the selection object (allows you to change selection)
|
||||||
|
selection.removeAllRanges()// remove any selections already made
|
||||||
|
selection.addRange(range)// make the range you have just created the visible selection
|
||||||
|
} else if (document.selection) {
|
||||||
|
// IE 8 and lower
|
||||||
|
range = document.body.createTextRange()// Create a range (a range is a like the selection but invisible)
|
||||||
|
range.moveToElementText(contentEditableElement)// Select the entire contents of the element with the range
|
||||||
|
range.collapse(false)// collapse the range to the end point. false means collapse to end rather than the start
|
||||||
|
range.select()// Select the range (make it the visible selection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function calculateWidthForText (text) {
|
||||||
|
if (spacer === undefined) { // on first call only.
|
||||||
|
spacer = document.createElement('span')
|
||||||
|
spacer.style.visibility = 'hidden'
|
||||||
|
spacer.style.position = 'fixed'
|
||||||
|
spacer.style.outline = '0'
|
||||||
|
spacer.style.margin = '0'
|
||||||
|
spacer.style.padding = '0'
|
||||||
|
spacer.style.border = '0'
|
||||||
|
spacer.style.left = '0'
|
||||||
|
spacer.style.whiteSpace = 'pre'
|
||||||
|
spacer.style.fontSize = fontSize
|
||||||
|
spacer.style.fontFamily = fontFamily
|
||||||
|
spacer.style.fontWeight = 'normal'
|
||||||
|
document.body.appendChild(spacer)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Used to encode an HTML string into a plain text.
|
||||||
|
// taken from http://stackoverflow.com/questions/1219860/javascript-jquery-html-encoding
|
||||||
|
spacer.innerHTML = String(text).replace(/&/g, '&')
|
||||||
|
.replace(/"/g, '"')
|
||||||
|
.replace(/'/g, ''')
|
||||||
|
.replace(/</g, '<')
|
||||||
|
.replace(/>/g, '>')
|
||||||
|
return spacer.getBoundingClientRect().right
|
||||||
|
}
|
||||||
|
|
||||||
|
var rs = {
|
||||||
|
onArrowDown: function () { }, // defaults to no action.
|
||||||
|
onArrowUp: function () { }, // defaults to no action.
|
||||||
|
onEnter: function () { }, // defaults to no action.
|
||||||
|
onTab: function () { }, // defaults to no action.
|
||||||
|
startFrom: 0,
|
||||||
|
options: [],
|
||||||
|
element: null,
|
||||||
|
elementHint: null,
|
||||||
|
elementStyle: null,
|
||||||
|
wrapper: wrapper, // Only to allow easy access to the HTML elements to the final user (possibly for minor customizations)
|
||||||
|
show: function (element, startPos, options) {
|
||||||
|
this.startFrom = startPos
|
||||||
|
this.wrapper.remove()
|
||||||
|
if (this.elementHint) {
|
||||||
|
this.elementHint.remove()
|
||||||
|
this.elementHint = null
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fontSize === '') {
|
||||||
|
fontSize = window.getComputedStyle(element).getPropertyValue('font-size')
|
||||||
|
}
|
||||||
|
if (fontFamily === '') {
|
||||||
|
fontFamily = window.getComputedStyle(element).getPropertyValue('font-family')
|
||||||
|
}
|
||||||
|
|
||||||
|
dropDown.style.marginLeft = '0'
|
||||||
|
dropDown.style.marginTop = element.getBoundingClientRect().height + 'px'
|
||||||
|
this.options = options
|
||||||
|
|
||||||
|
if (this.element !== element) {
|
||||||
|
this.element = element
|
||||||
|
this.elementStyle = {
|
||||||
|
zIndex: this.element.style.zIndex,
|
||||||
|
position: this.element.style.position,
|
||||||
|
backgroundColor: this.element.style.backgroundColor,
|
||||||
|
borderColor: this.element.style.borderColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.element.style.zIndex = 3
|
||||||
|
this.element.style.position = 'relative'
|
||||||
|
this.element.style.backgroundColor = 'transparent'
|
||||||
|
this.element.style.borderColor = 'transparent'
|
||||||
|
|
||||||
|
this.elementHint = element.cloneNode()
|
||||||
|
this.elementHint.className = 'autocomplete hint'
|
||||||
|
this.elementHint.style.zIndex = 2
|
||||||
|
this.elementHint.style.position = 'absolute'
|
||||||
|
this.elementHint.onfocus = function () { this.element.focus() }.bind(this)
|
||||||
|
|
||||||
|
if (this.element.addEventListener) {
|
||||||
|
this.element.removeEventListener('keydown', keyDownHandler)
|
||||||
|
this.element.addEventListener('keydown', keyDownHandler, false)
|
||||||
|
this.element.removeEventListener('blur', onBlurHandler)
|
||||||
|
this.element.addEventListener('blur', onBlurHandler, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
wrapper.appendChild(this.elementHint)
|
||||||
|
wrapper.appendChild(dropDown)
|
||||||
|
element.parentElement.appendChild(wrapper)
|
||||||
|
|
||||||
|
this.repaint(element)
|
||||||
|
},
|
||||||
|
setText: function (text) {
|
||||||
|
this.element.innerText = text
|
||||||
|
},
|
||||||
|
getText: function () {
|
||||||
|
return this.element.innerText
|
||||||
|
},
|
||||||
|
hideDropDown: function () {
|
||||||
|
this.wrapper.remove()
|
||||||
|
if (this.elementHint) {
|
||||||
|
this.elementHint.remove()
|
||||||
|
this.elementHint = null
|
||||||
|
dropDownController.hide()
|
||||||
|
this.element.style.zIndex = this.elementStyle.zIndex
|
||||||
|
this.element.style.position = this.elementStyle.position
|
||||||
|
this.element.style.backgroundColor = this.elementStyle.backgroundColor
|
||||||
|
this.element.style.borderColor = this.elementStyle.borderColor
|
||||||
|
}
|
||||||
|
},
|
||||||
|
repaint: function (element) {
|
||||||
|
var text = element.innerText
|
||||||
|
text = text.replace('\n', '')
|
||||||
|
|
||||||
|
var optionsLength = this.options.length
|
||||||
|
|
||||||
|
// breaking text in leftSide and token.
|
||||||
|
|
||||||
|
var token = text.substring(this.startFrom)
|
||||||
|
leftSide = text.substring(0, this.startFrom)
|
||||||
|
|
||||||
|
for (var i = 0; i < optionsLength; i++) {
|
||||||
|
var opt = this.options[i]
|
||||||
|
if ((!config.caseSensitive && opt.toLowerCase().indexOf(token.toLowerCase()) === 0) ||
|
||||||
|
(config.caseSensitive && opt.indexOf(token) === 0)) { // <-- how about upperCase vs. lowercase
|
||||||
|
this.elementHint.innerText = leftSide + token + opt.substring(token.length)
|
||||||
|
this.elementHint.realInnerText = leftSide + opt
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// moving the dropDown and refreshing it.
|
||||||
|
dropDown.style.left = calculateWidthForText(leftSide) + 'px'
|
||||||
|
dropDownController.refresh(token, this.options)
|
||||||
|
this.elementHint.style.width = calculateWidthForText(this.elementHint.innerText) + 10 + 'px'
|
||||||
|
var wasDropDownHidden = (dropDown.style.visibility === 'hidden')
|
||||||
|
if (!wasDropDownHidden) { this.elementHint.style.width = calculateWidthForText(this.elementHint.innerText) + dropDown.clientWidth + 'px' }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var dropDownController = createDropDownController(dropDown, rs)
|
||||||
|
|
||||||
|
var keyDownHandler = function (e) {
|
||||||
|
// console.log("Keydown:" + e.keyCode);
|
||||||
|
e = e || window.event
|
||||||
|
var keyCode = e.keyCode
|
||||||
|
|
||||||
|
if (this.elementHint == null) return
|
||||||
|
|
||||||
|
if (keyCode === 33) { return } // page up (do nothing)
|
||||||
|
if (keyCode === 34) { return } // page down (do nothing);
|
||||||
|
|
||||||
|
if (keyCode === 27) { // escape
|
||||||
|
rs.hideDropDown()
|
||||||
|
rs.element.focus()
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var text = this.element.innerText
|
||||||
|
text = text.replace('\n', '')
|
||||||
|
|
||||||
|
if (config.confirmKeys.indexOf(keyCode) >= 0) { // (autocomplete triggered)
|
||||||
|
if (keyCode === 9) {
|
||||||
|
if (this.elementHint.innerText.length === 0) {
|
||||||
|
rs.onTab()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.elementHint.innerText.length > 0) { // if there is a hint
|
||||||
|
if (this.element.innerText !== this.elementHint.realInnerText) {
|
||||||
|
this.element.innerText = this.elementHint.realInnerText
|
||||||
|
rs.hideDropDown()
|
||||||
|
setEndOfContenteditable(this.element)
|
||||||
|
if (keyCode === 9) {
|
||||||
|
rs.element.focus()
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyCode === 13) { // enter (autocomplete triggered)
|
||||||
|
if (this.elementHint.innerText.length === 0) { // if there is a hint
|
||||||
|
rs.onEnter()
|
||||||
|
} else {
|
||||||
|
var wasDropDownHidden = (dropDown.style.visibility === 'hidden')
|
||||||
|
dropDownController.hide()
|
||||||
|
|
||||||
|
if (wasDropDownHidden) {
|
||||||
|
rs.hideDropDown()
|
||||||
|
rs.element.focus()
|
||||||
|
rs.onEnter()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.element.innerText = this.elementHint.realInnerText
|
||||||
|
rs.hideDropDown()
|
||||||
|
setEndOfContenteditable(this.element)
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyCode === 40) { // down
|
||||||
|
const token = text.substring(this.startFrom)
|
||||||
|
const m = dropDownController.move(+1)
|
||||||
|
if (m === '') { rs.onArrowDown() }
|
||||||
|
this.elementHint.innerText = leftSide + token + m.substring(token.length)
|
||||||
|
this.elementHint.realInnerText = leftSide + m
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if (keyCode === 38) { // up
|
||||||
|
const token = text.substring(this.startFrom)
|
||||||
|
const m = dropDownController.move(-1)
|
||||||
|
if (m === '') { rs.onArrowUp() }
|
||||||
|
this.elementHint.innerText = leftSide + token + m.substring(token.length)
|
||||||
|
this.elementHint.realInnerText = leftSide + m
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
}
|
||||||
|
}.bind(rs)
|
||||||
|
|
||||||
|
var onBlurHandler = function (e) {
|
||||||
|
rs.hideDropDown()
|
||||||
|
// console.log("Lost focus.");
|
||||||
|
}
|
||||||
|
|
||||||
|
dropDownController.onmouseselection = function (text, rs) {
|
||||||
|
rs.element.innerText = rs.elementHint.innerText = leftSide + text
|
||||||
|
rs.hideDropDown()
|
||||||
|
window.setTimeout(function () {
|
||||||
|
rs.element.focus()
|
||||||
|
setEndOfContenteditable(rs.element)
|
||||||
|
}, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return rs
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = completely
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
|
|
||||||
exports.DEFAULT_MODAL_ANCHOR = document.body;
|
exports.DEFAULT_MODAL_ANCHOR = document.body
|
||||||
exports.SIZE_LARGE = 10 * 1024 * 1024; // 10 MB
|
exports.SIZE_LARGE = 10 * 1024 * 1024 // 10 MB
|
||||||
|
|
||||||
exports.MAX_PREVIEW_CHARACTERS = 20000;
|
exports.MAX_PREVIEW_CHARACTERS = 20000
|
||||||
|
|
||||||
exports.PREVIEW_HISTORY_LIMIT = 2 * 1024 * 1024 * 1024; // 2 GB
|
exports.PREVIEW_HISTORY_LIMIT = 2 * 1024 * 1024 * 1024 // 2 GB
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
var util = require('./util');
|
var util = require('./util')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an anchor element absolutely positioned in the `parent`
|
* Create an anchor element absolutely positioned in the `parent`
|
||||||
|
@ -9,58 +9,58 @@ var util = require('./util');
|
||||||
* @returns {HTMLElement}
|
* @returns {HTMLElement}
|
||||||
*/
|
*/
|
||||||
exports.createAbsoluteAnchor = function (anchor, parent, onDestroy) {
|
exports.createAbsoluteAnchor = function (anchor, parent, onDestroy) {
|
||||||
var root = getRootNode(anchor);
|
var root = getRootNode(anchor)
|
||||||
var eventListeners = {};
|
var eventListeners = {}
|
||||||
|
|
||||||
var anchorRect = anchor.getBoundingClientRect();
|
var anchorRect = anchor.getBoundingClientRect()
|
||||||
var frameRect = parent.getBoundingClientRect();
|
var frameRect = parent.getBoundingClientRect()
|
||||||
|
|
||||||
var absoluteAnchor = document.createElement('div');
|
var absoluteAnchor = document.createElement('div')
|
||||||
absoluteAnchor.className = 'jsoneditor-anchor';
|
absoluteAnchor.className = 'jsoneditor-anchor'
|
||||||
absoluteAnchor.style.position = 'absolute';
|
absoluteAnchor.style.position = 'absolute'
|
||||||
absoluteAnchor.style.left = (anchorRect.left - frameRect.left) + 'px';
|
absoluteAnchor.style.left = (anchorRect.left - frameRect.left) + 'px'
|
||||||
absoluteAnchor.style.top = (anchorRect.top - frameRect.top) + 'px';
|
absoluteAnchor.style.top = (anchorRect.top - frameRect.top) + 'px'
|
||||||
absoluteAnchor.style.width = (anchorRect.width - 2) + 'px';
|
absoluteAnchor.style.width = (anchorRect.width - 2) + 'px'
|
||||||
absoluteAnchor.style.height = (anchorRect.height - 2) + 'px';
|
absoluteAnchor.style.height = (anchorRect.height - 2) + 'px'
|
||||||
absoluteAnchor.style.boxSizing = 'border-box';
|
absoluteAnchor.style.boxSizing = 'border-box'
|
||||||
parent.appendChild(absoluteAnchor);
|
parent.appendChild(absoluteAnchor)
|
||||||
|
|
||||||
function destroy () {
|
function destroy () {
|
||||||
// remove temporary absolutely positioned anchor
|
// remove temporary absolutely positioned anchor
|
||||||
if (absoluteAnchor && absoluteAnchor.parentNode) {
|
if (absoluteAnchor && absoluteAnchor.parentNode) {
|
||||||
absoluteAnchor.parentNode.removeChild(absoluteAnchor);
|
absoluteAnchor.parentNode.removeChild(absoluteAnchor)
|
||||||
|
|
||||||
// remove all event listeners
|
// remove all event listeners
|
||||||
// all event listeners are supposed to be attached to document.
|
// all event listeners are supposed to be attached to document.
|
||||||
for (var name in eventListeners) {
|
for (var name in eventListeners) {
|
||||||
if (eventListeners.hasOwnProperty(name)) {
|
if (hasOwnProperty(eventListeners, name)) {
|
||||||
var fn = eventListeners[name];
|
var fn = eventListeners[name]
|
||||||
if (fn) {
|
if (fn) {
|
||||||
util.removeEventListener(root, name, fn);
|
util.removeEventListener(root, name, fn)
|
||||||
}
|
}
|
||||||
delete eventListeners[name];
|
delete eventListeners[name]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof onDestroy === 'function') {
|
if (typeof onDestroy === 'function') {
|
||||||
onDestroy(anchor);
|
onDestroy(anchor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// create and attach event listeners
|
// create and attach event listeners
|
||||||
var destroyIfOutside = function (event) {
|
var destroyIfOutside = function (event) {
|
||||||
var target = event.target;
|
var target = event.target
|
||||||
if ((target !== absoluteAnchor) && !util.isChildOf(target, absoluteAnchor)) {
|
if ((target !== absoluteAnchor) && !util.isChildOf(target, absoluteAnchor)) {
|
||||||
destroy();
|
destroy()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eventListeners.mousedown = util.addEventListener(root, 'mousedown', destroyIfOutside);
|
eventListeners.mousedown = util.addEventListener(root, 'mousedown', destroyIfOutside)
|
||||||
eventListeners.mousewheel = util.addEventListener(root, 'mousewheel', destroyIfOutside);
|
eventListeners.mousewheel = util.addEventListener(root, 'mousewheel', destroyIfOutside)
|
||||||
// eventListeners.scroll = util.addEventListener(root, 'scroll', destroyIfOutside);
|
// eventListeners.scroll = util.addEventListener(root, 'scroll', destroyIfOutside);
|
||||||
|
|
||||||
absoluteAnchor.destroy = destroy;
|
absoluteAnchor.destroy = destroy
|
||||||
|
|
||||||
return absoluteAnchor
|
return absoluteAnchor
|
||||||
}
|
}
|
||||||
|
@ -70,8 +70,12 @@ exports.createAbsoluteAnchor = function (anchor, parent, onDestroy) {
|
||||||
* @param {HTMLElement} node node to check
|
* @param {HTMLElement} node node to check
|
||||||
* @return {HTMLElement} node's rootNode or `window` if there is ShadowDOM is not supported.
|
* @return {HTMLElement} node's rootNode or `window` if there is ShadowDOM is not supported.
|
||||||
*/
|
*/
|
||||||
function getRootNode(node){
|
function getRootNode (node) {
|
||||||
return (typeof node.getRootNode === 'function')
|
return (typeof node.getRootNode === 'function')
|
||||||
? node.getRootNode()
|
? node.getRootNode()
|
||||||
: window;
|
: window
|
||||||
|
}
|
||||||
|
|
||||||
|
function hasOwnProperty (object, key) {
|
||||||
|
return Object.prototype.hasOwnProperty.call(object, key)
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,4 +26,4 @@
|
||||||
* @author Jos de Jong, <wjosdejong@gmail.com>
|
* @author Jos de Jong, <wjosdejong@gmail.com>
|
||||||
* @version @@version
|
* @version @@version
|
||||||
* @date @@date
|
* @date @@date
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
'use strict';
|
'use strict'
|
||||||
|
|
||||||
require('./polyfills');
|
/* eslint-disable no-template-curly-in-string */
|
||||||
|
|
||||||
var _locales = ['en', 'pt-BR', 'zh-CN', 'tr'];
|
require('./polyfills')
|
||||||
|
|
||||||
|
var _locales = ['en', 'pt-BR', 'zh-CN', 'tr']
|
||||||
var _defs = {
|
var _defs = {
|
||||||
en: {
|
en: {
|
||||||
array: 'Array',
|
array: 'Array',
|
||||||
|
@ -93,7 +95,7 @@ var _defs = {
|
||||||
modePreviewText: 'Preview',
|
modePreviewText: 'Preview',
|
||||||
modePreviewTitle: 'Switch to preview mode',
|
modePreviewTitle: 'Switch to preview mode',
|
||||||
examples: 'Examples',
|
examples: 'Examples',
|
||||||
default: 'Default',
|
default: 'Default'
|
||||||
},
|
},
|
||||||
'zh-CN': {
|
'zh-CN': {
|
||||||
array: '数组',
|
array: '数组',
|
||||||
|
@ -184,7 +186,7 @@ var _defs = {
|
||||||
modePreviewText: '预览',
|
modePreviewText: '预览',
|
||||||
modePreviewTitle: '切换至预览模式',
|
modePreviewTitle: '切换至预览模式',
|
||||||
examples: '例子',
|
examples: '例子',
|
||||||
default: '缺省',
|
default: '缺省'
|
||||||
},
|
},
|
||||||
'pt-BR': {
|
'pt-BR': {
|
||||||
array: 'Lista',
|
array: 'Lista',
|
||||||
|
@ -283,7 +285,7 @@ var _defs = {
|
||||||
'Campo do tipo nao é determinado através do seu valor, ' +
|
'Campo do tipo nao é determinado através do seu valor, ' +
|
||||||
'mas sempre retornara um texto.',
|
'mas sempre retornara um texto.',
|
||||||
examples: 'Exemplos',
|
examples: 'Exemplos',
|
||||||
default: 'Revelia',
|
default: 'Revelia'
|
||||||
},
|
},
|
||||||
tr: {
|
tr: {
|
||||||
array: 'Dizin',
|
array: 'Dizin',
|
||||||
|
@ -370,20 +372,20 @@ var _defs = {
|
||||||
modeViewText: 'Görünüm',
|
modeViewText: 'Görünüm',
|
||||||
modeViewTitle: 'Ağaç görünümüne geç',
|
modeViewTitle: 'Ağaç görünümüne geç',
|
||||||
examples: 'Örnekler',
|
examples: 'Örnekler',
|
||||||
default: 'Varsayılan',
|
default: 'Varsayılan'
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
var _defaultLang = 'en';
|
var _defaultLang = 'en'
|
||||||
var _lang;
|
var _lang
|
||||||
var userLang = typeof navigator !== 'undefined' ?
|
var userLang = typeof navigator !== 'undefined'
|
||||||
navigator.language || navigator.userLanguage :
|
? navigator.language || navigator.userLanguage
|
||||||
undefined;
|
: undefined
|
||||||
_lang = _locales.find(function (l) {
|
_lang = _locales.find(function (l) {
|
||||||
return l === userLang;
|
return l === userLang
|
||||||
});
|
})
|
||||||
if (!_lang) {
|
if (!_lang) {
|
||||||
_lang = _defaultLang;
|
_lang = _defaultLang
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
@ -393,41 +395,41 @@ module.exports = {
|
||||||
_lang: _lang,
|
_lang: _lang,
|
||||||
setLanguage: function (lang) {
|
setLanguage: function (lang) {
|
||||||
if (!lang) {
|
if (!lang) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
var langFound = _locales.find(function (l) {
|
var langFound = _locales.find(function (l) {
|
||||||
return l === lang;
|
return l === lang
|
||||||
});
|
})
|
||||||
if (langFound) {
|
if (langFound) {
|
||||||
_lang = langFound;
|
_lang = langFound
|
||||||
} else {
|
} else {
|
||||||
console.error('Language not found');
|
console.error('Language not found')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
setLanguages: function (languages) {
|
setLanguages: function (languages) {
|
||||||
if (!languages) {
|
if (!languages) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
for (var key in languages) {
|
for (var key in languages) {
|
||||||
var langFound = _locales.find(function (l) {
|
var langFound = _locales.find(function (l) {
|
||||||
return l === key;
|
return l === key
|
||||||
});
|
})
|
||||||
if (!langFound) {
|
if (!langFound) {
|
||||||
_locales.push(key);
|
_locales.push(key)
|
||||||
}
|
}
|
||||||
_defs[key] = Object.assign({}, _defs[_defaultLang], _defs[key], languages[key]);
|
_defs[key] = Object.assign({}, _defs[_defaultLang], _defs[key], languages[key])
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
translate: function (key, data, lang) {
|
translate: function (key, data, lang) {
|
||||||
if (!lang) {
|
if (!lang) {
|
||||||
lang = _lang;
|
lang = _lang
|
||||||
}
|
}
|
||||||
var text = _defs[lang][key];
|
var text = _defs[lang][key]
|
||||||
if (data) {
|
if (data) {
|
||||||
for (key in data) {
|
for (key in data) {
|
||||||
text = text.replace('${' + key + '}', data[key]);
|
text = text.replace('${' + key + '}', data[key])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return text || key;
|
return text || key
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
'use strict';
|
'use strict'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert part of a JSON object to a JSON string.
|
* Convert part of a JSON object to a JSON string.
|
||||||
|
@ -21,26 +21,24 @@
|
||||||
*
|
*
|
||||||
* @returns {string | undefined} Returns the string representation of the JSON object.
|
* @returns {string | undefined} Returns the string representation of the JSON object.
|
||||||
*/
|
*/
|
||||||
function stringifyPartial(value, space, limit) {
|
function stringifyPartial (value, space, limit) {
|
||||||
var _space; // undefined by default
|
var _space // undefined by default
|
||||||
if (typeof space === 'number') {
|
if (typeof space === 'number') {
|
||||||
if (space > 10) {
|
if (space > 10) {
|
||||||
_space = repeat(' ', 10);
|
_space = repeat(' ', 10)
|
||||||
}
|
} else if (space >= 1) {
|
||||||
else if (space >= 1) {
|
_space = repeat(' ', space)
|
||||||
_space = repeat(' ', space);
|
|
||||||
}
|
}
|
||||||
// else ignore
|
// else ignore
|
||||||
}
|
} else if (typeof space === 'string' && space !== '') {
|
||||||
else if (typeof space === 'string' && space !== '') {
|
_space = space
|
||||||
_space = space;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var output = stringifyValue(value, _space, '', limit);
|
var output = stringifyValue(value, _space, '', limit)
|
||||||
|
|
||||||
return output.length > limit
|
return output.length > limit
|
||||||
? (slice(output, limit) + '...')
|
? (slice(output, limit) + '...')
|
||||||
: output;
|
: output
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,27 +49,27 @@ function stringifyPartial(value, space, limit) {
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @return {string | undefined}
|
* @return {string | undefined}
|
||||||
*/
|
*/
|
||||||
function stringifyValue(value, space, indent, limit) {
|
function stringifyValue (value, space, indent, limit) {
|
||||||
// boolean, null, number, string, or date
|
// boolean, null, number, string, or date
|
||||||
if (typeof value === 'boolean' || value instanceof Boolean ||
|
if (typeof value === 'boolean' || value instanceof Boolean ||
|
||||||
value === null ||
|
value === null ||
|
||||||
typeof value === 'number' || value instanceof Number ||
|
typeof value === 'number' || value instanceof Number ||
|
||||||
typeof value === 'string' || value instanceof String ||
|
typeof value === 'string' || value instanceof String ||
|
||||||
value instanceof Date) {
|
value instanceof Date) {
|
||||||
return JSON.stringify(value);
|
return JSON.stringify(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// array
|
// array
|
||||||
if (Array.isArray(value)) {
|
if (Array.isArray(value)) {
|
||||||
return stringifyArray(value, space, indent, limit);
|
return stringifyArray(value, space, indent, limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
// object (test lastly!)
|
// object (test lastly!)
|
||||||
if (value && typeof value === 'object') {
|
if (value && typeof value === 'object') {
|
||||||
return stringifyObject(value, space, indent, limit);
|
return stringifyObject(value, space, indent, limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
return undefined;
|
return undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -82,36 +80,35 @@ function stringifyValue(value, space, indent, limit) {
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
function stringifyArray(array, space, indent, limit) {
|
function stringifyArray (array, space, indent, limit) {
|
||||||
var childIndent = space ? (indent + space) : undefined;
|
var childIndent = space ? (indent + space) : undefined
|
||||||
var str = space ? '[\n' : '[';
|
var str = space ? '[\n' : '['
|
||||||
|
|
||||||
for (var i = 0; i < array.length; i++) {
|
for (var i = 0; i < array.length; i++) {
|
||||||
var item = array[i];
|
var item = array[i]
|
||||||
|
|
||||||
if (space) {
|
if (space) {
|
||||||
str += childIndent;
|
str += childIndent
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof item !== 'undefined' && typeof item !== 'function') {
|
if (typeof item !== 'undefined' && typeof item !== 'function') {
|
||||||
str += stringifyValue(item, space, childIndent, limit);
|
str += stringifyValue(item, space, childIndent, limit)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
str += 'null'
|
str += 'null'
|
||||||
}
|
}
|
||||||
|
|
||||||
if (i < array.length - 1) {
|
if (i < array.length - 1) {
|
||||||
str += space ? ',\n' : ',';
|
str += space ? ',\n' : ','
|
||||||
}
|
}
|
||||||
|
|
||||||
// stop as soon as we're exceeding the limit
|
// stop as soon as we're exceeding the limit
|
||||||
if (str.length > limit) {
|
if (str.length > limit) {
|
||||||
return str + '...';
|
return str + '...'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
str += space ? ('\n' + indent + ']') : ']';
|
str += space ? ('\n' + indent + ']') : ']'
|
||||||
return str;
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -122,41 +119,40 @@ function stringifyArray(array, space, indent, limit) {
|
||||||
* @param {number} limit
|
* @param {number} limit
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
function stringifyObject(object, space, indent, limit) {
|
function stringifyObject (object, space, indent, limit) {
|
||||||
var childIndent = space ? (indent + space) : undefined;
|
var childIndent = space ? (indent + space) : undefined
|
||||||
var first = true;
|
var first = true
|
||||||
var str = space ? '{\n' : '{';
|
var str = space ? '{\n' : '{'
|
||||||
|
|
||||||
if (typeof object.toJSON === 'function') {
|
if (typeof object.toJSON === 'function') {
|
||||||
return stringifyValue(object.toJSON(), space, indent, limit);
|
return stringifyValue(object.toJSON(), space, indent, limit)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var key in object) {
|
for (var key in object) {
|
||||||
if (object.hasOwnProperty(key)) {
|
if (hasOwnProperty(object, key)) {
|
||||||
var value = object[key];
|
var value = object[key]
|
||||||
|
|
||||||
if (first) {
|
if (first) {
|
||||||
first = false;
|
first = false
|
||||||
}
|
} else {
|
||||||
else {
|
str += space ? ',\n' : ','
|
||||||
str += space ? ',\n' : ',';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
str += space
|
str += space
|
||||||
? (childIndent + '"' + key + '": ')
|
? (childIndent + '"' + key + '": ')
|
||||||
: ('"' + key + '":');
|
: ('"' + key + '":')
|
||||||
|
|
||||||
str += stringifyValue(value, space, childIndent, limit);
|
str += stringifyValue(value, space, childIndent, limit)
|
||||||
|
|
||||||
// stop as soon as we're exceeding the limit
|
// stop as soon as we're exceeding the limit
|
||||||
if (str.length > limit) {
|
if (str.length > limit) {
|
||||||
return str + '...';
|
return str + '...'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
str += space ? ('\n' + indent + '}') : '}';
|
str += space ? ('\n' + indent + '}') : '}'
|
||||||
return str;
|
return str
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -167,11 +163,11 @@ function stringifyObject(object, space, indent, limit) {
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
function repeat (text, times) {
|
function repeat (text, times) {
|
||||||
var res = '';
|
var res = ''
|
||||||
while (times-- > 0) {
|
while (times-- > 0) {
|
||||||
res += text;
|
res += text
|
||||||
}
|
}
|
||||||
return res;
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -180,10 +176,10 @@ function repeat (text, times) {
|
||||||
* @param {number} [limit]
|
* @param {number} [limit]
|
||||||
* @return {string}
|
* @return {string}
|
||||||
*/
|
*/
|
||||||
function slice(text, limit) {
|
function slice (text, limit) {
|
||||||
return typeof limit === 'number'
|
return typeof limit === 'number'
|
||||||
? text.slice(0, limit)
|
? text.slice(0, limit)
|
||||||
: text;
|
: text
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -196,5 +192,9 @@ function containsArray (jsonText) {
|
||||||
return /^\s*\[/.test(jsonText)
|
return /^\s*\[/.test(jsonText)
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.stringifyPartial = stringifyPartial;
|
function hasOwnProperty (object, key) {
|
||||||
exports.containsArray = containsArray;
|
return Object.prototype.hasOwnProperty.call(object, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.stringifyPartial = stringifyPartial
|
||||||
|
exports.containsArray = containsArray
|
||||||
|
|
|
@ -3,42 +3,33 @@ if (typeof Element !== 'undefined') {
|
||||||
// Polyfill for array remove
|
// Polyfill for array remove
|
||||||
(function () {
|
(function () {
|
||||||
function polyfill (item) {
|
function polyfill (item) {
|
||||||
if (item.hasOwnProperty('remove')) {
|
if ('remove' in item) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
Object.defineProperty(item, 'remove', {
|
Object.defineProperty(item, 'remove', {
|
||||||
configurable: true,
|
configurable: true,
|
||||||
enumerable: true,
|
enumerable: true,
|
||||||
writable: true,
|
writable: true,
|
||||||
value: function remove() {
|
value: function remove () {
|
||||||
if (this.parentNode != null)
|
if (this.parentNode !== undefined) { this.parentNode.removeChild(this) }
|
||||||
this.parentNode.removeChild(this);
|
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeof Element !== 'undefined') { polyfill(Element.prototype); }
|
if (typeof window.Element !== 'undefined') { polyfill(window.Element.prototype) }
|
||||||
if (typeof CharacterData !== 'undefined') { polyfill(CharacterData.prototype); }
|
if (typeof window.CharacterData !== 'undefined') { polyfill(window.CharacterData.prototype) }
|
||||||
if (typeof DocumentType !== 'undefined') { polyfill(DocumentType.prototype); }
|
if (typeof window.DocumentType !== 'undefined') { polyfill(window.DocumentType.prototype) }
|
||||||
})();
|
})()
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Polyfill for startsWith
|
|
||||||
if (!String.prototype.startsWith) {
|
|
||||||
String.prototype.startsWith = function (searchString, position) {
|
|
||||||
position = position || 0;
|
|
||||||
return this.substr(position, searchString.length) === searchString;
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Polyfill for Array.find
|
// Polyfill for Array.find
|
||||||
if (!Array.prototype.find) {
|
if (!Array.prototype.find) {
|
||||||
Array.prototype.find = function(callback) {
|
// eslint-disable-next-line no-extend-native
|
||||||
|
Array.prototype.find = function (callback) {
|
||||||
for (var i = 0; i < this.length; i++) {
|
for (var i = 0; i < this.length; i++) {
|
||||||
var element = this[i];
|
var element = this[i]
|
||||||
if ( callback.call(this, element, i, this) ) {
|
if (callback.call(this, element, i, this)) {
|
||||||
return element;
|
return element
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,7 +37,8 @@ if (!Array.prototype.find) {
|
||||||
|
|
||||||
// Polyfill for String.trim
|
// Polyfill for String.trim
|
||||||
if (!String.prototype.trim) {
|
if (!String.prototype.trim) {
|
||||||
|
// eslint-disable-next-line no-extend-native
|
||||||
String.prototype.trim = function () {
|
String.prototype.trim = function () {
|
||||||
return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
|
return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,21 @@
|
||||||
'use strict';
|
'use strict'
|
||||||
|
|
||||||
var jmespath = require('jmespath');
|
var jmespath = require('jmespath')
|
||||||
var translate = require('./i18n').translate;
|
var translate = require('./i18n').translate
|
||||||
var ModeSwitcher = require('./ModeSwitcher');
|
var ModeSwitcher = require('./ModeSwitcher')
|
||||||
var ErrorTable = require('./ErrorTable');
|
var ErrorTable = require('./ErrorTable')
|
||||||
var textmode = require('./textmode')[0].mixin;
|
var textmode = require('./textmode')[0].mixin
|
||||||
var showSortModal = require('./showSortModal');
|
var showSortModal = require('./showSortModal')
|
||||||
var showTransformModal = require('./showTransformModal');
|
var showTransformModal = require('./showTransformModal')
|
||||||
var MAX_PREVIEW_CHARACTERS = require('./constants').MAX_PREVIEW_CHARACTERS;
|
var MAX_PREVIEW_CHARACTERS = require('./constants').MAX_PREVIEW_CHARACTERS
|
||||||
var DEFAULT_MODAL_ANCHOR = require('./constants').DEFAULT_MODAL_ANCHOR;
|
var DEFAULT_MODAL_ANCHOR = require('./constants').DEFAULT_MODAL_ANCHOR
|
||||||
var SIZE_LARGE = require('./constants').SIZE_LARGE;
|
var SIZE_LARGE = require('./constants').SIZE_LARGE
|
||||||
var PREVIEW_HISTORY_LIMIT = require('./constants').PREVIEW_HISTORY_LIMIT;
|
var PREVIEW_HISTORY_LIMIT = require('./constants').PREVIEW_HISTORY_LIMIT
|
||||||
var util = require('./util');
|
var util = require('./util')
|
||||||
var History = require('./History');
|
var History = require('./History')
|
||||||
|
|
||||||
// create a mixin with the functions for text mode
|
// create a mixin with the functions for text mode
|
||||||
var previewmode = {};
|
var previewmode = {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a JSON document preview, suitable for processing of large documents
|
* Create a JSON document preview, suitable for processing of large documents
|
||||||
|
@ -25,274 +25,269 @@ var previewmode = {};
|
||||||
*/
|
*/
|
||||||
previewmode.create = function (container, options) {
|
previewmode.create = function (container, options) {
|
||||||
// read options
|
// read options
|
||||||
options = options || {};
|
options = options || {}
|
||||||
|
|
||||||
if (typeof options.statusBar === 'undefined') {
|
if (typeof options.statusBar === 'undefined') {
|
||||||
options.statusBar = true;
|
options.statusBar = true
|
||||||
}
|
}
|
||||||
|
|
||||||
// setting default for previewmode
|
// setting default for previewmode
|
||||||
options.mainMenuBar = options.mainMenuBar !== false;
|
options.mainMenuBar = options.mainMenuBar !== false
|
||||||
options.enableSort = options.enableSort !== false;
|
options.enableSort = options.enableSort !== false
|
||||||
options.enableTransform = options.enableTransform !== false;
|
options.enableTransform = options.enableTransform !== false
|
||||||
|
|
||||||
this.options = options;
|
this.options = options
|
||||||
|
|
||||||
// indentation
|
// indentation
|
||||||
if (options.indentation) {
|
if (options.indentation) {
|
||||||
this.indentation = Number(options.indentation);
|
this.indentation = Number(options.indentation)
|
||||||
}
|
} else {
|
||||||
else {
|
this.indentation = 2 // number of spaces
|
||||||
this.indentation = 2; // number of spaces
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine mode
|
// determine mode
|
||||||
this.mode = 'preview';
|
this.mode = 'preview'
|
||||||
|
|
||||||
var me = this;
|
var me = this
|
||||||
this.container = container;
|
this.container = container
|
||||||
this.dom = {};
|
this.dom = {}
|
||||||
|
|
||||||
this.json = undefined;
|
this.json = undefined
|
||||||
this.text = '';
|
this.text = ''
|
||||||
|
|
||||||
// TODO: JSON Schema support
|
// TODO: JSON Schema support
|
||||||
|
|
||||||
// create a debounced validate function
|
// create a debounced validate function
|
||||||
this._debouncedValidate = util.debounce(this.validate.bind(this), this.DEBOUNCE_INTERVAL);
|
this._debouncedValidate = util.debounce(this.validate.bind(this), this.DEBOUNCE_INTERVAL)
|
||||||
|
|
||||||
this.width = container.clientWidth;
|
this.width = container.clientWidth
|
||||||
this.height = container.clientHeight;
|
this.height = container.clientHeight
|
||||||
|
|
||||||
this.frame = document.createElement('div');
|
this.frame = document.createElement('div')
|
||||||
this.frame.className = 'jsoneditor jsoneditor-mode-preview';
|
this.frame.className = 'jsoneditor jsoneditor-mode-preview'
|
||||||
this.frame.onclick = function (event) {
|
this.frame.onclick = function (event) {
|
||||||
// prevent default submit action when the editor is located inside a form
|
// prevent default submit action when the editor is located inside a form
|
||||||
event.preventDefault();
|
event.preventDefault()
|
||||||
};
|
}
|
||||||
|
|
||||||
this.content = document.createElement('div');
|
this.content = document.createElement('div')
|
||||||
this.content.className = 'jsoneditor-outer';
|
this.content.className = 'jsoneditor-outer'
|
||||||
|
|
||||||
this.dom.busy = document.createElement('div')
|
this.dom.busy = document.createElement('div')
|
||||||
this.dom.busy.className = 'jsoneditor-busy';
|
this.dom.busy.className = 'jsoneditor-busy'
|
||||||
this.dom.busyContent = document.createElement('span');
|
this.dom.busyContent = document.createElement('span')
|
||||||
this.dom.busyContent.innerHTML = 'busy...';
|
this.dom.busyContent.innerHTML = 'busy...'
|
||||||
this.dom.busy.appendChild(this.dom.busyContent);
|
this.dom.busy.appendChild(this.dom.busyContent)
|
||||||
this.content.appendChild(this.dom.busy);
|
this.content.appendChild(this.dom.busy)
|
||||||
|
|
||||||
this.dom.previewContent = document.createElement('pre');
|
this.dom.previewContent = document.createElement('pre')
|
||||||
this.dom.previewContent.className = 'jsoneditor-preview';
|
this.dom.previewContent.className = 'jsoneditor-preview'
|
||||||
this.dom.previewText = document.createTextNode('');
|
this.dom.previewText = document.createTextNode('')
|
||||||
this.dom.previewContent.appendChild(this.dom.previewText);
|
this.dom.previewContent.appendChild(this.dom.previewText)
|
||||||
this.content.appendChild(this.dom.previewContent);
|
this.content.appendChild(this.dom.previewContent)
|
||||||
|
|
||||||
if (this.options.mainMenuBar) {
|
if (this.options.mainMenuBar) {
|
||||||
util.addClassName(this.content, 'has-main-menu-bar');
|
util.addClassName(this.content, 'has-main-menu-bar')
|
||||||
|
|
||||||
// create menu
|
// create menu
|
||||||
this.menu = document.createElement('div');
|
this.menu = document.createElement('div')
|
||||||
this.menu.className = 'jsoneditor-menu';
|
this.menu.className = 'jsoneditor-menu'
|
||||||
this.frame.appendChild(this.menu);
|
this.frame.appendChild(this.menu)
|
||||||
|
|
||||||
// create format button
|
// create format button
|
||||||
var buttonFormat = document.createElement('button');
|
var buttonFormat = document.createElement('button')
|
||||||
buttonFormat.type = 'button';
|
buttonFormat.type = 'button'
|
||||||
buttonFormat.className = 'jsoneditor-format';
|
buttonFormat.className = 'jsoneditor-format'
|
||||||
buttonFormat.title = 'Format JSON data, with proper indentation and line feeds (Ctrl+\\)';
|
buttonFormat.title = 'Format JSON data, with proper indentation and line feeds (Ctrl+\\)'
|
||||||
this.menu.appendChild(buttonFormat);
|
this.menu.appendChild(buttonFormat)
|
||||||
buttonFormat.onclick = function handleFormat() {
|
buttonFormat.onclick = function handleFormat () {
|
||||||
me.executeWithBusyMessage(function () {
|
me.executeWithBusyMessage(function () {
|
||||||
try {
|
try {
|
||||||
me.format();
|
me.format()
|
||||||
|
} catch (err) {
|
||||||
|
me._onError(err)
|
||||||
}
|
}
|
||||||
catch (err) {
|
}, 'formatting...')
|
||||||
me._onError(err);
|
}
|
||||||
}
|
|
||||||
}, 'formatting...');
|
|
||||||
};
|
|
||||||
|
|
||||||
// create compact button
|
// create compact button
|
||||||
var buttonCompact = document.createElement('button');
|
var buttonCompact = document.createElement('button')
|
||||||
buttonCompact.type = 'button';
|
buttonCompact.type = 'button'
|
||||||
buttonCompact.className = 'jsoneditor-compact';
|
buttonCompact.className = 'jsoneditor-compact'
|
||||||
buttonCompact.title = 'Compact JSON data, remove all whitespaces (Ctrl+Shift+\\)';
|
buttonCompact.title = 'Compact JSON data, remove all whitespaces (Ctrl+Shift+\\)'
|
||||||
this.menu.appendChild(buttonCompact);
|
this.menu.appendChild(buttonCompact)
|
||||||
buttonCompact.onclick = function handleCompact() {
|
buttonCompact.onclick = function handleCompact () {
|
||||||
me.executeWithBusyMessage(function () {
|
me.executeWithBusyMessage(function () {
|
||||||
try {
|
try {
|
||||||
me.compact();
|
me.compact()
|
||||||
|
} catch (err) {
|
||||||
|
me._onError(err)
|
||||||
}
|
}
|
||||||
catch (err) {
|
}, 'compacting...')
|
||||||
me._onError(err);
|
}
|
||||||
}
|
|
||||||
}, 'compacting...');
|
|
||||||
};
|
|
||||||
|
|
||||||
// create sort button
|
// create sort button
|
||||||
if (this.options.enableSort) {
|
if (this.options.enableSort) {
|
||||||
var sort = document.createElement('button');
|
var sort = document.createElement('button')
|
||||||
sort.type = 'button';
|
sort.type = 'button'
|
||||||
sort.className = 'jsoneditor-sort';
|
sort.className = 'jsoneditor-sort'
|
||||||
sort.title = translate('sortTitleShort');
|
sort.title = translate('sortTitleShort')
|
||||||
sort.onclick = function () {
|
sort.onclick = function () {
|
||||||
me._showSortModal();
|
me._showSortModal()
|
||||||
};
|
}
|
||||||
this.menu.appendChild(sort);
|
this.menu.appendChild(sort)
|
||||||
}
|
}
|
||||||
|
|
||||||
// create transform button
|
// create transform button
|
||||||
if (this.options.enableTransform) {
|
if (this.options.enableTransform) {
|
||||||
var transform = document.createElement('button');
|
var transform = document.createElement('button')
|
||||||
transform.type = 'button';
|
transform.type = 'button'
|
||||||
transform.title = translate('transformTitleShort');
|
transform.title = translate('transformTitleShort')
|
||||||
transform.className = 'jsoneditor-transform';
|
transform.className = 'jsoneditor-transform'
|
||||||
transform.onclick = function () {
|
transform.onclick = function () {
|
||||||
me._showTransformModal();
|
me._showTransformModal()
|
||||||
};
|
}
|
||||||
this.dom.transform = transform;
|
this.dom.transform = transform
|
||||||
this.menu.appendChild(transform);
|
this.menu.appendChild(transform)
|
||||||
}
|
}
|
||||||
|
|
||||||
// create repair button
|
// create repair button
|
||||||
var buttonRepair = document.createElement('button');
|
var buttonRepair = document.createElement('button')
|
||||||
buttonRepair.type = 'button';
|
buttonRepair.type = 'button'
|
||||||
buttonRepair.className = 'jsoneditor-repair';
|
buttonRepair.className = 'jsoneditor-repair'
|
||||||
buttonRepair.title = 'Repair JSON: fix quotes and escape characters, remove comments and JSONP notation, turn JavaScript objects into JSON.';
|
buttonRepair.title = 'Repair JSON: fix quotes and escape characters, remove comments and JSONP notation, turn JavaScript objects into JSON.'
|
||||||
this.menu.appendChild(buttonRepair);
|
this.menu.appendChild(buttonRepair)
|
||||||
buttonRepair.onclick = function () {
|
buttonRepair.onclick = function () {
|
||||||
if (me.json === undefined) { // only repair if we don't have valid JSON
|
if (me.json === undefined) { // only repair if we don't have valid JSON
|
||||||
me.executeWithBusyMessage(function () {
|
me.executeWithBusyMessage(function () {
|
||||||
try {
|
try {
|
||||||
me.repair();
|
me.repair()
|
||||||
|
} catch (err) {
|
||||||
|
me._onError(err)
|
||||||
}
|
}
|
||||||
catch (err) {
|
}, 'repairing...')
|
||||||
me._onError(err);
|
|
||||||
}
|
|
||||||
}, 'repairing...');
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
// create history and undo/redo buttons
|
// create history and undo/redo buttons
|
||||||
if (this.options.history !== false) { // default option value is true
|
if (this.options.history !== false) { // default option value is true
|
||||||
var onHistoryChange = function () {
|
var onHistoryChange = function () {
|
||||||
me.dom.undo.disabled = !me.history.canUndo();
|
me.dom.undo.disabled = !me.history.canUndo()
|
||||||
me.dom.redo.disabled = !me.history.canRedo();
|
me.dom.redo.disabled = !me.history.canRedo()
|
||||||
};
|
|
||||||
|
|
||||||
var calculateItemSize = function (item) {
|
|
||||||
return item.text.length * 2; // times two to account for the json object
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.history = new History(onHistoryChange, calculateItemSize, PREVIEW_HISTORY_LIMIT);
|
var calculateItemSize = function (item) {
|
||||||
|
return item.text.length * 2 // times two to account for the json object
|
||||||
|
}
|
||||||
|
|
||||||
|
this.history = new History(onHistoryChange, calculateItemSize, PREVIEW_HISTORY_LIMIT)
|
||||||
|
|
||||||
// create undo button
|
// create undo button
|
||||||
var undo = document.createElement('button');
|
var undo = document.createElement('button')
|
||||||
undo.type = 'button';
|
undo.type = 'button'
|
||||||
undo.className = 'jsoneditor-undo jsoneditor-separator';
|
undo.className = 'jsoneditor-undo jsoneditor-separator'
|
||||||
undo.title = translate('undo');
|
undo.title = translate('undo')
|
||||||
undo.onclick = function () {
|
undo.onclick = function () {
|
||||||
var action = me.history.undo();
|
var action = me.history.undo()
|
||||||
if (action) {
|
if (action) {
|
||||||
me._applyHistory(action);
|
me._applyHistory(action)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
this.menu.appendChild(undo);
|
this.menu.appendChild(undo)
|
||||||
this.dom.undo = undo;
|
this.dom.undo = undo
|
||||||
|
|
||||||
// create redo button
|
// create redo button
|
||||||
var redo = document.createElement('button');
|
var redo = document.createElement('button')
|
||||||
redo.type = 'button';
|
redo.type = 'button'
|
||||||
redo.className = 'jsoneditor-redo';
|
redo.className = 'jsoneditor-redo'
|
||||||
redo.title = translate('redo');
|
redo.title = translate('redo')
|
||||||
redo.onclick = function () {
|
redo.onclick = function () {
|
||||||
var action = me.history.redo();
|
var action = me.history.redo()
|
||||||
if (action) {
|
if (action) {
|
||||||
me._applyHistory(action);
|
me._applyHistory(action)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
this.menu.appendChild(redo);
|
this.menu.appendChild(redo)
|
||||||
this.dom.redo = redo;
|
this.dom.redo = redo
|
||||||
|
|
||||||
// force enabling/disabling the undo/redo button
|
// force enabling/disabling the undo/redo button
|
||||||
this.history.onChange();
|
this.history.onChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
// create mode box
|
// create mode box
|
||||||
if (this.options && this.options.modes && this.options.modes.length) {
|
if (this.options && this.options.modes && this.options.modes.length) {
|
||||||
this.modeSwitcher = new ModeSwitcher(this.menu, this.options.modes, this.options.mode, function onSwitch(mode) {
|
this.modeSwitcher = new ModeSwitcher(this.menu, this.options.modes, this.options.mode, function onSwitch (mode) {
|
||||||
// switch mode and restore focus
|
// switch mode and restore focus
|
||||||
me.setMode(mode);
|
me.setMode(mode)
|
||||||
me.modeSwitcher.focus();
|
me.modeSwitcher.focus()
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.errorTable = new ErrorTable({
|
this.errorTable = new ErrorTable({
|
||||||
errorTableVisible: true,
|
errorTableVisible: true,
|
||||||
onToggleVisibility: function () {
|
onToggleVisibility: function () {
|
||||||
me.validate();
|
me.validate()
|
||||||
},
|
},
|
||||||
onFocusLine: null,
|
onFocusLine: null,
|
||||||
onChangeHeight: function (height) {
|
onChangeHeight: function (height) {
|
||||||
// TODO: change CSS to using flex box, remove setting height using JavaScript
|
// TODO: change CSS to using flex box, remove setting height using JavaScript
|
||||||
var statusBarHeight = me.dom.statusBar ? me.dom.statusBar.clientHeight : 0;
|
var statusBarHeight = me.dom.statusBar ? me.dom.statusBar.clientHeight : 0
|
||||||
var totalHeight = height + statusBarHeight + 1;
|
var totalHeight = height + statusBarHeight + 1
|
||||||
me.content.style.marginBottom = (-totalHeight) + 'px';
|
me.content.style.marginBottom = (-totalHeight) + 'px'
|
||||||
me.content.style.paddingBottom = totalHeight + 'px';
|
me.content.style.paddingBottom = totalHeight + 'px'
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
this.frame.appendChild(this.content);
|
this.frame.appendChild(this.content)
|
||||||
this.frame.appendChild(this.errorTable.getErrorTable());
|
this.frame.appendChild(this.errorTable.getErrorTable())
|
||||||
this.container.appendChild(this.frame);
|
this.container.appendChild(this.frame)
|
||||||
|
|
||||||
if (options.statusBar) {
|
if (options.statusBar) {
|
||||||
util.addClassName(this.content, 'has-status-bar');
|
util.addClassName(this.content, 'has-status-bar')
|
||||||
|
|
||||||
var statusBar = document.createElement('div');
|
var statusBar = document.createElement('div')
|
||||||
this.dom.statusBar = statusBar;
|
this.dom.statusBar = statusBar
|
||||||
statusBar.className = 'jsoneditor-statusbar';
|
statusBar.className = 'jsoneditor-statusbar'
|
||||||
this.frame.appendChild(statusBar);
|
this.frame.appendChild(statusBar)
|
||||||
|
|
||||||
this.dom.fileSizeInfo = document.createElement('span');
|
this.dom.fileSizeInfo = document.createElement('span')
|
||||||
this.dom.fileSizeInfo.className = 'jsoneditor-size-info';
|
this.dom.fileSizeInfo.className = 'jsoneditor-size-info'
|
||||||
this.dom.fileSizeInfo.innerText = '';
|
this.dom.fileSizeInfo.innerText = ''
|
||||||
statusBar.appendChild(this.dom.fileSizeInfo);
|
statusBar.appendChild(this.dom.fileSizeInfo)
|
||||||
|
|
||||||
this.dom.arrayInfo = document.createElement('span');
|
this.dom.arrayInfo = document.createElement('span')
|
||||||
this.dom.arrayInfo.className = 'jsoneditor-size-info';
|
this.dom.arrayInfo.className = 'jsoneditor-size-info'
|
||||||
this.dom.arrayInfo.innerText = '';
|
this.dom.arrayInfo.innerText = ''
|
||||||
statusBar.appendChild(this.dom.arrayInfo);
|
statusBar.appendChild(this.dom.arrayInfo)
|
||||||
|
|
||||||
statusBar.appendChild(this.errorTable.getErrorCounter());
|
statusBar.appendChild(this.errorTable.getErrorCounter())
|
||||||
statusBar.appendChild(this.errorTable.getWarningIcon());
|
statusBar.appendChild(this.errorTable.getWarningIcon())
|
||||||
statusBar.appendChild(this.errorTable.getErrorIcon());
|
statusBar.appendChild(this.errorTable.getErrorIcon())
|
||||||
}
|
}
|
||||||
|
|
||||||
this._renderPreview();
|
this._renderPreview()
|
||||||
|
|
||||||
this.setSchema(this.options.schema, this.options.schemaRefs);
|
this.setSchema(this.options.schema, this.options.schemaRefs)
|
||||||
};
|
}
|
||||||
|
|
||||||
previewmode._renderPreview = function () {
|
previewmode._renderPreview = function () {
|
||||||
var text = this.getText();
|
var text = this.getText()
|
||||||
|
|
||||||
this.dom.previewText.nodeValue = util.limitCharacters(text, MAX_PREVIEW_CHARACTERS);
|
this.dom.previewText.nodeValue = util.limitCharacters(text, MAX_PREVIEW_CHARACTERS)
|
||||||
|
|
||||||
if (this.dom.fileSizeInfo) {
|
if (this.dom.fileSizeInfo) {
|
||||||
this.dom.fileSizeInfo.innerText = 'Size: ' + util.formatSize(text.length);
|
this.dom.fileSizeInfo.innerText = 'Size: ' + util.formatSize(text.length)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.dom.arrayInfo) {
|
if (this.dom.arrayInfo) {
|
||||||
if (Array.isArray(this.json)) {
|
if (Array.isArray(this.json)) {
|
||||||
this.dom.arrayInfo.innerText = ('Array: ' + this.json.length + ' items');
|
this.dom.arrayInfo.innerText = ('Array: ' + this.json.length + ' items')
|
||||||
}
|
} else {
|
||||||
else {
|
this.dom.arrayInfo.innerText = ''
|
||||||
this.dom.arrayInfo.innerText = '';
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle a change:
|
* Handle a change:
|
||||||
|
@ -302,73 +297,70 @@ previewmode._renderPreview = function () {
|
||||||
*/
|
*/
|
||||||
previewmode._onChange = function () {
|
previewmode._onChange = function () {
|
||||||
// validate JSON schema (if configured)
|
// validate JSON schema (if configured)
|
||||||
this._debouncedValidate();
|
this._debouncedValidate()
|
||||||
|
|
||||||
// trigger the onChange callback
|
// trigger the onChange callback
|
||||||
if (this.options.onChange) {
|
if (this.options.onChange) {
|
||||||
try {
|
try {
|
||||||
this.options.onChange();
|
this.options.onChange()
|
||||||
}
|
} catch (err) {
|
||||||
catch (err) {
|
console.error('Error in onChange callback: ', err)
|
||||||
console.error('Error in onChange callback: ', err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// trigger the onChangeJSON callback
|
// trigger the onChangeJSON callback
|
||||||
if (this.options.onChangeJSON) {
|
if (this.options.onChangeJSON) {
|
||||||
try {
|
try {
|
||||||
this.options.onChangeJSON(this.get());
|
this.options.onChangeJSON(this.get())
|
||||||
}
|
} catch (err) {
|
||||||
catch (err) {
|
console.error('Error in onChangeJSON callback: ', err)
|
||||||
console.error('Error in onChangeJSON callback: ', err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// trigger the onChangeText callback
|
// trigger the onChangeText callback
|
||||||
if (this.options.onChangeText) {
|
if (this.options.onChangeText) {
|
||||||
try {
|
try {
|
||||||
this.options.onChangeText(this.getText());
|
this.options.onChangeText(this.getText())
|
||||||
}
|
} catch (err) {
|
||||||
catch (err) {
|
console.error('Error in onChangeText callback: ', err)
|
||||||
console.error('Error in onChangeText callback: ', err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Open a sort modal
|
* Open a sort modal
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
previewmode._showSortModal = function () {
|
previewmode._showSortModal = function () {
|
||||||
var me = this;
|
var me = this
|
||||||
|
|
||||||
function onSort (json, sortedBy) {
|
function onSort (json, sortedBy) {
|
||||||
if (Array.isArray(json)) {
|
if (Array.isArray(json)) {
|
||||||
var sortedArray = util.sort(json, sortedBy.path, sortedBy.direction);
|
var sortedArray = util.sort(json, sortedBy.path, sortedBy.direction)
|
||||||
|
|
||||||
me.sortedBy = sortedBy
|
me.sortedBy = sortedBy
|
||||||
me._setAndFireOnChange(sortedArray);
|
me._setAndFireOnChange(sortedArray)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (util.isObject(json)) {
|
if (util.isObject(json)) {
|
||||||
var sortedObject = util.sortObjectKeys(json, sortedBy.direction);
|
var sortedObject = util.sortObjectKeys(json, sortedBy.direction)
|
||||||
|
|
||||||
me.sortedBy = sortedBy;
|
me.sortedBy = sortedBy
|
||||||
me._setAndFireOnChange(sortedObject);
|
me._setAndFireOnChange(sortedObject)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this.executeWithBusyMessage(function () {
|
this.executeWithBusyMessage(function () {
|
||||||
var container = me.options.modalAnchor || DEFAULT_MODAL_ANCHOR;
|
var container = me.options.modalAnchor || DEFAULT_MODAL_ANCHOR
|
||||||
var json = me.get();
|
var json = me.get()
|
||||||
me._renderPreview(); // update array count
|
me._renderPreview() // update array count
|
||||||
|
|
||||||
showSortModal(container, json, function (sortedBy) {
|
showSortModal(container, json, function (sortedBy) {
|
||||||
me.executeWithBusyMessage(function () {
|
me.executeWithBusyMessage(function () {
|
||||||
onSort(json, sortedBy);
|
onSort(json, sortedBy)
|
||||||
}, 'sorting...');
|
}, 'sorting...')
|
||||||
}, me.sortedBy)
|
}, me.sortedBy)
|
||||||
}, 'parsing...');
|
}, 'parsing...')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -376,17 +368,17 @@ previewmode._showSortModal = function () {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
previewmode._showTransformModal = function () {
|
previewmode._showTransformModal = function () {
|
||||||
var me = this;
|
var me = this
|
||||||
|
|
||||||
this.executeWithBusyMessage(function () {
|
this.executeWithBusyMessage(function () {
|
||||||
var anchor = me.options.modalAnchor || DEFAULT_MODAL_ANCHOR;
|
var anchor = me.options.modalAnchor || DEFAULT_MODAL_ANCHOR
|
||||||
var json = me.get();
|
var json = me.get()
|
||||||
me._renderPreview(); // update array count
|
me._renderPreview() // update array count
|
||||||
|
|
||||||
showTransformModal(anchor, json, function (query) {
|
showTransformModal(anchor, json, function (query) {
|
||||||
me.executeWithBusyMessage(function () {
|
me.executeWithBusyMessage(function () {
|
||||||
var updatedJson = jmespath.search(json, query);
|
var updatedJson = jmespath.search(json, query)
|
||||||
me._setAndFireOnChange(updatedJson);
|
me._setAndFireOnChange(updatedJson)
|
||||||
}, 'transforming...')
|
}, 'transforming...')
|
||||||
})
|
})
|
||||||
}, 'parsing...')
|
}, 'parsing...')
|
||||||
|
@ -397,51 +389,51 @@ previewmode._showTransformModal = function () {
|
||||||
*/
|
*/
|
||||||
previewmode.destroy = function () {
|
previewmode.destroy = function () {
|
||||||
if (this.frame && this.container && this.frame.parentNode === this.container) {
|
if (this.frame && this.container && this.frame.parentNode === this.container) {
|
||||||
this.container.removeChild(this.frame);
|
this.container.removeChild(this.frame)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.modeSwitcher) {
|
if (this.modeSwitcher) {
|
||||||
this.modeSwitcher.destroy();
|
this.modeSwitcher.destroy()
|
||||||
this.modeSwitcher = null;
|
this.modeSwitcher = null
|
||||||
}
|
}
|
||||||
|
|
||||||
this._debouncedValidate = null;
|
this._debouncedValidate = null
|
||||||
|
|
||||||
this.history.clear();
|
this.history.clear()
|
||||||
this.history = null;
|
this.history = null
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compact the code in the text editor
|
* Compact the code in the text editor
|
||||||
*/
|
*/
|
||||||
previewmode.compact = function () {
|
previewmode.compact = function () {
|
||||||
var json = this.get();
|
var json = this.get()
|
||||||
var text = JSON.stringify(json);
|
var text = JSON.stringify(json)
|
||||||
|
|
||||||
// we know that in this case the json is still the same, so we pass json too
|
// we know that in this case the json is still the same, so we pass json too
|
||||||
this._setTextAndFireOnChange(text, json);
|
this._setTextAndFireOnChange(text, json)
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Format the code in the text editor
|
* Format the code in the text editor
|
||||||
*/
|
*/
|
||||||
previewmode.format = function () {
|
previewmode.format = function () {
|
||||||
var json = this.get();
|
var json = this.get()
|
||||||
var text = JSON.stringify(json, null, this.indentation);
|
var text = JSON.stringify(json, null, this.indentation)
|
||||||
|
|
||||||
// we know that in this case the json is still the same, so we pass json too
|
// we know that in this case the json is still the same, so we pass json too
|
||||||
this._setTextAndFireOnChange(text, json);
|
this._setTextAndFireOnChange(text, json)
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Repair the code in the text editor
|
* Repair the code in the text editor
|
||||||
*/
|
*/
|
||||||
previewmode.repair = function () {
|
previewmode.repair = function () {
|
||||||
var text = this.getText();
|
var text = this.getText()
|
||||||
var repairedText = util.repair(text);
|
var repairedText = util.repair(text)
|
||||||
|
|
||||||
this._setTextAndFireOnChange(repairedText);
|
this._setTextAndFireOnChange(repairedText)
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set focus to the editor
|
* Set focus to the editor
|
||||||
|
@ -449,104 +441,104 @@ previewmode.repair = function () {
|
||||||
previewmode.focus = function () {
|
previewmode.focus = function () {
|
||||||
// we don't really have a place to focus,
|
// we don't really have a place to focus,
|
||||||
// let's focus on the transform button
|
// let's focus on the transform button
|
||||||
this.dom.transform.focus();
|
this.dom.transform.focus()
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set json data in the editor
|
* Set json data in the editor
|
||||||
* @param {*} json
|
* @param {*} json
|
||||||
*/
|
*/
|
||||||
previewmode.set = function(json) {
|
previewmode.set = function (json) {
|
||||||
if (this.history) {
|
if (this.history) {
|
||||||
this.history.clear();
|
this.history.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
this._set(json);
|
this._set(json)
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update data. Same as calling `set` in text/code mode.
|
* Update data. Same as calling `set` in text/code mode.
|
||||||
* @param {*} json
|
* @param {*} json
|
||||||
*/
|
*/
|
||||||
previewmode.update = function(json) {
|
previewmode.update = function (json) {
|
||||||
this._set(json);
|
this._set(json)
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set json data
|
* Set json data
|
||||||
* @param {*} json
|
* @param {*} json
|
||||||
*/
|
*/
|
||||||
previewmode._set = function(json) {
|
previewmode._set = function (json) {
|
||||||
this.text = undefined;
|
this.text = undefined
|
||||||
this.json = json;
|
this.json = json
|
||||||
|
|
||||||
this._renderPreview();
|
this._renderPreview()
|
||||||
|
|
||||||
this._pushHistory();
|
this._pushHistory()
|
||||||
|
|
||||||
// validate JSON schema
|
// validate JSON schema
|
||||||
this._debouncedValidate();
|
this._debouncedValidate()
|
||||||
};
|
}
|
||||||
|
|
||||||
previewmode._setAndFireOnChange = function (json) {
|
previewmode._setAndFireOnChange = function (json) {
|
||||||
this._set(json);
|
this._set(json)
|
||||||
this._onChange();
|
this._onChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get json data
|
* Get json data
|
||||||
* @return {*} json
|
* @return {*} json
|
||||||
*/
|
*/
|
||||||
previewmode.get = function() {
|
previewmode.get = function () {
|
||||||
if (this.json === undefined) {
|
if (this.json === undefined) {
|
||||||
var text = this.getText();
|
var text = this.getText()
|
||||||
|
|
||||||
this.json = util.parse(text); // this can throw an error
|
this.json = util.parse(text) // this can throw an error
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.json;
|
return this.json
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the text contents of the editor
|
* Get the text contents of the editor
|
||||||
* @return {String} jsonText
|
* @return {String} jsonText
|
||||||
*/
|
*/
|
||||||
previewmode.getText = function() {
|
previewmode.getText = function () {
|
||||||
if (this.text === undefined) {
|
if (this.text === undefined) {
|
||||||
this.text = JSON.stringify(this.json, null, this.indentation);
|
this.text = JSON.stringify(this.json, null, this.indentation)
|
||||||
|
|
||||||
if (this.options.escapeUnicode === true) {
|
if (this.options.escapeUnicode === true) {
|
||||||
this.text = util.escapeUnicodeChars(this.text);
|
this.text = util.escapeUnicodeChars(this.text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.text;
|
return this.text
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the text contents of the editor
|
* Set the text contents of the editor
|
||||||
* @param {String} jsonText
|
* @param {String} jsonText
|
||||||
*/
|
*/
|
||||||
previewmode.setText = function(jsonText) {
|
previewmode.setText = function (jsonText) {
|
||||||
if (this.history) {
|
if (this.history) {
|
||||||
this.history.clear();
|
this.history.clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
this._setText(jsonText);
|
this._setText(jsonText)
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the text contents
|
* Update the text contents
|
||||||
* @param {string} jsonText
|
* @param {string} jsonText
|
||||||
*/
|
*/
|
||||||
previewmode.updateText = function(jsonText) {
|
previewmode.updateText = function (jsonText) {
|
||||||
// don't update if there are no changes
|
// don't update if there are no changes
|
||||||
if (this.getText() === jsonText) {
|
if (this.getText() === jsonText) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
this._setText(jsonText);
|
this._setText(jsonText)
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the text contents of the editor
|
* Set the text contents of the editor
|
||||||
|
@ -554,37 +546,34 @@ previewmode.updateText = function(jsonText) {
|
||||||
* @param {*} [json] Optional JSON instance of the text
|
* @param {*} [json] Optional JSON instance of the text
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
previewmode._setText = function(jsonText, json) {
|
previewmode._setText = function (jsonText, json) {
|
||||||
if (this.options.escapeUnicode === true) {
|
if (this.options.escapeUnicode === true) {
|
||||||
this.text = util.escapeUnicodeChars(jsonText);
|
this.text = util.escapeUnicodeChars(jsonText)
|
||||||
|
} else {
|
||||||
|
this.text = jsonText
|
||||||
}
|
}
|
||||||
else {
|
this.json = json
|
||||||
this.text = jsonText;
|
|
||||||
}
|
|
||||||
this.json = json;
|
|
||||||
|
|
||||||
this._renderPreview();
|
this._renderPreview()
|
||||||
|
|
||||||
if (this.json === undefined) {
|
if (this.json === undefined) {
|
||||||
var me = this;
|
var me = this
|
||||||
this.executeWithBusyMessage(function () {
|
this.executeWithBusyMessage(function () {
|
||||||
try {
|
try {
|
||||||
// force parsing the json now, else it will be done in validate without feedback
|
// force parsing the json now, else it will be done in validate without feedback
|
||||||
me.json = me.get();
|
me.json = me.get()
|
||||||
me._renderPreview();
|
me._renderPreview()
|
||||||
me._pushHistory();
|
me._pushHistory()
|
||||||
}
|
} catch (err) {
|
||||||
catch (err) {
|
|
||||||
// no need to throw an error, validation will show an error
|
// no need to throw an error, validation will show an error
|
||||||
}
|
}
|
||||||
}, 'parsing...');
|
}, 'parsing...')
|
||||||
}
|
} else {
|
||||||
else {
|
this._pushHistory()
|
||||||
this._pushHistory();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._debouncedValidate();
|
this._debouncedValidate()
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set text and fire onChange callback
|
* Set text and fire onChange callback
|
||||||
|
@ -593,8 +582,8 @@ previewmode._setText = function(jsonText, json) {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
previewmode._setTextAndFireOnChange = function (jsonText, json) {
|
previewmode._setTextAndFireOnChange = function (jsonText, json) {
|
||||||
this._setText(jsonText, json);
|
this._setText(jsonText, json)
|
||||||
this._onChange();
|
this._onChange()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -603,13 +592,13 @@ previewmode._setTextAndFireOnChange = function (jsonText, json) {
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
previewmode._applyHistory = function (action) {
|
previewmode._applyHistory = function (action) {
|
||||||
this.json = action.json;
|
this.json = action.json
|
||||||
this.text = action.text;
|
this.text = action.text
|
||||||
|
|
||||||
this._renderPreview();
|
this._renderPreview()
|
||||||
|
|
||||||
this._debouncedValidate();
|
this._debouncedValidate()
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Push the current state to history
|
* Push the current state to history
|
||||||
|
@ -617,15 +606,15 @@ previewmode._applyHistory = function (action) {
|
||||||
*/
|
*/
|
||||||
previewmode._pushHistory = function () {
|
previewmode._pushHistory = function () {
|
||||||
if (!this.history) {
|
if (!this.history) {
|
||||||
return;
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var action = {
|
var action = {
|
||||||
text: this.text,
|
text: this.text,
|
||||||
json: this.json
|
json: this.json
|
||||||
};
|
}
|
||||||
|
|
||||||
this.history.add(action);
|
this.history.add(action)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -635,23 +624,22 @@ previewmode._pushHistory = function () {
|
||||||
* @param {string} message
|
* @param {string} message
|
||||||
*/
|
*/
|
||||||
previewmode.executeWithBusyMessage = function (fn, message) {
|
previewmode.executeWithBusyMessage = function (fn, message) {
|
||||||
var size = this.getText().length;
|
var size = this.getText().length
|
||||||
|
|
||||||
if (size > SIZE_LARGE) {
|
if (size > SIZE_LARGE) {
|
||||||
var me = this;
|
var me = this
|
||||||
util.addClassName(me.frame, 'busy');
|
util.addClassName(me.frame, 'busy')
|
||||||
me.dom.busyContent.innerText = message;
|
me.dom.busyContent.innerText = message
|
||||||
|
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
fn();
|
fn()
|
||||||
util.removeClassName(me.frame, 'busy');
|
util.removeClassName(me.frame, 'busy')
|
||||||
me.dom.busyContent.innerText = '';
|
me.dom.busyContent.innerText = ''
|
||||||
}, 100);
|
}, 100)
|
||||||
|
} else {
|
||||||
|
fn()
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
fn();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// TODO: refactor into composable functions instead of this shaky mixin-like structure
|
// TODO: refactor into composable functions instead of this shaky mixin-like structure
|
||||||
previewmode.validate = textmode.validate
|
previewmode.validate = textmode.validate
|
||||||
|
@ -664,4 +652,4 @@ module.exports = [
|
||||||
mixin: previewmode,
|
mixin: previewmode,
|
||||||
data: 'json'
|
data: 'json'
|
||||||
}
|
}
|
||||||
];
|
]
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
'use strict';
|
'use strict'
|
||||||
|
|
||||||
var translate = require('./i18n').translate;
|
var translate = require('./i18n').translate
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A factory function to create an ShowMoreNode, which depends on a Node
|
* A factory function to create an ShowMoreNode, which depends on a Node
|
||||||
* @param {function} Node
|
* @param {function} Node
|
||||||
*/
|
*/
|
||||||
function showMoreNodeFactory(Node) {
|
function showMoreNodeFactory (Node) {
|
||||||
/**
|
/**
|
||||||
* @constructor ShowMoreNode
|
* @constructor ShowMoreNode
|
||||||
* @extends Node
|
* @extends Node
|
||||||
|
@ -17,12 +17,12 @@ function showMoreNodeFactory(Node) {
|
||||||
*/
|
*/
|
||||||
function ShowMoreNode (editor, parent) {
|
function ShowMoreNode (editor, parent) {
|
||||||
/** @type {TreeEditor} */
|
/** @type {TreeEditor} */
|
||||||
this.editor = editor;
|
this.editor = editor
|
||||||
this.parent = parent;
|
this.parent = parent
|
||||||
this.dom = {};
|
this.dom = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
ShowMoreNode.prototype = new Node();
|
ShowMoreNode.prototype = new Node()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a table row with an append button.
|
* Return a table row with an append button.
|
||||||
|
@ -30,105 +30,104 @@ function showMoreNodeFactory(Node) {
|
||||||
*/
|
*/
|
||||||
ShowMoreNode.prototype.getDom = function () {
|
ShowMoreNode.prototype.getDom = function () {
|
||||||
if (this.dom.tr) {
|
if (this.dom.tr) {
|
||||||
return this.dom.tr;
|
return this.dom.tr
|
||||||
}
|
}
|
||||||
|
|
||||||
this._updateEditability();
|
this._updateEditability()
|
||||||
|
|
||||||
// display "show more"
|
// display "show more"
|
||||||
if (!this.dom.tr) {
|
if (!this.dom.tr) {
|
||||||
var me = this;
|
var me = this
|
||||||
var parent = this.parent;
|
var parent = this.parent
|
||||||
var showMoreButton = document.createElement('a');
|
var showMoreButton = document.createElement('a')
|
||||||
showMoreButton.appendChild(document.createTextNode(translate('showMore')));
|
showMoreButton.appendChild(document.createTextNode(translate('showMore')))
|
||||||
showMoreButton.href = '#';
|
showMoreButton.href = '#'
|
||||||
showMoreButton.onclick = function (event) {
|
showMoreButton.onclick = function (event) {
|
||||||
// TODO: use callback instead of accessing a method of the parent
|
// TODO: use callback instead of accessing a method of the parent
|
||||||
parent.visibleChilds = Math.floor(parent.visibleChilds / parent.getMaxVisibleChilds() + 1) *
|
parent.visibleChilds = Math.floor(parent.visibleChilds / parent.getMaxVisibleChilds() + 1) *
|
||||||
parent.getMaxVisibleChilds();
|
parent.getMaxVisibleChilds()
|
||||||
me.updateDom();
|
me.updateDom()
|
||||||
parent.showChilds();
|
parent.showChilds()
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault()
|
||||||
return false;
|
return false
|
||||||
};
|
}
|
||||||
|
|
||||||
var showAllButton = document.createElement('a');
|
var showAllButton = document.createElement('a')
|
||||||
showAllButton.appendChild(document.createTextNode(translate('showAll')));
|
showAllButton.appendChild(document.createTextNode(translate('showAll')))
|
||||||
showAllButton.href = '#';
|
showAllButton.href = '#'
|
||||||
showAllButton.onclick = function (event) {
|
showAllButton.onclick = function (event) {
|
||||||
// TODO: use callback instead of accessing a method of the parent
|
// TODO: use callback instead of accessing a method of the parent
|
||||||
parent.visibleChilds = Infinity;
|
parent.visibleChilds = Infinity
|
||||||
me.updateDom();
|
me.updateDom()
|
||||||
parent.showChilds();
|
parent.showChilds()
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault()
|
||||||
return false;
|
return false
|
||||||
};
|
|
||||||
|
|
||||||
var moreContents = document.createElement('div');
|
|
||||||
var moreText = document.createTextNode(this._getShowMoreText());
|
|
||||||
moreContents.className = 'jsoneditor-show-more';
|
|
||||||
moreContents.appendChild(moreText);
|
|
||||||
moreContents.appendChild(showMoreButton);
|
|
||||||
moreContents.appendChild(document.createTextNode('. '));
|
|
||||||
moreContents.appendChild(showAllButton);
|
|
||||||
moreContents.appendChild(document.createTextNode('. '));
|
|
||||||
|
|
||||||
var tdContents = document.createElement('td');
|
|
||||||
tdContents.appendChild(moreContents);
|
|
||||||
|
|
||||||
var moreTr = document.createElement('tr');
|
|
||||||
if (this.editor.options.mode === 'tree') {
|
|
||||||
moreTr.appendChild(document.createElement('td'));
|
|
||||||
moreTr.appendChild(document.createElement('td'));
|
|
||||||
}
|
}
|
||||||
moreTr.appendChild(tdContents);
|
|
||||||
moreTr.className = 'jsoneditor-show-more';
|
var moreContents = document.createElement('div')
|
||||||
this.dom.tr = moreTr;
|
var moreText = document.createTextNode(this._getShowMoreText())
|
||||||
this.dom.moreContents = moreContents;
|
moreContents.className = 'jsoneditor-show-more'
|
||||||
this.dom.moreText = moreText;
|
moreContents.appendChild(moreText)
|
||||||
|
moreContents.appendChild(showMoreButton)
|
||||||
|
moreContents.appendChild(document.createTextNode('. '))
|
||||||
|
moreContents.appendChild(showAllButton)
|
||||||
|
moreContents.appendChild(document.createTextNode('. '))
|
||||||
|
|
||||||
|
var tdContents = document.createElement('td')
|
||||||
|
tdContents.appendChild(moreContents)
|
||||||
|
|
||||||
|
var moreTr = document.createElement('tr')
|
||||||
|
if (this.editor.options.mode === 'tree') {
|
||||||
|
moreTr.appendChild(document.createElement('td'))
|
||||||
|
moreTr.appendChild(document.createElement('td'))
|
||||||
|
}
|
||||||
|
moreTr.appendChild(tdContents)
|
||||||
|
moreTr.className = 'jsoneditor-show-more'
|
||||||
|
this.dom.tr = moreTr
|
||||||
|
this.dom.moreContents = moreContents
|
||||||
|
this.dom.moreText = moreText
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateDom();
|
this.updateDom()
|
||||||
|
|
||||||
return this.dom.tr;
|
return this.dom.tr
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the HTML dom of the Node
|
* Update the HTML dom of the Node
|
||||||
*/
|
*/
|
||||||
ShowMoreNode.prototype.updateDom = function(options) {
|
ShowMoreNode.prototype.updateDom = function (options) {
|
||||||
if (this.isVisible()) {
|
if (this.isVisible()) {
|
||||||
// attach to the right child node (the first non-visible child)
|
// attach to the right child node (the first non-visible child)
|
||||||
this.dom.tr.node = this.parent.childs[this.parent.visibleChilds];
|
this.dom.tr.node = this.parent.childs[this.parent.visibleChilds]
|
||||||
|
|
||||||
if (!this.dom.tr.parentNode) {
|
if (!this.dom.tr.parentNode) {
|
||||||
var nextTr = this.parent._getNextTr();
|
var nextTr = this.parent._getNextTr()
|
||||||
if (nextTr) {
|
if (nextTr) {
|
||||||
nextTr.parentNode.insertBefore(this.dom.tr, nextTr);
|
nextTr.parentNode.insertBefore(this.dom.tr, nextTr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// update the counts in the text
|
// update the counts in the text
|
||||||
this.dom.moreText.nodeValue = this._getShowMoreText();
|
this.dom.moreText.nodeValue = this._getShowMoreText()
|
||||||
|
|
||||||
// update left margin
|
// update left margin
|
||||||
this.dom.moreContents.style.marginLeft = (this.getLevel() + 1) * 24 + 'px';
|
this.dom.moreContents.style.marginLeft = (this.getLevel() + 1) * 24 + 'px'
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if (this.dom.tr && this.dom.tr.parentNode) {
|
if (this.dom.tr && this.dom.tr.parentNode) {
|
||||||
this.dom.tr.parentNode.removeChild(this.dom.tr);
|
this.dom.tr.parentNode.removeChild(this.dom.tr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
ShowMoreNode.prototype._getShowMoreText = function() {
|
ShowMoreNode.prototype._getShowMoreText = function () {
|
||||||
return translate('showMoreStatus', {
|
return translate('showMoreStatus', {
|
||||||
visibleChilds: this.parent.visibleChilds,
|
visibleChilds: this.parent.visibleChilds,
|
||||||
totalChilds: this.parent.childs.length
|
totalChilds: this.parent.childs.length
|
||||||
}) + ' ';
|
}) + ' '
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check whether the ShowMoreNode is currently visible.
|
* Check whether the ShowMoreNode is currently visible.
|
||||||
|
@ -137,21 +136,21 @@ function showMoreNodeFactory(Node) {
|
||||||
* @return {boolean} isVisible
|
* @return {boolean} isVisible
|
||||||
*/
|
*/
|
||||||
ShowMoreNode.prototype.isVisible = function () {
|
ShowMoreNode.prototype.isVisible = function () {
|
||||||
return this.parent.expanded && this.parent.childs.length > this.parent.visibleChilds;
|
return this.parent.expanded && this.parent.childs.length > this.parent.visibleChilds
|
||||||
};
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle an event. The event is caught centrally by the editor
|
* Handle an event. The event is caught centrally by the editor
|
||||||
* @param {Event} event
|
* @param {Event} event
|
||||||
*/
|
*/
|
||||||
ShowMoreNode.prototype.onEvent = function (event) {
|
ShowMoreNode.prototype.onEvent = function (event) {
|
||||||
var type = event.type;
|
var type = event.type
|
||||||
if (type === 'keydown') {
|
if (type === 'keydown') {
|
||||||
this.onKeyDown(event);
|
this.onKeyDown(event)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
|
||||||
return ShowMoreNode;
|
return ShowMoreNode
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = showMoreNodeFactory;
|
module.exports = showMoreNodeFactory
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
var picoModal = require('picomodal');
|
var picoModal = require('picomodal')
|
||||||
var translate = require('./i18n').translate;
|
var translate = require('./i18n').translate
|
||||||
var util = require('./util');
|
var util = require('./util')
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show advanced sorting modal
|
* Show advanced sorting modal
|
||||||
|
@ -17,12 +17,12 @@ var util = require('./util');
|
||||||
*/
|
*/
|
||||||
function showSortModal (container, json, onSort, options) {
|
function showSortModal (container, json, onSort, options) {
|
||||||
var paths = Array.isArray(json)
|
var paths = Array.isArray(json)
|
||||||
? util.getChildPaths(json)
|
? util.getChildPaths(json)
|
||||||
: [''];
|
: ['']
|
||||||
var selectedPath = options && options.path && util.contains(paths, options.path)
|
var selectedPath = options && options.path && util.contains(paths, options.path)
|
||||||
? options.path
|
? options.path
|
||||||
: paths[0]
|
: paths[0]
|
||||||
var selectedDirection = options && options.direction || 'asc'
|
var selectedDirection = (options && options.direction) || 'asc'
|
||||||
|
|
||||||
var content = '<div class="pico-modal-contents">' +
|
var content = '<div class="pico-modal-contents">' +
|
||||||
'<div class="pico-modal-header">' + translate('sort') + '</div>' +
|
'<div class="pico-modal-header">' + translate('sort') + '</div>' +
|
||||||
|
@ -44,7 +44,7 @@ function showSortModal (container, json, onSort, options) {
|
||||||
' <div id="direction" class="jsoneditor-button-group">' +
|
' <div id="direction" class="jsoneditor-button-group">' +
|
||||||
'<input type="button" ' +
|
'<input type="button" ' +
|
||||||
'value="' + translate('sortAscending') + '" ' +
|
'value="' + translate('sortAscending') + '" ' +
|
||||||
'title="' + translate('sortAscendingTitle') + '" ' +
|
'title="' + translate('sortAscendingTitle') + '" ' +
|
||||||
'data-value="asc" ' +
|
'data-value="asc" ' +
|
||||||
'class="jsoneditor-button-first jsoneditor-button-asc"/>' +
|
'class="jsoneditor-button-first jsoneditor-button-asc"/>' +
|
||||||
'<input type="button" ' +
|
'<input type="button" ' +
|
||||||
|
@ -63,71 +63,71 @@ function showSortModal (container, json, onSort, options) {
|
||||||
'</tbody>' +
|
'</tbody>' +
|
||||||
'</table>' +
|
'</table>' +
|
||||||
'</form>' +
|
'</form>' +
|
||||||
'</div>';
|
'</div>'
|
||||||
|
|
||||||
picoModal({
|
picoModal({
|
||||||
parent: container,
|
parent: container,
|
||||||
content: content,
|
content: content,
|
||||||
overlayClass: 'jsoneditor-modal-overlay',
|
overlayClass: 'jsoneditor-modal-overlay',
|
||||||
overlayStyles: {
|
overlayStyles: {
|
||||||
backgroundColor: "rgb(1,1,1)",
|
backgroundColor: 'rgb(1,1,1)',
|
||||||
opacity: 0.3
|
opacity: 0.3
|
||||||
},
|
},
|
||||||
modalClass: 'jsoneditor-modal jsoneditor-modal-sort'
|
modalClass: 'jsoneditor-modal jsoneditor-modal-sort'
|
||||||
})
|
})
|
||||||
.afterCreate(function (modal) {
|
.afterCreate(function (modal) {
|
||||||
var form = modal.modalElem().querySelector('form');
|
var form = modal.modalElem().querySelector('form')
|
||||||
var ok = modal.modalElem().querySelector('#ok');
|
var ok = modal.modalElem().querySelector('#ok')
|
||||||
var field = modal.modalElem().querySelector('#field');
|
var field = modal.modalElem().querySelector('#field')
|
||||||
var direction = modal.modalElem().querySelector('#direction');
|
var direction = modal.modalElem().querySelector('#direction')
|
||||||
|
|
||||||
function preprocessPath(path) {
|
function preprocessPath (path) {
|
||||||
return (path === '')
|
return (path === '')
|
||||||
? '@'
|
? '@'
|
||||||
: (path[0] === '.')
|
: (path[0] === '.')
|
||||||
? path.slice(1)
|
? path.slice(1)
|
||||||
: path;
|
: path
|
||||||
}
|
}
|
||||||
|
|
||||||
paths.forEach(function (path) {
|
paths.forEach(function (path) {
|
||||||
var option = document.createElement('option');
|
var option = document.createElement('option')
|
||||||
option.text = preprocessPath(path);
|
option.text = preprocessPath(path)
|
||||||
option.value = path;
|
option.value = path
|
||||||
field.appendChild(option);
|
field.appendChild(option)
|
||||||
});
|
|
||||||
|
|
||||||
function setDirection(value) {
|
|
||||||
direction.value = value;
|
|
||||||
direction.className = 'jsoneditor-button-group jsoneditor-button-group-value-' + direction.value;
|
|
||||||
}
|
|
||||||
|
|
||||||
field.value = selectedPath || paths[0];
|
|
||||||
setDirection(selectedDirection || 'asc');
|
|
||||||
|
|
||||||
direction.onclick = function (event) {
|
|
||||||
setDirection(event.target.getAttribute('data-value'));
|
|
||||||
};
|
|
||||||
|
|
||||||
ok.onclick = function (event) {
|
|
||||||
event.preventDefault();
|
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
modal.close();
|
|
||||||
|
|
||||||
onSort({
|
|
||||||
path: field.value,
|
|
||||||
direction: direction.value
|
|
||||||
})
|
|
||||||
};
|
|
||||||
|
|
||||||
if (form) { // form is not available when JSONEditor is created inside a form
|
|
||||||
form.onsubmit = ok.onclick;
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
.afterClose(function (modal) {
|
|
||||||
modal.destroy();
|
function setDirection (value) {
|
||||||
})
|
direction.value = value
|
||||||
.show();
|
direction.className = 'jsoneditor-button-group jsoneditor-button-group-value-' + direction.value
|
||||||
|
}
|
||||||
|
|
||||||
|
field.value = selectedPath || paths[0]
|
||||||
|
setDirection(selectedDirection || 'asc')
|
||||||
|
|
||||||
|
direction.onclick = function (event) {
|
||||||
|
setDirection(event.target.getAttribute('data-value'))
|
||||||
|
}
|
||||||
|
|
||||||
|
ok.onclick = function (event) {
|
||||||
|
event.preventDefault()
|
||||||
|
event.stopPropagation()
|
||||||
|
|
||||||
|
modal.close()
|
||||||
|
|
||||||
|
onSort({
|
||||||
|
path: field.value,
|
||||||
|
direction: direction.value
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
if (form) { // form is not available when JSONEditor is created inside a form
|
||||||
|
form.onsubmit = ok.onclick
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.afterClose(function (modal) {
|
||||||
|
modal.destroy()
|
||||||
|
})
|
||||||
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = showSortModal;
|
module.exports = showSortModal
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
var jmespath = require('jmespath');
|
var jmespath = require('jmespath')
|
||||||
var picoModal = require('picomodal');
|
var picoModal = require('picomodal')
|
||||||
var Selectr = require('./assets/selectr/selectr');
|
var Selectr = require('./assets/selectr/selectr')
|
||||||
var translate = require('./i18n').translate;
|
var translate = require('./i18n').translate
|
||||||
var stringifyPartial = require('./jsonUtils').stringifyPartial;
|
var stringifyPartial = require('./jsonUtils').stringifyPartial
|
||||||
var util = require('./util');
|
var util = require('./util')
|
||||||
var MAX_PREVIEW_CHARACTERS = require('./constants').MAX_PREVIEW_CHARACTERS
|
var MAX_PREVIEW_CHARACTERS = require('./constants').MAX_PREVIEW_CHARACTERS
|
||||||
var debounce = util.debounce;
|
var debounce = util.debounce
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show advanced filter and transform modal using JMESPath
|
* Show advanced filter and transform modal using JMESPath
|
||||||
|
@ -16,7 +16,7 @@ var debounce = util.debounce;
|
||||||
* query as callback
|
* query as callback
|
||||||
*/
|
*/
|
||||||
function showTransformModal (container, json, onTransform) {
|
function showTransformModal (container, json, onTransform) {
|
||||||
var value = json;
|
var value = json
|
||||||
|
|
||||||
var content = '<label class="pico-modal-contents">' +
|
var content = '<label class="pico-modal-contents">' +
|
||||||
'<div class="pico-modal-header">' + translate('transform') + '</div>' +
|
'<div class="pico-modal-header">' + translate('transform') + '</div>' +
|
||||||
|
@ -93,208 +93,202 @@ function showTransformModal (container, json, onTransform) {
|
||||||
'<div class="jsoneditor-jmespath-block jsoneditor-modal-actions">' +
|
'<div class="jsoneditor-jmespath-block jsoneditor-modal-actions">' +
|
||||||
' <input type="submit" id="ok" value="' + translate('ok') + '" autofocus />' +
|
' <input type="submit" id="ok" value="' + translate('ok') + '" autofocus />' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'</div>';
|
'</div>'
|
||||||
|
|
||||||
picoModal({
|
picoModal({
|
||||||
parent: container,
|
parent: container,
|
||||||
content: content,
|
content: content,
|
||||||
overlayClass: 'jsoneditor-modal-overlay',
|
overlayClass: 'jsoneditor-modal-overlay',
|
||||||
overlayStyles: {
|
overlayStyles: {
|
||||||
backgroundColor: "rgb(1,1,1)",
|
backgroundColor: 'rgb(1,1,1)',
|
||||||
opacity: 0.3
|
opacity: 0.3
|
||||||
},
|
},
|
||||||
modalClass: 'jsoneditor-modal jsoneditor-modal-transform',
|
modalClass: 'jsoneditor-modal jsoneditor-modal-transform',
|
||||||
focus: false
|
focus: false
|
||||||
})
|
})
|
||||||
.afterCreate(function (modal) {
|
.afterCreate(function (modal) {
|
||||||
var elem = modal.modalElem();
|
var elem = modal.modalElem()
|
||||||
|
|
||||||
var wizard = elem.querySelector('#wizard');
|
var wizard = elem.querySelector('#wizard')
|
||||||
var ok = elem.querySelector('#ok');
|
var ok = elem.querySelector('#ok')
|
||||||
var filterField = elem.querySelector('#filterField');
|
var filterField = elem.querySelector('#filterField')
|
||||||
var filterRelation = elem.querySelector('#filterRelation');
|
var filterRelation = elem.querySelector('#filterRelation')
|
||||||
var filterValue = elem.querySelector('#filterValue');
|
var filterValue = elem.querySelector('#filterValue')
|
||||||
var sortField = elem.querySelector('#sortField');
|
var sortField = elem.querySelector('#sortField')
|
||||||
var sortOrder = elem.querySelector('#sortOrder');
|
var sortOrder = elem.querySelector('#sortOrder')
|
||||||
var selectFields = elem.querySelector('#selectFields');
|
var selectFields = elem.querySelector('#selectFields')
|
||||||
var query = elem.querySelector('#query');
|
var query = elem.querySelector('#query')
|
||||||
var preview = elem.querySelector('#preview');
|
var preview = elem.querySelector('#preview')
|
||||||
|
|
||||||
if (!Array.isArray(value)) {
|
if (!Array.isArray(value)) {
|
||||||
wizard.style.fontStyle = 'italic';
|
wizard.style.fontStyle = 'italic'
|
||||||
wizard.innerHTML = '(wizard not available for objects, only for arrays)'
|
wizard.innerHTML = '(wizard not available for objects, only for arrays)'
|
||||||
|
}
|
||||||
|
|
||||||
|
var sortablePaths = util.getChildPaths(json)
|
||||||
|
|
||||||
|
sortablePaths.forEach(function (path) {
|
||||||
|
var formattedPath = preprocessPath(path)
|
||||||
|
var filterOption = document.createElement('option')
|
||||||
|
filterOption.text = formattedPath
|
||||||
|
filterOption.value = formattedPath
|
||||||
|
filterField.appendChild(filterOption)
|
||||||
|
|
||||||
|
var sortOption = document.createElement('option')
|
||||||
|
sortOption.text = formattedPath
|
||||||
|
sortOption.value = formattedPath
|
||||||
|
sortField.appendChild(sortOption)
|
||||||
|
})
|
||||||
|
|
||||||
|
var selectablePaths = util.getChildPaths(json, true).filter(function (path) {
|
||||||
|
return path !== ''
|
||||||
|
})
|
||||||
|
if (selectablePaths.length > 0) {
|
||||||
|
selectablePaths.forEach(function (path) {
|
||||||
|
var formattedPath = preprocessPath(path)
|
||||||
|
var option = document.createElement('option')
|
||||||
|
option.text = formattedPath
|
||||||
|
option.value = formattedPath
|
||||||
|
selectFields.appendChild(option)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
var selectFieldsPart = elem.querySelector('#selectFieldsPart')
|
||||||
|
if (selectFieldsPart) {
|
||||||
|
selectFieldsPart.style.display = 'none'
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var sortablePaths = util.getChildPaths(json);
|
var selectrFilterField = new Selectr(filterField, { defaultSelected: false, clearable: true, allowDeselect: true, placeholder: 'field...' })
|
||||||
|
var selectrFilterRelation = new Selectr(filterRelation, { defaultSelected: false, clearable: true, allowDeselect: true, placeholder: 'compare...' })
|
||||||
|
var selectrSortField = new Selectr(sortField, { defaultSelected: false, clearable: true, allowDeselect: true, placeholder: 'field...' })
|
||||||
|
var selectrSortOrder = new Selectr(sortOrder, { defaultSelected: false, clearable: true, allowDeselect: true, placeholder: 'order...' })
|
||||||
|
var selectrSelectFields = new Selectr(selectFields, { multiple: true, clearable: true, defaultSelected: false, placeholder: 'select fields...' })
|
||||||
|
|
||||||
sortablePaths.forEach(function (path) {
|
selectrFilterField.on('selectr.change', generateQueryFromWizard)
|
||||||
var formattedPath = preprocessPath(path);
|
selectrFilterRelation.on('selectr.change', generateQueryFromWizard)
|
||||||
var filterOption = document.createElement('option');
|
filterValue.oninput = generateQueryFromWizard
|
||||||
filterOption.text = formattedPath;
|
selectrSortField.on('selectr.change', generateQueryFromWizard)
|
||||||
filterOption.value = formattedPath;
|
selectrSortOrder.on('selectr.change', generateQueryFromWizard)
|
||||||
filterField.appendChild(filterOption);
|
selectrSelectFields.on('selectr.change', generateQueryFromWizard)
|
||||||
|
|
||||||
var sortOption = document.createElement('option');
|
elem.querySelector('.pico-modal-contents').onclick = function (event) {
|
||||||
sortOption.text = formattedPath;
|
// prevent the first clear button (in any select box) from getting
|
||||||
sortOption.value = formattedPath;
|
// focus when clicking anywhere in the modal. Only allow clicking links.
|
||||||
sortField.appendChild(sortOption);
|
if (event.target.nodeName !== 'A') {
|
||||||
});
|
event.preventDefault()
|
||||||
|
|
||||||
var selectablePaths = util.getChildPaths(json, true).filter(function(path) {
|
|
||||||
return path !== '';
|
|
||||||
});
|
|
||||||
if (selectablePaths.length > 0) {
|
|
||||||
selectablePaths.forEach(function (path) {
|
|
||||||
var formattedPath = preprocessPath(path);
|
|
||||||
var option = document.createElement('option');
|
|
||||||
option.text = formattedPath;
|
|
||||||
option.value = formattedPath;
|
|
||||||
selectFields.appendChild(option);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
var selectFieldsPart = elem.querySelector('#selectFieldsPart');
|
|
||||||
if (selectFieldsPart) {
|
|
||||||
selectFieldsPart.style.display = 'none';
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var selectrFilterField = new Selectr(filterField, { defaultSelected: false, clearable: true, allowDeselect: true, placeholder: 'field...' });
|
query.value = Array.isArray(value) ? '[*]' : '@'
|
||||||
var selectrFilterRelation = new Selectr(filterRelation, { defaultSelected: false, clearable: true, allowDeselect: true, placeholder: 'compare...' });
|
|
||||||
var selectrSortField = new Selectr(sortField, { defaultSelected: false, clearable: true, allowDeselect: true, placeholder: 'field...' });
|
|
||||||
var selectrSortOrder = new Selectr(sortOrder, { defaultSelected: false, clearable: true, allowDeselect: true, placeholder: 'order...' });
|
|
||||||
var selectrSelectFields = new Selectr(selectFields, {multiple: true, clearable: true, defaultSelected: false, placeholder: 'select fields...'});
|
|
||||||
|
|
||||||
selectrFilterField.on('selectr.change', generateQueryFromWizard);
|
function preprocessPath (path) {
|
||||||
selectrFilterRelation.on('selectr.change', generateQueryFromWizard);
|
return (path === '')
|
||||||
filterValue.oninput = generateQueryFromWizard;
|
? '@'
|
||||||
selectrSortField.on('selectr.change', generateQueryFromWizard);
|
: (path[0] === '.')
|
||||||
selectrSortOrder.on('selectr.change', generateQueryFromWizard);
|
? path.slice(1)
|
||||||
selectrSelectFields.on('selectr.change', generateQueryFromWizard);
|
: path
|
||||||
|
}
|
||||||
|
|
||||||
elem.querySelector('.pico-modal-contents').onclick = function (event) {
|
function generateQueryFromWizard () {
|
||||||
// prevent the first clear button (in any select box) from getting
|
if (filterField.value && filterRelation.value && filterValue.value) {
|
||||||
// focus when clicking anywhere in the modal. Only allow clicking links.
|
var field1 = filterField.value
|
||||||
if (event.target.nodeName !== 'A') {
|
var examplePath = field1 !== '@'
|
||||||
event.preventDefault();
|
? ['0'].concat(util.parsePath('.' + field1))
|
||||||
}
|
: ['0']
|
||||||
};
|
var exampleValue = util.get(value, examplePath)
|
||||||
|
var value1 = typeof exampleValue === 'string'
|
||||||
|
? filterValue.value
|
||||||
|
: util.parseString(filterValue.value)
|
||||||
|
|
||||||
query.value = Array.isArray(value) ? '[*]' : '@';
|
query.value = '[? ' +
|
||||||
|
|
||||||
function preprocessPath(path) {
|
|
||||||
return (path === '')
|
|
||||||
? '@'
|
|
||||||
: (path[0] === '.')
|
|
||||||
? path.slice(1)
|
|
||||||
: path;
|
|
||||||
}
|
|
||||||
|
|
||||||
function generateQueryFromWizard () {
|
|
||||||
if (filterField.value && filterRelation.value && filterValue.value) {
|
|
||||||
var field1 = filterField.value;
|
|
||||||
var examplePath = field1 !== '@'
|
|
||||||
? ['0'].concat(util.parsePath('.' + field1))
|
|
||||||
: ['0']
|
|
||||||
var exampleValue = util.get(value, examplePath)
|
|
||||||
var value1 = typeof exampleValue === 'string'
|
|
||||||
? filterValue.value
|
|
||||||
: util.parseString(filterValue.value);
|
|
||||||
|
|
||||||
query.value = '[? ' +
|
|
||||||
field1 + ' ' +
|
field1 + ' ' +
|
||||||
filterRelation.value + ' ' +
|
filterRelation.value + ' ' +
|
||||||
'`' + JSON.stringify(value1) + '`' +
|
'`' + JSON.stringify(value1) + '`' +
|
||||||
']';
|
']'
|
||||||
}
|
} else {
|
||||||
else {
|
query.value = '[*]'
|
||||||
query.value = '[*]';
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (sortField.value && sortOrder.value) {
|
if (sortField.value && sortOrder.value) {
|
||||||
var field2 = sortField.value;
|
var field2 = sortField.value
|
||||||
if (sortOrder.value === 'desc') {
|
if (sortOrder.value === 'desc') {
|
||||||
query.value += ' | reverse(sort_by(@, &' + field2 + '))';
|
query.value += ' | reverse(sort_by(@, &' + field2 + '))'
|
||||||
}
|
} else {
|
||||||
else {
|
query.value += ' | sort_by(@, &' + field2 + ')'
|
||||||
query.value += ' | sort_by(@, &' + field2 + ')';
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selectFields.value) {
|
||||||
|
var values = []
|
||||||
|
for (var i = 0; i < selectFields.options.length; i++) {
|
||||||
|
if (selectFields.options[i].selected) {
|
||||||
|
var selectedValue = selectFields.options[i].value
|
||||||
|
values.push(selectedValue)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (selectFields.value) {
|
if (query.value[query.value.length - 1] !== ']') {
|
||||||
var values = [];
|
query.value += ' | [*]'
|
||||||
for (var i=0; i < selectFields.options.length; i++) {
|
}
|
||||||
if (selectFields.options[i].selected) {
|
|
||||||
var selectedValue = selectFields.options[i].value;
|
|
||||||
values.push(selectedValue);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (query.value[query.value.length - 1] !== ']') {
|
if (values.length === 1) {
|
||||||
query.value += ' | [*]';
|
query.value += '.' + values[0]
|
||||||
}
|
} else if (values.length > 1) {
|
||||||
|
query.value += '.{' +
|
||||||
if (values.length === 1) {
|
|
||||||
query.value += '.' + values[0];
|
|
||||||
}
|
|
||||||
else if (values.length > 1) {
|
|
||||||
query.value += '.{' +
|
|
||||||
values.map(function (value) {
|
values.map(function (value) {
|
||||||
var parts = value.split('.');
|
var parts = value.split('.')
|
||||||
var last = parts[parts.length - 1];
|
var last = parts[parts.length - 1]
|
||||||
return last + ': ' + value;
|
return last + ': ' + value
|
||||||
}).join(', ') +
|
}).join(', ') +
|
||||||
'}';
|
'}'
|
||||||
}
|
} else { // values.length === 0
|
||||||
else { // values.length === 0
|
// ignore
|
||||||
// ignore
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
debouncedUpdatePreview();
|
|
||||||
}
|
|
||||||
|
|
||||||
function updatePreview() {
|
|
||||||
try {
|
|
||||||
var transformed = jmespath.search(value, query.value);
|
|
||||||
|
|
||||||
preview.className = 'jsoneditor-transform-preview';
|
|
||||||
preview.value = stringifyPartial(transformed, 2, MAX_PREVIEW_CHARACTERS);
|
|
||||||
|
|
||||||
ok.disabled = false;
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
preview.className = 'jsoneditor-transform-preview jsoneditor-error';
|
|
||||||
preview.value = err.toString();
|
|
||||||
ok.disabled = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var debouncedUpdatePreview = debounce(updatePreview, 300);
|
debouncedUpdatePreview()
|
||||||
|
}
|
||||||
|
|
||||||
query.oninput = debouncedUpdatePreview;
|
function updatePreview () {
|
||||||
debouncedUpdatePreview();
|
try {
|
||||||
|
var transformed = jmespath.search(value, query.value)
|
||||||
|
|
||||||
ok.onclick = function (event) {
|
preview.className = 'jsoneditor-transform-preview'
|
||||||
event.preventDefault();
|
preview.value = stringifyPartial(transformed, 2, MAX_PREVIEW_CHARACTERS)
|
||||||
event.stopPropagation();
|
|
||||||
|
|
||||||
modal.close();
|
ok.disabled = false
|
||||||
|
} catch (err) {
|
||||||
|
preview.className = 'jsoneditor-transform-preview jsoneditor-error'
|
||||||
|
preview.value = err.toString()
|
||||||
|
ok.disabled = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onTransform(query.value)
|
var debouncedUpdatePreview = debounce(updatePreview, 300)
|
||||||
};
|
|
||||||
|
|
||||||
setTimeout(function () {
|
query.oninput = debouncedUpdatePreview
|
||||||
query.select();
|
debouncedUpdatePreview()
|
||||||
query.focus();
|
|
||||||
query.selectionStart = 3;
|
ok.onclick = function (event) {
|
||||||
query.selectionEnd = 3;
|
event.preventDefault()
|
||||||
});
|
event.stopPropagation()
|
||||||
|
|
||||||
|
modal.close()
|
||||||
|
|
||||||
|
onTransform(query.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
setTimeout(function () {
|
||||||
|
query.select()
|
||||||
|
query.focus()
|
||||||
|
query.selectionStart = 3
|
||||||
|
query.selectionEnd = 3
|
||||||
})
|
})
|
||||||
.afterClose(function (modal) {
|
})
|
||||||
modal.destroy();
|
.afterClose(function (modal) {
|
||||||
})
|
modal.destroy()
|
||||||
.show();
|
})
|
||||||
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = showTransformModal;
|
module.exports = showTransformModal
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
1533
src/js/treemode.js
1533
src/js/treemode.js
File diff suppressed because it is too large
Load Diff
1115
src/js/util.js
1115
src/js/util.js
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
||||||
var isPromise = require('./util').isPromise;
|
var isPromise = require('./util').isPromise
|
||||||
var isValidValidationError = require('./util').isValidValidationError;
|
var isValidValidationError = require('./util').isValidValidationError
|
||||||
var stringifyPath = require('./util').stringifyPath;
|
var stringifyPath = require('./util').stringifyPath
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute custom validation if configured.
|
* Execute custom validation if configured.
|
||||||
|
@ -9,46 +9,44 @@ var stringifyPath = require('./util').stringifyPath;
|
||||||
*/
|
*/
|
||||||
function validateCustom (json, onValidate) {
|
function validateCustom (json, onValidate) {
|
||||||
if (!onValidate) {
|
if (!onValidate) {
|
||||||
return Promise.resolve([]);
|
return Promise.resolve([])
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
var customValidateResults = onValidate(json);
|
var customValidateResults = onValidate(json)
|
||||||
|
|
||||||
var resultPromise = isPromise(customValidateResults)
|
var resultPromise = isPromise(customValidateResults)
|
||||||
? customValidateResults
|
? customValidateResults
|
||||||
: Promise.resolve(customValidateResults);
|
: Promise.resolve(customValidateResults)
|
||||||
|
|
||||||
return resultPromise.then(function (customValidationPathErrors) {
|
return resultPromise.then(function (customValidationPathErrors) {
|
||||||
if (Array.isArray(customValidationPathErrors)) {
|
if (Array.isArray(customValidationPathErrors)) {
|
||||||
return customValidationPathErrors
|
return customValidationPathErrors
|
||||||
.filter(function (error) {
|
.filter(function (error) {
|
||||||
var valid = isValidValidationError(error);
|
var valid = isValidValidationError(error)
|
||||||
|
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
console.warn('Ignoring a custom validation error with invalid structure. ' +
|
console.warn('Ignoring a custom validation error with invalid structure. ' +
|
||||||
'Expected structure: {path: [...], message: "..."}. ' +
|
'Expected structure: {path: [...], message: "..."}. ' +
|
||||||
'Actual error:', error);
|
'Actual error:', error)
|
||||||
}
|
}
|
||||||
|
|
||||||
return valid;
|
return valid
|
||||||
})
|
})
|
||||||
.map(function (error) {
|
.map(function (error) {
|
||||||
// change data structure into the structure matching the JSON schema errors
|
// change data structure into the structure matching the JSON schema errors
|
||||||
return {
|
return {
|
||||||
dataPath: stringifyPath(error.path),
|
dataPath: stringifyPath(error.path),
|
||||||
message: error.message
|
message: error.message
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
} else {
|
||||||
|
return []
|
||||||
}
|
}
|
||||||
else {
|
})
|
||||||
return [];
|
} catch (err) {
|
||||||
}
|
return Promise.reject(err)
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (err) {
|
|
||||||
return Promise.reject(err);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.validateCustom = validateCustom;
|
exports.validateCustom = validateCustom
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
var VanillaPicker;
|
var VanillaPicker
|
||||||
|
|
||||||
if (window.Picker) {
|
if (window.Picker) {
|
||||||
// use the already loaded instance of VanillaPicker
|
// use the already loaded instance of VanillaPicker
|
||||||
VanillaPicker = window.Picker;
|
VanillaPicker = window.Picker
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
try {
|
try {
|
||||||
// load color picker
|
// load color picker
|
||||||
VanillaPicker = require('vanilla-picker');
|
VanillaPicker = require('vanilla-picker')
|
||||||
}
|
} catch (err) {
|
||||||
catch (err) {
|
|
||||||
// probably running the minimalist bundle
|
// probably running the minimalist bundle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = VanillaPicker;
|
module.exports = VanillaPicker
|
||||||
|
|
|
@ -1,295 +1,287 @@
|
||||||
var assert = require('assert');
|
var assert = require('assert')
|
||||||
var setUpTestEnvironment = require('./setup');
|
var setUpTestEnvironment = require('./setup')
|
||||||
setUpTestEnvironment();
|
setUpTestEnvironment()
|
||||||
|
|
||||||
var JSONEditor = require('../src/js/JSONEditor');
|
var Node = require('../src/js/Node')
|
||||||
var Node = require('../src/js/Node');
|
|
||||||
|
|
||||||
describe('Node', function () {
|
describe('Node', function () {
|
||||||
var node;
|
describe('_findSchema', function () {
|
||||||
|
it('should find schema', function () {
|
||||||
beforeEach(function () {
|
var schema = {
|
||||||
var editor = new JSONEditor(document.createElement('foo'));
|
type: 'object',
|
||||||
node = new Node(editor);
|
properties: {
|
||||||
});
|
child: {
|
||||||
|
type: 'string'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var path = ['child']
|
||||||
|
assert.strictEqual(Node._findSchema(schema, {}, path), schema.properties.child)
|
||||||
|
})
|
||||||
|
|
||||||
describe('_findSchema', function () {
|
it('should find schema inside an array item', function () {
|
||||||
it('should find schema', function () {
|
var schema = {
|
||||||
var schema = {
|
properties: {
|
||||||
|
job: {
|
||||||
|
type: 'array',
|
||||||
|
items: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
company: {
|
||||||
|
enum: ['test1', 'test2']
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.strictEqual(Node._findSchema(schema, {}, []), schema)
|
||||||
|
|
||||||
|
assert.strictEqual(Node._findSchema(schema, {}, ['job']), schema.properties.job)
|
||||||
|
|
||||||
|
assert.strictEqual(Node._findSchema(schema, {}, ['job', 0]),
|
||||||
|
schema.properties.job.items)
|
||||||
|
|
||||||
|
assert.strictEqual(Node._findSchema(schema, {}, ['job', 0, 'company']),
|
||||||
|
schema.properties.job.items.properties.company)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should find schema within multi-level object properties', function () {
|
||||||
|
var schema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
levelTwo: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
levelThree: {
|
||||||
type: 'object',
|
type: 'object',
|
||||||
properties: {
|
properties: {
|
||||||
child: {
|
bool: {
|
||||||
type: 'string'
|
type: 'boolean'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
var path = ['child'];
|
}
|
||||||
assert.strictEqual(Node._findSchema(schema, {}, path), schema.properties.child);
|
}
|
||||||
});
|
}
|
||||||
|
}
|
||||||
|
var path = []
|
||||||
|
assert.strictEqual(Node._findSchema(schema, {}, path), schema)
|
||||||
|
path = ['levelTwo']
|
||||||
|
assert.strictEqual(Node._findSchema(schema, {}, path), schema.properties.levelTwo)
|
||||||
|
path = ['levelTwo', 'levelThree']
|
||||||
|
assert.strictEqual(Node._findSchema(schema, {}, path), schema.properties.levelTwo.properties.levelThree)
|
||||||
|
path = ['levelTwo', 'levelThree', 'bool']
|
||||||
|
assert.strictEqual(
|
||||||
|
Node._findSchema(schema, {}, path),
|
||||||
|
schema.properties.levelTwo.properties.levelThree.properties.bool
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
it('should find schema inside an array item', function () {
|
it('should return null for path that has no schema', function () {
|
||||||
var schema = {
|
var schema = {
|
||||||
properties: {
|
type: 'object',
|
||||||
job: {
|
properties: {
|
||||||
type: 'array',
|
foo: {
|
||||||
items: {
|
type: 'object',
|
||||||
type: 'object',
|
properties: {
|
||||||
properties: {
|
baz: {
|
||||||
company: {
|
type: 'number'
|
||||||
enum: ['test1', 'test2']
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
var path = ['bar']
|
||||||
|
assert.strictEqual(Node._findSchema(schema, {}, path), null)
|
||||||
|
path = ['foo', 'bar']
|
||||||
|
assert.strictEqual(Node._findSchema(schema, {}, path), null)
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with $ref', function () {
|
||||||
|
it('should find a referenced schema', function () {
|
||||||
|
var schema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
foo: {
|
||||||
|
$ref: 'foo'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var fooSchema = {
|
||||||
|
type: 'number',
|
||||||
|
title: 'Foo'
|
||||||
|
}
|
||||||
|
var path = ['foo']
|
||||||
|
assert.strictEqual(Node._findSchema(schema, { foo: fooSchema }, path), fooSchema)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe('with pattern properties', function () {
|
||||||
|
it('should find schema', function () {
|
||||||
|
var schema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
str: {
|
||||||
|
title: 'str',
|
||||||
|
type: 'boolean'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
patternProperties: {
|
||||||
|
'^foo[0-9]': {
|
||||||
|
title: 'foo[0-] pattern property',
|
||||||
|
type: 'string'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var path = []
|
||||||
|
assert.strictEqual(Node._findSchema(schema, {}, path), schema, 'top level')
|
||||||
|
path = ['str']
|
||||||
|
assert.strictEqual(Node._findSchema(schema, {}, path), schema.properties.str, 'normal property')
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should find schema within multi-level object properties', function () {
|
||||||
|
var schema = {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
levelTwo: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
levelThree: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
bool: {
|
||||||
|
title: 'bool',
|
||||||
|
type: 'boolean'
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
patternProperties: {
|
||||||
|
'^foo[0-9]': {
|
||||||
|
title: 'foo[0-9] pattern property',
|
||||||
|
type: 'string'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var path = []
|
||||||
|
assert.strictEqual(Node._findSchema(schema, {}, path), schema, 'top level')
|
||||||
|
path = ['levelTwo']
|
||||||
|
assert.strictEqual(Node._findSchema(schema, {}, path), schema.properties.levelTwo, 'level two')
|
||||||
|
path = ['levelTwo', 'levelThree']
|
||||||
|
assert.strictEqual(Node._findSchema(schema, {}, path), schema.properties.levelTwo.properties.levelThree, 'level three')
|
||||||
|
path = ['levelTwo', 'levelThree', 'bool']
|
||||||
|
assert.strictEqual(
|
||||||
|
Node._findSchema(schema, {}, path),
|
||||||
|
schema.properties.levelTwo.properties.levelThree.properties.bool,
|
||||||
|
'normal property'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
assert.strictEqual(Node._findSchema(schema, {}, []), schema);
|
it('should find schema for pattern properties', function () {
|
||||||
|
var schema = {
|
||||||
|
type: 'object',
|
||||||
|
patternProperties: {
|
||||||
|
'^foo[0-9]': {
|
||||||
|
title: 'foo[0-9] pattern property',
|
||||||
|
type: 'string'
|
||||||
|
},
|
||||||
|
'^bar[0-9]': {
|
||||||
|
title: 'bar[0-9] pattern property',
|
||||||
|
type: 'string'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var path = ['foo1']
|
||||||
|
assert.strictEqual(
|
||||||
|
Node._findSchema(schema, {}, path),
|
||||||
|
schema.patternProperties['^foo[0-9]'],
|
||||||
|
'first pattern property'
|
||||||
|
)
|
||||||
|
path = ['bar5']
|
||||||
|
assert.strictEqual(
|
||||||
|
Node._findSchema(schema, {}, path),
|
||||||
|
schema.patternProperties['^bar[0-9]'],
|
||||||
|
'second pattern property'
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
assert.strictEqual(Node._findSchema(schema, {}, ['job']), schema.properties.job);
|
it('should find schema for multi-level pattern properties', function () {
|
||||||
|
var schema = {
|
||||||
assert.strictEqual(Node._findSchema(schema, {}, ['job', 0]),
|
type: 'object',
|
||||||
schema.properties.job.items);
|
patternProperties: {
|
||||||
|
'^foo[0-9]': {
|
||||||
assert.strictEqual(Node._findSchema(schema, {}, ['job', 0, 'company']),
|
title: 'foo[0-9] pattern property',
|
||||||
schema.properties.job.items.properties.company);
|
type: 'object',
|
||||||
});
|
properties: {
|
||||||
|
fooChild: {
|
||||||
it('should find schema within multi-level object properties', function () {
|
type: 'object',
|
||||||
var schema = {
|
properties: {
|
||||||
type: 'object',
|
fooChild2: {
|
||||||
properties: {
|
type: 'string'
|
||||||
levelTwo: {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
levelThree: {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
bool: {
|
|
||||||
type: 'boolean'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
var path = [];
|
},
|
||||||
assert.strictEqual(Node._findSchema(schema, {}, path), schema);
|
'^bar[0-9]': {
|
||||||
path = ['levelTwo'];
|
title: 'bar[0-9] pattern property',
|
||||||
assert.strictEqual(Node._findSchema(schema, {}, path), schema.properties.levelTwo);
|
type: 'object',
|
||||||
path = ['levelTwo', 'levelThree'];
|
properties: {
|
||||||
assert.strictEqual(Node._findSchema(schema, {}, path), schema.properties.levelTwo.properties.levelThree);
|
barChild: {
|
||||||
path = ['levelTwo', 'levelThree', 'bool'];
|
type: 'string'
|
||||||
assert.strictEqual(
|
|
||||||
Node._findSchema(schema, {}, path),
|
|
||||||
schema.properties.levelTwo.properties.levelThree.properties.bool
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return null for path that has no schema', function () {
|
|
||||||
var schema = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
foo: {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
baz: {
|
|
||||||
type: 'number'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
|
||||||
var path = ['bar'];
|
|
||||||
assert.strictEqual(Node._findSchema(schema, {}, path), null);
|
|
||||||
path = ['foo', 'bar'];
|
|
||||||
assert.strictEqual(Node._findSchema(schema, {}, path), null);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('with $ref', function () {
|
}
|
||||||
it('should find a referenced schema', function () {
|
}
|
||||||
var schema = {
|
}
|
||||||
type: 'object',
|
}
|
||||||
properties: {
|
var path = ['foo1', 'fooChild', 'fooChild2']
|
||||||
foo: {
|
assert.strictEqual(
|
||||||
$ref: 'foo'
|
Node._findSchema(schema, {}, path),
|
||||||
}
|
schema.patternProperties['^foo[0-9]'].properties.fooChild.properties.fooChild2,
|
||||||
}
|
'first pattern property child of child'
|
||||||
};
|
)
|
||||||
var fooSchema = {
|
path = ['bar5', 'barChild']
|
||||||
type: 'number',
|
assert.strictEqual(
|
||||||
title: 'Foo'
|
Node._findSchema(schema, {}, path),
|
||||||
};
|
schema.patternProperties['^bar[0-9]'].properties.barChild,
|
||||||
var path = ['foo'];
|
'second pattern property child'
|
||||||
assert.strictEqual(Node._findSchema(schema, {foo: fooSchema}, path), fooSchema);
|
)
|
||||||
});
|
})
|
||||||
});
|
|
||||||
|
|
||||||
describe('with pattern properties', function () {
|
it('should return null for path that has no schema', function () {
|
||||||
it('should find schema', function () {
|
var schema = {
|
||||||
var schema = {
|
type: 'object',
|
||||||
type: 'object',
|
properties: {
|
||||||
properties: {
|
levelTwo: {
|
||||||
str: {
|
type: 'object',
|
||||||
title: 'str',
|
properties: {
|
||||||
type: 'boolean'
|
levelThree: {
|
||||||
}
|
type: 'number'
|
||||||
},
|
}
|
||||||
patternProperties: {
|
}
|
||||||
'^foo[0-9]': {
|
}
|
||||||
title: 'foo[0-] pattern property',
|
},
|
||||||
type: 'string'
|
patternProperties: {
|
||||||
}
|
'^foo[0-9]': {
|
||||||
}
|
title: 'foo[0-9] pattern property',
|
||||||
};
|
type: 'string'
|
||||||
var path = [];
|
},
|
||||||
assert.strictEqual(Node._findSchema(schema, {}, path), schema, 'top level');
|
'^bar[0-9]': {
|
||||||
path = ['str'];
|
title: 'bar[0-9] pattern property',
|
||||||
assert.strictEqual(Node._findSchema(schema, {}, path), schema.properties.str, 'normal property');
|
type: 'string'
|
||||||
});
|
}
|
||||||
|
}
|
||||||
it('should find schema within multi-level object properties', function () {
|
}
|
||||||
var schema = {
|
var path = ['not-in-schema']
|
||||||
type: 'object',
|
assert.strictEqual(Node._findSchema(schema, {}, path), null)
|
||||||
properties: {
|
path = ['levelOne', 'not-in-schema']
|
||||||
levelTwo: {
|
assert.strictEqual(Node._findSchema(schema, {}, path), null)
|
||||||
type: 'object',
|
})
|
||||||
properties: {
|
})
|
||||||
levelThree: {
|
})
|
||||||
type: 'object',
|
})
|
||||||
properties: {
|
|
||||||
bool: {
|
|
||||||
title: 'bool',
|
|
||||||
type: 'boolean'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
patternProperties: {
|
|
||||||
'^foo[0-9]': {
|
|
||||||
title: 'foo[0-9] pattern property',
|
|
||||||
type: 'string'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var path = [];
|
|
||||||
assert.strictEqual(Node._findSchema(schema, {}, path), schema, 'top level');
|
|
||||||
path = ['levelTwo'];
|
|
||||||
assert.strictEqual(Node._findSchema(schema, {}, path), schema.properties.levelTwo, 'level two');
|
|
||||||
path = ['levelTwo', 'levelThree'];
|
|
||||||
assert.strictEqual(Node._findSchema(schema, {}, path), schema.properties.levelTwo.properties.levelThree, 'level three');
|
|
||||||
path = ['levelTwo', 'levelThree', 'bool'];
|
|
||||||
assert.strictEqual(
|
|
||||||
Node._findSchema(schema, {}, path),
|
|
||||||
schema.properties.levelTwo.properties.levelThree.properties.bool,
|
|
||||||
'normal property'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should find schema for pattern properties', function () {
|
|
||||||
var schema = {
|
|
||||||
type: 'object',
|
|
||||||
patternProperties: {
|
|
||||||
'^foo[0-9]': {
|
|
||||||
title: 'foo[0-9] pattern property',
|
|
||||||
type: 'string'
|
|
||||||
},
|
|
||||||
'^bar[0-9]': {
|
|
||||||
title: 'bar[0-9] pattern property',
|
|
||||||
type: 'string'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var path = ['foo1'];
|
|
||||||
assert.strictEqual(
|
|
||||||
Node._findSchema(schema, {}, path),
|
|
||||||
schema.patternProperties['^foo[0-9]'],
|
|
||||||
'first pattern property'
|
|
||||||
);
|
|
||||||
path = ['bar5'];
|
|
||||||
assert.strictEqual(
|
|
||||||
Node._findSchema(schema, {}, path),
|
|
||||||
schema.patternProperties['^bar[0-9]'],
|
|
||||||
'second pattern property'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should find schema for multi-level pattern properties', function () {
|
|
||||||
var schema = {
|
|
||||||
type: 'object',
|
|
||||||
patternProperties: {
|
|
||||||
'^foo[0-9]': {
|
|
||||||
title: 'foo[0-9] pattern property',
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
fooChild: {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
fooChild2: {
|
|
||||||
type: 'string'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'^bar[0-9]': {
|
|
||||||
title: 'bar[0-9] pattern property',
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
barChild: {
|
|
||||||
type: 'string'
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var path = ['foo1', 'fooChild', 'fooChild2'];
|
|
||||||
assert.strictEqual(
|
|
||||||
Node._findSchema(schema, {}, path),
|
|
||||||
schema.patternProperties['^foo[0-9]'].properties.fooChild.properties.fooChild2,
|
|
||||||
'first pattern property child of child'
|
|
||||||
);
|
|
||||||
path = ['bar5', 'barChild'];
|
|
||||||
assert.strictEqual(
|
|
||||||
Node._findSchema(schema, {}, path),
|
|
||||||
schema.patternProperties['^bar[0-9]'].properties.barChild,
|
|
||||||
'second pattern property child'
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return null for path that has no schema', function () {
|
|
||||||
var schema = {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
levelTwo: {
|
|
||||||
type: 'object',
|
|
||||||
properties: {
|
|
||||||
levelThree: {
|
|
||||||
type: 'number'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
patternProperties: {
|
|
||||||
'^foo[0-9]': {
|
|
||||||
title: 'foo[0-9] pattern property',
|
|
||||||
type: 'string'
|
|
||||||
},
|
|
||||||
'^bar[0-9]': {
|
|
||||||
title: 'bar[0-9] pattern property',
|
|
||||||
type: 'string'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
var path = ['not-in-schema'];
|
|
||||||
assert.strictEqual(Node._findSchema(schema, {}, path), null);
|
|
||||||
path = ['levelOne', 'not-in-schema'];
|
|
||||||
assert.strictEqual(Node._findSchema(schema, {}, path), null);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
|
@ -1,21 +1,20 @@
|
||||||
var assert = require('assert');
|
var assert = require('assert')
|
||||||
var stringifyPartial = require('../src/js/jsonUtils').stringifyPartial;
|
var stringifyPartial = require('../src/js/jsonUtils').stringifyPartial
|
||||||
var containsArray = require('../src/js/jsonUtils').containsArray;
|
var containsArray = require('../src/js/jsonUtils').containsArray
|
||||||
|
|
||||||
describe('jsonUtils', function () {
|
describe('jsonUtils', function () {
|
||||||
|
|
||||||
it('should stringify a small object', function () {
|
it('should stringify a small object', function () {
|
||||||
var json = {
|
var json = {
|
||||||
a: 2,
|
a: 2,
|
||||||
b: 'foo',
|
b: 'foo',
|
||||||
c: null,
|
c: null,
|
||||||
d: false,
|
d: false,
|
||||||
e: [ 1, 2, 3],
|
e: [1, 2, 3],
|
||||||
f: { g: 'h' }
|
f: { g: 'h' }
|
||||||
};
|
}
|
||||||
|
|
||||||
assert.strictEqual(stringifyPartial(json), '{"a":2,"b":"foo","c":null,"d":false,"e":[1,2,3],"f":{"g":"h"}}');
|
assert.strictEqual(stringifyPartial(json), '{"a":2,"b":"foo","c":null,"d":false,"e":[1,2,3],"f":{"g":"h"}}')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should stringify a small object with formatting', function () {
|
it('should stringify a small object with formatting', function () {
|
||||||
var json = {
|
var json = {
|
||||||
|
@ -23,12 +22,12 @@ describe('jsonUtils', function () {
|
||||||
b: 'foo',
|
b: 'foo',
|
||||||
c: null,
|
c: null,
|
||||||
d: false,
|
d: false,
|
||||||
e: [ 1, 2, 3],
|
e: [1, 2, 3],
|
||||||
f: { g: 'h' }
|
f: { g: 'h' }
|
||||||
};
|
}
|
||||||
|
|
||||||
assert.strictEqual(stringifyPartial(json, 2),
|
assert.strictEqual(stringifyPartial(json, 2),
|
||||||
'{\n' +
|
'{\n' +
|
||||||
' "a": 2,\n' +
|
' "a": 2,\n' +
|
||||||
' "b": "foo",\n' +
|
' "b": "foo",\n' +
|
||||||
' "c": null,\n' +
|
' "c": null,\n' +
|
||||||
|
@ -41,7 +40,7 @@ describe('jsonUtils', function () {
|
||||||
' "f": {\n' +
|
' "f": {\n' +
|
||||||
' "g": "h"\n' +
|
' "g": "h"\n' +
|
||||||
' }\n' +
|
' }\n' +
|
||||||
'}');
|
'}')
|
||||||
|
|
||||||
assert.strictEqual(stringifyPartial(json, ' '), '{\n' +
|
assert.strictEqual(stringifyPartial(json, ' '), '{\n' +
|
||||||
' "a": 2,\n' +
|
' "a": 2,\n' +
|
||||||
|
@ -56,8 +55,8 @@ describe('jsonUtils', function () {
|
||||||
' "f": {\n' +
|
' "f": {\n' +
|
||||||
' "g": "h"\n' +
|
' "g": "h"\n' +
|
||||||
' }\n' +
|
' }\n' +
|
||||||
'}');
|
'}')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should limit stringified output', function () {
|
it('should limit stringified output', function () {
|
||||||
var json = {
|
var json = {
|
||||||
|
@ -65,23 +64,23 @@ describe('jsonUtils', function () {
|
||||||
b: 'foo',
|
b: 'foo',
|
||||||
c: null,
|
c: null,
|
||||||
d: false,
|
d: false,
|
||||||
e: [ 1, 2, 3],
|
e: [1, 2, 3],
|
||||||
f: { g: 'h' }
|
f: { g: 'h' }
|
||||||
};
|
}
|
||||||
|
|
||||||
var all = '{"a":2,"b":"foo","c":null,"d":false,"e":[1,2,3],"f":{"g":"h"}}';
|
var all = '{"a":2,"b":"foo","c":null,"d":false,"e":[1,2,3],"f":{"g":"h"}}'
|
||||||
var limit = 20;
|
var limit = 20
|
||||||
|
|
||||||
assert.strictEqual(stringifyPartial(json, undefined, limit),
|
assert.strictEqual(stringifyPartial(json, undefined, limit),
|
||||||
all.slice(0, limit) + '...');
|
all.slice(0, limit) + '...')
|
||||||
|
|
||||||
assert.strictEqual(stringifyPartial(json, undefined, all.length), all);
|
assert.strictEqual(stringifyPartial(json, undefined, all.length), all)
|
||||||
|
|
||||||
assert.strictEqual(stringifyPartial([1,2,3,4,5,6,7,8,9,10], undefined, 10),
|
assert.strictEqual(stringifyPartial([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], undefined, 10),
|
||||||
'[1,2,3,4,5...');
|
'[1,2,3,4,5...')
|
||||||
|
|
||||||
assert.strictEqual(stringifyPartial(12345678, undefined, 4),'1234...');
|
assert.strictEqual(stringifyPartial(12345678, undefined, 4), '1234...')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should count array items', function () {
|
it('should count array items', function () {
|
||||||
// assert.strictEqual(countArrayItems('[1,2,3]'), 3)
|
// assert.strictEqual(countArrayItems('[1,2,3]'), 3)
|
||||||
|
@ -93,6 +92,5 @@ describe('jsonUtils', function () {
|
||||||
assert.strictEqual(containsArray('2'), false)
|
assert.strictEqual(containsArray('2'), false)
|
||||||
assert.strictEqual(containsArray('null'), false)
|
assert.strictEqual(containsArray('null'), false)
|
||||||
assert.strictEqual(containsArray('{}'), false)
|
assert.strictEqual(containsArray('{}'), false)
|
||||||
});
|
})
|
||||||
|
})
|
||||||
});
|
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
var JSDOM = require('jsdom').JSDOM;
|
var JSDOM = require('jsdom').JSDOM
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set up the test environment by simulating browser globals.
|
* Set up the test environment by simulating browser globals.
|
||||||
* @param {string} [locale=en] A locale to set in navigator.language
|
* @param {string} [locale=en] A locale to set in navigator.language
|
||||||
* @return {void}
|
* @return {void}
|
||||||
*/
|
*/
|
||||||
module.exports = function setUpTestEnvironment(locale) {
|
module.exports = function setUpTestEnvironment (locale) {
|
||||||
if (!locale) {
|
if (!locale) {
|
||||||
locale = 'en'
|
locale = 'en'
|
||||||
}
|
}
|
||||||
|
|
||||||
var dom = new JSDOM('...');
|
var dom = new JSDOM('...')
|
||||||
global.window = dom.window;
|
global.window = dom.window
|
||||||
global.document = dom.window.document;
|
global.document = dom.window.document
|
||||||
global.navigator = dom.window.navigator;
|
global.navigator = dom.window.navigator
|
||||||
|
|
||||||
// JSDom has no setter defined for navigator.language, so defineProperty is necessary in order to override it
|
// JSDom has no setter defined for navigator.language, so defineProperty is necessary in order to override it
|
||||||
Object.defineProperty(navigator, 'language', {value: locale})
|
Object.defineProperty(navigator, 'language', { value: locale })
|
||||||
};
|
}
|
||||||
|
|
|
@ -1,38 +1,36 @@
|
||||||
var assert = require('assert');
|
var assert = require('assert')
|
||||||
var util = require('../src/js/util');
|
var util = require('../src/js/util')
|
||||||
|
|
||||||
describe('util', function () {
|
describe('util', function () {
|
||||||
|
|
||||||
describe('repair', function () {
|
describe('repair', function () {
|
||||||
|
|
||||||
it('should leave valid JSON as is', function () {
|
it('should leave valid JSON as is', function () {
|
||||||
assert.strictEqual(util.repair('{"a":2}'), '{"a":2}');
|
assert.strictEqual(util.repair('{"a":2}'), '{"a":2}')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should replace JavaScript with JSON', function () {
|
it('should replace JavaScript with JSON', function () {
|
||||||
assert.strictEqual(util.repair('{a:2}'), '{"a":2}');
|
assert.strictEqual(util.repair('{a:2}'), '{"a":2}')
|
||||||
assert.strictEqual(util.repair('{a: 2}'), '{"a": 2}');
|
assert.strictEqual(util.repair('{a: 2}'), '{"a": 2}')
|
||||||
assert.strictEqual(util.repair('{\n a: 2\n}'), '{\n "a": 2\n}');
|
assert.strictEqual(util.repair('{\n a: 2\n}'), '{\n "a": 2\n}')
|
||||||
assert.strictEqual(util.repair('{\'a\':2}'), '{"a":2}');
|
assert.strictEqual(util.repair('{\'a\':2}'), '{"a":2}')
|
||||||
assert.strictEqual(util.repair('{a:\'foo\'}'), '{"a":"foo"}');
|
assert.strictEqual(util.repair('{a:\'foo\'}'), '{"a":"foo"}')
|
||||||
assert.strictEqual(util.repair('{a:\'foo\',b:\'bar\'}'), '{"a":"foo","b":"bar"}');
|
assert.strictEqual(util.repair('{a:\'foo\',b:\'bar\'}'), '{"a":"foo","b":"bar"}')
|
||||||
|
|
||||||
// should leave string content untouched
|
// should leave string content untouched
|
||||||
assert.strictEqual(util.repair('"{a:b}"'), '"{a:b}"');
|
assert.strictEqual(util.repair('"{a:b}"'), '"{a:b}"')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should add/remove escape characters', function () {
|
it('should add/remove escape characters', function () {
|
||||||
assert.strictEqual(util.repair('"foo\'bar"'), '"foo\'bar"');
|
assert.strictEqual(util.repair('"foo\'bar"'), '"foo\'bar"')
|
||||||
assert.strictEqual(util.repair('"foo\\"bar"'), '"foo\\"bar"');
|
assert.strictEqual(util.repair('"foo\\"bar"'), '"foo\\"bar"')
|
||||||
assert.strictEqual(util.repair('\'foo"bar\''), '"foo\\"bar"');
|
assert.strictEqual(util.repair('\'foo"bar\''), '"foo\\"bar"')
|
||||||
assert.strictEqual(util.repair('\'foo\\\'bar\''), '"foo\'bar"');
|
assert.strictEqual(util.repair('\'foo\\\'bar\''), '"foo\'bar"')
|
||||||
assert.strictEqual(util.repair('"foo\\\'bar"'), '"foo\'bar"');
|
assert.strictEqual(util.repair('"foo\\\'bar"'), '"foo\'bar"')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should replace special white characters', function () {
|
it('should replace special white characters', function () {
|
||||||
assert.strictEqual(util.repair('{"a":\u00a0"foo\u00a0bar"}'), '{"a": "foo\u00a0bar"}');
|
assert.strictEqual(util.repair('{"a":\u00a0"foo\u00a0bar"}'), '{"a": "foo\u00a0bar"}')
|
||||||
assert.strictEqual(util.repair('{"a":\u2009"foo"}'), '{"a": "foo"}');
|
assert.strictEqual(util.repair('{"a":\u2009"foo"}'), '{"a": "foo"}')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should escape unescaped control characters', function () {
|
it('should escape unescaped control characters', function () {
|
||||||
assert.strictEqual(util.repair('"hello\bworld"'), '"hello\\bworld"')
|
assert.strictEqual(util.repair('"hello\bworld"'), '"hello\\bworld"')
|
||||||
|
@ -47,50 +45,50 @@ describe('util', function () {
|
||||||
assert.strictEqual(util.repair('\u2018foo\u2019'), '"foo"')
|
assert.strictEqual(util.repair('\u2018foo\u2019'), '"foo"')
|
||||||
assert.strictEqual(util.repair('\u201Cfoo\u201D'), '"foo"')
|
assert.strictEqual(util.repair('\u201Cfoo\u201D'), '"foo"')
|
||||||
assert.strictEqual(util.repair('\u0060foo\u00B4'), '"foo"')
|
assert.strictEqual(util.repair('\u0060foo\u00B4'), '"foo"')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('remove comments', function () {
|
it('remove comments', function () {
|
||||||
assert.strictEqual(util.repair('/* foo */ {}'), ' {}');
|
assert.strictEqual(util.repair('/* foo */ {}'), ' {}')
|
||||||
assert.strictEqual(util.repair('/* foo */ {}'), ' {}');
|
assert.strictEqual(util.repair('/* foo */ {}'), ' {}')
|
||||||
assert.strictEqual(util.repair('{a:\'foo\',/*hello*/b:\'bar\'}'), '{"a":"foo","b":"bar"}');
|
assert.strictEqual(util.repair('{a:\'foo\',/*hello*/b:\'bar\'}'), '{"a":"foo","b":"bar"}')
|
||||||
assert.strictEqual(util.repair('{\na:\'foo\',//hello\nb:\'bar\'\n}'), '{\n"a":"foo",\n"b":"bar"\n}');
|
assert.strictEqual(util.repair('{\na:\'foo\',//hello\nb:\'bar\'\n}'), '{\n"a":"foo",\n"b":"bar"\n}')
|
||||||
|
|
||||||
// should not remove comments in string
|
// should not remove comments in string
|
||||||
assert.strictEqual(util.repair('{"str":"/* foo */"}'), '{"str":"/* foo */"}');
|
assert.strictEqual(util.repair('{"str":"/* foo */"}'), '{"str":"/* foo */"}')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should strip JSONP notation', function () {
|
it('should strip JSONP notation', function () {
|
||||||
// matching
|
// matching
|
||||||
assert.strictEqual(util.repair('callback_123({});'), '{}');
|
assert.strictEqual(util.repair('callback_123({});'), '{}')
|
||||||
assert.strictEqual(util.repair('callback_123([]);'), '[]');
|
assert.strictEqual(util.repair('callback_123([]);'), '[]')
|
||||||
assert.strictEqual(util.repair('callback_123(2);'), '2');
|
assert.strictEqual(util.repair('callback_123(2);'), '2')
|
||||||
assert.strictEqual(util.repair('callback_123("foo");'), '"foo"');
|
assert.strictEqual(util.repair('callback_123("foo");'), '"foo"')
|
||||||
assert.strictEqual(util.repair('callback_123(null);'), 'null');
|
assert.strictEqual(util.repair('callback_123(null);'), 'null')
|
||||||
assert.strictEqual(util.repair('callback_123(true);'), 'true');
|
assert.strictEqual(util.repair('callback_123(true);'), 'true')
|
||||||
assert.strictEqual(util.repair('callback_123(false);'), 'false');
|
assert.strictEqual(util.repair('callback_123(false);'), 'false')
|
||||||
assert.strictEqual(util.repair('/* foo bar */ callback_123 ({})'), '{}');
|
assert.strictEqual(util.repair('/* foo bar */ callback_123 ({})'), '{}')
|
||||||
assert.strictEqual(util.repair('/* foo bar */ callback_123 ({})'), '{}');
|
assert.strictEqual(util.repair('/* foo bar */ callback_123 ({})'), '{}')
|
||||||
assert.strictEqual(util.repair('/* foo bar */\ncallback_123({})'), '{}');
|
assert.strictEqual(util.repair('/* foo bar */\ncallback_123({})'), '{}')
|
||||||
assert.strictEqual(util.repair('/* foo bar */ callback_123 ( {} )'), ' {} ');
|
assert.strictEqual(util.repair('/* foo bar */ callback_123 ( {} )'), ' {} ')
|
||||||
assert.strictEqual(util.repair(' /* foo bar */ callback_123 ({}); '), '{}');
|
assert.strictEqual(util.repair(' /* foo bar */ callback_123 ({}); '), '{}')
|
||||||
assert.strictEqual(util.repair('\n/* foo\nbar */\ncallback_123 ({});\n\n'), '{}');
|
assert.strictEqual(util.repair('\n/* foo\nbar */\ncallback_123 ({});\n\n'), '{}')
|
||||||
|
|
||||||
// non-matching
|
// non-matching
|
||||||
assert.strictEqual(util.repair('callback {}'), 'callback {}');
|
assert.strictEqual(util.repair('callback {}'), 'callback {}')
|
||||||
assert.strictEqual(util.repair('callback({}'), 'callback({}');
|
assert.strictEqual(util.repair('callback({}'), 'callback({}')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should strip trailing zeros', function () {
|
it('should strip trailing zeros', function () {
|
||||||
// matching
|
// matching
|
||||||
assert.strictEqual(util.repair('[1,2,3,]'), '[1,2,3]');
|
assert.strictEqual(util.repair('[1,2,3,]'), '[1,2,3]')
|
||||||
assert.strictEqual(util.repair('[1,2,3,\n]'), '[1,2,3\n]');
|
assert.strictEqual(util.repair('[1,2,3,\n]'), '[1,2,3\n]')
|
||||||
assert.strictEqual(util.repair('[1,2,3, \n ]'), '[1,2,3 \n ]');
|
assert.strictEqual(util.repair('[1,2,3, \n ]'), '[1,2,3 \n ]')
|
||||||
assert.strictEqual(util.repair('{"a":2,}'), '{"a":2}');
|
assert.strictEqual(util.repair('{"a":2,}'), '{"a":2}')
|
||||||
|
|
||||||
// not matching
|
// not matching
|
||||||
assert.strictEqual(util.repair('"[1,2,3,]"'), '"[1,2,3,]"');
|
assert.strictEqual(util.repair('"[1,2,3,]"'), '"[1,2,3,]"')
|
||||||
assert.strictEqual(util.repair('"{a:2,}"'), '"{a:2,}"');
|
assert.strictEqual(util.repair('"{a:2,}"'), '"{a:2,}"')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should strip MongoDB data types', function () {
|
it('should strip MongoDB data types', function () {
|
||||||
var mongoDocument = '{\n' +
|
var mongoDocument = '{\n' +
|
||||||
|
@ -103,7 +101,7 @@ describe('util', function () {
|
||||||
' "int2" : NumberInt(3),\n' +
|
' "int2" : NumberInt(3),\n' +
|
||||||
' "decimal" : NumberDecimal("4"),\n' +
|
' "decimal" : NumberDecimal("4"),\n' +
|
||||||
' "decimal2" : NumberDecimal(4)\n' +
|
' "decimal2" : NumberDecimal(4)\n' +
|
||||||
'}';
|
'}'
|
||||||
|
|
||||||
var expectedJson = '{\n' +
|
var expectedJson = '{\n' +
|
||||||
' "_id" : "123",\n' +
|
' "_id" : "123",\n' +
|
||||||
|
@ -115,78 +113,75 @@ describe('util', function () {
|
||||||
' "int2" : 3,\n' +
|
' "int2" : 3,\n' +
|
||||||
' "decimal" : "4",\n' +
|
' "decimal" : "4",\n' +
|
||||||
' "decimal2" : 4\n' +
|
' "decimal2" : 4\n' +
|
||||||
'}';
|
'}'
|
||||||
|
|
||||||
assert.strictEqual(util.repair(mongoDocument), expectedJson);
|
assert.strictEqual(util.repair(mongoDocument), expectedJson)
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
describe('jsonPath', function () {
|
describe('jsonPath', function () {
|
||||||
|
it('should stringify an array of paths', function () {
|
||||||
it('should stringify an array of paths', function() {
|
assert.deepStrictEqual(util.stringifyPath([]), '')
|
||||||
assert.deepStrictEqual(util.stringifyPath([]), '');
|
assert.deepStrictEqual(util.stringifyPath(['foo']), '.foo')
|
||||||
assert.deepStrictEqual(util.stringifyPath(['foo']), '.foo');
|
assert.deepStrictEqual(util.stringifyPath(['foo', 'bar']), '.foo.bar')
|
||||||
assert.deepStrictEqual(util.stringifyPath(['foo', 'bar']), '.foo.bar');
|
assert.deepStrictEqual(util.stringifyPath(['foo', 2]), '.foo[2]')
|
||||||
assert.deepStrictEqual(util.stringifyPath(['foo', 2]), '.foo[2]');
|
assert.deepStrictEqual(util.stringifyPath(['foo', 2, 'bar']), '.foo[2].bar')
|
||||||
assert.deepStrictEqual(util.stringifyPath(['foo', 2, 'bar']), '.foo[2].bar');
|
assert.deepStrictEqual(util.stringifyPath(['foo', 2, 'bar_baz']), '.foo[2].bar_baz')
|
||||||
assert.deepStrictEqual(util.stringifyPath(['foo', 2, 'bar_baz']), '.foo[2].bar_baz');
|
assert.deepStrictEqual(util.stringifyPath([2]), '[2]')
|
||||||
assert.deepStrictEqual(util.stringifyPath([2]), '[2]');
|
assert.deepStrictEqual(util.stringifyPath(['foo', 'prop-with-hyphens']), '.foo["prop-with-hyphens"]')
|
||||||
assert.deepStrictEqual(util.stringifyPath(['foo', 'prop-with-hyphens']), '.foo["prop-with-hyphens"]');
|
assert.deepStrictEqual(util.stringifyPath(['foo', 'prop with spaces']), '.foo["prop with spaces"]')
|
||||||
assert.deepStrictEqual(util.stringifyPath(['foo', 'prop with spaces']), '.foo["prop with spaces"]');
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it ('should parse a json path', function () {
|
it('should parse a json path', function () {
|
||||||
assert.deepStrictEqual(util.parsePath(''), []);
|
assert.deepStrictEqual(util.parsePath(''), [])
|
||||||
assert.deepStrictEqual(util.parsePath('.foo'), ['foo']);
|
assert.deepStrictEqual(util.parsePath('.foo'), ['foo'])
|
||||||
assert.deepStrictEqual(util.parsePath('.foo.bar'), ['foo', 'bar']);
|
assert.deepStrictEqual(util.parsePath('.foo.bar'), ['foo', 'bar'])
|
||||||
assert.deepStrictEqual(util.parsePath('.foo[2]'), ['foo', 2]);
|
assert.deepStrictEqual(util.parsePath('.foo[2]'), ['foo', 2])
|
||||||
assert.deepStrictEqual(util.parsePath('.foo[2].bar'), ['foo', 2, 'bar']);
|
assert.deepStrictEqual(util.parsePath('.foo[2].bar'), ['foo', 2, 'bar'])
|
||||||
assert.deepStrictEqual(util.parsePath('.foo["prop with spaces"]'), ['foo', 'prop with spaces']);
|
assert.deepStrictEqual(util.parsePath('.foo["prop with spaces"]'), ['foo', 'prop with spaces'])
|
||||||
assert.deepStrictEqual(util.parsePath('.foo[\'prop with single quotes as outputted by ajv library\']'), ['foo', 'prop with single quotes as outputted by ajv library']);
|
assert.deepStrictEqual(util.parsePath('.foo[\'prop with single quotes as outputted by ajv library\']'), ['foo', 'prop with single quotes as outputted by ajv library'])
|
||||||
assert.deepStrictEqual(util.parsePath('.foo["prop with . dot"]'), ['foo', 'prop with . dot']);
|
assert.deepStrictEqual(util.parsePath('.foo["prop with . dot"]'), ['foo', 'prop with . dot'])
|
||||||
assert.deepStrictEqual(util.parsePath('.foo["prop with ] character"]'), ['foo', 'prop with ] character']);
|
assert.deepStrictEqual(util.parsePath('.foo["prop with ] character"]'), ['foo', 'prop with ] character'])
|
||||||
assert.deepStrictEqual(util.parsePath('.foo[*].bar'), ['foo', '*', 'bar']);
|
assert.deepStrictEqual(util.parsePath('.foo[*].bar'), ['foo', '*', 'bar'])
|
||||||
assert.deepStrictEqual(util.parsePath('[2]'), [2]);
|
assert.deepStrictEqual(util.parsePath('[2]'), [2])
|
||||||
});
|
})
|
||||||
|
|
||||||
it ('should throw an exception in case of an invalid path', function () {
|
it('should throw an exception in case of an invalid path', function () {
|
||||||
assert.throws(function () {util.parsePath('.')}, /Invalid JSON path: property name expected at index 1/);
|
assert.throws(function () { util.parsePath('.') }, /Invalid JSON path: property name expected at index 1/)
|
||||||
assert.throws(function () {util.parsePath('[')}, /Invalid JSON path: unexpected end, character ] expected/);
|
assert.throws(function () { util.parsePath('[') }, /Invalid JSON path: unexpected end, character ] expected/)
|
||||||
assert.throws(function () {util.parsePath('[]')}, /Invalid JSON path: array value expected at index 1/);
|
assert.throws(function () { util.parsePath('[]') }, /Invalid JSON path: array value expected at index 1/)
|
||||||
assert.throws(function () {util.parsePath('.foo[ ]')}, /Invalid JSON path: array value expected at index 7/);
|
assert.throws(function () { util.parsePath('.foo[ ]') }, /Invalid JSON path: array value expected at index 7/)
|
||||||
assert.throws(function () {util.parsePath('.[]')}, /Invalid JSON path: property name expected at index 1/);
|
assert.throws(function () { util.parsePath('.[]') }, /Invalid JSON path: property name expected at index 1/)
|
||||||
assert.throws(function () {util.parsePath('["23]')}, /Invalid JSON path: unexpected end, character " expected/);
|
assert.throws(function () { util.parsePath('["23]') }, /Invalid JSON path: unexpected end, character " expected/)
|
||||||
assert.throws(function () {util.parsePath('.foo bar')}, /Invalid JSON path: unexpected character " " at index 4/);
|
assert.throws(function () { util.parsePath('.foo bar') }, /Invalid JSON path: unexpected character " " at index 4/)
|
||||||
});
|
})
|
||||||
|
})
|
||||||
});
|
|
||||||
|
|
||||||
describe('getIndexForPosition', function () {
|
describe('getIndexForPosition', function () {
|
||||||
var el = {
|
var el = {
|
||||||
value: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\nUt enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\nDuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\nExcepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
|
value: 'Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\nUt enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.\nDuis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.\nExcepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.'
|
||||||
};
|
}
|
||||||
|
|
||||||
it('happy flows - row and column in range', function () {
|
it('happy flows - row and column in range', function () {
|
||||||
assert.strictEqual(util.getIndexForPosition(el, 1, 1), 0);
|
assert.strictEqual(util.getIndexForPosition(el, 1, 1), 0)
|
||||||
assert.strictEqual(util.getIndexForPosition(el, 2, 1), 124);
|
assert.strictEqual(util.getIndexForPosition(el, 2, 1), 124)
|
||||||
assert.strictEqual(util.getIndexForPosition(el, 3, 8), 239);
|
assert.strictEqual(util.getIndexForPosition(el, 3, 8), 239)
|
||||||
assert.strictEqual(util.getIndexForPosition(el, 4, 22), 356);
|
assert.strictEqual(util.getIndexForPosition(el, 4, 22), 356)
|
||||||
});
|
})
|
||||||
|
|
||||||
it('if range exceeds it should be considered as if it is last row or column length', function () {
|
it('if range exceeds it should be considered as if it is last row or column length', function () {
|
||||||
assert.strictEqual(util.getIndexForPosition(el, 1, 100000), 123);
|
assert.strictEqual(util.getIndexForPosition(el, 1, 100000), 123)
|
||||||
assert.strictEqual(util.getIndexForPosition(el, 100000, 1), 335);
|
assert.strictEqual(util.getIndexForPosition(el, 100000, 1), 335)
|
||||||
assert.strictEqual(util.getIndexForPosition(el, 100000, 100000), 445);
|
assert.strictEqual(util.getIndexForPosition(el, 100000, 100000), 445)
|
||||||
});
|
})
|
||||||
|
|
||||||
it('missing or wrong input sould return -1', function () {
|
it('missing or wrong input sould return -1', function () {
|
||||||
assert.strictEqual(util.getIndexForPosition(el), -1);
|
assert.strictEqual(util.getIndexForPosition(el), -1)
|
||||||
assert.strictEqual(util.getIndexForPosition(el, undefined, 1), -1);
|
assert.strictEqual(util.getIndexForPosition(el, undefined, 1), -1)
|
||||||
assert.strictEqual(util.getIndexForPosition(el, 1, undefined), -1);
|
assert.strictEqual(util.getIndexForPosition(el, 1, undefined), -1)
|
||||||
assert.strictEqual(util.getIndexForPosition(el, -2, -2), -1);
|
assert.strictEqual(util.getIndexForPosition(el, -2, -2), -1)
|
||||||
});
|
})
|
||||||
|
})
|
||||||
});
|
|
||||||
|
|
||||||
describe('get', function () {
|
describe('get', function () {
|
||||||
it('should get a nested property from an object', function () {
|
it('should get a nested property from an object', function () {
|
||||||
|
@ -199,105 +194,105 @@ describe('util', function () {
|
||||||
e: undefined
|
e: undefined
|
||||||
}
|
}
|
||||||
|
|
||||||
assert.strictEqual(util.get(obj, ['a', 'b']), 2);
|
assert.strictEqual(util.get(obj, ['a', 'b']), 2)
|
||||||
assert.strictEqual(util.get(obj, ['c']), 3);
|
assert.strictEqual(util.get(obj, ['c']), 3)
|
||||||
assert.deepStrictEqual(util.get(obj, ['a']), { b: 2});
|
assert.deepStrictEqual(util.get(obj, ['a']), { b: 2 })
|
||||||
assert.strictEqual(util.get(obj, ['a', 'foo']), undefined);
|
assert.strictEqual(util.get(obj, ['a', 'foo']), undefined)
|
||||||
assert.strictEqual(util.get(obj, ['a', 'foo', 'bar']), undefined);
|
assert.strictEqual(util.get(obj, ['a', 'foo', 'bar']), undefined)
|
||||||
assert.strictEqual(util.get(obj, ['d']), null);
|
assert.strictEqual(util.get(obj, ['d']), null)
|
||||||
assert.strictEqual(util.get(obj, ['d', 'foo', 'bar']), null);
|
assert.strictEqual(util.get(obj, ['d', 'foo', 'bar']), null)
|
||||||
assert.strictEqual(util.get(obj, ['e']), undefined);
|
assert.strictEqual(util.get(obj, ['e']), undefined)
|
||||||
})
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
describe('makeFieldTooltip', function () {
|
describe('makeFieldTooltip', function () {
|
||||||
it('should return empty string when the schema is missing all relevant fields', function () {
|
it('should return empty string when the schema is missing all relevant fields', function () {
|
||||||
assert.strictEqual(util.makeFieldTooltip({}), '')
|
assert.strictEqual(util.makeFieldTooltip({}), '')
|
||||||
assert.strictEqual(util.makeFieldTooltip({additionalProperties: false}), '')
|
assert.strictEqual(util.makeFieldTooltip({ additionalProperties: false }), '')
|
||||||
assert.strictEqual(util.makeFieldTooltip(), '')
|
assert.strictEqual(util.makeFieldTooltip(), '')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should make tooltips with only title', function () {
|
it('should make tooltips with only title', function () {
|
||||||
assert.strictEqual(util.makeFieldTooltip({title: 'foo'}), 'foo');
|
assert.strictEqual(util.makeFieldTooltip({ title: 'foo' }), 'foo')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should make tooltips with only description', function () {
|
it('should make tooltips with only description', function () {
|
||||||
assert.strictEqual(util.makeFieldTooltip({description: 'foo'}), 'foo');
|
assert.strictEqual(util.makeFieldTooltip({ description: 'foo' }), 'foo')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should make tooltips with only default', function () {
|
it('should make tooltips with only default', function () {
|
||||||
assert.strictEqual(util.makeFieldTooltip({default: 'foo'}), 'Default\n"foo"');
|
assert.strictEqual(util.makeFieldTooltip({ default: 'foo' }), 'Default\n"foo"')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should make tooltips with only examples', function () {
|
it('should make tooltips with only examples', function () {
|
||||||
assert.strictEqual(util.makeFieldTooltip({examples: ['foo', 'bar']}), 'Examples\n"foo"\n"bar"');
|
assert.strictEqual(util.makeFieldTooltip({ examples: ['foo', 'bar'] }), 'Examples\n"foo"\n"bar"')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should make tooltips with title and description', function () {
|
it('should make tooltips with title and description', function () {
|
||||||
assert.strictEqual(util.makeFieldTooltip({title: 'foo', description: 'bar'}), 'foo\nbar');
|
assert.strictEqual(util.makeFieldTooltip({ title: 'foo', description: 'bar' }), 'foo\nbar')
|
||||||
|
|
||||||
var longTitle = 'Lorem Ipsum Dolor';
|
var longTitle = 'Lorem Ipsum Dolor'
|
||||||
var longDescription = 'Duis id elit non ante gravida vestibulum non nec est. ' +
|
var longDescription = 'Duis id elit non ante gravida vestibulum non nec est. ' +
|
||||||
'Proin vitae ligula at elit dapibus tempor. ' +
|
'Proin vitae ligula at elit dapibus tempor. ' +
|
||||||
'Etiam lacinia augue vel condimentum interdum. ';
|
'Etiam lacinia augue vel condimentum interdum. '
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
util.makeFieldTooltip({title: longTitle, description: longDescription}),
|
util.makeFieldTooltip({ title: longTitle, description: longDescription }),
|
||||||
longTitle + '\n' + longDescription
|
longTitle + '\n' + longDescription
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should make tooltips with title, description, and examples', function () {
|
it('should make tooltips with title, description, and examples', function () {
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
util.makeFieldTooltip({title: 'foo', description: 'bar', examples: ['baz']}),
|
util.makeFieldTooltip({ title: 'foo', description: 'bar', examples: ['baz'] }),
|
||||||
'foo\nbar\n\nExamples\n"baz"',
|
'foo\nbar\n\nExamples\n"baz"'
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should make tooltips with title, description, default, and examples', function () {
|
it('should make tooltips with title, description, default, and examples', function () {
|
||||||
assert.strictEqual(
|
assert.strictEqual(
|
||||||
util.makeFieldTooltip({title: 'foo', description: 'bar', default: 'bat', examples: ['baz']}),
|
util.makeFieldTooltip({ title: 'foo', description: 'bar', default: 'bat', examples: ['baz'] }),
|
||||||
'foo\nbar\n\nDefault\n"bat"\n\nExamples\n"baz"',
|
'foo\nbar\n\nDefault\n"bat"\n\nExamples\n"baz"'
|
||||||
);
|
)
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should handle empty fields', function () {
|
it('should handle empty fields', function () {
|
||||||
assert.strictEqual(util.makeFieldTooltip({title: '', description: 'bar'}), 'bar');
|
assert.strictEqual(util.makeFieldTooltip({ title: '', description: 'bar' }), 'bar')
|
||||||
assert.strictEqual(util.makeFieldTooltip({title: 'foo', description: ''}), 'foo');
|
assert.strictEqual(util.makeFieldTooltip({ title: 'foo', description: '' }), 'foo')
|
||||||
assert.strictEqual(util.makeFieldTooltip({description: 'bar', examples: []}), 'bar');
|
assert.strictEqual(util.makeFieldTooltip({ description: 'bar', examples: [] }), 'bar')
|
||||||
assert.strictEqual(util.makeFieldTooltip({description: 'bar', examples: ['']}), 'bar\n\nExamples\n""');
|
assert.strictEqual(util.makeFieldTooltip({ description: 'bar', examples: [''] }), 'bar\n\nExamples\n""')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should internationalize "Defaults" correctly', function () {
|
it('should internationalize "Defaults" correctly', function () {
|
||||||
assert.strictEqual(util.makeFieldTooltip({default: 'foo'}, 'pt-BR'), 'Revelia\n"foo"');
|
assert.strictEqual(util.makeFieldTooltip({ default: 'foo' }, 'pt-BR'), 'Revelia\n"foo"')
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should internationalize "Examples" correctly', function () {
|
it('should internationalize "Examples" correctly', function () {
|
||||||
assert.strictEqual(util.makeFieldTooltip({examples: ['foo']}, 'pt-BR'), 'Exemplos\n"foo"');
|
assert.strictEqual(util.makeFieldTooltip({ examples: ['foo'] }, 'pt-BR'), 'Exemplos\n"foo"')
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
describe('getChildPaths', function () {
|
describe('getChildPaths', function () {
|
||||||
it('should extract all child paths of an array containing objects', function () {
|
it('should extract all child paths of an array containing objects', function () {
|
||||||
var json = [
|
var json = [
|
||||||
{ name: 'A', location: {latitude: 1, longitude: 2} },
|
{ name: 'A', location: { latitude: 1, longitude: 2 } },
|
||||||
{ name: 'B', location: {latitude: 1, longitude: 2} },
|
{ name: 'B', location: { latitude: 1, longitude: 2 } },
|
||||||
{ name: 'C', timestamp: 0 },
|
{ name: 'C', timestamp: 0 }
|
||||||
];
|
]
|
||||||
|
|
||||||
assert.deepStrictEqual(util.getChildPaths(json), [
|
assert.deepStrictEqual(util.getChildPaths(json), [
|
||||||
'.location.latitude',
|
'.location.latitude',
|
||||||
'.location.longitude',
|
'.location.longitude',
|
||||||
'.name',
|
'.name',
|
||||||
'.timestamp',
|
'.timestamp'
|
||||||
])
|
])
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should extract all child paths of an array containing objects, including objects', function () {
|
it('should extract all child paths of an array containing objects, including objects', function () {
|
||||||
var json = [
|
var json = [
|
||||||
{ name: 'A', location: {latitude: 1, longitude: 2} },
|
{ name: 'A', location: { latitude: 1, longitude: 2 } },
|
||||||
{ name: 'B', location: {latitude: 1, longitude: 2} },
|
{ name: 'B', location: { latitude: 1, longitude: 2 } },
|
||||||
{ name: 'C', timestamp: 0 },
|
{ name: 'C', timestamp: 0 }
|
||||||
];
|
]
|
||||||
|
|
||||||
assert.deepStrictEqual(util.getChildPaths(json, true), [
|
assert.deepStrictEqual(util.getChildPaths(json, true), [
|
||||||
'',
|
'',
|
||||||
|
@ -305,41 +300,41 @@ describe('util', function () {
|
||||||
'.location.latitude',
|
'.location.latitude',
|
||||||
'.location.longitude',
|
'.location.longitude',
|
||||||
'.name',
|
'.name',
|
||||||
'.timestamp',
|
'.timestamp'
|
||||||
])
|
])
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should extract all child paths of an array containing values', function () {
|
it('should extract all child paths of an array containing values', function () {
|
||||||
var json = [ 1, 2, 3 ];
|
var json = [1, 2, 3]
|
||||||
|
|
||||||
assert.deepStrictEqual(util.getChildPaths(json), [
|
assert.deepStrictEqual(util.getChildPaths(json), [
|
||||||
''
|
''
|
||||||
])
|
])
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should extract all child paths of a non-array', function () {
|
it('should extract all child paths of a non-array', function () {
|
||||||
assert.deepStrictEqual(util.getChildPaths({a: 2, b: {c: 3}}), [''])
|
assert.deepStrictEqual(util.getChildPaths({ a: 2, b: { c: 3 } }), [''])
|
||||||
assert.deepStrictEqual(util.getChildPaths('foo'), [''])
|
assert.deepStrictEqual(util.getChildPaths('foo'), [''])
|
||||||
assert.deepStrictEqual(util.getChildPaths(123), [''])
|
assert.deepStrictEqual(util.getChildPaths(123), [''])
|
||||||
});
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should test whether something is an object', function () {
|
it('should test whether something is an object', function () {
|
||||||
assert.strictEqual(util.isObject({}), true);
|
assert.strictEqual(util.isObject({}), true)
|
||||||
assert.strictEqual(util.isObject(new Date()), true);
|
assert.strictEqual(util.isObject(new Date()), true)
|
||||||
assert.strictEqual(util.isObject([]), false);
|
assert.strictEqual(util.isObject([]), false)
|
||||||
assert.strictEqual(util.isObject(2), false);
|
assert.strictEqual(util.isObject(2), false)
|
||||||
assert.strictEqual(util.isObject(null), false);
|
assert.strictEqual(util.isObject(null), false)
|
||||||
assert.strictEqual(util.isObject(undefined), false);
|
assert.strictEqual(util.isObject(undefined), false)
|
||||||
assert.strictEqual(util.isObject(), false);
|
assert.strictEqual(util.isObject(), false)
|
||||||
});
|
})
|
||||||
|
|
||||||
describe('sort', function () {
|
describe('sort', function () {
|
||||||
it('should sort an array', function () {
|
it('should sort an array', function () {
|
||||||
var array = [4, 1, 10, 2];
|
var array = [4, 1, 10, 2]
|
||||||
assert.deepStrictEqual(util.sort(array), [1, 2, 4, 10]);
|
assert.deepStrictEqual(util.sort(array), [1, 2, 4, 10])
|
||||||
assert.deepStrictEqual(util.sort(array, '.', 'desc'), [10, 4, 2, 1]);
|
assert.deepStrictEqual(util.sort(array, '.', 'desc'), [10, 4, 2, 1])
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should sort an array containing objects', function () {
|
it('should sort an array containing objects', function () {
|
||||||
var array = [
|
var array = [
|
||||||
|
@ -347,23 +342,23 @@ describe('util', function () {
|
||||||
{ value: 1 },
|
{ value: 1 },
|
||||||
{ value: 10 },
|
{ value: 10 },
|
||||||
{ value: 2 }
|
{ value: 2 }
|
||||||
];
|
]
|
||||||
|
|
||||||
assert.deepStrictEqual(util.sort(array, '.value'), [
|
assert.deepStrictEqual(util.sort(array, '.value'), [
|
||||||
{ value: 1 },
|
{ value: 1 },
|
||||||
{ value: 2 },
|
{ value: 2 },
|
||||||
{ value: 4 },
|
{ value: 4 },
|
||||||
{ value: 10 }
|
{ value: 10 }
|
||||||
]);
|
])
|
||||||
|
|
||||||
assert.deepStrictEqual(util.sort(array, '.value', 'desc'), [
|
assert.deepStrictEqual(util.sort(array, '.value', 'desc'), [
|
||||||
{ value: 10 },
|
{ value: 10 },
|
||||||
{ value: 4 },
|
{ value: 4 },
|
||||||
{ value: 2 },
|
{ value: 2 },
|
||||||
{ value: 1 }
|
{ value: 1 }
|
||||||
]);
|
])
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
describe('sortObjectKeys', function () {
|
describe('sortObjectKeys', function () {
|
||||||
it('should sort the keys of an object', function () {
|
it('should sort the keys of an object', function () {
|
||||||
|
@ -376,16 +371,16 @@ describe('util', function () {
|
||||||
assert.strictEqual(JSON.stringify(util.sortObjectKeys(object)), '{"a":"a","b":"b","c":"c"}')
|
assert.strictEqual(JSON.stringify(util.sortObjectKeys(object)), '{"a":"a","b":"b","c":"c"}')
|
||||||
assert.strictEqual(JSON.stringify(util.sortObjectKeys(object, 'asc')), '{"a":"a","b":"b","c":"c"}')
|
assert.strictEqual(JSON.stringify(util.sortObjectKeys(object, 'asc')), '{"a":"a","b":"b","c":"c"}')
|
||||||
assert.strictEqual(JSON.stringify(util.sortObjectKeys(object, 'desc')), '{"c":"c","b":"b","a":"a"}')
|
assert.strictEqual(JSON.stringify(util.sortObjectKeys(object, 'desc')), '{"c":"c","b":"b","a":"a"}')
|
||||||
});
|
})
|
||||||
});
|
})
|
||||||
|
|
||||||
it('should parse a string', function () {
|
it('should parse a string', function () {
|
||||||
assert.strictEqual(util.parseString('foo'), 'foo');
|
assert.strictEqual(util.parseString('foo'), 'foo')
|
||||||
assert.strictEqual(util.parseString('234foo'), '234foo');
|
assert.strictEqual(util.parseString('234foo'), '234foo')
|
||||||
assert.strictEqual(util.parseString('2.3'), 2.3);
|
assert.strictEqual(util.parseString('2.3'), 2.3)
|
||||||
assert.strictEqual(util.parseString('null'), null);
|
assert.strictEqual(util.parseString('null'), null)
|
||||||
assert.strictEqual(util.parseString('true'), true);
|
assert.strictEqual(util.parseString('true'), true)
|
||||||
assert.strictEqual(util.parseString('false'), false);
|
assert.strictEqual(util.parseString('false'), false)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should find a unique name', function () {
|
it('should find a unique name', function () {
|
||||||
|
@ -434,20 +429,20 @@ describe('util', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should format a document size in a human readable way', function () {
|
it('should format a document size in a human readable way', function () {
|
||||||
assert.strictEqual(util.formatSize(500), '500 B');
|
assert.strictEqual(util.formatSize(500), '500 B')
|
||||||
assert.strictEqual(util.formatSize(900), '0.9 KiB');
|
assert.strictEqual(util.formatSize(900), '0.9 KiB')
|
||||||
assert.strictEqual(util.formatSize(77.89 * 1024), '77.9 KiB');
|
assert.strictEqual(util.formatSize(77.89 * 1024), '77.9 KiB')
|
||||||
assert.strictEqual(util.formatSize(950 * 1024), '0.9 MiB');
|
assert.strictEqual(util.formatSize(950 * 1024), '0.9 MiB')
|
||||||
assert.strictEqual(util.formatSize(7.22 * 1024 * 1024), '7.2 MiB');
|
assert.strictEqual(util.formatSize(7.22 * 1024 * 1024), '7.2 MiB')
|
||||||
assert.strictEqual(util.formatSize(955.4 * 1024 * 1024), '0.9 GiB');
|
assert.strictEqual(util.formatSize(955.4 * 1024 * 1024), '0.9 GiB')
|
||||||
assert.strictEqual(util.formatSize(22.37 * 1024 * 1024 * 1024), '22.4 GiB');
|
assert.strictEqual(util.formatSize(22.37 * 1024 * 1024 * 1024), '22.4 GiB')
|
||||||
assert.strictEqual(util.formatSize(1024 * 1024 * 1024 * 1024), '1.0 TiB');
|
assert.strictEqual(util.formatSize(1024 * 1024 * 1024 * 1024), '1.0 TiB')
|
||||||
});
|
})
|
||||||
|
|
||||||
it ('should limit characters', function () {
|
it('should limit characters', function () {
|
||||||
assert.strictEqual(util.limitCharacters('hello world', 11), 'hello world');
|
assert.strictEqual(util.limitCharacters('hello world', 11), 'hello world')
|
||||||
assert.strictEqual(util.limitCharacters('hello world', 5), 'hello...');
|
assert.strictEqual(util.limitCharacters('hello world', 5), 'hello...')
|
||||||
assert.strictEqual(util.limitCharacters('hello world', 100), 'hello world');
|
assert.strictEqual(util.limitCharacters('hello world', 100), 'hello world')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should compile a JSON pointer', function () {
|
it('should compile a JSON pointer', function () {
|
||||||
|
@ -455,7 +450,7 @@ describe('util', function () {
|
||||||
assert.strictEqual(util.compileJSONPointer(['foo', '/~ ~/']), '/foo/~1~0 ~0~1')
|
assert.strictEqual(util.compileJSONPointer(['foo', '/~ ~/']), '/foo/~1~0 ~0~1')
|
||||||
assert.strictEqual(util.compileJSONPointer(['']), '/')
|
assert.strictEqual(util.compileJSONPointer(['']), '/')
|
||||||
assert.strictEqual(util.compileJSONPointer([]), '')
|
assert.strictEqual(util.compileJSONPointer([]), '')
|
||||||
});
|
})
|
||||||
|
|
||||||
// TODO: thoroughly test all util methods
|
// TODO: thoroughly test all util methods
|
||||||
});
|
})
|
||||||
|
|
Loading…
Reference in New Issue