Set up code style linting with standardjs

This commit is contained in:
jos 2019-08-28 13:21:14 +02:00
parent 8e2a7de17c
commit a5d6b8a65b
43 changed files with 7982 additions and 6993 deletions

View File

@ -1,3 +1,10 @@
language: node_js
node_js:
- "lts/*"
jobs:
include:
- name: Lint
stage: other
script: npm run lint
node_js: lts/*

View File

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

View File

@ -96,9 +96,9 @@ with npm (recommended):
<script>
// create the editor
var container = document.getElementById("jsoneditor");
var options = {};
var editor = new JSONEditor(container, options);
var container = document.getElementById("jsoneditor")
var options = {}
var editor = new JSONEditor(container, options)
// set json
var json = {
@ -108,11 +108,11 @@ with npm (recommended):
"Number": 123,
"Object": {"a": "b", "c": "d"},
"String": "Hello World"
};
editor.set(json);
}
editor.set(json)
// get json
var json = editor.get();
var json = editor.get()
</script>
</body>
</html>

View File

@ -9,7 +9,7 @@
}
</style>
<link rel="stylesheet" type="text/css" href="../../dist/jsoneditor.css">
<script data-main="scripts/main" src="scripts/require.js"></script>
<script data-main="scripts/main" src="https://requirejs.org/docs/release/2.3.6/minified/require.js"></script>
</head>
<body>
<p>

View File

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

View File

@ -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);

View File

@ -1,38 +1,38 @@
var fs = require('fs');
var path = require('path');
var gulp = require('gulp');
var log = require('fancy-log');
var format = require('date-format');
var concatCss = require('gulp-concat-css');
var minifyCSS = require('gulp-clean-css');
var fs = require('fs')
var path = require('path')
var gulp = require('gulp')
var log = require('fancy-log')
var format = require('date-format')
var concatCss = require('gulp-concat-css')
var minifyCSS = require('gulp-clean-css')
var sass = require('gulp-sass')
var mkdirp = require('mkdirp');
var webpack = require('webpack');
var uglify = require('uglify-js');
var mkdirp = require('mkdirp')
var webpack = require('webpack')
var uglify = require('uglify-js')
var NAME = 'jsoneditor';
var NAME_MINIMALIST = 'jsoneditor-minimalist';
var ENTRY = './src/js/JSONEditor.js';
var HEADER = './src/js/header.js';
var IMAGE = './src/scss/img/jsoneditor-icons.svg';
var DOCS = './src/docs/*';
var DIST = path.join(__dirname, 'dist');
var NAME = 'jsoneditor'
var NAME_MINIMALIST = 'jsoneditor-minimalist'
var ENTRY = './src/js/JSONEditor.js'
var HEADER = './src/js/header.js'
var IMAGE = './src/scss/img/jsoneditor-icons.svg'
var DOCS = './src/docs/*'
var DIST = path.join(__dirname, 'dist')
// generate banner with today's date and correct version
function createBanner() {
var today = format.asString('yyyy-MM-dd', new Date()); // today, formatted as yyyy-MM-dd
var version = require('./package.json').version; // math.js version
function createBanner () {
var today = format.asString('yyyy-MM-dd', new Date()) // today, formatted as yyyy-MM-dd
var version = require('./package.json').version // math.js version
return String(fs.readFileSync(HEADER))
.replace('@@date', today)
.replace('@@version', version);
.replace('@@version', version)
}
var bannerPlugin = new webpack.BannerPlugin({
banner: createBanner(),
entryOnly: true,
raw: true
});
})
var webpackConfigModule = {
rules: [
@ -47,7 +47,7 @@ var webpackConfigModule = {
}
}
]
};
}
// create a single instance of the compiler to allow caching
var compiler = webpack({
@ -66,10 +66,10 @@ var compiler = webpack({
module: webpackConfigModule,
resolve: {
extensions: ['.js'],
mainFields: [ 'main' ], // pick ES5 version of vanilla-picker
mainFields: ['main'] // pick ES5 version of vanilla-picker
},
cache: true
});
})
// create a single instance of the compiler to allow caching
var compilerMinimalist = webpack({
@ -92,10 +92,10 @@ var compilerMinimalist = webpack({
minimize: false
},
cache: true
});
})
function minify(name) {
var code = String(fs.readFileSync(DIST + '/' + name + '.js'));
function minify (name) {
var code = String(fs.readFileSync(DIST + '/' + name + '.js'))
var result = uglify.minify(code, {
sourceMap: {
url: name + '.map'
@ -104,80 +104,80 @@ function minify(name) {
comments: /@license/,
max_line_len: 64000 // extra large because we have embedded code for workers
}
});
})
if (result.error) {
throw result.error;
throw result.error
}
var fileMin = DIST + '/' + name + '.min.js';
var fileMap = DIST + '/' + name + '.map';
var fileMin = DIST + '/' + name + '.min.js'
var fileMap = DIST + '/' + name + '.map'
fs.writeFileSync(fileMin, result.code);
fs.writeFileSync(fileMap, result.map);
fs.writeFileSync(fileMin, result.code)
fs.writeFileSync(fileMap, result.map)
log('Minified ' + fileMin);
log('Mapped ' + fileMap);
log('Minified ' + fileMin)
log('Mapped ' + fileMap)
}
// make dist folder structure
gulp.task('mkdir', function(done) {
mkdirp.sync(DIST);
mkdirp.sync(DIST + '/img');
gulp.task('mkdir', function (done) {
mkdirp.sync(DIST)
mkdirp.sync(DIST + '/img')
done();
});
done()
})
// 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)
bannerPlugin.banner = createBanner();
bannerPlugin.banner = createBanner()
compiler.run(function(err, stats) {
compiler.run(function (err, stats) {
if (err) {
log(err);
log(err)
}
log('bundled ' + NAME + '.js');
log('bundled ' + NAME + '.js')
done();
});
});
done()
})
})
// 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)
bannerPlugin.banner = createBanner();
bannerPlugin.banner = createBanner()
compilerMinimalist.run(function(err, stats) {
compilerMinimalist.run(function (err, stats) {
if (err) {
log(err);
log(err)
}
log('bundled ' + NAME_MINIMALIST + '.js');
log('bundled ' + NAME_MINIMALIST + '.js')
done();
});
});
done()
})
})
// bundle css
gulp.task('bundle-css', function(done) {
gulp.task('bundle-css', function (done) {
gulp
.src([
'src/scss/reset.scss',
'src/scss/jsoneditor.scss',
'src/scss/contextmenu.scss',
'src/scss/menu.scss',
'src/scss/searchbox.scss',
'src/scss/autocomplete.scss',
'src/scss/treepath.scss',
'src/scss/statusbar.scss',
'src/scss/navigationbar.scss',
'src/js/assets/selectr/selectr.scss',
])
.src([
'src/scss/reset.scss',
'src/scss/jsoneditor.scss',
'src/scss/contextmenu.scss',
'src/scss/menu.scss',
'src/scss/searchbox.scss',
'src/scss/autocomplete.scss',
'src/scss/treepath.scss',
'src/scss/statusbar.scss',
'src/scss/navigationbar.scss',
'src/js/assets/selectr/selectr.scss'
])
.pipe(
sass({
// importer: tildeImporter
// importer: tildeImporter
})
)
.pipe(concatCss(NAME + '.css'))
@ -189,48 +189,48 @@ gulp.task('bundle-css', function(done) {
})
// create a folder img and copy the icons
gulp.task('copy-img', function(done) {
gulp.src(IMAGE).pipe(gulp.dest(DIST + '/img'));
log('Copied images');
gulp.task('copy-img', function (done) {
gulp.src(IMAGE).pipe(gulp.dest(DIST + '/img'))
log('Copied images')
done();
});
done()
})
// create a folder img and copy the icons
gulp.task('copy-docs', function(done) {
gulp.src(DOCS).pipe(gulp.dest(DIST));
log('Copied doc');
gulp.task('copy-docs', function (done) {
gulp.src(DOCS).pipe(gulp.dest(DIST))
log('Copied doc')
done();
});
done()
})
gulp.task('minify', function(done) {
minify(NAME);
gulp.task('minify', function (done) {
minify(NAME)
done();
});
done()
})
gulp.task('minify-minimalist', function(done) {
minify(NAME_MINIMALIST);
gulp.task('minify-minimalist', function (done) {
minify(NAME_MINIMALIST)
done();
});
done()
})
// The watch task (to automatically rebuild when the source code changes)
// Does only generate jsoneditor.js and jsoneditor.css, and copy the image
// Does NOT minify the code and does NOT generate the minimalist version
gulp.task('watch', gulp.series('bundle', 'bundle-css', 'copy-img', function() {
gulp.watch(['src/**/*'], gulp.series('bundle', 'bundle-css', 'copy-img'));
}));
gulp.task('watch', gulp.series('bundle', 'bundle-css', 'copy-img', function () {
gulp.watch(['src/**/*'], gulp.series('bundle', 'bundle-css', 'copy-img'))
}))
// The default task (called when you run `gulp`)
gulp.task('default', gulp.series(
'mkdir',
gulp.parallel(
'copy-img',
'copy-docs',
'bundle-css',
gulp.series('bundle', 'minify'),
gulp.series('bundle-minimalist', 'minify-minimalist')
)
));
'mkdir',
gulp.parallel(
'copy-img',
'copy-docs',
'bundle-css',
gulp.series('bundle', 'minify'),
gulp.series('bundle-minimalist', 'minify-minimalist')
)
))

View File

@ -1 +1 @@
module.exports = require('./src/js/JSONEditor');
module.exports = require('./src/js/JSONEditor')

1331
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,8 @@
"build": "gulp",
"minify": "gulp minify",
"start": "gulp watch",
"test": "mocha test"
"test": "mocha test",
"lint": "standard --env=mocha"
},
"dependencies": {
"ajv": "6.10.2",
@ -47,7 +48,14 @@
"json-loader": "0.5.7",
"mkdirp": "0.5.1",
"mocha": "6.2.0",
"standard": "14.0.2",
"uglify-js": "3.6.0",
"webpack": "4.39.3"
},
"standard": {
"ignore": [
"src/js/assets",
"examples/react*"
]
}
}

View File

@ -1,8 +1,8 @@
'use strict';
'use strict'
var createAbsoluteAnchor = require('./createAbsoluteAnchor').createAbsoluteAnchor;
var util = require('./util');
var translate = require('./i18n').translate;
var createAbsoluteAnchor = require('./createAbsoluteAnchor').createAbsoluteAnchor
var util = require('./util')
var translate = require('./i18n').translate
/**
* A context menu
@ -14,153 +14,150 @@ var translate = require('./i18n').translate;
* @constructor
*/
function ContextMenu (items, options) {
this.dom = {};
this.dom = {}
var me = this;
var dom = this.dom;
this.anchor = undefined;
this.items = items;
this.eventListeners = {};
this.selection = undefined; // holds the selection before the menu was opened
this.onClose = options ? options.close : undefined;
var me = this
var dom = this.dom
this.anchor = undefined
this.items = items
this.eventListeners = {}
this.selection = undefined // holds the selection before the menu was opened
this.onClose = options ? options.close : undefined
// create root element
var root = document.createElement('div');
root.className = 'jsoneditor-contextmenu-root';
dom.root = root;
var root = document.createElement('div')
root.className = 'jsoneditor-contextmenu-root'
dom.root = root
// create a container element
var menu = document.createElement('div');
menu.className = 'jsoneditor-contextmenu';
dom.menu = menu;
root.appendChild(menu);
var menu = document.createElement('div')
menu.className = 'jsoneditor-contextmenu'
dom.menu = menu
root.appendChild(menu)
// create a list to hold the menu items
var list = document.createElement('ul');
list.className = 'jsoneditor-menu';
menu.appendChild(list);
dom.list = list;
dom.items = []; // list with all buttons
var list = document.createElement('ul')
list.className = 'jsoneditor-menu'
menu.appendChild(list)
dom.list = list
dom.items = [] // list with all buttons
// create a (non-visible) button to set the focus to the menu
var focusButton = document.createElement('button');
focusButton.type = 'button';
dom.focusButton = focusButton;
var li = document.createElement('li');
li.style.overflow = 'hidden';
li.style.height = '0';
li.appendChild(focusButton);
list.appendChild(li);
var focusButton = document.createElement('button')
focusButton.type = 'button'
dom.focusButton = focusButton
var li = document.createElement('li')
li.style.overflow = 'hidden'
li.style.height = '0'
li.appendChild(focusButton)
list.appendChild(li)
function createMenuItems (list, domItems, items) {
items.forEach(function (item) {
if (item.type == 'separator') {
if (item.type === 'separator') {
// create a separator
var separator = document.createElement('div');
separator.className = 'jsoneditor-separator';
li = document.createElement('li');
li.appendChild(separator);
list.appendChild(li);
}
else {
var domItem = {};
var separator = document.createElement('div')
separator.className = 'jsoneditor-separator'
const li = document.createElement('li')
li.appendChild(separator)
list.appendChild(li)
} else {
var domItem = {}
// create a menu item
var li = document.createElement('li');
list.appendChild(li);
const li = document.createElement('li')
list.appendChild(li)
// create a button in the menu item
var button = document.createElement('button');
button.type = 'button';
button.className = item.className;
domItem.button = button;
var button = document.createElement('button')
button.type = 'button'
button.className = item.className
domItem.button = button
if (item.title) {
button.title = item.title;
button.title = item.title
}
if (item.click) {
button.onclick = function (event) {
event.preventDefault();
me.hide();
item.click();
};
event.preventDefault()
me.hide()
item.click()
}
}
li.appendChild(button);
li.appendChild(button)
// create the contents of the button
if (item.submenu) {
// add the icon to the button
var divIcon = document.createElement('div');
divIcon.className = 'jsoneditor-icon';
button.appendChild(divIcon);
var divText = document.createElement('div');
var divIcon = document.createElement('div')
divIcon.className = 'jsoneditor-icon'
button.appendChild(divIcon)
var divText = document.createElement('div')
divText.className = 'jsoneditor-text' +
(item.click ? '' : ' jsoneditor-right-margin');
divText.appendChild(document.createTextNode(item.text));
button.appendChild(divText);
(item.click ? '' : ' jsoneditor-right-margin')
divText.appendChild(document.createTextNode(item.text))
button.appendChild(divText)
var buttonSubmenu;
var buttonSubmenu
if (item.click) {
// submenu and a button with a click handler
button.className += ' jsoneditor-default';
button.className += ' jsoneditor-default'
var buttonExpand = document.createElement('button');
buttonExpand.type = 'button';
domItem.buttonExpand = buttonExpand;
buttonExpand.className = 'jsoneditor-expand';
buttonExpand.innerHTML = '<div class="jsoneditor-expand"></div>';
li.appendChild(buttonExpand);
var buttonExpand = document.createElement('button')
buttonExpand.type = 'button'
domItem.buttonExpand = buttonExpand
buttonExpand.className = 'jsoneditor-expand'
buttonExpand.innerHTML = '<div class="jsoneditor-expand"></div>'
li.appendChild(buttonExpand)
if (item.submenuTitle) {
buttonExpand.title = item.submenuTitle;
buttonExpand.title = item.submenuTitle
}
buttonSubmenu = buttonExpand;
}
else {
buttonSubmenu = buttonExpand
} else {
// submenu and a button without a click handler
var divExpand = document.createElement('div');
divExpand.className = 'jsoneditor-expand';
button.appendChild(divExpand);
var divExpand = document.createElement('div')
divExpand.className = 'jsoneditor-expand'
button.appendChild(divExpand)
buttonSubmenu = button;
buttonSubmenu = button
}
// attach a handler to expand/collapse the submenu
buttonSubmenu.onclick = function (event) {
event.preventDefault();
me._onExpandItem(domItem);
buttonSubmenu.focus();
};
event.preventDefault()
me._onExpandItem(domItem)
buttonSubmenu.focus()
}
// create the submenu
var domSubItems = [];
domItem.subItems = domSubItems;
var ul = document.createElement('ul');
domItem.ul = ul;
ul.className = 'jsoneditor-menu';
ul.style.height = '0';
li.appendChild(ul);
createMenuItems(ul, domSubItems, item.submenu);
}
else {
var domSubItems = []
domItem.subItems = domSubItems
var ul = document.createElement('ul')
domItem.ul = ul
ul.className = 'jsoneditor-menu'
ul.style.height = '0'
li.appendChild(ul)
createMenuItems(ul, domSubItems, item.submenu)
} else {
// no submenu, just a button with clickhandler
button.innerHTML = '<div class="jsoneditor-icon"></div>' +
'<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?
// 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) {
var height = (items.length + (item.submenu ? item.submenu.length : 0)) * 24;
me.maxHeight = Math.max(me.maxHeight, height);
});
var height = (items.length + (item.submenu ? item.submenu.length : 0)) * 24
me.maxHeight = Math.max(me.maxHeight, height)
})
}
/**
@ -169,29 +166,29 @@ function ContextMenu (items, options) {
* @private
*/
ContextMenu.prototype._getVisibleButtons = function () {
var buttons = [];
var me = this;
var buttons = []
var me = this
this.dom.items.forEach(function (item) {
buttons.push(item.button);
buttons.push(item.button)
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) {
buttons.push(subItem.button);
buttons.push(subItem.button)
if (subItem.buttonExpand) {
buttons.push(subItem.buttonExpand);
buttons.push(subItem.buttonExpand)
}
// TODO: change to fully recursive method
});
})
}
});
})
return buttons;
};
return buttons
}
// 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
@ -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
*/
ContextMenu.prototype.show = function (anchor, frame, ignoreParent) {
this.hide();
this.hide()
// determine whether to display the menu below or above the anchor
var showBelow = true;
var parent = anchor.parentNode;
var anchorRect = anchor.getBoundingClientRect();
var parentRect = parent.getBoundingClientRect();
var frameRect = frame.getBoundingClientRect();
var showBelow = true
var parent = anchor.parentNode
var anchorRect = anchor.getBoundingClientRect()
var parentRect = parent.getBoundingClientRect()
var frameRect = frame.getBoundingClientRect()
var me = this;
var me = this
this.dom.absoluteAnchor = createAbsoluteAnchor(anchor, frame, function () {
me.hide()
});
})
if (anchorRect.bottom + this.maxHeight < frameRect.bottom) {
// fits below -> show below
}
else if (anchorRect.top - this.maxHeight > frameRect.top) {
} else if (anchorRect.top - this.maxHeight > frameRect.top) {
// fits above -> show above
showBelow = false;
}
else {
showBelow = false
} else {
// doesn't fit above nor below -> show below
}
var topGap = ignoreParent ? 0 : (anchorRect.top - parentRect.top);
var topGap = ignoreParent ? 0 : (anchorRect.top - parentRect.top)
// position the menu
if (showBelow) {
// display the menu below the anchor
var anchorHeight = anchor.offsetHeight;
this.dom.menu.style.left = '0';
this.dom.menu.style.top = topGap + anchorHeight + 'px';
this.dom.menu.style.bottom = '';
}
else {
var anchorHeight = anchor.offsetHeight
this.dom.menu.style.left = '0'
this.dom.menu.style.top = topGap + anchorHeight + 'px'
this.dom.menu.style.bottom = ''
} else {
// display the menu above the anchor
this.dom.menu.style.left = '0';
this.dom.menu.style.top = '';
this.dom.menu.style.bottom = '0px';
this.dom.menu.style.left = '0'
this.dom.menu.style.top = ''
this.dom.menu.style.bottom = '0px'
}
// attach the menu to the temporary, absolute anchor
// parent.insertBefore(this.dom.root, anchor);
this.dom.absoluteAnchor.appendChild(this.dom.root);
this.dom.absoluteAnchor.appendChild(this.dom.root)
// move focus to the first button in the context menu
this.selection = util.getSelection();
this.anchor = anchor;
this.selection = util.getSelection()
this.anchor = anchor
setTimeout(function () {
me.dom.focusButton.focus();
}, 0);
me.dom.focusButton.focus()
}, 0)
if (ContextMenu.visibleMenu) {
ContextMenu.visibleMenu.hide();
ContextMenu.visibleMenu.hide()
}
ContextMenu.visibleMenu = this;
};
ContextMenu.visibleMenu = this
}
/**
* Hide the context menu if visible
@ -265,22 +259,22 @@ ContextMenu.prototype.show = function (anchor, frame, ignoreParent) {
ContextMenu.prototype.hide = function () {
// remove temporary absolutely positioned anchor
if (this.dom.absoluteAnchor) {
this.dom.absoluteAnchor.destroy();
delete this.dom.absoluteAnchor;
this.dom.absoluteAnchor.destroy()
delete this.dom.absoluteAnchor
}
// remove the menu from the DOM
if (this.dom.root.parentNode) {
this.dom.root.parentNode.removeChild(this.dom.root);
this.dom.root.parentNode.removeChild(this.dom.root)
if (this.onClose) {
this.onClose();
this.onClose()
}
}
if (ContextMenu.visibleMenu == this) {
ContextMenu.visibleMenu = undefined;
if (ContextMenu.visibleMenu === this) {
ContextMenu.visibleMenu = undefined
}
};
}
/**
* Expand a submenu
@ -289,42 +283,43 @@ ContextMenu.prototype.hide = function () {
* @private
*/
ContextMenu.prototype._onExpandItem = function (domItem) {
var me = this;
var alreadyVisible = (domItem == this.expandedItem);
var me = this
var alreadyVisible = (domItem === this.expandedItem)
// hide the currently visible submenu
var expandedItem = this.expandedItem;
var expandedItem = this.expandedItem
if (expandedItem) {
//var ul = expandedItem.ul;
expandedItem.ul.style.height = '0';
expandedItem.ul.style.padding = '';
// var ul = expandedItem.ul;
expandedItem.ul.style.height = '0'
expandedItem.ul.style.padding = ''
setTimeout(function () {
if (me.expandedItem != expandedItem) {
expandedItem.ul.style.display = '';
util.removeClassName(expandedItem.ul.parentNode, 'jsoneditor-selected');
if (me.expandedItem !== expandedItem) {
expandedItem.ul.style.display = ''
util.removeClassName(expandedItem.ul.parentNode, 'jsoneditor-selected')
}
}, 300); // timeout duration must match the css transition duration
this.expandedItem = undefined;
}, 300) // timeout duration must match the css transition duration
this.expandedItem = undefined
}
if (!alreadyVisible) {
var ul = domItem.ul;
ul.style.display = 'block';
var height = ul.clientHeight; // force a reflow in Firefox
var ul = domItem.ul
ul.style.display = 'block'
// eslint-disable-next-line no-unused-expressions
ul.clientHeight // force a reflow in Firefox
setTimeout(function () {
if (me.expandedItem == domItem) {
var childsHeight = 0;
if (me.expandedItem === domItem) {
var childsHeight = 0
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.padding = '5px 10px';
ul.style.height = childsHeight + 'px'
ul.style.padding = '5px 10px'
}
}, 0);
util.addClassName(ul.parentNode, 'jsoneditor-selected');
this.expandedItem = domItem;
}, 0)
util.addClassName(ul.parentNode, 'jsoneditor-selected')
this.expandedItem = domItem
}
};
}
/**
* Handle onkeydown event
@ -332,107 +327,101 @@ ContextMenu.prototype._onExpandItem = function (domItem) {
* @private
*/
ContextMenu.prototype._onKeyDown = function (event) {
var target = event.target;
var keynum = event.which;
var handled = false;
var buttons, targetIndex, prevButton, nextButton;
var target = event.target
var keynum = event.which
var handled = false
var buttons, targetIndex, prevButton, nextButton
if (keynum == 27) { // ESC
if (keynum === 27) { // ESC
// hide the menu on ESC key
// restore previous selection and focus
if (this.selection) {
util.setSelection(this.selection);
util.setSelection(this.selection)
}
if (this.anchor) {
this.anchor.focus();
this.anchor.focus()
}
this.hide();
this.hide()
handled = true;
}
else if (keynum == 9) { // Tab
handled = true
} else if (keynum === 9) { // Tab
if (!event.shiftKey) { // Tab
buttons = this._getVisibleButtons();
targetIndex = buttons.indexOf(target);
if (targetIndex == buttons.length - 1) {
buttons = this._getVisibleButtons()
targetIndex = buttons.indexOf(target)
if (targetIndex === buttons.length - 1) {
// move to first button
buttons[0].focus();
handled = true;
buttons[0].focus()
handled = true
}
}
else { // Shift+Tab
buttons = this._getVisibleButtons();
targetIndex = buttons.indexOf(target);
if (targetIndex == 0) {
} else { // Shift+Tab
buttons = this._getVisibleButtons()
targetIndex = buttons.indexOf(target)
if (targetIndex === 0) {
// move to last button
buttons[buttons.length - 1].focus();
handled = true;
buttons[buttons.length - 1].focus()
handled = true
}
}
}
else if (keynum == 37) { // Arrow Left
if (target.className == 'jsoneditor-expand') {
buttons = this._getVisibleButtons();
targetIndex = buttons.indexOf(target);
prevButton = buttons[targetIndex - 1];
} else if (keynum === 37) { // Arrow Left
if (target.className === 'jsoneditor-expand') {
buttons = this._getVisibleButtons()
targetIndex = buttons.indexOf(target)
prevButton = buttons[targetIndex - 1]
if (prevButton) {
prevButton.focus();
prevButton.focus()
}
}
handled = true;
}
else if (keynum == 38) { // Arrow Up
buttons = this._getVisibleButtons();
targetIndex = buttons.indexOf(target);
prevButton = buttons[targetIndex - 1];
if (prevButton && prevButton.className == 'jsoneditor-expand') {
handled = true
} else if (keynum === 38) { // Arrow Up
buttons = this._getVisibleButtons()
targetIndex = buttons.indexOf(target)
prevButton = buttons[targetIndex - 1]
if (prevButton && prevButton.className === 'jsoneditor-expand') {
// skip expand button
prevButton = buttons[targetIndex - 2];
prevButton = buttons[targetIndex - 2]
}
if (!prevButton) {
// move to last button
prevButton = buttons[buttons.length - 1];
prevButton = buttons[buttons.length - 1]
}
if (prevButton) {
prevButton.focus();
prevButton.focus()
}
handled = true;
}
else if (keynum == 39) { // Arrow Right
buttons = this._getVisibleButtons();
targetIndex = buttons.indexOf(target);
nextButton = buttons[targetIndex + 1];
if (nextButton && nextButton.className == 'jsoneditor-expand') {
nextButton.focus();
handled = true
} else if (keynum === 39) { // Arrow Right
buttons = this._getVisibleButtons()
targetIndex = buttons.indexOf(target)
nextButton = buttons[targetIndex + 1]
if (nextButton && nextButton.className === 'jsoneditor-expand') {
nextButton.focus()
}
handled = true;
}
else if (keynum == 40) { // Arrow Down
buttons = this._getVisibleButtons();
targetIndex = buttons.indexOf(target);
nextButton = buttons[targetIndex + 1];
if (nextButton && nextButton.className == 'jsoneditor-expand') {
handled = true
} else if (keynum === 40) { // Arrow Down
buttons = this._getVisibleButtons()
targetIndex = buttons.indexOf(target)
nextButton = buttons[targetIndex + 1]
if (nextButton && nextButton.className === 'jsoneditor-expand') {
// skip expand button
nextButton = buttons[targetIndex + 2];
nextButton = buttons[targetIndex + 2]
}
if (!nextButton) {
// move to first button
nextButton = buttons[0];
nextButton = buttons[0]
}
if (nextButton) {
nextButton.focus();
handled = true;
nextButton.focus()
handled = true
}
handled = true;
handled = true
}
// TODO: arrow left and right
if (handled) {
event.stopPropagation();
event.preventDefault();
event.stopPropagation()
event.preventDefault()
}
};
}
module.exports = ContextMenu;
module.exports = ContextMenu

View File

@ -8,170 +8,167 @@
* @constructor
*/
function ErrorTable (config) {
this.errorTableVisible = config.errorTableVisible;
this.onToggleVisibility = config.onToggleVisibility;
this.onFocusLine = config.onFocusLine || function () {};
this.onChangeHeight = config.onChangeHeight;
this.errorTableVisible = config.errorTableVisible
this.onToggleVisibility = config.onToggleVisibility
this.onFocusLine = config.onFocusLine || function () {}
this.onChangeHeight = config.onChangeHeight
this.dom = {};
this.dom = {}
var validationErrorsContainer = document.createElement('div');
validationErrorsContainer.className = 'jsoneditor-validation-errors-container';
this.dom.validationErrorsContainer = validationErrorsContainer;
var validationErrorsContainer = document.createElement('div')
validationErrorsContainer.className = 'jsoneditor-validation-errors-container'
this.dom.validationErrorsContainer = validationErrorsContainer
var additionalErrorsIndication = document.createElement('div');
additionalErrorsIndication.style.display = 'none';
additionalErrorsIndication.className = "jsoneditor-additional-errors fadein";
additionalErrorsIndication.innerHTML = "Scroll for more &#9663;";
this.dom.additionalErrorsIndication = additionalErrorsIndication;
validationErrorsContainer.appendChild(additionalErrorsIndication);
var additionalErrorsIndication = document.createElement('div')
additionalErrorsIndication.style.display = 'none'
additionalErrorsIndication.className = 'jsoneditor-additional-errors fadein'
additionalErrorsIndication.innerHTML = 'Scroll for more &#9663;'
this.dom.additionalErrorsIndication = additionalErrorsIndication
validationErrorsContainer.appendChild(additionalErrorsIndication)
var validationErrorIcon = document.createElement('span');
validationErrorIcon.className = 'jsoneditor-validation-error-icon';
validationErrorIcon.style.display = 'none';
this.dom.validationErrorIcon = validationErrorIcon;
var validationErrorIcon = document.createElement('span')
validationErrorIcon.className = 'jsoneditor-validation-error-icon'
validationErrorIcon.style.display = 'none'
this.dom.validationErrorIcon = validationErrorIcon
var validationErrorCount = document.createElement('span');
validationErrorCount.className = 'jsoneditor-validation-error-count';
validationErrorCount.style.display = 'none';
this.dom.validationErrorCount = validationErrorCount;
var validationErrorCount = document.createElement('span')
validationErrorCount.className = 'jsoneditor-validation-error-count'
validationErrorCount.style.display = 'none'
this.dom.validationErrorCount = validationErrorCount
this.dom.parseErrorIndication = document.createElement('span');
this.dom.parseErrorIndication.className = 'jsoneditor-parse-error-icon';
this.dom.parseErrorIndication.style.display = 'none';
this.dom.parseErrorIndication = document.createElement('span')
this.dom.parseErrorIndication.className = 'jsoneditor-parse-error-icon'
this.dom.parseErrorIndication.style.display = 'none'
}
ErrorTable.prototype.getErrorTable = function () {
return this.dom.validationErrorsContainer;
};
return this.dom.validationErrorsContainer
}
ErrorTable.prototype.getErrorCounter = function () {
return this.dom.validationErrorCount;
};
return this.dom.validationErrorCount
}
ErrorTable.prototype.getWarningIcon = function () {
return this.dom.validationErrorIcon;
};
return this.dom.validationErrorIcon
}
ErrorTable.prototype.getErrorIcon = function () {
return this.dom.parseErrorIndication;
};
return this.dom.parseErrorIndication
}
ErrorTable.prototype.toggleTableVisibility = function () {
this.errorTableVisible = !this.errorTableVisible;
this.onToggleVisibility(this.errorTableVisible);
this.errorTableVisible = !this.errorTableVisible
this.onToggleVisibility(this.errorTableVisible)
}
ErrorTable.prototype.setErrors = function (errors, errorLocations) {
var me = this;
var me = this
// clear any previous errors
if (this.dom.validationErrors) {
this.dom.validationErrors.parentNode.removeChild(this.dom.validationErrors);
this.dom.validationErrors = null;
this.dom.additionalErrorsIndication.style.display = 'none';
this.dom.validationErrors.parentNode.removeChild(this.dom.validationErrors)
this.dom.validationErrors = null
this.dom.additionalErrorsIndication.style.display = 'none'
}
// create the table with errors
// keep default behavior for parse errors
if (this.errorTableVisible && errors.length > 0) {
var validationErrors = document.createElement('div');
validationErrors.className = 'jsoneditor-validation-errors';
validationErrors.innerHTML = '<table class="jsoneditor-text-errors"><tbody></tbody></table>';
var tbody = validationErrors.getElementsByTagName('tbody')[0];
var validationErrors = document.createElement('div')
validationErrors.className = 'jsoneditor-validation-errors'
validationErrors.innerHTML = '<table class="jsoneditor-text-errors"><tbody></tbody></table>'
var tbody = validationErrors.getElementsByTagName('tbody')[0]
errors.forEach(function (error) {
var message;
var message
if (typeof error === 'string') {
message = '<td colspan="2"><pre>' + error + '</pre></td>';
}
else {
message = '<td colspan="2"><pre>' + error + '</pre></td>'
} else {
message =
'<td>' + (error.dataPath || '') + '</td>' +
'<td><pre>' + error.message + '</pre></td>';
'<td><pre>' + error.message + '</pre></td>'
}
var line;
var line
if (!isNaN(error.line)) {
line = error.line;
line = error.line
} 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) {
line = errLoc.line + 1;
line = errLoc.line + 1
}
}
var trEl = document.createElement('tr');
trEl.className = !isNaN(line) ? 'jump-to-line' : '';
var trEl = document.createElement('tr')
trEl.className = !isNaN(line) ? 'jump-to-line' : ''
if (error.type === 'error') {
trEl.className += ' parse-error';
trEl.className += ' parse-error'
} 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.onclick = function() {
me.onFocusLine(line);
};
trEl.innerHTML = ('<td><button class="jsoneditor-schema-error"></button></td><td style="white-space:nowrap;">' + (!isNaN(line) ? ('Ln ' + line) : '') + '</td>' + message)
trEl.onclick = function () {
me.onFocusLine(line)
}
tbody.appendChild(trEl);
});
tbody.appendChild(trEl)
})
this.dom.validationErrors = validationErrors;
this.dom.validationErrorsContainer.appendChild(validationErrors);
this.dom.additionalErrorsIndication.title = errors.length + " errors total";
this.dom.validationErrors = validationErrors
this.dom.validationErrorsContainer.appendChild(validationErrors)
this.dom.additionalErrorsIndication.title = errors.length + ' errors total'
if (this.dom.validationErrorsContainer.clientHeight < this.dom.validationErrorsContainer.scrollHeight) {
this.dom.additionalErrorsIndication.style.display = 'block';
this.dom.additionalErrorsIndication.style.display = 'block'
this.dom.validationErrorsContainer.onscroll = function () {
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 {
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.paddingBottom = height + 'px';
this.onChangeHeight(height);
this.onChangeHeight(height)
} else {
this.onChangeHeight(0);
this.onChangeHeight(0)
}
// update the status bar
var validationErrorsCount = errors.filter(function (error) {
return error.type !== 'error'
}).length;
}).length
if (validationErrorsCount > 0) {
this.dom.validationErrorCount.style.display = 'inline';
this.dom.validationErrorCount.innerText = validationErrorsCount;
this.dom.validationErrorCount.onclick = this.toggleTableVisibility.bind(this);
this.dom.validationErrorCount.style.display = 'inline'
this.dom.validationErrorCount.innerText = validationErrorsCount
this.dom.validationErrorCount.onclick = this.toggleTableVisibility.bind(this)
this.dom.validationErrorIcon.style.display = 'inline';
this.dom.validationErrorIcon.title = validationErrorsCount + ' schema validation error(s) found';
this.dom.validationErrorIcon.onclick = this.toggleTableVisibility.bind(this);
}
else {
this.dom.validationErrorCount.style.display = 'none';
this.dom.validationErrorIcon.style.display = 'none';
this.dom.validationErrorIcon.style.display = 'inline'
this.dom.validationErrorIcon.title = validationErrorsCount + ' schema validation error(s) found'
this.dom.validationErrorIcon.onclick = this.toggleTableVisibility.bind(this)
} else {
this.dom.validationErrorCount.style.display = 'none'
this.dom.validationErrorIcon.style.display = 'none'
}
// update the parse error icon
var hasParseErrors = errors.some(function (error) {
return error.type === 'error'
});
})
if (hasParseErrors) {
var line = errors[0].line
this.dom.parseErrorIndication.style.display = 'block';
this.dom.parseErrorIndication.style.display = 'block'
this.dom.parseErrorIndication.title = !isNaN(line)
? ('parse error on line ' + line)
: 'parse error - check that the json is valid';
? ('parse error on line ' + line)
: '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

View File

@ -1,4 +1,4 @@
'use strict';
'use strict'
/**
* The highlighter can highlight/unhighlight a node, and
@ -6,7 +6,7 @@
* @constructor Highlighter
*/
function Highlighter () {
this.locked = false;
this.locked = false
}
/**
@ -15,23 +15,23 @@ function Highlighter () {
*/
Highlighter.prototype.highlight = function (node) {
if (this.locked) {
return;
return
}
if (this.node != node) {
if (this.node !== node) {
// unhighlight current node
if (this.node) {
this.node.setHighlight(false);
this.node.setHighlight(false)
}
// highlight new node
this.node = node;
this.node.setHighlight(true);
this.node = node
this.node.setHighlight(true)
}
// cancel any current timeout
this._cancelUnhighlight();
};
this._cancelUnhighlight()
}
/**
* Unhighlight currently highlighted node.
@ -39,23 +39,23 @@ Highlighter.prototype.highlight = function (node) {
*/
Highlighter.prototype.unhighlight = function () {
if (this.locked) {
return;
return
}
var me = this;
var me = this
if (this.node) {
this._cancelUnhighlight();
this._cancelUnhighlight()
// do the unhighlighting after a small delay, to prevent re-highlighting
// the same node when moving from the drag-icon to the contextmenu-icon
// or vice versa.
this.unhighlightTimer = setTimeout(function () {
me.node.setHighlight(false);
me.node = undefined;
me.unhighlightTimer = undefined;
}, 0);
me.node.setHighlight(false)
me.node = undefined
me.unhighlightTimer = undefined
}, 0)
}
};
}
/**
* Cancel an unhighlight action (if before the timeout of the unhighlight action)
@ -63,24 +63,24 @@ Highlighter.prototype.unhighlight = function () {
*/
Highlighter.prototype._cancelUnhighlight = function () {
if (this.unhighlightTimer) {
clearTimeout(this.unhighlightTimer);
this.unhighlightTimer = undefined;
clearTimeout(this.unhighlightTimer)
this.unhighlightTimer = undefined
}
};
}
/**
* Lock highlighting or unhighlighting nodes.
* methods highlight and unhighlight do not work while locked.
*/
Highlighter.prototype.lock = function () {
this.locked = true;
};
this.locked = true
}
/**
* Unlock highlighting or unhighlighting nodes
*/
Highlighter.prototype.unlock = function () {
this.locked = false;
};
this.locked = false
}
module.exports = Highlighter;
module.exports = Highlighter

View File

@ -7,82 +7,81 @@
* @constructor
*/
function History (onChange, calculateItemSize, limit) {
this.onChange = onChange;
this.onChange = onChange
this.calculateItemSize = calculateItemSize || function () {
return 1;
};
this.limit = limit;
return 1
}
this.limit = limit
this.items = [];
this.index = -1;
this.items = []
this.index = -1
}
History.prototype.add = function (item) {
// limit number of items in history so that the total size doesn't
// always keep at least one item in memory
while (this._calculateHistorySize() > this.limit && this.items.length > 1) {
this.items.shift();
this.index--;
this.items.shift()
this.index--
}
// cleanup any redo action that are not valid anymore
this.items = this.items.slice(0, this.index + 1);
this.items = this.items.slice(0, this.index + 1)
this.items.push(item);
this.index++;
this.items.push(item)
this.index++
this.onChange();
};
this.onChange()
}
History.prototype._calculateHistorySize = function () {
var calculateItemSize = this.calculateItemSize;
var totalSize = 0;
var calculateItemSize = this.calculateItemSize
var totalSize = 0
this.items.forEach(function (item) {
totalSize += calculateItemSize(item);
});
totalSize += calculateItemSize(item)
})
return totalSize;
return totalSize
}
History.prototype.undo = function () {
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 () {
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 () {
return this.index > 0;
};
return this.index > 0
}
History.prototype.canRedo = function () {
return this.index < this.items.length - 1;
};
return this.index < this.items.length - 1
}
History.prototype.clear = function () {
this.items = [];
this.index = -1;
this.items = []
this.index = -1
this.onChange();
};
this.onChange()
}
module.exports = History;
module.exports = History

View File

@ -1,23 +1,22 @@
'use strict';
'use strict'
var Ajv;
var Ajv
try {
Ajv = require('ajv');
}
catch (err) {
Ajv = require('ajv')
} catch (err) {
// 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 VanillaPicker = require('./vanilla-picker'); // 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 treemode = require('./treemode');
var textmode = require('./textmode');
var previewmode = require('./previewmode');
var util = require('./util');
var treemode = require('./treemode')
var textmode = require('./textmode')
var previewmode = require('./previewmode')
var util = require('./util')
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
* modes 'form', 'tree' and
* 'view'
* {Number} maxVisibleChilds Number of children allowed for a node
* in 'tree', 'view', or 'form' mode before
* the "show more/show all" buttons appear.
* {Number} maxVisibleChilds Number of children allowed for a node
* in 'tree', 'view', or 'form' mode before
* the "show more/show all" buttons appear.
* 100 by default.
*
* @param {Object | undefined} json JSON object
*/
function JSONEditor (container, options, json) {
if (!(this instanceof JSONEditor)) {
throw new Error('JSONEditor constructor called without "new".');
throw new Error('JSONEditor constructor called without "new".')
}
// check for unsupported browser (IE8 and older)
var ieVersion = util.getInternetExplorerVersion();
if (ieVersion != -1 && ieVersion < 9) {
var ieVersion = util.getInternetExplorerVersion()
if (ieVersion !== -1 && ieVersion < 9) {
throw new Error('Unsupported browser, IE9 or newer required. ' +
'Please install the newest version of your browser.');
'Please install the newest version of your browser.')
}
if (options) {
// check for deprecated options
if (options.error) {
console.warn('Option "error" has been renamed to "onError"');
options.onError = options.error;
delete options.error;
console.warn('Option "error" has been renamed to "onError"')
options.onError = options.error
delete options.error
}
if (options.change) {
console.warn('Option "change" has been renamed to "onChange"');
options.onChange = options.change;
delete options.change;
console.warn('Option "change" has been renamed to "onChange"')
options.onChange = options.change
delete options.change
}
if (options.editable) {
console.warn('Option "editable" has been renamed to "onEditable"');
options.onEditable = options.editable;
delete options.editable;
console.warn('Option "editable" has been renamed to "onEditable"')
options.onEditable = options.editable
delete options.editable
}
// warn if onChangeJSON is used when mode can be `text` or `code`
@ -131,7 +130,7 @@ function JSONEditor (container, options, json) {
if (options.mode === 'text' || options.mode === 'code' ||
(options.modes && (options.modes.indexOf('text') !== -1 || options.modes.indexOf('code') !== -1))) {
console.warn('Option "onChangeJSON" is not applicable to modes "text" and "code". ' +
'Use "onChangeText" or "onChange" instead.');
'Use "onChangeText" or "onChange" instead.')
}
}
@ -139,14 +138,14 @@ function JSONEditor (container, options, json) {
if (options) {
Object.keys(options).forEach(function (option) {
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) {
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} > }
*/
JSONEditor.modes = {};
JSONEditor.modes = {}
// debounce interval for JSON schema vaidation in milliseconds
JSONEditor.prototype.DEBOUNCE_INTERVAL = 150;
JSONEditor.prototype.DEBOUNCE_INTERVAL = 150
JSONEditor.VALID_OPTIONS = [
'ajv', 'schema', 'schemaRefs','templates',
'ajv', 'schema', 'schemaRefs', 'templates',
'ace', 'theme', 'autocomplete',
'onChange', 'onChangeJSON', 'onChangeText',
'onEditable', 'onError', 'onEvent', 'onModeChange', 'onNodeName', 'onValidate', 'onCreateMenu',
@ -181,7 +180,7 @@ JSONEditor.VALID_OPTIONS = [
'escapeUnicode', 'history', 'search', 'mode', 'modes', 'name', 'indentation',
'sortObjectKeys', 'navigationBar', 'statusBar', 'mainMenuBar', 'languages', 'language', 'enableSort', 'enableTransform',
'maxVisibleChilds'
];
]
/**
* Create the JSONEditor
@ -191,50 +190,50 @@ JSONEditor.VALID_OPTIONS = [
* @private
*/
JSONEditor.prototype._create = function (container, options, json) {
this.container = container;
this.options = options || {};
this.json = json || {};
this.container = container
this.options = options || {}
this.json = json || {}
var mode = this.options.mode || (this.options.modes && this.options.modes[0]) || 'tree';
this.setMode(mode);
};
var mode = this.options.mode || (this.options.modes && this.options.modes[0]) || 'tree'
this.setMode(mode)
}
/**
* Destroy the editor. Clean up DOM, event listeners, and web workers.
*/
JSONEditor.prototype.destroy = function () {};
JSONEditor.prototype.destroy = function () {}
/**
* Set JSON object in editor
* @param {Object | undefined} json JSON data
*/
JSONEditor.prototype.set = function (json) {
this.json = json;
};
this.json = json
}
/**
* Get JSON from the editor
* @returns {Object} json
*/
JSONEditor.prototype.get = function () {
return this.json;
};
return this.json
}
/**
* Set string containing JSON for the editor
* @param {String | undefined} jsonText
*/
JSONEditor.prototype.setText = function (jsonText) {
this.json = util.parse(jsonText);
};
this.json = util.parse(jsonText)
}
/**
* Get stringified JSON contents from the editor
* @returns {String} jsonText
*/
JSONEditor.prototype.getText = function () {
return JSON.stringify(this.json);
};
return JSON.stringify(this.json)
}
/**
* Set a field name for the root node.
@ -242,18 +241,18 @@ JSONEditor.prototype.getText = function () {
*/
JSONEditor.prototype.setName = function (name) {
if (!this.options) {
this.options = {};
this.options = {}
}
this.options.name = name;
};
this.options.name = name
}
/**
* Get the field name for the root node.
* @return {String | undefined} name
*/
JSONEditor.prototype.getName = function () {
return this.options && this.options.name;
};
return this.options && this.options.name
}
/**
* Change the mode of the editor.
@ -264,65 +263,61 @@ JSONEditor.prototype.getName = function () {
JSONEditor.prototype.setMode = function (mode) {
// if the mode is the same as current mode (and it's not the first time), do nothing.
if (mode === this.options.mode && this.create) {
return;
return
}
var container = this.container;
var options = util.extend({}, this.options);
var oldMode = options.mode;
var data;
var name;
var container = this.container
var options = util.extend({}, this.options)
var oldMode = options.mode
var data
var name
options.mode = mode;
var config = JSONEditor.modes[mode];
options.mode = mode
var config = JSONEditor.modes[mode]
if (config) {
try {
var asText = (config.data == 'text');
name = this.getName();
data = this[asText ? 'getText' : 'get'](); // get text or json
var asText = (config.data === 'text')
name = this.getName()
data = this[asText ? 'getText' : 'get']() // get text or json
this.destroy();
util.clear(this);
util.extend(this, config.mixin);
this.create(container, options);
this.destroy()
util.clear(this)
util.extend(this, config.mixin)
this.create(container, options)
this.setName(name);
this[asText ? 'setText' : 'set'](data); // set text or json
this.setName(name)
this[asText ? 'setText' : 'set'](data) // set text or json
if (typeof config.load === 'function') {
try {
config.load.call(this);
}
catch (err) {
console.error(err);
config.load.call(this)
} catch (err) {
console.error(err)
}
}
if (typeof options.onModeChange === 'function' && mode !== oldMode) {
try {
options.onModeChange(mode, oldMode);
}
catch (err) {
console.error(err);
options.onModeChange(mode, oldMode)
} catch (err) {
console.error(err)
}
}
} catch (err) {
this._onError(err)
}
catch (err) {
this._onError(err);
}
} else {
throw new Error('Unknown mode "' + options.mode + '"')
}
else {
throw new Error('Unknown mode "' + options.mode + '"');
}
};
}
/**
* Get the current mode
* @return {string}
*/
JSONEditor.prototype.getMode = function () {
return this.options.mode;
};
return this.options.mode
}
/**
* Throw an error. If an error callback is configured in options.error, this
@ -330,14 +325,13 @@ JSONEditor.prototype.getMode = function () {
* @param {Error} err
* @private
*/
JSONEditor.prototype._onError = function(err) {
JSONEditor.prototype._onError = function (err) {
if (this.options && typeof this.options.onError === 'function') {
this.options.onError(err);
this.options.onError(err)
} else {
throw err
}
else {
throw err;
}
};
}
/**
* Set a JSON schema for validation of the JSON object.
@ -349,60 +343,57 @@ JSONEditor.prototype._onError = function(err) {
JSONEditor.prototype.setSchema = function (schema, schemaRefs) {
// compile a JSON schema validator if a JSON schema is provided
if (schema) {
var ajv;
var ajv
try {
// grab ajv from options if provided, else create a new instance
if (this.options.ajv) {
ajv = this.options.ajv
}
else {
} else {
ajv = Ajv({
allErrors: true,
verbose: true,
schemaId: 'auto',
$data: true
});
})
// support both draft-04 and draft-06 alongside the latest draft-07
ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-04.json'));
ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-06.json'));
ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-04.json'))
ajv.addMetaSchema(require('ajv/lib/refs/json-schema-draft-06.json'))
}
}
catch (err) {
console.warn('Failed to create an instance of Ajv, JSON Schema validation is not available. Please use a JSONEditor bundle including Ajv, or pass an instance of Ajv as via the configuration option `ajv`.');
} catch (err) {
console.warn('Failed to create an instance of Ajv, JSON Schema validation is not available. Please use a JSONEditor bundle including Ajv, or pass an instance of Ajv as via the configuration option `ajv`.')
}
if (ajv) {
if(schemaRefs) {
if (schemaRefs) {
for (var ref in schemaRefs) {
ajv.removeSchema(ref); // When updating a schema - old refs has to be removed first
if(schemaRefs[ref]) {
ajv.addSchema(schemaRefs[ref], ref);
ajv.removeSchema(ref) // When updating a schema - old refs has to be removed first
if (schemaRefs[ref]) {
ajv.addSchema(schemaRefs[ref], ref)
}
}
this.options.schemaRefs = schemaRefs;
this.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,
// the set schema is not lost
this.options.schema = schema;
this.options.schema = schema
// validate now
this.validate();
this.validate()
}
this.refresh(); // update DOM
}
else {
this.refresh() // update DOM
} else {
// remove current schema
this.validateSchema = null;
this.options.schema = null;
this.options.schemaRefs = null;
this.validate(); // to clear current error messages
this.refresh(); // update DOM
this.validateSchema = null
this.options.schema = null
this.options.schemaRefs = null
this.validate() // to clear current error messages
this.refresh() // update DOM
}
};
}
/**
* Validate current JSON object against the configured JSON schema
@ -410,14 +401,14 @@ JSONEditor.prototype.setSchema = function (schema, schemaRefs) {
*/
JSONEditor.prototype.validate = function () {
// must be implemented by treemode and textmode
};
}
/**
* Refresh the rendered contents
*/
JSONEditor.prototype.refresh = function () {
// can be implemented by treemode and textmode
};
}
/**
* Register a plugin with one ore multiple modes for the JSON Editor.
@ -439,51 +430,50 @@ JSONEditor.prototype.refresh = function () {
* @param {Object | Array} mode A mode object or an array with multiple mode objects.
*/
JSONEditor.registerMode = function (mode) {
var i, prop;
var i, prop
if (util.isArray(mode)) {
// multiple modes
for (i = 0; i < mode.length; i++) {
JSONEditor.registerMode(mode[i]);
JSONEditor.registerMode(mode[i])
}
}
else {
} else {
// validate the new mode
if (!('mode' in mode)) throw new Error('Property "mode" missing');
if (!('mixin' in mode)) throw new Error('Property "mixin" missing');
if (!('data' in mode)) throw new Error('Property "data" missing');
var name = mode.mode;
if (!('mode' in mode)) throw new Error('Property "mode" missing')
if (!('mixin' in mode)) throw new Error('Property "mixin" missing')
if (!('data' in mode)) throw new Error('Property "data" missing')
var name = mode.mode
if (name in JSONEditor.modes) {
throw new Error('Mode "' + name + '" already registered');
throw new Error('Mode "' + name + '" already registered')
}
// validate the mixin
if (typeof mode.mixin.create !== 'function') {
throw new Error('Required function "create" missing on mixin');
throw new Error('Required function "create" missing on mixin')
}
var reserved = ['setMode', 'registerMode', 'modes'];
var reserved = ['setMode', 'registerMode', 'modes']
for (i = 0; i < reserved.length; i++) {
prop = reserved[i];
prop = reserved[i]
if (prop in mode.mixin) {
throw new Error('Reserved property "' + prop + '" not allowed in mixin');
throw new Error('Reserved property "' + prop + '" not allowed in mixin')
}
}
JSONEditor.modes[name] = mode;
JSONEditor.modes[name] = mode
}
};
}
// register tree, text, and preview modes
JSONEditor.registerMode(treemode);
JSONEditor.registerMode(textmode);
JSONEditor.registerMode(previewmode);
JSONEditor.registerMode(treemode)
JSONEditor.registerMode(textmode)
JSONEditor.registerMode(previewmode)
// expose some of the libraries that can be used customized
JSONEditor.ace = ace;
JSONEditor.Ajv = Ajv;
JSONEditor.VanillaPicker = VanillaPicker;
JSONEditor.ace = ace
JSONEditor.Ajv = Ajv
JSONEditor.VanillaPicker = VanillaPicker
// default export for TypeScript ES6 projects
JSONEditor.default = JSONEditor;
JSONEditor.default = JSONEditor
module.exports = JSONEditor;
module.exports = JSONEditor

View File

@ -1,7 +1,7 @@
'use strict';
'use strict'
var ContextMenu = require('./ContextMenu');
var translate = require('./i18n').translate;
var ContextMenu = require('./ContextMenu')
var translate = require('./i18n').translate
/**
* 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
* @constructor
*/
function ModeSwitcher(container, modes, current, onSwitch) {
function ModeSwitcher (container, modes, current, onSwitch) {
// available modes
var availableModes = {
code: {
'text': translate('modeCodeText'),
'title': translate('modeCodeTitle'),
'click': function () {
text: translate('modeCodeText'),
title: translate('modeCodeTitle'),
click: function () {
onSwitch('code')
}
},
form: {
'text': translate('modeFormText'),
'title': translate('modeFormTitle'),
'click': function () {
onSwitch('form');
text: translate('modeFormText'),
title: translate('modeFormTitle'),
click: function () {
onSwitch('form')
}
},
text: {
'text': translate('modeTextText'),
'title': translate('modeTextTitle'),
'click': function () {
onSwitch('text');
text: translate('modeTextText'),
title: translate('modeTextTitle'),
click: function () {
onSwitch('text')
}
},
tree: {
'text': translate('modeTreeText'),
'title': translate('modeTreeTitle'),
'click': function () {
onSwitch('tree');
text: translate('modeTreeText'),
title: translate('modeTreeTitle'),
click: function () {
onSwitch('tree')
}
},
view: {
'text': translate('modeViewText'),
'title': translate('modeViewTitle'),
'click': function () {
onSwitch('view');
text: translate('modeViewText'),
title: translate('modeViewTitle'),
click: function () {
onSwitch('view')
}
},
preview: {
'text': translate('modePreviewText'),
'title': translate('modePreviewTitle'),
'click': function () {
onSwitch('preview');
text: translate('modePreviewText'),
title: translate('modePreviewTitle'),
click: function () {
onSwitch('preview')
}
}
};
}
// list the selected modes
var items = [];
var items = []
for (var i = 0; i < modes.length; i++) {
var mode = modes[i];
var item = availableModes[mode];
var mode = modes[i]
var item = availableModes[mode]
if (!item) {
throw new Error('Unknown mode "' + mode + '"');
throw new Error('Unknown mode "' + mode + '"')
}
item.className = 'jsoneditor-type-modes' + ((current == mode) ? ' jsoneditor-selected' : '');
items.push(item);
item.className = 'jsoneditor-type-modes' + ((current === mode) ? ' jsoneditor-selected' : '')
items.push(item)
}
// retrieve the title of current mode
var currentMode = availableModes[current];
var currentMode = availableModes[current]
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
var box = document.createElement('button');
box.type = 'button';
box.className = 'jsoneditor-modes jsoneditor-separator';
box.innerHTML = currentTitle + ' &#x25BE;';
box.title = 'Switch editor mode';
var box = document.createElement('button')
box.type = 'button'
box.className = 'jsoneditor-modes jsoneditor-separator'
box.innerHTML = currentTitle + ' &#x25BE;'
box.title = 'Switch editor mode'
box.onclick = function () {
var menu = new ContextMenu(items);
menu.show(box, container);
};
var menu = new ContextMenu(items)
menu.show(box, container)
}
var frame = document.createElement('div');
frame.className = 'jsoneditor-modes';
frame.style.position = 'relative';
frame.appendChild(box);
var frame = document.createElement('div')
frame.className = 'jsoneditor-modes'
frame.style.position = 'relative'
frame.appendChild(box)
container.appendChild(frame);
container.appendChild(frame)
this.dom = {
container: container,
box: box,
frame: frame
};
}
}
/**
* Set focus to switcher
*/
ModeSwitcher.prototype.focus = function () {
this.dom.box.focus();
};
this.dom.box.focus()
}
/**
* Destroy the ModeSwitcher, remove from DOM
*/
ModeSwitcher.prototype.destroy = function () {
if (this.dom && this.dom.frame && this.dom.frame.parentNode) {
this.dom.frame.parentNode.removeChild(this.dom.frame);
this.dom.frame.parentNode.removeChild(this.dom.frame)
}
this.dom = null;
};
this.dom = null
}
module.exports = ModeSwitcher;
module.exports = ModeSwitcher

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
'use strict';
'use strict'
var util = require('./util');
var util = require('./util')
/**
* @constructor History
@ -8,190 +8,190 @@ var util = require('./util');
* @param {JSONEditor} editor
*/
function NodeHistory (editor) {
this.editor = editor;
this.history = [];
this.index = -1;
this.editor = editor
this.history = []
this.index = -1
this.clear();
this.clear()
// helper function to find a Node from a path
function findNode(path) {
function findNode (path) {
return editor.node.findNodeByInternalPath(path)
}
// map with all supported actions
this.actions = {
'editField': {
'undo': function (params) {
var parentNode = findNode(params.parentPath);
var node = parentNode.childs[params.index];
node.updateField(params.oldValue);
editField: {
undo: function (params) {
var parentNode = findNode(params.parentPath)
var node = parentNode.childs[params.index]
node.updateField(params.oldValue)
},
'redo': function (params) {
var parentNode = findNode(params.parentPath);
var node = parentNode.childs[params.index];
node.updateField(params.newValue);
redo: function (params) {
var parentNode = findNode(params.parentPath)
var node = parentNode.childs[params.index]
node.updateField(params.newValue)
}
},
'editValue': {
'undo': function (params) {
findNode(params.path).updateValue(params.oldValue);
editValue: {
undo: function (params) {
findNode(params.path).updateValue(params.oldValue)
},
'redo': function (params) {
findNode(params.path).updateValue(params.newValue);
redo: function (params) {
findNode(params.path).updateValue(params.newValue)
}
},
'changeType': {
'undo': function (params) {
findNode(params.path).changeType(params.oldType);
changeType: {
undo: function (params) {
findNode(params.path).changeType(params.oldType)
},
'redo': function (params) {
findNode(params.path).changeType(params.newType);
redo: function (params) {
findNode(params.path).changeType(params.newType)
}
},
'appendNodes': {
'undo': function (params) {
var parentNode = findNode(params.parentPath);
appendNodes: {
undo: function (params) {
var parentNode = findNode(params.parentPath)
params.paths.map(findNode).forEach(function (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);
});
parentNode.removeChild(node)
})
},
'redo': function (params) {
var parentNode = findNode(params.parentPath);
var beforeNode = findNode(params.beforePath);
redo: function (params) {
var parentNode = findNode(params.parentPath)
params.nodes.forEach(function (node) {
parentNode.insertBefore(node, beforeNode);
});
parentNode.appendChild(node)
})
}
},
'insertAfterNodes': {
'undo': function (params) {
var parentNode = findNode(params.parentPath);
insertBeforeNodes: {
undo: function (params) {
var parentNode = findNode(params.parentPath)
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);
redo: function (params) {
var parentNode = findNode(params.parentPath)
var beforeNode = findNode(params.beforePath)
params.nodes.forEach(function (node) {
parentNode.insertAfter(node, afterNode);
afterNode = node;
});
parentNode.insertBefore(node, beforeNode)
})
}
},
'removeNodes': {
'undo': function (params) {
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);
insertAfterNodes: {
undo: function (params) {
var parentNode = findNode(params.parentPath)
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': {
'undo': function (params) {
var parentNode = findNode(params.parentPath);
removeNodes: {
undo: function (params) {
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) {
parentNode.removeChild(node);
});
parentNode.removeChild(node)
})
},
'redo': function (params) {
var parentNode = findNode(params.parentPath);
var afterNode = findNode(params.afterPath);
var nodes = params.paths.map(findNode);
redo: function (params) {
var parentNode = findNode(params.parentPath)
var afterNode = findNode(params.afterPath)
var nodes = params.paths.map(findNode)
nodes.forEach(function (node) {
var clone = node.clone();
var clone = node.clone()
if (parentNode.type === 'object') {
var existingFieldNames = parentNode.getFieldNames();
clone.field = util.findUniqueName(node.field, existingFieldNames);
var existingFieldNames = parentNode.getFieldNames()
clone.field = util.findUniqueName(node.field, existingFieldNames)
}
parentNode.insertAfter(clone, afterNode);
afterNode = clone;
});
parentNode.insertAfter(clone, afterNode)
afterNode = clone
})
}
},
'moveNodes': {
'undo': function (params) {
var oldParentNode = findNode(params.oldParentPath);
var newParentNode = findNode(params.newParentPath);
var oldBeforeNode = oldParentNode.childs[params.oldIndex] || oldParentNode.append;
moveNodes: {
undo: function (params) {
var oldParentNode = findNode(params.oldParentPath)
var newParentNode = findNode(params.newParentPath)
var oldBeforeNode = oldParentNode.childs[params.oldIndex] || oldParentNode.append
// 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) {
node.field = params.fieldNames[index];
oldParentNode.moveBefore(node, oldBeforeNode);
});
node.field = params.fieldNames[index]
oldParentNode.moveBefore(node, oldBeforeNode)
})
// This is a hack to work around an issue that we don't know tha original
// path of the new parent after dragging, as the node is already moved at that time.
if (params.newParentPathRedo === null) {
params.newParentPathRedo = newParentNode.getInternalPath();
params.newParentPathRedo = newParentNode.getInternalPath()
}
},
'redo': function (params) {
var oldParentNode = findNode(params.oldParentPathRedo);
var newParentNode = findNode(params.newParentPathRedo);
var newBeforeNode = newParentNode.childs[params.newIndexRedo] || newParentNode.append;
redo: function (params) {
var oldParentNode = findNode(params.oldParentPathRedo)
var newParentNode = findNode(params.newParentPathRedo)
var newBeforeNode = newParentNode.childs[params.newIndexRedo] || newParentNode.append
// 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) {
node.field = params.fieldNames[index];
newParentNode.moveBefore(node, newBeforeNode);
});
node.field = params.fieldNames[index]
newParentNode.moveBefore(node, newBeforeNode)
})
}
},
'sort': {
'undo': function (params) {
var node = findNode(params.path);
node.hideChilds();
node.childs = params.oldChilds;
node.updateDom({updateIndexes: true});
node.showChilds();
sort: {
undo: function (params) {
var node = findNode(params.path)
node.hideChilds()
node.childs = params.oldChilds
node.updateDom({ updateIndexes: true })
node.showChilds()
},
'redo': function (params) {
var node = findNode(params.path);
node.hideChilds();
node.childs = params.newChilds;
node.updateDom({updateIndexes: true});
node.showChilds();
redo: function (params) {
var node = findNode(params.path)
node.hideChilds()
node.childs = params.newChilds
node.updateDom({ updateIndexes: true })
node.showChilds()
}
},
'transform': {
'undo': function (params) {
findNode(params.path).setInternalValue(params.oldValue);
transform: {
undo: function (params) {
findNode(params.path).setInternalValue(params.oldValue)
// TODO: would be nice to restore the state of the node and childs
},
'redo': function (params) {
findNode(params.path).setInternalValue(params.newValue);
redo: function (params) {
findNode(params.path).setInternalValue(params.newValue)
// 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: implement history for actions "expand", "collapse", "scroll", "setDocument"
};
}
}
/**
* The method onChange is executed when the History is changed, and can
* be overloaded.
*/
NodeHistory.prototype.onChange = function () {};
NodeHistory.prototype.onChange = function () {}
/**
* Add a new action to the history
@ -220,118 +220,114 @@ NodeHistory.prototype.onChange = function () {};
* needed to undo or redo the action.
*/
NodeHistory.prototype.add = function (action, params) {
this.index++;
this.index++
this.history[this.index] = {
'action': action,
'params': params,
'timestamp': new Date()
};
action: action,
params: params,
timestamp: new Date()
}
// remove redo actions which are invalid now
if (this.index < this.history.length - 1) {
this.history.splice(this.index + 1, this.history.length - this.index - 1);
this.history.splice(this.index + 1, this.history.length - this.index - 1)
}
// fire onchange event
this.onChange();
};
this.onChange()
}
/**
* Clear history
*/
NodeHistory.prototype.clear = function () {
this.history = [];
this.index = -1;
this.history = []
this.index = -1
// fire onchange event
this.onChange();
};
this.onChange()
}
/**
* Check if there is an action available for undo
* @return {Boolean} canUndo
*/
NodeHistory.prototype.canUndo = function () {
return (this.index >= 0);
};
return (this.index >= 0)
}
/**
* Check if there is an action available for redo
* @return {Boolean} canRedo
*/
NodeHistory.prototype.canRedo = function () {
return (this.index < this.history.length - 1);
};
return (this.index < this.history.length - 1)
}
/**
* Undo the last action
*/
NodeHistory.prototype.undo = function () {
if (this.canUndo()) {
var obj = this.history[this.index];
var obj = this.history[this.index]
if (obj) {
var action = this.actions[obj.action];
var action = this.actions[obj.action]
if (action && action.undo) {
action.undo(obj.params);
action.undo(obj.params)
if (obj.params.oldSelection) {
try {
this.editor.setDomSelection(obj.params.oldSelection);
}
catch (err) {
console.error(err);
this.editor.setDomSelection(obj.params.oldSelection)
} catch (err) {
console.error(err)
}
}
}
else {
console.error(new Error('unknown action "' + obj.action + '"'));
} else {
console.error(new Error('unknown action "' + obj.action + '"'))
}
}
this.index--;
this.index--
// fire onchange event
this.onChange();
this.onChange()
}
};
}
/**
* Redo the last action
*/
NodeHistory.prototype.redo = function () {
if (this.canRedo()) {
this.index++;
this.index++
var obj = this.history[this.index];
var obj = this.history[this.index]
if (obj) {
var action = this.actions[obj.action];
var action = this.actions[obj.action]
if (action && action.redo) {
action.redo(obj.params);
action.redo(obj.params)
if (obj.params.newSelection) {
try {
this.editor.setDomSelection(obj.params.newSelection);
}
catch (err) {
console.error(err);
this.editor.setDomSelection(obj.params.newSelection)
} catch (err) {
console.error(err)
}
}
}
else {
console.error(new Error('unknown action "' + obj.action + '"'));
} else {
console.error(new Error('unknown action "' + obj.action + '"'))
}
}
// fire onchange event
this.onChange();
this.onChange()
}
};
}
/**
* Destroy history
*/
NodeHistory.prototype.destroy = function () {
this.editor = null;
this.editor = null
this.history = [];
this.index = -1;
};
this.history = []
this.index = -1
}
module.exports = NodeHistory;
module.exports = NodeHistory

View File

@ -1,4 +1,4 @@
"use strict";
'use strict'
/**
* @constructor SearchBox
@ -7,80 +7,80 @@
* @param {Element} container HTML container element of where to
* create the search box
*/
function SearchBox(editor, container) {
var searchBox = this;
function SearchBox (editor, container) {
var searchBox = this
this.editor = editor;
this.timeout = undefined;
this.delay = 200; // ms
this.lastText = undefined;
this.editor = editor
this.timeout = undefined
this.delay = 200 // ms
this.lastText = undefined
this.dom = {};
this.dom.container = container;
this.dom = {}
this.dom.container = container
var wrapper = document.createElement("div");
this.dom.wrapper = wrapper;
wrapper.className = "jsoneditor-search";
container.appendChild(wrapper);
var wrapper = document.createElement('div')
this.dom.wrapper = wrapper
wrapper.className = 'jsoneditor-search'
container.appendChild(wrapper)
var results = document.createElement("div");
this.dom.results = results;
results.className = "jsoneditor-results";
wrapper.appendChild(results);
var results = document.createElement('div')
this.dom.results = results
results.className = 'jsoneditor-results'
wrapper.appendChild(results)
var divInput = document.createElement("div");
this.dom.input = divInput;
divInput.className = "jsoneditor-frame";
divInput.title = "Search fields and values";
wrapper.appendChild(divInput);
var divInput = document.createElement('div')
this.dom.input = divInput
divInput.className = 'jsoneditor-frame'
divInput.title = 'Search fields and values'
wrapper.appendChild(divInput)
var refreshSearch = document.createElement("button");
refreshSearch.type = "button";
refreshSearch.className = "jsoneditor-refresh";
divInput.appendChild(refreshSearch);
var refreshSearch = document.createElement('button')
refreshSearch.type = 'button'
refreshSearch.className = 'jsoneditor-refresh'
divInput.appendChild(refreshSearch)
var search = document.createElement("input");
search.type = "text";
this.dom.search = search;
search.oninput = function(event) {
searchBox._onDelayedSearch(event);
};
search.onchange = function(event) {
var search = document.createElement('input')
search.type = 'text'
this.dom.search = search
search.oninput = function (event) {
searchBox._onDelayedSearch(event)
}
search.onchange = function (event) {
// For IE 9
searchBox._onSearch();
};
search.onkeydown = function(event) {
searchBox._onKeyDown(event);
};
search.onkeyup = function(event) {
searchBox._onKeyUp(event);
};
refreshSearch.onclick = function(event) {
search.select();
};
searchBox._onSearch()
}
search.onkeydown = function (event) {
searchBox._onKeyDown(event)
}
search.onkeyup = function (event) {
searchBox._onKeyUp(event)
}
refreshSearch.onclick = function (event) {
search.select()
}
// TODO: ESC in FF restores the last input, is a FF bug, https://bugzilla.mozilla.org/show_bug.cgi?id=598819
divInput.appendChild(search);
divInput.appendChild(search)
var searchNext = document.createElement("button");
searchNext.type = "button";
searchNext.title = "Next result (Enter)";
searchNext.className = "jsoneditor-next";
searchNext.onclick = function() {
searchBox.next();
};
var searchNext = document.createElement('button')
searchNext.type = 'button'
searchNext.title = 'Next result (Enter)'
searchNext.className = 'jsoneditor-next'
searchNext.onclick = function () {
searchBox.next()
}
divInput.appendChild(searchNext);
divInput.appendChild(searchNext)
var searchPrevious = document.createElement("button");
searchPrevious.type = "button";
searchPrevious.title = "Previous result (Shift+Enter)";
searchPrevious.className = "jsoneditor-previous";
searchPrevious.onclick = function() {
searchBox.previous();
};
var searchPrevious = document.createElement('button')
searchPrevious.type = 'button'
searchPrevious.title = 'Previous result (Shift+Enter)'
searchPrevious.className = 'jsoneditor-previous'
searchPrevious.onclick = function () {
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
* focus is false by default.
*/
SearchBox.prototype.next = function(focus) {
if (this.results != undefined) {
var index = this.resultIndex != undefined ? this.resultIndex + 1 : 0;
SearchBox.prototype.next = function (focus) {
if (this.results !== null) {
var index = this.resultIndex !== null ? this.resultIndex + 1 : 0
if (index > this.results.length - 1) {
index = 0;
index = 0
}
this._setActiveResult(index, focus);
this._setActiveResult(index, focus)
}
};
}
/**
* Go to the prevous search result
* @param {boolean} [focus] If true, focus will be set to the next result
* focus is false by default.
*/
SearchBox.prototype.previous = function(focus) {
if (this.results != undefined) {
var max = this.results.length - 1;
var index = this.resultIndex != undefined ? this.resultIndex - 1 : max;
SearchBox.prototype.previous = function (focus) {
if (this.results !== null) {
var max = this.results.length - 1
var index = this.resultIndex !== null ? this.resultIndex - 1 : max
if (index < 0) {
index = max;
index = max
}
this._setActiveResult(index, focus);
this._setActiveResult(index, focus)
}
};
}
/**
* Set new value for the current active result
@ -121,57 +121,57 @@ SearchBox.prototype.previous = function(focus) {
* focus is false by default.
* @private
*/
SearchBox.prototype._setActiveResult = function(index, focus) {
SearchBox.prototype._setActiveResult = function (index, focus) {
// de-activate current active result
if (this.activeResult) {
var prevNode = this.activeResult.node;
var prevElem = this.activeResult.elem;
if (prevElem == "field") {
delete prevNode.searchFieldActive;
var prevNode = this.activeResult.node
var prevElem = this.activeResult.elem
if (prevElem === 'field') {
delete prevNode.searchFieldActive
} else {
delete prevNode.searchValueActive;
delete prevNode.searchValueActive
}
prevNode.updateDom();
prevNode.updateDom()
}
if (!this.results || !this.results[index]) {
// out of range, set to undefined
this.resultIndex = undefined;
this.activeResult = undefined;
return;
this.resultIndex = undefined
this.activeResult = undefined
return
}
this.resultIndex = index;
this.resultIndex = index
// set new node active
var node = this.results[this.resultIndex].node;
var elem = this.results[this.resultIndex].elem;
if (elem == "field") {
node.searchFieldActive = true;
var node = this.results[this.resultIndex].node
var elem = this.results[this.resultIndex].elem
if (elem === 'field') {
node.searchFieldActive = true
} else {
node.searchValueActive = true;
node.searchValueActive = true
}
this.activeResult = this.results[this.resultIndex];
node.updateDom();
this.activeResult = this.results[this.resultIndex]
node.updateDom()
// TODO: not so nice that the focus is only set after the animation is finished
node.scrollTo(function() {
node.scrollTo(function () {
if (focus) {
node.focus(elem);
node.focus(elem)
}
});
};
})
}
/**
* Cancel any running onDelayedSearch.
* @private
*/
SearchBox.prototype._clearDelay = function() {
if (this.timeout != undefined) {
clearTimeout(this.timeout);
delete this.timeout;
SearchBox.prototype._clearDelay = function () {
if (this.timeout !== undefined) {
clearTimeout(this.timeout)
delete this.timeout
}
};
}
/**
* Start a timer to execute a search after a short delay.
@ -179,15 +179,15 @@ SearchBox.prototype._clearDelay = function() {
* @param {Event} event
* @private
*/
SearchBox.prototype._onDelayedSearch = function(event) {
SearchBox.prototype._onDelayedSearch = function (event) {
// execute the search after a short delay (reduces the number of
// search actions while typing in the search text box)
this._clearDelay();
var searchBox = this;
this.timeout = setTimeout(function(event) {
searchBox._onSearch();
}, this.delay);
};
this._clearDelay()
var searchBox = this
this.timeout = setTimeout(function (event) {
searchBox._onSearch()
}, this.delay)
}
/**
* Handle onSearch event
@ -196,128 +196,128 @@ SearchBox.prototype._onDelayedSearch = function(event) {
* Default is false.
* @private
*/
SearchBox.prototype._onSearch = function(forceSearch) {
this._clearDelay();
SearchBox.prototype._onSearch = function (forceSearch) {
this._clearDelay()
var value = this.dom.search.value;
var text = value.length > 0 ? value : undefined;
var value = this.dom.search.value
var text = value.length > 0 ? value : undefined
if (text !== this.lastText || forceSearch) {
// only search again when changed
this.lastText = text;
this.results = this.editor.search(text);
this.lastText = text
this.results = this.editor.search(text)
var MAX_SEARCH_RESULTS = this.results[0]
? 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
var activeResultIndex = 0;
var activeResultIndex = 0
if (this.activeResult) {
for (var i = 0; i < this.results.length; i++) {
if (this.results[i].node === this.activeResult.node) {
activeResultIndex = i;
break;
activeResultIndex = i
break
}
}
}
this._setActiveResult(activeResultIndex, false);
this._setActiveResult(activeResultIndex, false)
// display search results
if (text !== undefined) {
var resultCount = this.results.length;
var resultCount = this.results.length
if (resultCount === 0) {
this.dom.results.innerHTML = "no&nbsp;results";
this.dom.results.innerHTML = 'no&nbsp;results'
} else if (resultCount === 1) {
this.dom.results.innerHTML = "1&nbsp;result";
this.dom.results.innerHTML = '1&nbsp;result'
} else if (resultCount > MAX_SEARCH_RESULTS) {
this.dom.results.innerHTML = MAX_SEARCH_RESULTS + "+&nbsp;results";
this.dom.results.innerHTML = MAX_SEARCH_RESULTS + '+&nbsp;results'
} else {
this.dom.results.innerHTML = resultCount + "&nbsp;results";
this.dom.results.innerHTML = resultCount + '&nbsp;results'
}
} else {
this.dom.results.innerHTML = "";
this.dom.results.innerHTML = ''
}
}
};
}
/**
* Handle onKeyDown event in the input box
* @param {Event} event
* @private
*/
SearchBox.prototype._onKeyDown = function(event) {
var keynum = event.which;
if (keynum == 27) {
SearchBox.prototype._onKeyDown = function (event) {
var keynum = event.which
if (keynum === 27) {
// ESC
this.dom.search.value = ""; // clear search
this._onSearch();
event.preventDefault();
event.stopPropagation();
} else if (keynum == 13) {
this.dom.search.value = '' // clear search
this._onSearch()
event.preventDefault()
event.stopPropagation()
} else if (keynum === 13) {
// Enter
if (event.ctrlKey) {
// force to search again
this._onSearch(true);
this._onSearch(true)
} else if (event.shiftKey) {
// move to the previous search result
this.previous();
this.previous()
} else {
// move to the next search result
this.next();
this.next()
}
event.preventDefault();
event.stopPropagation();
event.preventDefault()
event.stopPropagation()
}
};
}
/**
* Handle onKeyUp event in the input box
* @param {Event} event
* @private
*/
SearchBox.prototype._onKeyUp = function(event) {
var keynum = event.keyCode;
if (keynum != 27 && keynum != 13) {
SearchBox.prototype._onKeyUp = function (event) {
var keynum = event.keyCode
if (keynum !== 27 && keynum !== 13) {
// !show and !Enter
this._onDelayedSearch(event); // For IE 9
this._onDelayedSearch(event) // For IE 9
}
};
}
/**
* Clear the search results
*/
SearchBox.prototype.clear = function() {
this.dom.search.value = "";
this._onSearch();
};
SearchBox.prototype.clear = function () {
this.dom.search.value = ''
this._onSearch()
}
/**
* Refresh searchResults if there is a search value
*/
SearchBox.prototype.forceSearch = function() {
this._onSearch(true);
};
SearchBox.prototype.forceSearch = function () {
this._onSearch(true)
}
/**
* Test whether the search box value is empty
* @returns {boolean} Returns true when empty.
*/
SearchBox.prototype.isEmpty = function() {
return this.dom.search.value === "";
};
SearchBox.prototype.isEmpty = function () {
return this.dom.search.value === ''
}
/**
* Destroy the search box
*/
SearchBox.prototype.destroy = function() {
this.editor = null;
this.dom.container.removeChild(this.dom.wrapper);
this.dom = null;
SearchBox.prototype.destroy = function () {
this.editor = null
this.dom.container.removeChild(this.dom.wrapper)
this.dom = null
this.results = null;
this.activeResult = null;
this.results = null
this.activeResult = null
this._clearDelay();
};
this._clearDelay()
}
module.exports = SearchBox;
module.exports = SearchBox

View File

@ -1,24 +1,24 @@
'use strict';
'use strict'
var ContextMenu = require('./ContextMenu');
var translate = require('./i18n').translate;
var util = require('./util');
var ContextMenu = require('./ContextMenu')
var translate = require('./i18n').translate
var util = require('./util')
/**
* Creates a component that visualize path selection in tree based editors
* @param {HTMLElement} container
* @param {HTMLElement} container
* @param {HTMLElement} root
* @constructor
*/
function TreePath(container, root) {
function TreePath (container, root) {
if (container) {
this.root = root;
this.path = document.createElement('div');
this.path.className = 'jsoneditor-treepath';
this.path.setAttribute('tabindex',0);
this.contentMenuClicked;
container.appendChild(this.path);
this.reset();
this.root = root
this.path = document.createElement('div')
this.path.className = 'jsoneditor-treepath'
this.path.setAttribute('tabindex', 0)
this.contentMenuClicked = false
container.appendChild(this.path)
this.reset()
}
}
@ -26,98 +26,98 @@ function TreePath(container, root) {
* Reset component to initial status
*/
TreePath.prototype.reset = function () {
this.path.innerHTML = translate('selectNode');
};
this.path.innerHTML = translate('selectNode')
}
/**
* Renders the component UI according to a given path objects
* @param {Array<{name: String, childs: Array}>} pathObjs a list of path objects
*
*
*/
TreePath.prototype.setPath = function (pathObjs) {
var me = this;
var me = this
this.path.innerHTML = '';
this.path.innerHTML = ''
if (pathObjs && pathObjs.length) {
pathObjs.forEach(function (pathObj, idx) {
var pathEl = document.createElement('span');
var sepEl;
pathEl.className = 'jsoneditor-treepath-element';
pathEl.innerText = pathObj.name;
pathEl.onclick = _onSegmentClick.bind(me, pathObj);
me.path.appendChild(pathEl);
var pathEl = document.createElement('span')
var sepEl
pathEl.className = 'jsoneditor-treepath-element'
pathEl.innerText = pathObj.name
pathEl.onclick = _onSegmentClick.bind(me, pathObj)
me.path.appendChild(pathEl)
if (pathObj.children.length) {
sepEl = document.createElement('span');
sepEl.className = 'jsoneditor-treepath-seperator';
sepEl.innerHTML = '&#9658;';
sepEl = document.createElement('span')
sepEl.className = 'jsoneditor-treepath-seperator'
sepEl.innerHTML = '&#9658;'
sepEl.onclick = function () {
me.contentMenuClicked = true;
var items = [];
me.contentMenuClicked = true
var items = []
pathObj.children.forEach(function (child) {
items.push({
'text': child.name,
'className': 'jsoneditor-type-modes' + (pathObjs[idx + 1] + 1 && pathObjs[idx + 1].name === child.name ? ' jsoneditor-selected' : ''),
'click': _onContextMenuItemClick.bind(me, pathObj, child.name)
});
});
var menu = new ContextMenu(items);
menu.show(sepEl, me.root, true);
};
text: child.name,
className: 'jsoneditor-type-modes' + (pathObjs[idx + 1] + 1 && pathObjs[idx + 1].name === child.name ? ' jsoneditor-selected' : ''),
click: _onContextMenuItemClick.bind(me, pathObj, child.name)
})
})
var menu = new ContextMenu(items)
menu.show(sepEl, me.root, true)
}
me.path.appendChild(sepEl);
me.path.appendChild(sepEl)
}
if(idx === pathObjs.length - 1) {
var leftRectPos = (sepEl || pathEl).getBoundingClientRect().right;
if(me.path.offsetWidth < leftRectPos) {
me.path.scrollLeft = leftRectPos;
if (idx === pathObjs.length - 1) {
var leftRectPos = (sepEl || pathEl).getBoundingClientRect().right
if (me.path.offsetWidth < leftRectPos) {
me.path.scrollLeft = leftRectPos
}
if (me.path.scrollLeft) {
var showAllBtn = document.createElement('span');
showAllBtn.className = 'jsoneditor-treepath-show-all-btn';
showAllBtn.title = 'show all path';
showAllBtn.innerHTML = '...';
showAllBtn.onclick = _onShowAllClick.bind(me, pathObjs);
me.path.insertBefore(showAllBtn, me.path.firstChild);
var showAllBtn = document.createElement('span')
showAllBtn.className = 'jsoneditor-treepath-show-all-btn'
showAllBtn.title = 'show all path'
showAllBtn.innerHTML = '...'
showAllBtn.onclick = _onShowAllClick.bind(me, pathObjs)
me.path.insertBefore(showAllBtn, me.path.firstChild)
}
}
});
})
}
function _onShowAllClick(pathObjs) {
me.contentMenuClicked = false;
util.addClassName(me.path, 'show-all');
me.path.style.width = me.path.parentNode.getBoundingClientRect().width - 10 + 'px';
me.path.onblur = function() {
function _onShowAllClick (pathObjs) {
me.contentMenuClicked = false
util.addClassName(me.path, 'show-all')
me.path.style.width = me.path.parentNode.getBoundingClientRect().width - 10 + 'px'
me.path.onblur = function () {
if (me.contentMenuClicked) {
me.contentMenuClicked = false;
me.path.focus();
return;
me.contentMenuClicked = false
me.path.focus()
return
}
util.removeClassName(me.path, 'show-all');
me.path.onblur = undefined;
me.path.style.width = '';
me.setPath(pathObjs);
};
util.removeClassName(me.path, 'show-all')
me.path.onblur = undefined
me.path.style.width = ''
me.setPath(pathObjs)
}
}
function _onSegmentClick(pathObj) {
function _onSegmentClick (pathObj) {
if (this.selectionCallback) {
this.selectionCallback(pathObj);
this.selectionCallback(pathObj)
}
}
function _onContextMenuItemClick(pathObj, selection) {
function _onContextMenuItemClick (pathObj, selection) {
if (this.contextMenuCallback) {
this.contextMenuCallback(pathObj, selection);
this.contextMenuCallback(pathObj, selection)
}
}
};
}
/**
* set a callback function for selection of path section
@ -125,9 +125,9 @@ TreePath.prototype.setPath = function (pathObjs) {
*/
TreePath.prototype.onSectionSelected = function (callback) {
if (typeof callback === 'function') {
this.selectionCallback = callback;
this.selectionCallback = callback
}
};
}
/**
* set a callback function for selection of path section
@ -135,8 +135,8 @@ TreePath.prototype.onSectionSelected = function (callback) {
*/
TreePath.prototype.onContextMenuItemSelected = function (callback) {
if (typeof callback === 'function') {
this.contextMenuCallback = callback;
this.contextMenuCallback = callback
}
};
}
module.exports = TreePath;
module.exports = TreePath

View File

@ -2,20 +2,18 @@ var ace
if (window.ace) {
// use the already loaded instance of Ace
ace = window.ace
}
else {
} else {
try {
// load brace
ace = require('brace');
ace = require('brace')
// load required Ace plugins
require('brace/mode/json');
require('brace/ext/searchbox');
}
catch (err) {
require('brace/mode/json')
require('brace/ext/searchbox')
} catch (err) {
// failed to load brace (can be minimalist bundle).
// No worries, the editor will fall back to plain text if needed.
}
}
module.exports = ace;
module.exports = ace

View File

@ -3,7 +3,7 @@
*
* Copyright (c) 2010, Ajax.org B.V.
* All rights reserved.
*
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
@ -14,7 +14,7 @@
* * Neither the name of Ajax.org B.V. nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
@ -28,118 +28,117 @@
*
* ***** 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;
exports.cssClass = "ace-jsoneditor";
exports.cssText = ".ace-jsoneditor .ace_gutter {\
background: #ebebeb;\
color: #333\
}\
\
.ace-jsoneditor.ace_editor {\
font-family: \"dejavu sans mono\", \"droid sans mono\", consolas, monaco, \"lucida console\", \"courier new\", courier, monospace, sans-serif;\
line-height: 1.3;\
background-color: #fff;\
}\
.ace-jsoneditor .ace_print-margin {\
width: 1px;\
background: #e8e8e8\
}\
.ace-jsoneditor .ace_scroller {\
background-color: #FFFFFF\
}\
.ace-jsoneditor .ace_text-layer {\
color: gray\
}\
.ace-jsoneditor .ace_variable {\
color: #1a1a1a\
}\
.ace-jsoneditor .ace_cursor {\
border-left: 2px solid #000000\
}\
.ace-jsoneditor .ace_overwrite-cursors .ace_cursor {\
border-left: 0px;\
border-bottom: 1px solid #000000\
}\
.ace-jsoneditor .ace_marker-layer .ace_selection {\
background: lightgray\
}\
.ace-jsoneditor.ace_multiselect .ace_selection.ace_start {\
box-shadow: 0 0 3px 0px #FFFFFF;\
border-radius: 2px\
}\
.ace-jsoneditor .ace_marker-layer .ace_step {\
background: rgb(255, 255, 0)\
}\
.ace-jsoneditor .ace_marker-layer .ace_bracket {\
margin: -1px 0 0 -1px;\
border: 1px solid #BFBFBF\
}\
.ace-jsoneditor .ace_marker-layer .ace_active-line {\
background: #FFFBD1\
}\
.ace-jsoneditor .ace_gutter-active-line {\
background-color : #dcdcdc\
}\
.ace-jsoneditor .ace_marker-layer .ace_selected-word {\
border: 1px solid lightgray\
}\
.ace-jsoneditor .ace_invisible {\
color: #BFBFBF\
}\
.ace-jsoneditor .ace_keyword,\
.ace-jsoneditor .ace_meta,\
.ace-jsoneditor .ace_support.ace_constant.ace_property-value {\
color: #AF956F\
}\
.ace-jsoneditor .ace_keyword.ace_operator {\
color: #484848\
}\
.ace-jsoneditor .ace_keyword.ace_other.ace_unit {\
color: #96DC5F\
}\
.ace-jsoneditor .ace_constant.ace_language {\
color: darkorange\
}\
.ace-jsoneditor .ace_constant.ace_numeric {\
color: red\
}\
.ace-jsoneditor .ace_constant.ace_character.ace_entity {\
color: #BF78CC\
}\
.ace-jsoneditor .ace_invalid {\
color: #FFFFFF;\
background-color: #FF002A;\
}\
.ace-jsoneditor .ace_fold {\
background-color: #AF956F;\
border-color: #000000\
}\
.ace-jsoneditor .ace_storage,\
.ace-jsoneditor .ace_support.ace_class,\
.ace-jsoneditor .ace_support.ace_function,\
.ace-jsoneditor .ace_support.ace_other,\
.ace-jsoneditor .ace_support.ace_type {\
color: #C52727\
}\
.ace-jsoneditor .ace_string {\
color: green\
}\
.ace-jsoneditor .ace_comment {\
color: #BCC8BA\
}\
.ace-jsoneditor .ace_entity.ace_name.ace_tag,\
.ace-jsoneditor .ace_entity.ace_other.ace_attribute-name {\
color: #606060\
}\
.ace-jsoneditor .ace_markup.ace_underline {\
text-decoration: underline\
}\
.ace-jsoneditor .ace_indent-guide {\
background: url(\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==\") right repeat-y\
}";
.ace-jsoneditor.ace_editor {
font-family: "dejavu sans mono", "droid sans mono", consolas, monaco, "lucida console", "courier new", courier, monospace, sans-serif;
line-height: 1.3;
background-color: #fff;
}
.ace-jsoneditor .ace_print-margin {
width: 1px;
background: #e8e8e8
}
.ace-jsoneditor .ace_scroller {
background-color: #FFFFFF
}
.ace-jsoneditor .ace_text-layer {
color: gray
}
.ace-jsoneditor .ace_variable {
color: #1a1a1a
}
.ace-jsoneditor .ace_cursor {
border-left: 2px solid #000000
}
.ace-jsoneditor .ace_overwrite-cursors .ace_cursor {
border-left: 0px;
border-bottom: 1px solid #000000
}
.ace-jsoneditor .ace_marker-layer .ace_selection {
background: lightgray
}
.ace-jsoneditor.ace_multiselect .ace_selection.ace_start {
box-shadow: 0 0 3px 0px #FFFFFF;
border-radius: 2px
}
.ace-jsoneditor .ace_marker-layer .ace_step {
background: rgb(255, 255, 0)
}
.ace-jsoneditor .ace_marker-layer .ace_bracket {
margin: -1px 0 0 -1px;
border: 1px solid #BFBFBF
}
.ace-jsoneditor .ace_marker-layer .ace_active-line {
background: #FFFBD1
}
.ace-jsoneditor .ace_gutter-active-line {
background-color : #dcdcdc
}
.ace-jsoneditor .ace_marker-layer .ace_selected-word {
border: 1px solid lightgray
}
.ace-jsoneditor .ace_invisible {
color: #BFBFBF
}
.ace-jsoneditor .ace_keyword,
.ace-jsoneditor .ace_meta,
.ace-jsoneditor .ace_support.ace_constant.ace_property-value {
color: #AF956F
}
.ace-jsoneditor .ace_keyword.ace_operator {
color: #484848
}
.ace-jsoneditor .ace_keyword.ace_other.ace_unit {
color: #96DC5F
}
.ace-jsoneditor .ace_constant.ace_language {
color: darkorange
}
.ace-jsoneditor .ace_constant.ace_numeric {
color: red
}
.ace-jsoneditor .ace_constant.ace_character.ace_entity {
color: #BF78CC
}
.ace-jsoneditor .ace_invalid {
color: #FFFFFF;
background-color: #FF002A;
}
.ace-jsoneditor .ace_fold {
background-color: #AF956F;
border-color: #000000
}
.ace-jsoneditor .ace_storage,
.ace-jsoneditor .ace_support.ace_class,
.ace-jsoneditor .ace_support.ace_function,
.ace-jsoneditor .ace_support.ace_other,
.ace-jsoneditor .ace_support.ace_type {
color: #C52727
}
.ace-jsoneditor .ace_string {
color: green
}
.ace-jsoneditor .ace_comment {
color: #BCC8BA
}
.ace-jsoneditor .ace_entity.ace_name.ace_tag,
.ace-jsoneditor .ace_entity.ace_other.ace_attribute-name {
color: #606060
}
.ace-jsoneditor .ace_markup.ace_underline {
text-decoration: underline
}
.ace-jsoneditor .ace_indent-guide {
background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAACCAYAAACZgbYnAAAAE0lEQVQImWP4////f4bLly//BwAmVgd1/w11/gAAAABJRU5ErkJggg==") right repeat-y
}`
var dom = acequire("../lib/dom");
dom.importCssString(exports.cssText, exports.cssClass);
});
var dom = acequire('../lib/dom')
dom.importCssString(exports.cssText, exports.cssClass)
})

View File

@ -1,14 +1,14 @@
'use strict';
'use strict'
var util = require('./util');
var ContextMenu = require('./ContextMenu');
var translate = require('./i18n').translate;
var util = require('./util')
var ContextMenu = require('./ContextMenu')
var translate = require('./i18n').translate
/**
* A factory function to create an AppendNode, which depends on a Node
* @param {Node} Node
*/
function appendNodeFactory(Node) {
function appendNodeFactory (Node) {
/**
* @constructor AppendNode
* @extends Node
@ -18,11 +18,11 @@ function appendNodeFactory(Node) {
*/
function AppendNode (editor) {
/** @type {TreeEditor} */
this.editor = editor;
this.dom = {};
this.editor = editor
this.dom = {}
}
AppendNode.prototype = new Node();
AppendNode.prototype = new Node()
/**
* Return a table row with an append button.
@ -30,109 +30,108 @@ function appendNodeFactory(Node) {
*/
AppendNode.prototype.getDom = function () {
// TODO: implement a new solution for the append node
var dom = this.dom;
var dom = this.dom
if (dom.tr) {
return dom.tr;
return dom.tr
}
this._updateEditability();
this._updateEditability()
// a row for the append button
var trAppend = document.createElement('tr');
trAppend.className = 'jsoneditor-append';
trAppend.node = this;
dom.tr = trAppend;
var trAppend = document.createElement('tr')
trAppend.className = 'jsoneditor-append'
trAppend.node = this
dom.tr = trAppend
// TODO: consistent naming
if (this.editor.options.mode === 'tree') {
// a cell for the dragarea column
dom.tdDrag = document.createElement('td');
dom.tdDrag = document.createElement('td')
// create context menu
var tdMenu = document.createElement('td');
dom.tdMenu = tdMenu;
var menu = document.createElement('button');
menu.type = 'button';
menu.className = 'jsoneditor-button jsoneditor-contextmenu';
menu.title = 'Click to open the actions menu (Ctrl+M)';
dom.menu = menu;
tdMenu.appendChild(dom.menu);
var tdMenu = document.createElement('td')
dom.tdMenu = tdMenu
var menu = document.createElement('button')
menu.type = 'button'
menu.className = 'jsoneditor-button jsoneditor-contextmenu'
menu.title = 'Click to open the actions menu (Ctrl+M)'
dom.menu = menu
tdMenu.appendChild(dom.menu)
}
// a cell for the contents (showing text 'empty')
var tdAppend = document.createElement('td');
var domText = document.createElement('div');
domText.innerHTML = '(' + translate('empty') + ')';
domText.className = 'jsoneditor-readonly';
tdAppend.appendChild(domText);
dom.td = tdAppend;
dom.text = domText;
var tdAppend = document.createElement('td')
var domText = document.createElement('div')
domText.innerHTML = '(' + translate('empty') + ')'
domText.className = 'jsoneditor-readonly'
tdAppend.appendChild(domText)
dom.td = tdAppend
dom.text = domText
this.updateDom();
this.updateDom()
return trAppend;
};
return trAppend
}
/**
* Append node doesn't have a path
* @returns {null}
*/
AppendNode.prototype.getPath = function() {
return null;
};
AppendNode.prototype.getPath = function () {
return null
}
/**
* Append node doesn't have an index
* @returns {null}
*/
AppendNode.prototype.getIndex = function() {
return null;
};
AppendNode.prototype.getIndex = function () {
return null
}
/**
* Update the HTML dom of the Node
*/
AppendNode.prototype.updateDom = function(options) {
var dom = this.dom;
var tdAppend = dom.td;
AppendNode.prototype.updateDom = function (options) {
var dom = this.dom
var tdAppend = dom.td
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
}
var domText = dom.text;
var domText = dom.text
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:
// 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 (dom.tr.firstChild) {
if (dom.tdDrag) {
trAppend.removeChild(dom.tdDrag);
trAppend.removeChild(dom.tdDrag)
}
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.tdDrag) {
trAppend.appendChild(dom.tdDrag);
trAppend.appendChild(dom.tdDrag)
}
if (dom.tdMenu) {
trAppend.appendChild(dom.tdMenu);
trAppend.appendChild(dom.tdMenu)
}
trAppend.appendChild(tdAppend);
trAppend.appendChild(tdAppend)
}
}
};
}
/**
* Check whether the AppendNode is currently visible.
@ -140,8 +139,8 @@ function appendNodeFactory(Node) {
* @return {boolean} isVisible
*/
AppendNode.prototype.isVisible = function () {
return (this.parent.childs.length == 0);
};
return (this.parent.childs.length === 0)
}
/**
* Show a contextmenu for this node
@ -150,110 +149,109 @@ function appendNodeFactory(Node) {
* is being closed.
*/
AppendNode.prototype.showContextMenu = function (anchor, onClose) {
var node = this;
var titles = Node.TYPE_TITLES;
var node = this
var titles = Node.TYPE_TITLES
var appendSubmenu = [
{
text: translate('auto'),
className: 'jsoneditor-type-auto',
title: titles.auto,
click: function () {
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');
}
{
text: translate('auto'),
className: 'jsoneditor-type-auto',
title: titles.auto,
click: function () {
node._onAppend('', '', 'auto')
}
];
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 = [
// create append button
{
'text': translate('appendText'),
'title': translate('appendTitleAuto'),
'submenuTitle': translate('appendSubmenuTitle'),
'className': 'jsoneditor-insert',
'click': function () {
node._onAppend('', '', 'auto');
text: translate('appendText'),
title: translate('appendTitleAuto'),
submenuTitle: translate('appendSubmenuTitle'),
className: 'jsoneditor-insert',
click: function () {
node._onAppend('', '', 'auto')
},
'submenu': appendSubmenu
submenu: appendSubmenu
}
];
]
if (this.editor.options.onCreateMenu) {
var path = node.parent.getPath();
var path = node.parent.getPath()
items = this.editor.options.onCreateMenu(items, {
type: 'append',
path: path,
paths: [path]
});
})
}
var menu = new ContextMenu(items, {close: onClose});
menu.show(anchor, this.editor.frame);
};
var menu = new ContextMenu(items, { close: onClose })
menu.show(anchor, this.editor.frame)
}
/**
* Handle an event. The event is caught centrally by the editor
* @param {Event} event
*/
AppendNode.prototype.onEvent = function (event) {
var type = event.type;
var target = event.target || event.srcElement;
var dom = this.dom;
var type = event.type
var target = event.target || event.srcElement
var dom = this.dom
// highlight the append nodes parent
var menu = dom.menu;
if (target == menu) {
if (type == 'mouseover') {
this.editor.highlighter.highlight(this.parent);
}
else if (type == 'mouseout') {
this.editor.highlighter.unhighlight();
var menu = dom.menu
if (target === menu) {
if (type === 'mouseover') {
this.editor.highlighter.highlight(this.parent)
} else if (type === 'mouseout') {
this.editor.highlighter.unhighlight()
}
}
// context menu events
if (type == 'click' && target == dom.menu) {
var highlighter = this.editor.highlighter;
highlighter.highlight(this.parent);
highlighter.lock();
util.addClassName(dom.menu, 'jsoneditor-selected');
if (type === 'click' && target === dom.menu) {
var highlighter = this.editor.highlighter
highlighter.highlight(this.parent)
highlighter.lock()
util.addClassName(dom.menu, 'jsoneditor-selected')
this.showContextMenu(dom.menu, function () {
util.removeClassName(dom.menu, 'jsoneditor-selected');
highlighter.unlock();
highlighter.unhighlight();
});
util.removeClassName(dom.menu, 'jsoneditor-selected')
highlighter.unlock()
highlighter.unhighlight()
})
}
if (type == 'keydown') {
this.onKeyDown(event);
if (type === 'keydown') {
this.onKeyDown(event)
}
};
}
return AppendNode;
return AppendNode
}
module.exports = appendNodeFactory;
module.exports = appendNodeFactory

View File

@ -1,396 +1,384 @@
'use strict';
'use strict'
var defaultFilterFunction = {
start: function (token, match, config) {
return match.indexOf(token) === 0;
return match.indexOf(token) === 0
},
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, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;');
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, '&amp;')
.replace(/"/g, '&quot;')
.replace(/'/g, '&#39;')
.replace(/</g, '&lt;')
.replace(/>/g, '&gt;')
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

View File

@ -1,7 +1,7 @@
exports.DEFAULT_MODAL_ANCHOR = document.body;
exports.SIZE_LARGE = 10 * 1024 * 1024; // 10 MB
exports.DEFAULT_MODAL_ANCHOR = document.body
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

View File

@ -1,4 +1,4 @@
var util = require('./util');
var util = require('./util')
/**
* Create an anchor element absolutely positioned in the `parent`
@ -9,58 +9,58 @@ var util = require('./util');
* @returns {HTMLElement}
*/
exports.createAbsoluteAnchor = function (anchor, parent, onDestroy) {
var root = getRootNode(anchor);
var eventListeners = {};
var root = getRootNode(anchor)
var eventListeners = {}
var anchorRect = anchor.getBoundingClientRect();
var frameRect = parent.getBoundingClientRect();
var anchorRect = anchor.getBoundingClientRect()
var frameRect = parent.getBoundingClientRect()
var absoluteAnchor = document.createElement('div');
absoluteAnchor.className = 'jsoneditor-anchor';
absoluteAnchor.style.position = 'absolute';
absoluteAnchor.style.left = (anchorRect.left - frameRect.left) + 'px';
absoluteAnchor.style.top = (anchorRect.top - frameRect.top) + 'px';
absoluteAnchor.style.width = (anchorRect.width - 2) + 'px';
absoluteAnchor.style.height = (anchorRect.height - 2) + 'px';
absoluteAnchor.style.boxSizing = 'border-box';
parent.appendChild(absoluteAnchor);
var absoluteAnchor = document.createElement('div')
absoluteAnchor.className = 'jsoneditor-anchor'
absoluteAnchor.style.position = 'absolute'
absoluteAnchor.style.left = (anchorRect.left - frameRect.left) + 'px'
absoluteAnchor.style.top = (anchorRect.top - frameRect.top) + 'px'
absoluteAnchor.style.width = (anchorRect.width - 2) + 'px'
absoluteAnchor.style.height = (anchorRect.height - 2) + 'px'
absoluteAnchor.style.boxSizing = 'border-box'
parent.appendChild(absoluteAnchor)
function destroy () {
// remove temporary absolutely positioned anchor
if (absoluteAnchor && absoluteAnchor.parentNode) {
absoluteAnchor.parentNode.removeChild(absoluteAnchor);
absoluteAnchor.parentNode.removeChild(absoluteAnchor)
// remove all event listeners
// all event listeners are supposed to be attached to document.
for (var name in eventListeners) {
if (eventListeners.hasOwnProperty(name)) {
var fn = eventListeners[name];
if (hasOwnProperty(eventListeners, name)) {
var fn = eventListeners[name]
if (fn) {
util.removeEventListener(root, name, fn);
util.removeEventListener(root, name, fn)
}
delete eventListeners[name];
delete eventListeners[name]
}
}
if (typeof onDestroy === 'function') {
onDestroy(anchor);
onDestroy(anchor)
}
}
}
// create and attach event listeners
var destroyIfOutside = function (event) {
var target = event.target;
var target = event.target
if ((target !== absoluteAnchor) && !util.isChildOf(target, absoluteAnchor)) {
destroy();
destroy()
}
}
eventListeners.mousedown = util.addEventListener(root, 'mousedown', destroyIfOutside);
eventListeners.mousewheel = util.addEventListener(root, 'mousewheel', destroyIfOutside);
eventListeners.mousedown = util.addEventListener(root, 'mousedown', destroyIfOutside)
eventListeners.mousewheel = util.addEventListener(root, 'mousewheel', destroyIfOutside)
// eventListeners.scroll = util.addEventListener(root, 'scroll', destroyIfOutside);
absoluteAnchor.destroy = destroy;
absoluteAnchor.destroy = destroy
return absoluteAnchor
}
@ -70,8 +70,12 @@ exports.createAbsoluteAnchor = function (anchor, parent, onDestroy) {
* @param {HTMLElement} node node to check
* @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')
? node.getRootNode()
: window;
? node.getRootNode()
: window
}
function hasOwnProperty (object, key) {
return Object.prototype.hasOwnProperty.call(object, key)
}

View File

@ -26,4 +26,4 @@
* @author Jos de Jong, <wjosdejong@gmail.com>
* @version @@version
* @date @@date
*/
*/

View File

@ -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 = {
en: {
array: 'Array',
@ -93,7 +95,7 @@ var _defs = {
modePreviewText: 'Preview',
modePreviewTitle: 'Switch to preview mode',
examples: 'Examples',
default: 'Default',
default: 'Default'
},
'zh-CN': {
array: '数组',
@ -184,7 +186,7 @@ var _defs = {
modePreviewText: '预览',
modePreviewTitle: '切换至预览模式',
examples: '例子',
default: '缺省',
default: '缺省'
},
'pt-BR': {
array: 'Lista',
@ -283,7 +285,7 @@ var _defs = {
'Campo do tipo nao é determinado através do seu valor, ' +
'mas sempre retornara um texto.',
examples: 'Exemplos',
default: 'Revelia',
default: 'Revelia'
},
tr: {
array: 'Dizin',
@ -370,20 +372,20 @@ var _defs = {
modeViewText: 'Görünüm',
modeViewTitle: 'Ağaç görünümüne geç',
examples: 'Örnekler',
default: 'Varsayılan',
default: 'Varsayılan'
}
};
}
var _defaultLang = 'en';
var _lang;
var userLang = typeof navigator !== 'undefined' ?
navigator.language || navigator.userLanguage :
undefined;
var _defaultLang = 'en'
var _lang
var userLang = typeof navigator !== 'undefined'
? navigator.language || navigator.userLanguage
: undefined
_lang = _locales.find(function (l) {
return l === userLang;
});
return l === userLang
})
if (!_lang) {
_lang = _defaultLang;
_lang = _defaultLang
}
module.exports = {
@ -393,41 +395,41 @@ module.exports = {
_lang: _lang,
setLanguage: function (lang) {
if (!lang) {
return;
return
}
var langFound = _locales.find(function (l) {
return l === lang;
});
return l === lang
})
if (langFound) {
_lang = langFound;
_lang = langFound
} else {
console.error('Language not found');
console.error('Language not found')
}
},
setLanguages: function (languages) {
if (!languages) {
return;
return
}
for (var key in languages) {
var langFound = _locales.find(function (l) {
return l === key;
});
return l === key
})
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) {
if (!lang) {
lang = _lang;
lang = _lang
}
var text = _defs[lang][key];
var text = _defs[lang][key]
if (data) {
for (key in data) {
text = text.replace('${' + key + '}', data[key]);
text = text.replace('${' + key + '}', data[key])
}
}
return text || key;
return text || key
}
};
}

View File

@ -1,4 +1,4 @@
'use strict';
'use strict'
/**
* 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.
*/
function stringifyPartial(value, space, limit) {
var _space; // undefined by default
function stringifyPartial (value, space, limit) {
var _space // undefined by default
if (typeof space === 'number') {
if (space > 10) {
_space = repeat(' ', 10);
}
else if (space >= 1) {
_space = repeat(' ', space);
_space = repeat(' ', 10)
} else if (space >= 1) {
_space = repeat(' ', space)
}
// else ignore
}
else if (typeof space === 'string' && space !== '') {
_space = space;
} else if (typeof space === 'string' && space !== '') {
_space = space
}
var output = stringifyValue(value, _space, '', limit);
var output = stringifyValue(value, _space, '', limit)
return output.length > limit
? (slice(output, limit) + '...')
: output;
? (slice(output, limit) + '...')
: output
}
/**
@ -51,27 +49,27 @@ function stringifyPartial(value, space, limit) {
* @param {number} limit
* @return {string | undefined}
*/
function stringifyValue(value, space, indent, limit) {
function stringifyValue (value, space, indent, limit) {
// boolean, null, number, string, or date
if (typeof value === 'boolean' || value instanceof Boolean ||
value === null ||
typeof value === 'number' || value instanceof Number ||
typeof value === 'string' || value instanceof String ||
value instanceof Date) {
return JSON.stringify(value);
return JSON.stringify(value)
}
// array
if (Array.isArray(value)) {
return stringifyArray(value, space, indent, limit);
return stringifyArray(value, space, indent, limit)
}
// object (test lastly!)
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
* @return {string}
*/
function stringifyArray(array, space, indent, limit) {
var childIndent = space ? (indent + space) : undefined;
var str = space ? '[\n' : '[';
function stringifyArray (array, space, indent, limit) {
var childIndent = space ? (indent + space) : undefined
var str = space ? '[\n' : '['
for (var i = 0; i < array.length; i++) {
var item = array[i];
var item = array[i]
if (space) {
str += childIndent;
str += childIndent
}
if (typeof item !== 'undefined' && typeof item !== 'function') {
str += stringifyValue(item, space, childIndent, limit);
}
else {
str += stringifyValue(item, space, childIndent, limit)
} else {
str += 'null'
}
if (i < array.length - 1) {
str += space ? ',\n' : ',';
str += space ? ',\n' : ','
}
// stop as soon as we're exceeding the limit
if (str.length > limit) {
return str + '...';
return str + '...'
}
}
str += space ? ('\n' + indent + ']') : ']';
return str;
str += space ? ('\n' + indent + ']') : ']'
return str
}
/**
@ -122,41 +119,40 @@ function stringifyArray(array, space, indent, limit) {
* @param {number} limit
* @return {string}
*/
function stringifyObject(object, space, indent, limit) {
var childIndent = space ? (indent + space) : undefined;
var first = true;
var str = space ? '{\n' : '{';
function stringifyObject (object, space, indent, limit) {
var childIndent = space ? (indent + space) : undefined
var first = true
var str = space ? '{\n' : '{'
if (typeof object.toJSON === 'function') {
return stringifyValue(object.toJSON(), space, indent, limit);
return stringifyValue(object.toJSON(), space, indent, limit)
}
for (var key in object) {
if (object.hasOwnProperty(key)) {
var value = object[key];
if (hasOwnProperty(object, key)) {
var value = object[key]
if (first) {
first = false;
}
else {
str += space ? ',\n' : ',';
first = false
} else {
str += space ? ',\n' : ','
}
str += space
? (childIndent + '"' + key + '": ')
: ('"' + key + '":');
? (childIndent + '"' + key + '": ')
: ('"' + key + '":')
str += stringifyValue(value, space, childIndent, limit);
str += stringifyValue(value, space, childIndent, limit)
// stop as soon as we're exceeding the limit
if (str.length > limit) {
return str + '...';
return str + '...'
}
}
}
str += space ? ('\n' + indent + '}') : '}';
return str;
str += space ? ('\n' + indent + '}') : '}'
return str
}
/**
@ -167,11 +163,11 @@ function stringifyObject(object, space, indent, limit) {
* @return {string}
*/
function repeat (text, times) {
var res = '';
var res = ''
while (times-- > 0) {
res += text;
res += text
}
return res;
return res
}
/**
@ -180,10 +176,10 @@ function repeat (text, times) {
* @param {number} [limit]
* @return {string}
*/
function slice(text, limit) {
function slice (text, limit) {
return typeof limit === 'number'
? text.slice(0, limit)
: text;
? text.slice(0, limit)
: text
}
/**
@ -196,5 +192,9 @@ function containsArray (jsonText) {
return /^\s*\[/.test(jsonText)
}
exports.stringifyPartial = stringifyPartial;
exports.containsArray = containsArray;
function hasOwnProperty (object, key) {
return Object.prototype.hasOwnProperty.call(object, key)
}
exports.stringifyPartial = stringifyPartial
exports.containsArray = containsArray

View File

@ -3,42 +3,33 @@ if (typeof Element !== 'undefined') {
// Polyfill for array remove
(function () {
function polyfill (item) {
if (item.hasOwnProperty('remove')) {
return;
if ('remove' in item) {
return
}
Object.defineProperty(item, 'remove', {
configurable: true,
enumerable: true,
writable: true,
value: function remove() {
if (this.parentNode != null)
this.parentNode.removeChild(this);
value: function remove () {
if (this.parentNode !== undefined) { this.parentNode.removeChild(this) }
}
});
})
}
if (typeof Element !== 'undefined') { polyfill(Element.prototype); }
if (typeof CharacterData !== 'undefined') { polyfill(CharacterData.prototype); }
if (typeof DocumentType !== 'undefined') { polyfill(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;
};
if (typeof window.Element !== 'undefined') { polyfill(window.Element.prototype) }
if (typeof window.CharacterData !== 'undefined') { polyfill(window.CharacterData.prototype) }
if (typeof window.DocumentType !== 'undefined') { polyfill(window.DocumentType.prototype) }
})()
}
// Polyfill for Array.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++) {
var element = this[i];
if ( callback.call(this, element, i, this) ) {
return element;
var element = this[i]
if (callback.call(this, element, i, this)) {
return element
}
}
}
@ -46,7 +37,8 @@ if (!Array.prototype.find) {
// Polyfill for String.trim
if (!String.prototype.trim) {
// eslint-disable-next-line no-extend-native
String.prototype.trim = function () {
return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
};
return this.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '')
}
}

View File

@ -1,21 +1,21 @@
'use strict';
'use strict'
var jmespath = require('jmespath');
var translate = require('./i18n').translate;
var ModeSwitcher = require('./ModeSwitcher');
var ErrorTable = require('./ErrorTable');
var textmode = require('./textmode')[0].mixin;
var showSortModal = require('./showSortModal');
var showTransformModal = require('./showTransformModal');
var MAX_PREVIEW_CHARACTERS = require('./constants').MAX_PREVIEW_CHARACTERS;
var DEFAULT_MODAL_ANCHOR = require('./constants').DEFAULT_MODAL_ANCHOR;
var SIZE_LARGE = require('./constants').SIZE_LARGE;
var PREVIEW_HISTORY_LIMIT = require('./constants').PREVIEW_HISTORY_LIMIT;
var util = require('./util');
var History = require('./History');
var jmespath = require('jmespath')
var translate = require('./i18n').translate
var ModeSwitcher = require('./ModeSwitcher')
var ErrorTable = require('./ErrorTable')
var textmode = require('./textmode')[0].mixin
var showSortModal = require('./showSortModal')
var showTransformModal = require('./showTransformModal')
var MAX_PREVIEW_CHARACTERS = require('./constants').MAX_PREVIEW_CHARACTERS
var DEFAULT_MODAL_ANCHOR = require('./constants').DEFAULT_MODAL_ANCHOR
var SIZE_LARGE = require('./constants').SIZE_LARGE
var PREVIEW_HISTORY_LIMIT = require('./constants').PREVIEW_HISTORY_LIMIT
var util = require('./util')
var History = require('./History')
// create a mixin with the functions for text mode
var previewmode = {};
var previewmode = {}
/**
* Create a JSON document preview, suitable for processing of large documents
@ -25,274 +25,269 @@ var previewmode = {};
*/
previewmode.create = function (container, options) {
// read options
options = options || {};
options = options || {}
if (typeof options.statusBar === 'undefined') {
options.statusBar = true;
options.statusBar = true
}
// setting default for previewmode
options.mainMenuBar = options.mainMenuBar !== false;
options.enableSort = options.enableSort !== false;
options.enableTransform = options.enableTransform !== false;
options.mainMenuBar = options.mainMenuBar !== false
options.enableSort = options.enableSort !== false
options.enableTransform = options.enableTransform !== false
this.options = options;
this.options = options
// indentation
if (options.indentation) {
this.indentation = Number(options.indentation);
}
else {
this.indentation = 2; // number of spaces
this.indentation = Number(options.indentation)
} else {
this.indentation = 2 // number of spaces
}
// determine mode
this.mode = 'preview';
this.mode = 'preview'
var me = this;
this.container = container;
this.dom = {};
var me = this
this.container = container
this.dom = {}
this.json = undefined;
this.text = '';
this.json = undefined
this.text = ''
// TODO: JSON Schema support
// 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.height = container.clientHeight;
this.width = container.clientWidth
this.height = container.clientHeight
this.frame = document.createElement('div');
this.frame.className = 'jsoneditor jsoneditor-mode-preview';
this.frame = document.createElement('div')
this.frame.className = 'jsoneditor jsoneditor-mode-preview'
this.frame.onclick = function (event) {
// prevent default submit action when the editor is located inside a form
event.preventDefault();
};
event.preventDefault()
}
this.content = document.createElement('div');
this.content.className = 'jsoneditor-outer';
this.content = document.createElement('div')
this.content.className = 'jsoneditor-outer'
this.dom.busy = document.createElement('div')
this.dom.busy.className = 'jsoneditor-busy';
this.dom.busyContent = document.createElement('span');
this.dom.busyContent.innerHTML = 'busy...';
this.dom.busy.appendChild(this.dom.busyContent);
this.content.appendChild(this.dom.busy);
this.dom.busy.className = 'jsoneditor-busy'
this.dom.busyContent = document.createElement('span')
this.dom.busyContent.innerHTML = 'busy...'
this.dom.busy.appendChild(this.dom.busyContent)
this.content.appendChild(this.dom.busy)
this.dom.previewContent = document.createElement('pre');
this.dom.previewContent.className = 'jsoneditor-preview';
this.dom.previewText = document.createTextNode('');
this.dom.previewContent.appendChild(this.dom.previewText);
this.content.appendChild(this.dom.previewContent);
this.dom.previewContent = document.createElement('pre')
this.dom.previewContent.className = 'jsoneditor-preview'
this.dom.previewText = document.createTextNode('')
this.dom.previewContent.appendChild(this.dom.previewText)
this.content.appendChild(this.dom.previewContent)
if (this.options.mainMenuBar) {
util.addClassName(this.content, 'has-main-menu-bar');
util.addClassName(this.content, 'has-main-menu-bar')
// create menu
this.menu = document.createElement('div');
this.menu.className = 'jsoneditor-menu';
this.frame.appendChild(this.menu);
this.menu = document.createElement('div')
this.menu.className = 'jsoneditor-menu'
this.frame.appendChild(this.menu)
// create format button
var buttonFormat = document.createElement('button');
buttonFormat.type = 'button';
buttonFormat.className = 'jsoneditor-format';
buttonFormat.title = 'Format JSON data, with proper indentation and line feeds (Ctrl+\\)';
this.menu.appendChild(buttonFormat);
buttonFormat.onclick = function handleFormat() {
var buttonFormat = document.createElement('button')
buttonFormat.type = 'button'
buttonFormat.className = 'jsoneditor-format'
buttonFormat.title = 'Format JSON data, with proper indentation and line feeds (Ctrl+\\)'
this.menu.appendChild(buttonFormat)
buttonFormat.onclick = function handleFormat () {
me.executeWithBusyMessage(function () {
try {
me.format();
me.format()
} catch (err) {
me._onError(err)
}
catch (err) {
me._onError(err);
}
}, 'formatting...');
};
}, 'formatting...')
}
// create compact button
var buttonCompact = document.createElement('button');
buttonCompact.type = 'button';
buttonCompact.className = 'jsoneditor-compact';
buttonCompact.title = 'Compact JSON data, remove all whitespaces (Ctrl+Shift+\\)';
this.menu.appendChild(buttonCompact);
buttonCompact.onclick = function handleCompact() {
var buttonCompact = document.createElement('button')
buttonCompact.type = 'button'
buttonCompact.className = 'jsoneditor-compact'
buttonCompact.title = 'Compact JSON data, remove all whitespaces (Ctrl+Shift+\\)'
this.menu.appendChild(buttonCompact)
buttonCompact.onclick = function handleCompact () {
me.executeWithBusyMessage(function () {
try {
me.compact();
me.compact()
} catch (err) {
me._onError(err)
}
catch (err) {
me._onError(err);
}
}, 'compacting...');
};
}, 'compacting...')
}
// create sort button
if (this.options.enableSort) {
var sort = document.createElement('button');
sort.type = 'button';
sort.className = 'jsoneditor-sort';
sort.title = translate('sortTitleShort');
var sort = document.createElement('button')
sort.type = 'button'
sort.className = 'jsoneditor-sort'
sort.title = translate('sortTitleShort')
sort.onclick = function () {
me._showSortModal();
};
this.menu.appendChild(sort);
me._showSortModal()
}
this.menu.appendChild(sort)
}
// create transform button
if (this.options.enableTransform) {
var transform = document.createElement('button');
transform.type = 'button';
transform.title = translate('transformTitleShort');
transform.className = 'jsoneditor-transform';
var transform = document.createElement('button')
transform.type = 'button'
transform.title = translate('transformTitleShort')
transform.className = 'jsoneditor-transform'
transform.onclick = function () {
me._showTransformModal();
};
this.dom.transform = transform;
this.menu.appendChild(transform);
me._showTransformModal()
}
this.dom.transform = transform
this.menu.appendChild(transform)
}
// create repair button
var buttonRepair = document.createElement('button');
buttonRepair.type = 'button';
buttonRepair.className = 'jsoneditor-repair';
buttonRepair.title = 'Repair JSON: fix quotes and escape characters, remove comments and JSONP notation, turn JavaScript objects into JSON.';
this.menu.appendChild(buttonRepair);
var buttonRepair = document.createElement('button')
buttonRepair.type = 'button'
buttonRepair.className = 'jsoneditor-repair'
buttonRepair.title = 'Repair JSON: fix quotes and escape characters, remove comments and JSONP notation, turn JavaScript objects into JSON.'
this.menu.appendChild(buttonRepair)
buttonRepair.onclick = function () {
if (me.json === undefined) { // only repair if we don't have valid JSON
me.executeWithBusyMessage(function () {
try {
me.repair();
me.repair()
} catch (err) {
me._onError(err)
}
catch (err) {
me._onError(err);
}
}, 'repairing...');
}, 'repairing...')
}
};
}
// create history and undo/redo buttons
if (this.options.history !== false) { // default option value is true
var onHistoryChange = function () {
me.dom.undo.disabled = !me.history.canUndo();
me.dom.redo.disabled = !me.history.canRedo();
};
var calculateItemSize = function (item) {
return item.text.length * 2; // times two to account for the json object
me.dom.undo.disabled = !me.history.canUndo()
me.dom.redo.disabled = !me.history.canRedo()
}
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
var undo = document.createElement('button');
undo.type = 'button';
undo.className = 'jsoneditor-undo jsoneditor-separator';
undo.title = translate('undo');
var undo = document.createElement('button')
undo.type = 'button'
undo.className = 'jsoneditor-undo jsoneditor-separator'
undo.title = translate('undo')
undo.onclick = function () {
var action = me.history.undo();
var action = me.history.undo()
if (action) {
me._applyHistory(action);
me._applyHistory(action)
}
};
this.menu.appendChild(undo);
this.dom.undo = undo;
}
this.menu.appendChild(undo)
this.dom.undo = undo
// create redo button
var redo = document.createElement('button');
redo.type = 'button';
redo.className = 'jsoneditor-redo';
redo.title = translate('redo');
var redo = document.createElement('button')
redo.type = 'button'
redo.className = 'jsoneditor-redo'
redo.title = translate('redo')
redo.onclick = function () {
var action = me.history.redo();
var action = me.history.redo()
if (action) {
me._applyHistory(action);
me._applyHistory(action)
}
};
this.menu.appendChild(redo);
this.dom.redo = redo;
}
this.menu.appendChild(redo)
this.dom.redo = redo
// force enabling/disabling the undo/redo button
this.history.onChange();
this.history.onChange()
}
// create mode box
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
me.setMode(mode);
me.modeSwitcher.focus();
});
me.setMode(mode)
me.modeSwitcher.focus()
})
}
}
this.errorTable = new ErrorTable({
errorTableVisible: true,
onToggleVisibility: function () {
me.validate();
me.validate()
},
onFocusLine: null,
onChangeHeight: function (height) {
// TODO: change CSS to using flex box, remove setting height using JavaScript
var statusBarHeight = me.dom.statusBar ? me.dom.statusBar.clientHeight : 0;
var totalHeight = height + statusBarHeight + 1;
me.content.style.marginBottom = (-totalHeight) + 'px';
me.content.style.paddingBottom = totalHeight + 'px';
var statusBarHeight = me.dom.statusBar ? me.dom.statusBar.clientHeight : 0
var totalHeight = height + statusBarHeight + 1
me.content.style.marginBottom = (-totalHeight) + 'px'
me.content.style.paddingBottom = totalHeight + 'px'
}
});
})
this.frame.appendChild(this.content);
this.frame.appendChild(this.errorTable.getErrorTable());
this.container.appendChild(this.frame);
this.frame.appendChild(this.content)
this.frame.appendChild(this.errorTable.getErrorTable())
this.container.appendChild(this.frame)
if (options.statusBar) {
util.addClassName(this.content, 'has-status-bar');
util.addClassName(this.content, 'has-status-bar')
var statusBar = document.createElement('div');
this.dom.statusBar = statusBar;
statusBar.className = 'jsoneditor-statusbar';
this.frame.appendChild(statusBar);
var statusBar = document.createElement('div')
this.dom.statusBar = statusBar
statusBar.className = 'jsoneditor-statusbar'
this.frame.appendChild(statusBar)
this.dom.fileSizeInfo = document.createElement('span');
this.dom.fileSizeInfo.className = 'jsoneditor-size-info';
this.dom.fileSizeInfo.innerText = '';
statusBar.appendChild(this.dom.fileSizeInfo);
this.dom.fileSizeInfo = document.createElement('span')
this.dom.fileSizeInfo.className = 'jsoneditor-size-info'
this.dom.fileSizeInfo.innerText = ''
statusBar.appendChild(this.dom.fileSizeInfo)
this.dom.arrayInfo = document.createElement('span');
this.dom.arrayInfo.className = 'jsoneditor-size-info';
this.dom.arrayInfo.innerText = '';
statusBar.appendChild(this.dom.arrayInfo);
this.dom.arrayInfo = document.createElement('span')
this.dom.arrayInfo.className = 'jsoneditor-size-info'
this.dom.arrayInfo.innerText = ''
statusBar.appendChild(this.dom.arrayInfo)
statusBar.appendChild(this.errorTable.getErrorCounter());
statusBar.appendChild(this.errorTable.getWarningIcon());
statusBar.appendChild(this.errorTable.getErrorIcon());
statusBar.appendChild(this.errorTable.getErrorCounter())
statusBar.appendChild(this.errorTable.getWarningIcon())
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 () {
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) {
this.dom.fileSizeInfo.innerText = 'Size: ' + util.formatSize(text.length);
this.dom.fileSizeInfo.innerText = 'Size: ' + util.formatSize(text.length)
}
if (this.dom.arrayInfo) {
if (Array.isArray(this.json)) {
this.dom.arrayInfo.innerText = ('Array: ' + this.json.length + ' items');
}
else {
this.dom.arrayInfo.innerText = '';
this.dom.arrayInfo.innerText = ('Array: ' + this.json.length + ' items')
} else {
this.dom.arrayInfo.innerText = ''
}
}
};
}
/**
* Handle a change:
@ -302,73 +297,70 @@ previewmode._renderPreview = function () {
*/
previewmode._onChange = function () {
// validate JSON schema (if configured)
this._debouncedValidate();
this._debouncedValidate()
// trigger the onChange callback
if (this.options.onChange) {
try {
this.options.onChange();
}
catch (err) {
console.error('Error in onChange callback: ', err);
this.options.onChange()
} catch (err) {
console.error('Error in onChange callback: ', err)
}
}
// trigger the onChangeJSON callback
if (this.options.onChangeJSON) {
try {
this.options.onChangeJSON(this.get());
}
catch (err) {
console.error('Error in onChangeJSON callback: ', err);
this.options.onChangeJSON(this.get())
} catch (err) {
console.error('Error in onChangeJSON callback: ', err)
}
}
// trigger the onChangeText callback
if (this.options.onChangeText) {
try {
this.options.onChangeText(this.getText());
}
catch (err) {
console.error('Error in onChangeText callback: ', err);
this.options.onChangeText(this.getText())
} catch (err) {
console.error('Error in onChangeText callback: ', err)
}
}
};
}
/**
* Open a sort modal
* @private
*/
previewmode._showSortModal = function () {
var me = this;
var me = this
function onSort (json, sortedBy) {
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._setAndFireOnChange(sortedArray);
me._setAndFireOnChange(sortedArray)
}
if (util.isObject(json)) {
var sortedObject = util.sortObjectKeys(json, sortedBy.direction);
var sortedObject = util.sortObjectKeys(json, sortedBy.direction)
me.sortedBy = sortedBy;
me._setAndFireOnChange(sortedObject);
me.sortedBy = sortedBy
me._setAndFireOnChange(sortedObject)
}
}
this.executeWithBusyMessage(function () {
var container = me.options.modalAnchor || DEFAULT_MODAL_ANCHOR;
var json = me.get();
me._renderPreview(); // update array count
var container = me.options.modalAnchor || DEFAULT_MODAL_ANCHOR
var json = me.get()
me._renderPreview() // update array count
showSortModal(container, json, function (sortedBy) {
me.executeWithBusyMessage(function () {
onSort(json, sortedBy);
}, 'sorting...');
onSort(json, sortedBy)
}, 'sorting...')
}, me.sortedBy)
}, 'parsing...');
}, 'parsing...')
}
/**
@ -376,17 +368,17 @@ previewmode._showSortModal = function () {
* @private
*/
previewmode._showTransformModal = function () {
var me = this;
var me = this
this.executeWithBusyMessage(function () {
var anchor = me.options.modalAnchor || DEFAULT_MODAL_ANCHOR;
var json = me.get();
me._renderPreview(); // update array count
var anchor = me.options.modalAnchor || DEFAULT_MODAL_ANCHOR
var json = me.get()
me._renderPreview() // update array count
showTransformModal(anchor, json, function (query) {
me.executeWithBusyMessage(function () {
var updatedJson = jmespath.search(json, query);
me._setAndFireOnChange(updatedJson);
var updatedJson = jmespath.search(json, query)
me._setAndFireOnChange(updatedJson)
}, 'transforming...')
})
}, 'parsing...')
@ -397,51 +389,51 @@ previewmode._showTransformModal = function () {
*/
previewmode.destroy = function () {
if (this.frame && this.container && this.frame.parentNode === this.container) {
this.container.removeChild(this.frame);
this.container.removeChild(this.frame)
}
if (this.modeSwitcher) {
this.modeSwitcher.destroy();
this.modeSwitcher = null;
this.modeSwitcher.destroy()
this.modeSwitcher = null
}
this._debouncedValidate = null;
this._debouncedValidate = null
this.history.clear();
this.history = null;
};
this.history.clear()
this.history = null
}
/**
* Compact the code in the text editor
*/
previewmode.compact = function () {
var json = this.get();
var text = JSON.stringify(json);
var json = this.get()
var text = JSON.stringify(json)
// 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
*/
previewmode.format = function () {
var json = this.get();
var text = JSON.stringify(json, null, this.indentation);
var json = this.get()
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
this._setTextAndFireOnChange(text, json);
};
this._setTextAndFireOnChange(text, json)
}
/**
* Repair the code in the text editor
*/
previewmode.repair = function () {
var text = this.getText();
var repairedText = util.repair(text);
var text = this.getText()
var repairedText = util.repair(text)
this._setTextAndFireOnChange(repairedText);
};
this._setTextAndFireOnChange(repairedText)
}
/**
* Set focus to the editor
@ -449,104 +441,104 @@ previewmode.repair = function () {
previewmode.focus = function () {
// we don't really have a place to focus,
// let's focus on the transform button
this.dom.transform.focus();
};
this.dom.transform.focus()
}
/**
* Set json data in the editor
* @param {*} json
*/
previewmode.set = function(json) {
previewmode.set = function (json) {
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.
* @param {*} json
*/
previewmode.update = function(json) {
this._set(json);
};
previewmode.update = function (json) {
this._set(json)
}
/**
* Set json data
* @param {*} json
*/
previewmode._set = function(json) {
this.text = undefined;
this.json = json;
previewmode._set = function (json) {
this.text = undefined
this.json = json
this._renderPreview();
this._renderPreview()
this._pushHistory();
this._pushHistory()
// validate JSON schema
this._debouncedValidate();
};
this._debouncedValidate()
}
previewmode._setAndFireOnChange = function (json) {
this._set(json);
this._onChange();
this._set(json)
this._onChange()
}
/**
* Get json data
* @return {*} json
*/
previewmode.get = function() {
previewmode.get = function () {
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
* @return {String} jsonText
*/
previewmode.getText = function() {
previewmode.getText = function () {
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) {
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
* @param {String} jsonText
*/
previewmode.setText = function(jsonText) {
previewmode.setText = function (jsonText) {
if (this.history) {
this.history.clear();
this.history.clear()
}
this._setText(jsonText);
};
this._setText(jsonText)
}
/**
* Update the text contents
* @param {string} jsonText
*/
previewmode.updateText = function(jsonText) {
previewmode.updateText = function (jsonText) {
// don't update if there are no changes
if (this.getText() === jsonText) {
return;
return
}
this._setText(jsonText);
};
this._setText(jsonText)
}
/**
* Set the text contents of the editor
@ -554,37 +546,34 @@ previewmode.updateText = function(jsonText) {
* @param {*} [json] Optional JSON instance of the text
* @private
*/
previewmode._setText = function(jsonText, json) {
previewmode._setText = function (jsonText, json) {
if (this.options.escapeUnicode === true) {
this.text = util.escapeUnicodeChars(jsonText);
this.text = util.escapeUnicodeChars(jsonText)
} else {
this.text = jsonText
}
else {
this.text = jsonText;
}
this.json = json;
this.json = json
this._renderPreview();
this._renderPreview()
if (this.json === undefined) {
var me = this;
var me = this
this.executeWithBusyMessage(function () {
try {
// force parsing the json now, else it will be done in validate without feedback
me.json = me.get();
me._renderPreview();
me._pushHistory();
}
catch (err) {
me.json = me.get()
me._renderPreview()
me._pushHistory()
} catch (err) {
// no need to throw an error, validation will show an error
}
}, 'parsing...');
}
else {
this._pushHistory();
}, 'parsing...')
} else {
this._pushHistory()
}
this._debouncedValidate();
};
this._debouncedValidate()
}
/**
* Set text and fire onChange callback
@ -593,8 +582,8 @@ previewmode._setText = function(jsonText, json) {
* @private
*/
previewmode._setTextAndFireOnChange = function (jsonText, json) {
this._setText(jsonText, json);
this._onChange();
this._setText(jsonText, json)
this._onChange()
}
/**
@ -603,13 +592,13 @@ previewmode._setTextAndFireOnChange = function (jsonText, json) {
* @private
*/
previewmode._applyHistory = function (action) {
this.json = action.json;
this.text = action.text;
this.json = action.json
this.text = action.text
this._renderPreview();
this._renderPreview()
this._debouncedValidate();
};
this._debouncedValidate()
}
/**
* Push the current state to history
@ -617,15 +606,15 @@ previewmode._applyHistory = function (action) {
*/
previewmode._pushHistory = function () {
if (!this.history) {
return;
return
}
var action = {
text: this.text,
json: this.json
};
}
this.history.add(action);
this.history.add(action)
}
/**
@ -635,23 +624,22 @@ previewmode._pushHistory = function () {
* @param {string} message
*/
previewmode.executeWithBusyMessage = function (fn, message) {
var size = this.getText().length;
var size = this.getText().length
if (size > SIZE_LARGE) {
var me = this;
util.addClassName(me.frame, 'busy');
me.dom.busyContent.innerText = message;
var me = this
util.addClassName(me.frame, 'busy')
me.dom.busyContent.innerText = message
setTimeout(function () {
fn();
util.removeClassName(me.frame, 'busy');
me.dom.busyContent.innerText = '';
}, 100);
fn()
util.removeClassName(me.frame, 'busy')
me.dom.busyContent.innerText = ''
}, 100)
} else {
fn()
}
else {
fn();
}
};
}
// TODO: refactor into composable functions instead of this shaky mixin-like structure
previewmode.validate = textmode.validate
@ -664,4 +652,4 @@ module.exports = [
mixin: previewmode,
data: 'json'
}
];
]

View File

@ -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
* @param {function} Node
*/
function showMoreNodeFactory(Node) {
function showMoreNodeFactory (Node) {
/**
* @constructor ShowMoreNode
* @extends Node
@ -17,12 +17,12 @@ function showMoreNodeFactory(Node) {
*/
function ShowMoreNode (editor, parent) {
/** @type {TreeEditor} */
this.editor = editor;
this.parent = parent;
this.dom = {};
this.editor = editor
this.parent = parent
this.dom = {}
}
ShowMoreNode.prototype = new Node();
ShowMoreNode.prototype = new Node()
/**
* Return a table row with an append button.
@ -30,105 +30,104 @@ function showMoreNodeFactory(Node) {
*/
ShowMoreNode.prototype.getDom = function () {
if (this.dom.tr) {
return this.dom.tr;
return this.dom.tr
}
this._updateEditability();
this._updateEditability()
// display "show more"
if (!this.dom.tr) {
var me = this;
var parent = this.parent;
var showMoreButton = document.createElement('a');
showMoreButton.appendChild(document.createTextNode(translate('showMore')));
showMoreButton.href = '#';
var me = this
var parent = this.parent
var showMoreButton = document.createElement('a')
showMoreButton.appendChild(document.createTextNode(translate('showMore')))
showMoreButton.href = '#'
showMoreButton.onclick = function (event) {
// TODO: use callback instead of accessing a method of the parent
parent.visibleChilds = Math.floor(parent.visibleChilds / parent.getMaxVisibleChilds() + 1) *
parent.getMaxVisibleChilds();
me.updateDom();
parent.showChilds();
parent.getMaxVisibleChilds()
me.updateDom()
parent.showChilds()
event.preventDefault();
return false;
};
event.preventDefault()
return false
}
var showAllButton = document.createElement('a');
showAllButton.appendChild(document.createTextNode(translate('showAll')));
showAllButton.href = '#';
var showAllButton = document.createElement('a')
showAllButton.appendChild(document.createTextNode(translate('showAll')))
showAllButton.href = '#'
showAllButton.onclick = function (event) {
// TODO: use callback instead of accessing a method of the parent
parent.visibleChilds = Infinity;
me.updateDom();
parent.showChilds();
parent.visibleChilds = Infinity
me.updateDom()
parent.showChilds()
event.preventDefault();
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'));
event.preventDefault()
return false
}
moreTr.appendChild(tdContents);
moreTr.className = 'jsoneditor-show-more';
this.dom.tr = moreTr;
this.dom.moreContents = moreContents;
this.dom.moreText = moreText;
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'
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
*/
ShowMoreNode.prototype.updateDom = function(options) {
ShowMoreNode.prototype.updateDom = function (options) {
if (this.isVisible()) {
// 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) {
var nextTr = this.parent._getNextTr();
var nextTr = this.parent._getNextTr()
if (nextTr) {
nextTr.parentNode.insertBefore(this.dom.tr, nextTr);
nextTr.parentNode.insertBefore(this.dom.tr, nextTr)
}
}
// update the counts in the text
this.dom.moreText.nodeValue = this._getShowMoreText();
this.dom.moreText.nodeValue = this._getShowMoreText()
// update left margin
this.dom.moreContents.style.marginLeft = (this.getLevel() + 1) * 24 + 'px';
}
else {
this.dom.moreContents.style.marginLeft = (this.getLevel() + 1) * 24 + 'px'
} else {
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', {
visibleChilds: this.parent.visibleChilds,
totalChilds: this.parent.childs.length
}) + ' ';
};
}) + ' '
}
/**
* Check whether the ShowMoreNode is currently visible.
@ -137,21 +136,21 @@ function showMoreNodeFactory(Node) {
* @return {boolean} isVisible
*/
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
* @param {Event} event
*/
ShowMoreNode.prototype.onEvent = function (event) {
var type = event.type;
var type = event.type
if (type === 'keydown') {
this.onKeyDown(event);
this.onKeyDown(event)
}
};
}
return ShowMoreNode;
return ShowMoreNode
}
module.exports = showMoreNodeFactory;
module.exports = showMoreNodeFactory

View File

@ -1,6 +1,6 @@
var picoModal = require('picomodal');
var translate = require('./i18n').translate;
var util = require('./util');
var picoModal = require('picomodal')
var translate = require('./i18n').translate
var util = require('./util')
/**
* Show advanced sorting modal
@ -17,12 +17,12 @@ var util = require('./util');
*/
function showSortModal (container, json, onSort, options) {
var paths = Array.isArray(json)
? util.getChildPaths(json)
: [''];
? util.getChildPaths(json)
: ['']
var selectedPath = options && options.path && util.contains(paths, options.path)
? options.path
: paths[0]
var selectedDirection = options && options.direction || 'asc'
? options.path
: paths[0]
var selectedDirection = (options && options.direction) || 'asc'
var content = '<div class="pico-modal-contents">' +
'<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">' +
'<input type="button" ' +
'value="' + translate('sortAscending') + '" ' +
'title="' + translate('sortAscendingTitle') + '" ' +
'title="' + translate('sortAscendingTitle') + '" ' +
'data-value="asc" ' +
'class="jsoneditor-button-first jsoneditor-button-asc"/>' +
'<input type="button" ' +
@ -63,71 +63,71 @@ function showSortModal (container, json, onSort, options) {
'</tbody>' +
'</table>' +
'</form>' +
'</div>';
'</div>'
picoModal({
parent: container,
content: content,
overlayClass: 'jsoneditor-modal-overlay',
overlayStyles: {
backgroundColor: "rgb(1,1,1)",
opacity: 0.3
backgroundColor: 'rgb(1,1,1)',
opacity: 0.3
},
modalClass: 'jsoneditor-modal jsoneditor-modal-sort'
})
.afterCreate(function (modal) {
var form = modal.modalElem().querySelector('form');
var ok = modal.modalElem().querySelector('#ok');
var field = modal.modalElem().querySelector('#field');
var direction = modal.modalElem().querySelector('#direction');
.afterCreate(function (modal) {
var form = modal.modalElem().querySelector('form')
var ok = modal.modalElem().querySelector('#ok')
var field = modal.modalElem().querySelector('#field')
var direction = modal.modalElem().querySelector('#direction')
function preprocessPath(path) {
return (path === '')
? '@'
: (path[0] === '.')
? path.slice(1)
: path;
}
function preprocessPath (path) {
return (path === '')
? '@'
: (path[0] === '.')
? path.slice(1)
: path
}
paths.forEach(function (path) {
var option = document.createElement('option');
option.text = preprocessPath(path);
option.value = path;
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;
}
paths.forEach(function (path) {
var option = document.createElement('option')
option.text = preprocessPath(path)
option.value = path
field.appendChild(option)
})
.afterClose(function (modal) {
modal.destroy();
})
.show();
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()
})
.show()
}
module.exports = showSortModal;
module.exports = showSortModal

View File

@ -1,11 +1,11 @@
var jmespath = require('jmespath');
var picoModal = require('picomodal');
var Selectr = require('./assets/selectr/selectr');
var translate = require('./i18n').translate;
var stringifyPartial = require('./jsonUtils').stringifyPartial;
var util = require('./util');
var jmespath = require('jmespath')
var picoModal = require('picomodal')
var Selectr = require('./assets/selectr/selectr')
var translate = require('./i18n').translate
var stringifyPartial = require('./jsonUtils').stringifyPartial
var util = require('./util')
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
@ -16,7 +16,7 @@ var debounce = util.debounce;
* query as callback
*/
function showTransformModal (container, json, onTransform) {
var value = json;
var value = json
var content = '<label class="pico-modal-contents">' +
'<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">' +
' <input type="submit" id="ok" value="' + translate('ok') + '" autofocus />' +
'</div>' +
'</div>';
'</div>'
picoModal({
parent: container,
content: content,
overlayClass: 'jsoneditor-modal-overlay',
overlayStyles: {
backgroundColor: "rgb(1,1,1)",
opacity: 0.3
backgroundColor: 'rgb(1,1,1)',
opacity: 0.3
},
modalClass: 'jsoneditor-modal jsoneditor-modal-transform',
focus: false
})
.afterCreate(function (modal) {
var elem = modal.modalElem();
.afterCreate(function (modal) {
var elem = modal.modalElem()
var wizard = elem.querySelector('#wizard');
var ok = elem.querySelector('#ok');
var filterField = elem.querySelector('#filterField');
var filterRelation = elem.querySelector('#filterRelation');
var filterValue = elem.querySelector('#filterValue');
var sortField = elem.querySelector('#sortField');
var sortOrder = elem.querySelector('#sortOrder');
var selectFields = elem.querySelector('#selectFields');
var query = elem.querySelector('#query');
var preview = elem.querySelector('#preview');
var wizard = elem.querySelector('#wizard')
var ok = elem.querySelector('#ok')
var filterField = elem.querySelector('#filterField')
var filterRelation = elem.querySelector('#filterRelation')
var filterValue = elem.querySelector('#filterValue')
var sortField = elem.querySelector('#sortField')
var sortOrder = elem.querySelector('#sortOrder')
var selectFields = elem.querySelector('#selectFields')
var query = elem.querySelector('#query')
var preview = elem.querySelector('#preview')
if (!Array.isArray(value)) {
wizard.style.fontStyle = 'italic';
wizard.innerHTML = '(wizard not available for objects, only for arrays)'
if (!Array.isArray(value)) {
wizard.style.fontStyle = 'italic'
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) {
var formattedPath = preprocessPath(path);
var filterOption = document.createElement('option');
filterOption.text = formattedPath;
filterOption.value = formattedPath;
filterField.appendChild(filterOption);
selectrFilterField.on('selectr.change', generateQueryFromWizard)
selectrFilterRelation.on('selectr.change', generateQueryFromWizard)
filterValue.oninput = generateQueryFromWizard
selectrSortField.on('selectr.change', generateQueryFromWizard)
selectrSortOrder.on('selectr.change', generateQueryFromWizard)
selectrSelectFields.on('selectr.change', generateQueryFromWizard)
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';
}
elem.querySelector('.pico-modal-contents').onclick = function (event) {
// prevent the first clear button (in any select box) from getting
// focus when clicking anywhere in the modal. Only allow clicking links.
if (event.target.nodeName !== 'A') {
event.preventDefault()
}
}
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...'});
query.value = Array.isArray(value) ? '[*]' : '@'
selectrFilterField.on('selectr.change', generateQueryFromWizard);
selectrFilterRelation.on('selectr.change', generateQueryFromWizard);
filterValue.oninput = generateQueryFromWizard;
selectrSortField.on('selectr.change', generateQueryFromWizard);
selectrSortOrder.on('selectr.change', generateQueryFromWizard);
selectrSelectFields.on('selectr.change', generateQueryFromWizard);
function preprocessPath (path) {
return (path === '')
? '@'
: (path[0] === '.')
? path.slice(1)
: path
}
elem.querySelector('.pico-modal-contents').onclick = function (event) {
// prevent the first clear button (in any select box) from getting
// focus when clicking anywhere in the modal. Only allow clicking links.
if (event.target.nodeName !== 'A') {
event.preventDefault();
}
};
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 = Array.isArray(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 = '[? ' +
query.value = '[? ' +
field1 + ' ' +
filterRelation.value + ' ' +
'`' + JSON.stringify(value1) + '`' +
']';
}
else {
query.value = '[*]';
}
']'
} else {
query.value = '[*]'
}
if (sortField.value && sortOrder.value) {
var field2 = sortField.value;
if (sortOrder.value === 'desc') {
query.value += ' | reverse(sort_by(@, &' + field2 + '))';
}
else {
query.value += ' | sort_by(@, &' + field2 + ')';
if (sortField.value && sortOrder.value) {
var field2 = sortField.value
if (sortOrder.value === 'desc') {
query.value += ' | reverse(sort_by(@, &' + field2 + '))'
} else {
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) {
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 (query.value[query.value.length - 1] !== ']') {
query.value += ' | [*]'
}
if (query.value[query.value.length - 1] !== ']') {
query.value += ' | [*]';
}
if (values.length === 1) {
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) {
var parts = value.split('.');
var last = parts[parts.length - 1];
return last + ': ' + value;
var parts = value.split('.')
var last = parts[parts.length - 1]
return last + ': ' + value
}).join(', ') +
'}';
}
else { // values.length === 0
// 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;
'}'
} else { // values.length === 0
// ignore
}
}
var debouncedUpdatePreview = debounce(updatePreview, 300);
debouncedUpdatePreview()
}
query.oninput = debouncedUpdatePreview;
debouncedUpdatePreview();
function updatePreview () {
try {
var transformed = jmespath.search(value, query.value)
ok.onclick = function (event) {
event.preventDefault();
event.stopPropagation();
preview.className = 'jsoneditor-transform-preview'
preview.value = stringifyPartial(transformed, 2, MAX_PREVIEW_CHARACTERS)
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.select();
query.focus();
query.selectionStart = 3;
query.selectionEnd = 3;
});
query.oninput = debouncedUpdatePreview
debouncedUpdatePreview()
ok.onclick = function (event) {
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();
})
.show();
})
.afterClose(function (modal) {
modal.destroy()
})
.show()
}
module.exports = showTransformModal;
module.exports = showTransformModal

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
var isPromise = require('./util').isPromise;
var isValidValidationError = require('./util').isValidValidationError;
var stringifyPath = require('./util').stringifyPath;
var isPromise = require('./util').isPromise
var isValidValidationError = require('./util').isValidValidationError
var stringifyPath = require('./util').stringifyPath
/**
* Execute custom validation if configured.
@ -9,46 +9,44 @@ var stringifyPath = require('./util').stringifyPath;
*/
function validateCustom (json, onValidate) {
if (!onValidate) {
return Promise.resolve([]);
return Promise.resolve([])
}
try {
var customValidateResults = onValidate(json);
var customValidateResults = onValidate(json)
var resultPromise = isPromise(customValidateResults)
? customValidateResults
: Promise.resolve(customValidateResults);
? customValidateResults
: Promise.resolve(customValidateResults)
return resultPromise.then(function (customValidationPathErrors) {
if (Array.isArray(customValidationPathErrors)) {
return customValidationPathErrors
.filter(function (error) {
var valid = isValidValidationError(error);
.filter(function (error) {
var valid = isValidValidationError(error)
if (!valid) {
console.warn('Ignoring a custom validation error with invalid structure. ' +
if (!valid) {
console.warn('Ignoring a custom validation error with invalid structure. ' +
'Expected structure: {path: [...], message: "..."}. ' +
'Actual error:', error);
}
'Actual error:', error)
}
return valid;
})
.map(function (error) {
// change data structure into the structure matching the JSON schema errors
return {
dataPath: stringifyPath(error.path),
message: error.message
}
});
return valid
})
.map(function (error) {
// change data structure into the structure matching the JSON schema errors
return {
dataPath: stringifyPath(error.path),
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

View File

@ -1,17 +1,15 @@
var VanillaPicker;
var VanillaPicker
if (window.Picker) {
// use the already loaded instance of VanillaPicker
VanillaPicker = window.Picker;
}
else {
VanillaPicker = window.Picker
} else {
try {
// load color picker
VanillaPicker = require('vanilla-picker');
}
catch (err) {
VanillaPicker = require('vanilla-picker')
} catch (err) {
// probably running the minimalist bundle
}
}
module.exports = VanillaPicker;
module.exports = VanillaPicker

View File

@ -1,295 +1,287 @@
var assert = require('assert');
var setUpTestEnvironment = require('./setup');
setUpTestEnvironment();
var assert = require('assert')
var setUpTestEnvironment = require('./setup')
setUpTestEnvironment()
var JSONEditor = require('../src/js/JSONEditor');
var Node = require('../src/js/Node');
var Node = require('../src/js/Node')
describe('Node', function () {
var node;
beforeEach(function () {
var editor = new JSONEditor(document.createElement('foo'));
node = new Node(editor);
});
describe('_findSchema', function () {
it('should find schema', function () {
var schema = {
type: 'object',
properties: {
child: {
type: 'string'
}
}
}
var path = ['child']
assert.strictEqual(Node._findSchema(schema, {}, path), schema.properties.child)
})
describe('_findSchema', function () {
it('should find schema', function () {
var schema = {
it('should find schema inside an array item', function () {
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',
properties: {
child: {
type: 'string'
}
bool: {
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 () {
var schema = {
properties: {
job: {
type: 'array',
items: {
type: 'object',
properties: {
company: {
enum: ['test1', 'test2']
}
}
}
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: {
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);
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',
properties: {
bool: {
type: 'boolean'
}
}
}
}
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'
}
}
}
};
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 return null for path that has no schema', function () {
var schema = {
type: 'object',
properties: {
foo: {
type: 'object',
properties: {
baz: {
type: 'number'
}
}
}
}
},
'^bar[0-9]': {
title: 'bar[0-9] pattern property',
type: 'object',
properties: {
barChild: {
type: 'string'
}
};
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);
});
});
}
}
}
}
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'
)
})
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'
);
});
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);
});
});
});
});
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)
})
})
})
})

View File

@ -1,21 +1,20 @@
var assert = require('assert');
var stringifyPartial = require('../src/js/jsonUtils').stringifyPartial;
var containsArray = require('../src/js/jsonUtils').containsArray;
var assert = require('assert')
var stringifyPartial = require('../src/js/jsonUtils').stringifyPartial
var containsArray = require('../src/js/jsonUtils').containsArray
describe('jsonUtils', function () {
it('should stringify a small object', function () {
var json = {
a: 2,
b: 'foo',
c: null,
d: false,
e: [ 1, 2, 3],
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"}}');
});
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 () {
var json = {
@ -23,12 +22,12 @@ describe('jsonUtils', function () {
b: 'foo',
c: null,
d: false,
e: [ 1, 2, 3],
e: [1, 2, 3],
f: { g: 'h' }
};
}
assert.strictEqual(stringifyPartial(json, 2),
'{\n' +
'{\n' +
' "a": 2,\n' +
' "b": "foo",\n' +
' "c": null,\n' +
@ -41,7 +40,7 @@ describe('jsonUtils', function () {
' "f": {\n' +
' "g": "h"\n' +
' }\n' +
'}');
'}')
assert.strictEqual(stringifyPartial(json, ' '), '{\n' +
' "a": 2,\n' +
@ -56,8 +55,8 @@ describe('jsonUtils', function () {
' "f": {\n' +
' "g": "h"\n' +
' }\n' +
'}');
});
'}')
})
it('should limit stringified output', function () {
var json = {
@ -65,23 +64,23 @@ describe('jsonUtils', function () {
b: 'foo',
c: null,
d: false,
e: [ 1, 2, 3],
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 all = '{"a":2,"b":"foo","c":null,"d":false,"e":[1,2,3],"f":{"g":"h"}}'
var limit = 20
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),
'[1,2,3,4,5...');
assert.strictEqual(stringifyPartial([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], undefined, 10),
'[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 () {
// assert.strictEqual(countArrayItems('[1,2,3]'), 3)
@ -93,6 +92,5 @@ describe('jsonUtils', function () {
assert.strictEqual(containsArray('2'), false)
assert.strictEqual(containsArray('null'), false)
assert.strictEqual(containsArray('{}'), false)
});
});
})
})

View File

@ -1,20 +1,20 @@
var JSDOM = require('jsdom').JSDOM;
var JSDOM = require('jsdom').JSDOM
/**
* Set up the test environment by simulating browser globals.
* @param {string} [locale=en] A locale to set in navigator.language
* @return {void}
*/
module.exports = function setUpTestEnvironment(locale) {
if (!locale) {
locale = 'en'
}
module.exports = function setUpTestEnvironment (locale) {
if (!locale) {
locale = 'en'
}
var dom = new JSDOM('...');
global.window = dom.window;
global.document = dom.window.document;
global.navigator = dom.window.navigator;
var dom = new JSDOM('...')
global.window = dom.window
global.document = dom.window.document
global.navigator = dom.window.navigator
// JSDom has no setter defined for navigator.language, so defineProperty is necessary in order to override it
Object.defineProperty(navigator, 'language', {value: locale})
};
// JSDom has no setter defined for navigator.language, so defineProperty is necessary in order to override it
Object.defineProperty(navigator, 'language', { value: locale })
}

View File

@ -1,38 +1,36 @@
var assert = require('assert');
var util = require('../src/js/util');
var assert = require('assert')
var util = require('../src/js/util')
describe('util', function () {
describe('repair', 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 () {
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('{\'a\':2}'), '{"a":2}');
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: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('{\'a\':2}'), '{"a":2}')
assert.strictEqual(util.repair('{a:\'foo\'}'), '{"a":"foo"}')
assert.strictEqual(util.repair('{a:\'foo\',b:\'bar\'}'), '{"a":"foo","b":"bar"}')
// 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 () {
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 () {
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":\u00a0"foo\u00a0bar"}'), '{"a": "foo\u00a0bar"}')
assert.strictEqual(util.repair('{"a":\u2009"foo"}'), '{"a": "foo"}')
})
it('should escape unescaped control characters', function () {
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('\u201Cfoo\u201D'), '"foo"')
assert.strictEqual(util.repair('\u0060foo\u00B4'), '"foo"')
});
})
it('remove comments', function () {
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('{\na:\'foo\',//hello\nb:\'bar\'\n}'), '{\n"a":"foo",\n"b":"bar"\n}');
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('{\na:\'foo\',//hello\nb:\'bar\'\n}'), '{\n"a":"foo",\n"b":"bar"\n}')
// 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 () {
// matching
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("foo");'), '"foo"');
assert.strictEqual(util.repair('callback_123(null);'), 'null');
assert.strictEqual(util.repair('callback_123(true);'), 'true');
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 */\ncallback_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('callback_123({});'), '{}')
assert.strictEqual(util.repair('callback_123([]);'), '[]')
assert.strictEqual(util.repair('callback_123(2);'), '2')
assert.strictEqual(util.repair('callback_123("foo");'), '"foo"')
assert.strictEqual(util.repair('callback_123(null);'), 'null')
assert.strictEqual(util.repair('callback_123(true);'), 'true')
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 */\ncallback_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'), '{}')
// 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 () {
// matching
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('{"a":2,}'), '{"a":2}');
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('{"a":2,}'), '{"a":2}')
// not matching
assert.strictEqual(util.repair('"[1,2,3,]"'), '"[1,2,3,]"');
assert.strictEqual(util.repair('"{a:2,}"'), '"{a:2,}"');
});
assert.strictEqual(util.repair('"[1,2,3,]"'), '"[1,2,3,]"')
assert.strictEqual(util.repair('"{a:2,}"'), '"{a:2,}"')
})
it('should strip MongoDB data types', function () {
var mongoDocument = '{\n' +
@ -103,7 +101,7 @@ describe('util', function () {
' "int2" : NumberInt(3),\n' +
' "decimal" : NumberDecimal("4"),\n' +
' "decimal2" : NumberDecimal(4)\n' +
'}';
'}'
var expectedJson = '{\n' +
' "_id" : "123",\n' +
@ -115,78 +113,75 @@ describe('util', function () {
' "int2" : 3,\n' +
' "decimal" : "4",\n' +
' "decimal2" : 4\n' +
'}';
'}'
assert.strictEqual(util.repair(mongoDocument), expectedJson);
});
});
assert.strictEqual(util.repair(mongoDocument), expectedJson)
})
})
describe('jsonPath', function () {
it('should stringify an array of paths', function() {
assert.deepStrictEqual(util.stringifyPath([]), '');
assert.deepStrictEqual(util.stringifyPath(['foo']), '.foo');
assert.deepStrictEqual(util.stringifyPath(['foo', 'bar']), '.foo.bar');
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_baz']), '.foo[2].bar_baz');
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 spaces']), '.foo["prop with spaces"]');
it('should stringify an array of paths', function () {
assert.deepStrictEqual(util.stringifyPath([]), '')
assert.deepStrictEqual(util.stringifyPath(['foo']), '.foo')
assert.deepStrictEqual(util.stringifyPath(['foo', 'bar']), '.foo.bar')
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_baz']), '.foo[2].bar_baz')
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 spaces']), '.foo["prop with spaces"]')
})
it ('should parse a json path', function () {
assert.deepStrictEqual(util.parsePath(''), []);
assert.deepStrictEqual(util.parsePath('.foo'), ['foo']);
assert.deepStrictEqual(util.parsePath('.foo.bar'), ['foo', 'bar']);
assert.deepStrictEqual(util.parsePath('.foo[2]'), ['foo', 2]);
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 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 ] character"]'), ['foo', 'prop with ] character']);
assert.deepStrictEqual(util.parsePath('.foo[*].bar'), ['foo', '*', 'bar']);
assert.deepStrictEqual(util.parsePath('[2]'), [2]);
});
it('should parse a json path', function () {
assert.deepStrictEqual(util.parsePath(''), [])
assert.deepStrictEqual(util.parsePath('.foo'), ['foo'])
assert.deepStrictEqual(util.parsePath('.foo.bar'), ['foo', 'bar'])
assert.deepStrictEqual(util.parsePath('.foo[2]'), ['foo', 2])
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 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 ] character"]'), ['foo', 'prop with ] character'])
assert.deepStrictEqual(util.parsePath('.foo[*].bar'), ['foo', '*', 'bar'])
assert.deepStrictEqual(util.parsePath('[2]'), [2])
})
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: unexpected end, character ] expected/);
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('.[]')}, /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('.foo bar')}, /Invalid JSON path: unexpected character " " at index 4/);
});
});
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: unexpected end, character ] expected/)
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('.[]') }, /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('.foo bar') }, /Invalid JSON path: unexpected character " " at index 4/)
})
})
describe('getIndexForPosition', function () {
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.'
};
}
it('happy flows - row and column in range', function () {
assert.strictEqual(util.getIndexForPosition(el, 1, 1), 0);
assert.strictEqual(util.getIndexForPosition(el, 2, 1), 124);
assert.strictEqual(util.getIndexForPosition(el, 3, 8), 239);
assert.strictEqual(util.getIndexForPosition(el, 4, 22), 356);
});
assert.strictEqual(util.getIndexForPosition(el, 1, 1), 0)
assert.strictEqual(util.getIndexForPosition(el, 2, 1), 124)
assert.strictEqual(util.getIndexForPosition(el, 3, 8), 239)
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 () {
assert.strictEqual(util.getIndexForPosition(el, 1, 100000), 123);
assert.strictEqual(util.getIndexForPosition(el, 100000, 1), 335);
assert.strictEqual(util.getIndexForPosition(el, 100000, 100000), 445);
});
assert.strictEqual(util.getIndexForPosition(el, 1, 100000), 123)
assert.strictEqual(util.getIndexForPosition(el, 100000, 1), 335)
assert.strictEqual(util.getIndexForPosition(el, 100000, 100000), 445)
})
it('missing or wrong input sould return -1', function () {
assert.strictEqual(util.getIndexForPosition(el), -1);
assert.strictEqual(util.getIndexForPosition(el, undefined, 1), -1);
assert.strictEqual(util.getIndexForPosition(el, 1, undefined), -1);
assert.strictEqual(util.getIndexForPosition(el, -2, -2), -1);
});
});
assert.strictEqual(util.getIndexForPosition(el), -1)
assert.strictEqual(util.getIndexForPosition(el, undefined, 1), -1)
assert.strictEqual(util.getIndexForPosition(el, 1, undefined), -1)
assert.strictEqual(util.getIndexForPosition(el, -2, -2), -1)
})
})
describe('get', function () {
it('should get a nested property from an object', function () {
@ -199,105 +194,105 @@ describe('util', function () {
e: undefined
}
assert.strictEqual(util.get(obj, ['a', 'b']), 2);
assert.strictEqual(util.get(obj, ['c']), 3);
assert.deepStrictEqual(util.get(obj, ['a']), { b: 2});
assert.strictEqual(util.get(obj, ['a', 'foo']), undefined);
assert.strictEqual(util.get(obj, ['a', 'foo', 'bar']), undefined);
assert.strictEqual(util.get(obj, ['d']), null);
assert.strictEqual(util.get(obj, ['d', 'foo', 'bar']), null);
assert.strictEqual(util.get(obj, ['e']), undefined);
assert.strictEqual(util.get(obj, ['a', 'b']), 2)
assert.strictEqual(util.get(obj, ['c']), 3)
assert.deepStrictEqual(util.get(obj, ['a']), { b: 2 })
assert.strictEqual(util.get(obj, ['a', 'foo']), undefined)
assert.strictEqual(util.get(obj, ['a', 'foo', 'bar']), undefined)
assert.strictEqual(util.get(obj, ['d']), null)
assert.strictEqual(util.get(obj, ['d', 'foo', 'bar']), null)
assert.strictEqual(util.get(obj, ['e']), undefined)
})
});
})
describe('makeFieldTooltip', function () {
it('should return empty string when the schema is missing all relevant fields', function () {
assert.strictEqual(util.makeFieldTooltip({}), '')
assert.strictEqual(util.makeFieldTooltip({additionalProperties: false}), '')
assert.strictEqual(util.makeFieldTooltip({ additionalProperties: false }), '')
assert.strictEqual(util.makeFieldTooltip(), '')
});
})
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 () {
assert.strictEqual(util.makeFieldTooltip({description: 'foo'}), 'foo');
});
assert.strictEqual(util.makeFieldTooltip({ description: 'foo' }), 'foo')
})
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 () {
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 () {
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. ' +
'Proin vitae ligula at elit dapibus tempor. ' +
'Etiam lacinia augue vel condimentum interdum. ';
'Etiam lacinia augue vel condimentum interdum. '
assert.strictEqual(
util.makeFieldTooltip({title: longTitle, description: longDescription}),
util.makeFieldTooltip({ title: longTitle, description: longDescription }),
longTitle + '\n' + longDescription
);
});
)
})
it('should make tooltips with title, description, and examples', function () {
assert.strictEqual(
util.makeFieldTooltip({title: 'foo', description: 'bar', examples: ['baz']}),
'foo\nbar\n\nExamples\n"baz"',
);
});
util.makeFieldTooltip({ title: 'foo', description: 'bar', examples: ['baz'] }),
'foo\nbar\n\nExamples\n"baz"'
)
})
it('should make tooltips with title, description, default, and examples', function () {
assert.strictEqual(
util.makeFieldTooltip({title: 'foo', description: 'bar', default: 'bat', examples: ['baz']}),
'foo\nbar\n\nDefault\n"bat"\n\nExamples\n"baz"',
);
});
util.makeFieldTooltip({ title: 'foo', description: 'bar', default: 'bat', examples: ['baz'] }),
'foo\nbar\n\nDefault\n"bat"\n\nExamples\n"baz"'
)
})
it('should handle empty fields', function () {
assert.strictEqual(util.makeFieldTooltip({title: '', description: 'bar'}), 'bar');
assert.strictEqual(util.makeFieldTooltip({title: 'foo', description: ''}), 'foo');
assert.strictEqual(util.makeFieldTooltip({description: 'bar', examples: []}), 'bar');
assert.strictEqual(util.makeFieldTooltip({description: 'bar', examples: ['']}), 'bar\n\nExamples\n""');
});
assert.strictEqual(util.makeFieldTooltip({ title: '', description: 'bar' }), 'bar')
assert.strictEqual(util.makeFieldTooltip({ title: 'foo', description: '' }), 'foo')
assert.strictEqual(util.makeFieldTooltip({ description: 'bar', examples: [] }), 'bar')
assert.strictEqual(util.makeFieldTooltip({ description: 'bar', examples: [''] }), 'bar\n\nExamples\n""')
})
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 () {
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 () {
it('should extract all child paths of an array containing objects', function () {
var json = [
{ name: 'A', location: {latitude: 1, longitude: 2} },
{ name: 'B', location: {latitude: 1, longitude: 2} },
{ name: 'C', timestamp: 0 },
];
{ name: 'A', location: { latitude: 1, longitude: 2 } },
{ name: 'B', location: { latitude: 1, longitude: 2 } },
{ name: 'C', timestamp: 0 }
]
assert.deepStrictEqual(util.getChildPaths(json), [
'.location.latitude',
'.location.longitude',
'.name',
'.timestamp',
'.timestamp'
])
});
})
it('should extract all child paths of an array containing objects, including objects', function () {
var json = [
{ name: 'A', location: {latitude: 1, longitude: 2} },
{ name: 'B', location: {latitude: 1, longitude: 2} },
{ name: 'C', timestamp: 0 },
];
{ name: 'A', location: { latitude: 1, longitude: 2 } },
{ name: 'B', location: { latitude: 1, longitude: 2 } },
{ name: 'C', timestamp: 0 }
]
assert.deepStrictEqual(util.getChildPaths(json, true), [
'',
@ -305,41 +300,41 @@ describe('util', function () {
'.location.latitude',
'.location.longitude',
'.name',
'.timestamp',
'.timestamp'
])
});
})
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), [
''
])
});
})
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(123), [''])
});
})
})
it('should test whether something is an object', function () {
assert.strictEqual(util.isObject({}), true);
assert.strictEqual(util.isObject(new Date()), true);
assert.strictEqual(util.isObject([]), false);
assert.strictEqual(util.isObject(2), false);
assert.strictEqual(util.isObject(null), false);
assert.strictEqual(util.isObject(undefined), false);
assert.strictEqual(util.isObject(), false);
});
assert.strictEqual(util.isObject({}), true)
assert.strictEqual(util.isObject(new Date()), true)
assert.strictEqual(util.isObject([]), false)
assert.strictEqual(util.isObject(2), false)
assert.strictEqual(util.isObject(null), false)
assert.strictEqual(util.isObject(undefined), false)
assert.strictEqual(util.isObject(), false)
})
describe('sort', function () {
it('should sort an array', function () {
var array = [4, 1, 10, 2];
assert.deepStrictEqual(util.sort(array), [1, 2, 4, 10]);
assert.deepStrictEqual(util.sort(array, '.', 'desc'), [10, 4, 2, 1]);
});
var array = [4, 1, 10, 2]
assert.deepStrictEqual(util.sort(array), [1, 2, 4, 10])
assert.deepStrictEqual(util.sort(array, '.', 'desc'), [10, 4, 2, 1])
})
it('should sort an array containing objects', function () {
var array = [
@ -347,23 +342,23 @@ describe('util', function () {
{ value: 1 },
{ value: 10 },
{ value: 2 }
];
]
assert.deepStrictEqual(util.sort(array, '.value'), [
{ value: 1 },
{ value: 2 },
{ value: 4 },
{ value: 10 }
]);
])
assert.deepStrictEqual(util.sort(array, '.value', 'desc'), [
{ value: 10 },
{ value: 4 },
{ value: 2 },
{ value: 1 }
]);
});
});
])
})
})
describe('sortObjectKeys', 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, 'asc')), '{"a":"a","b":"b","c":"c"}')
assert.strictEqual(JSON.stringify(util.sortObjectKeys(object, 'desc')), '{"c":"c","b":"b","a":"a"}')
});
});
})
})
it('should parse a string', function () {
assert.strictEqual(util.parseString('foo'), 'foo');
assert.strictEqual(util.parseString('234foo'), '234foo');
assert.strictEqual(util.parseString('2.3'), 2.3);
assert.strictEqual(util.parseString('null'), null);
assert.strictEqual(util.parseString('true'), true);
assert.strictEqual(util.parseString('false'), false);
assert.strictEqual(util.parseString('foo'), 'foo')
assert.strictEqual(util.parseString('234foo'), '234foo')
assert.strictEqual(util.parseString('2.3'), 2.3)
assert.strictEqual(util.parseString('null'), null)
assert.strictEqual(util.parseString('true'), true)
assert.strictEqual(util.parseString('false'), false)
})
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 () {
assert.strictEqual(util.formatSize(500), '500 B');
assert.strictEqual(util.formatSize(900), '0.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(7.22 * 1024 * 1024), '7.2 MiB');
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(1024 * 1024 * 1024 * 1024), '1.0 TiB');
});
assert.strictEqual(util.formatSize(500), '500 B')
assert.strictEqual(util.formatSize(900), '0.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(7.22 * 1024 * 1024), '7.2 MiB')
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(1024 * 1024 * 1024 * 1024), '1.0 TiB')
})
it ('should limit characters', function () {
assert.strictEqual(util.limitCharacters('hello world', 11), 'hello world');
assert.strictEqual(util.limitCharacters('hello world', 5), 'hello...');
assert.strictEqual(util.limitCharacters('hello world', 100), 'hello world');
it('should limit characters', function () {
assert.strictEqual(util.limitCharacters('hello world', 11), 'hello world')
assert.strictEqual(util.limitCharacters('hello world', 5), 'hello...')
assert.strictEqual(util.limitCharacters('hello world', 100), 'hello world')
})
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(['']), '/')
assert.strictEqual(util.compileJSONPointer([]), '')
});
})
// TODO: thoroughly test all util methods
});
})