Set up code style linting with standardjs
This commit is contained in:
parent
8e2a7de17c
commit
a5d6b8a65b
|
@ -1,3 +1,10 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- "lts/*"
|
||||
|
||||
jobs:
|
||||
include:
|
||||
- name: Lint
|
||||
stage: other
|
||||
script: npm run lint
|
||||
node_js: lts/*
|
||||
|
|
|
@ -6,10 +6,18 @@ up with ideas and suggestions, and contribute to the code.
|
|||
|
||||
There are a few preferences regarding code contributions:
|
||||
|
||||
- `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!
|
||||
|
|
12
README.md
12
README.md
|
@ -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>
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
}
|
||||
</style>
|
||||
<link rel="stylesheet" type="text/css" href="../../dist/jsoneditor.css">
|
||||
<script data-main="scripts/main" src="scripts/require.js"></script>
|
||||
<script data-main="scripts/main" src="https://requirejs.org/docs/release/2.3.6/minified/require.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<p>
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
var module = '../../../dist/jsoneditor';
|
||||
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))
|
||||
}
|
||||
})
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
/*
|
||||
RequireJS 2.1.13 Copyright (c) 2010-2014, The Dojo Foundation All Rights Reserved.
|
||||
Available via the MIT or new BSD license.
|
||||
see: http://github.com/jrburke/requirejs for details
|
||||
*/
|
||||
var requirejs,require,define;
|
||||
(function(ba){function G(b){return"[object Function]"===K.call(b)}function H(b){return"[object Array]"===K.call(b)}function v(b,c){if(b){var d;for(d=0;d<b.length&&(!b[d]||!c(b[d],d,b));d+=1);}}function T(b,c){if(b){var d;for(d=b.length-1;-1<d&&(!b[d]||!c(b[d],d,b));d-=1);}}function t(b,c){return fa.call(b,c)}function m(b,c){return t(b,c)&&b[c]}function B(b,c){for(var d in b)if(t(b,d)&&c(b[d],d))break}function U(b,c,d,e){c&&B(c,function(c,g){if(d||!t(b,g))e&&"object"===typeof c&&c&&!H(c)&&!G(c)&&!(c instanceof
|
||||
RegExp)?(b[g]||(b[g]={}),U(b[g],c,d,e)):b[g]=c});return b}function u(b,c){return function(){return c.apply(b,arguments)}}function ca(b){throw b;}function da(b){if(!b)return b;var c=ba;v(b.split("."),function(b){c=c[b]});return c}function C(b,c,d,e){c=Error(c+"\nhttp://requirejs.org/docs/errors.html#"+b);c.requireType=b;c.requireModules=e;d&&(c.originalError=d);return c}function ga(b){function c(a,k,b){var f,l,c,d,e,g,i,p,k=k&&k.split("/"),h=j.map,n=h&&h["*"];if(a){a=a.split("/");l=a.length-1;j.nodeIdCompat&&
|
||||
Q.test(a[l])&&(a[l]=a[l].replace(Q,""));"."===a[0].charAt(0)&&k&&(l=k.slice(0,k.length-1),a=l.concat(a));l=a;for(c=0;c<l.length;c++)if(d=l[c],"."===d)l.splice(c,1),c-=1;else if(".."===d&&!(0===c||1==c&&".."===l[2]||".."===l[c-1])&&0<c)l.splice(c-1,2),c-=2;a=a.join("/")}if(b&&h&&(k||n)){l=a.split("/");c=l.length;a:for(;0<c;c-=1){e=l.slice(0,c).join("/");if(k)for(d=k.length;0<d;d-=1)if(b=m(h,k.slice(0,d).join("/")))if(b=m(b,e)){f=b;g=c;break a}!i&&(n&&m(n,e))&&(i=m(n,e),p=c)}!f&&i&&(f=i,g=p);f&&(l.splice(0,
|
||||
g,f),a=l.join("/"))}return(f=m(j.pkgs,a))?f:a}function d(a){z&&v(document.getElementsByTagName("script"),function(k){if(k.getAttribute("data-requiremodule")===a&&k.getAttribute("data-requirecontext")===i.contextName)return k.parentNode.removeChild(k),!0})}function e(a){var k=m(j.paths,a);if(k&&H(k)&&1<k.length)return k.shift(),i.require.undef(a),i.makeRequire(null,{skipMap:!0})([a]),!0}function n(a){var k,c=a?a.indexOf("!"):-1;-1<c&&(k=a.substring(0,c),a=a.substring(c+1,a.length));return[k,a]}function p(a,
|
||||
k,b,f){var l,d,e=null,g=k?k.name:null,j=a,p=!0,h="";a||(p=!1,a="_@r"+(K+=1));a=n(a);e=a[0];a=a[1];e&&(e=c(e,g,f),d=m(r,e));a&&(e?h=d&&d.normalize?d.normalize(a,function(a){return c(a,g,f)}):c(a,g,f):(h=c(a,g,f),a=n(h),e=a[0],h=a[1],b=!0,l=i.nameToUrl(h)));b=e&&!d&&!b?"_unnormalized"+(O+=1):"";return{prefix:e,name:h,parentMap:k,unnormalized:!!b,url:l,originalName:j,isDefine:p,id:(e?e+"!"+h:h)+b}}function s(a){var k=a.id,b=m(h,k);b||(b=h[k]=new i.Module(a));return b}function q(a,k,b){var f=a.id,c=m(h,
|
||||
f);if(t(r,f)&&(!c||c.defineEmitComplete))"defined"===k&&b(r[f]);else if(c=s(a),c.error&&"error"===k)b(c.error);else c.on(k,b)}function w(a,b){var c=a.requireModules,f=!1;if(b)b(a);else if(v(c,function(b){if(b=m(h,b))b.error=a,b.events.error&&(f=!0,b.emit("error",a))}),!f)g.onError(a)}function x(){R.length&&(ha.apply(A,[A.length,0].concat(R)),R=[])}function y(a){delete h[a];delete V[a]}function F(a,b,c){var f=a.map.id;a.error?a.emit("error",a.error):(b[f]=!0,v(a.depMaps,function(f,d){var e=f.id,g=
|
||||
m(h,e);g&&(!a.depMatched[d]&&!c[e])&&(m(b,e)?(a.defineDep(d,r[e]),a.check()):F(g,b,c))}),c[f]=!0)}function D(){var a,b,c=(a=1E3*j.waitSeconds)&&i.startTime+a<(new Date).getTime(),f=[],l=[],g=!1,h=!0;if(!W){W=!0;B(V,function(a){var i=a.map,j=i.id;if(a.enabled&&(i.isDefine||l.push(a),!a.error))if(!a.inited&&c)e(j)?g=b=!0:(f.push(j),d(j));else if(!a.inited&&(a.fetched&&i.isDefine)&&(g=!0,!i.prefix))return h=!1});if(c&&f.length)return a=C("timeout","Load timeout for modules: "+f,null,f),a.contextName=
|
||||
i.contextName,w(a);h&&v(l,function(a){F(a,{},{})});if((!c||b)&&g)if((z||ea)&&!X)X=setTimeout(function(){X=0;D()},50);W=!1}}function E(a){t(r,a[0])||s(p(a[0],null,!0)).init(a[1],a[2])}function I(a){var a=a.currentTarget||a.srcElement,b=i.onScriptLoad;a.detachEvent&&!Y?a.detachEvent("onreadystatechange",b):a.removeEventListener("load",b,!1);b=i.onScriptError;(!a.detachEvent||Y)&&a.removeEventListener("error",b,!1);return{node:a,id:a&&a.getAttribute("data-requiremodule")}}function J(){var a;for(x();A.length;){a=
|
||||
A.shift();if(null===a[0])return w(C("mismatch","Mismatched anonymous define() module: "+a[a.length-1]));E(a)}}var W,Z,i,L,X,j={waitSeconds:7,baseUrl:"./",paths:{},bundles:{},pkgs:{},shim:{},config:{}},h={},V={},$={},A=[],r={},S={},aa={},K=1,O=1;L={require:function(a){return a.require?a.require:a.require=i.makeRequire(a.map)},exports:function(a){a.usingExports=!0;if(a.map.isDefine)return a.exports?r[a.map.id]=a.exports:a.exports=r[a.map.id]={}},module:function(a){return a.module?a.module:a.module=
|
||||
{id:a.map.id,uri:a.map.url,config:function(){return m(j.config,a.map.id)||{}},exports:a.exports||(a.exports={})}}};Z=function(a){this.events=m($,a.id)||{};this.map=a;this.shim=m(j.shim,a.id);this.depExports=[];this.depMaps=[];this.depMatched=[];this.pluginMaps={};this.depCount=0};Z.prototype={init:function(a,b,c,f){f=f||{};if(!this.inited){this.factory=b;if(c)this.on("error",c);else this.events.error&&(c=u(this,function(a){this.emit("error",a)}));this.depMaps=a&&a.slice(0);this.errback=c;this.inited=
|
||||
!0;this.ignore=f.ignore;f.enabled||this.enabled?this.enable():this.check()}},defineDep:function(a,b){this.depMatched[a]||(this.depMatched[a]=!0,this.depCount-=1,this.depExports[a]=b)},fetch:function(){if(!this.fetched){this.fetched=!0;i.startTime=(new Date).getTime();var a=this.map;if(this.shim)i.makeRequire(this.map,{enableBuildCallback:!0})(this.shim.deps||[],u(this,function(){return a.prefix?this.callPlugin():this.load()}));else return a.prefix?this.callPlugin():this.load()}},load:function(){var a=
|
||||
this.map.url;S[a]||(S[a]=!0,i.load(this.map.id,a))},check:function(){if(this.enabled&&!this.enabling){var a,b,c=this.map.id;b=this.depExports;var f=this.exports,l=this.factory;if(this.inited)if(this.error)this.emit("error",this.error);else{if(!this.defining){this.defining=!0;if(1>this.depCount&&!this.defined){if(G(l)){if(this.events.error&&this.map.isDefine||g.onError!==ca)try{f=i.execCb(c,l,b,f)}catch(d){a=d}else f=i.execCb(c,l,b,f);this.map.isDefine&&void 0===f&&((b=this.module)?f=b.exports:this.usingExports&&
|
||||
(f=this.exports));if(a)return a.requireMap=this.map,a.requireModules=this.map.isDefine?[this.map.id]:null,a.requireType=this.map.isDefine?"define":"require",w(this.error=a)}else f=l;this.exports=f;if(this.map.isDefine&&!this.ignore&&(r[c]=f,g.onResourceLoad))g.onResourceLoad(i,this.map,this.depMaps);y(c);this.defined=!0}this.defining=!1;this.defined&&!this.defineEmitted&&(this.defineEmitted=!0,this.emit("defined",this.exports),this.defineEmitComplete=!0)}}else this.fetch()}},callPlugin:function(){var a=
|
||||
this.map,b=a.id,d=p(a.prefix);this.depMaps.push(d);q(d,"defined",u(this,function(f){var l,d;d=m(aa,this.map.id);var e=this.map.name,P=this.map.parentMap?this.map.parentMap.name:null,n=i.makeRequire(a.parentMap,{enableBuildCallback:!0});if(this.map.unnormalized){if(f.normalize&&(e=f.normalize(e,function(a){return c(a,P,!0)})||""),f=p(a.prefix+"!"+e,this.map.parentMap),q(f,"defined",u(this,function(a){this.init([],function(){return a},null,{enabled:!0,ignore:!0})})),d=m(h,f.id)){this.depMaps.push(f);
|
||||
if(this.events.error)d.on("error",u(this,function(a){this.emit("error",a)}));d.enable()}}else d?(this.map.url=i.nameToUrl(d),this.load()):(l=u(this,function(a){this.init([],function(){return a},null,{enabled:!0})}),l.error=u(this,function(a){this.inited=!0;this.error=a;a.requireModules=[b];B(h,function(a){0===a.map.id.indexOf(b+"_unnormalized")&&y(a.map.id)});w(a)}),l.fromText=u(this,function(f,c){var d=a.name,e=p(d),P=M;c&&(f=c);P&&(M=!1);s(e);t(j.config,b)&&(j.config[d]=j.config[b]);try{g.exec(f)}catch(h){return w(C("fromtexteval",
|
||||
"fromText eval for "+b+" failed: "+h,h,[b]))}P&&(M=!0);this.depMaps.push(e);i.completeLoad(d);n([d],l)}),f.load(a.name,n,l,j))}));i.enable(d,this);this.pluginMaps[d.id]=d},enable:function(){V[this.map.id]=this;this.enabling=this.enabled=!0;v(this.depMaps,u(this,function(a,b){var c,f;if("string"===typeof a){a=p(a,this.map.isDefine?this.map:this.map.parentMap,!1,!this.skipMap);this.depMaps[b]=a;if(c=m(L,a.id)){this.depExports[b]=c(this);return}this.depCount+=1;q(a,"defined",u(this,function(a){this.defineDep(b,
|
||||
a);this.check()}));this.errback&&q(a,"error",u(this,this.errback))}c=a.id;f=h[c];!t(L,c)&&(f&&!f.enabled)&&i.enable(a,this)}));B(this.pluginMaps,u(this,function(a){var b=m(h,a.id);b&&!b.enabled&&i.enable(a,this)}));this.enabling=!1;this.check()},on:function(a,b){var c=this.events[a];c||(c=this.events[a]=[]);c.push(b)},emit:function(a,b){v(this.events[a],function(a){a(b)});"error"===a&&delete this.events[a]}};i={config:j,contextName:b,registry:h,defined:r,urlFetched:S,defQueue:A,Module:Z,makeModuleMap:p,
|
||||
nextTick:g.nextTick,onError:w,configure:function(a){a.baseUrl&&"/"!==a.baseUrl.charAt(a.baseUrl.length-1)&&(a.baseUrl+="/");var b=j.shim,c={paths:!0,bundles:!0,config:!0,map:!0};B(a,function(a,b){c[b]?(j[b]||(j[b]={}),U(j[b],a,!0,!0)):j[b]=a});a.bundles&&B(a.bundles,function(a,b){v(a,function(a){a!==b&&(aa[a]=b)})});a.shim&&(B(a.shim,function(a,c){H(a)&&(a={deps:a});if((a.exports||a.init)&&!a.exportsFn)a.exportsFn=i.makeShimExports(a);b[c]=a}),j.shim=b);a.packages&&v(a.packages,function(a){var b,
|
||||
a="string"===typeof a?{name:a}:a;b=a.name;a.location&&(j.paths[b]=a.location);j.pkgs[b]=a.name+"/"+(a.main||"main").replace(ia,"").replace(Q,"")});B(h,function(a,b){!a.inited&&!a.map.unnormalized&&(a.map=p(b))});if(a.deps||a.callback)i.require(a.deps||[],a.callback)},makeShimExports:function(a){return function(){var b;a.init&&(b=a.init.apply(ba,arguments));return b||a.exports&&da(a.exports)}},makeRequire:function(a,e){function j(c,d,m){var n,q;e.enableBuildCallback&&(d&&G(d))&&(d.__requireJsBuild=
|
||||
!0);if("string"===typeof c){if(G(d))return w(C("requireargs","Invalid require call"),m);if(a&&t(L,c))return L[c](h[a.id]);if(g.get)return g.get(i,c,a,j);n=p(c,a,!1,!0);n=n.id;return!t(r,n)?w(C("notloaded",'Module name "'+n+'" has not been loaded yet for context: '+b+(a?"":". Use require([])"))):r[n]}J();i.nextTick(function(){J();q=s(p(null,a));q.skipMap=e.skipMap;q.init(c,d,m,{enabled:!0});D()});return j}e=e||{};U(j,{isBrowser:z,toUrl:function(b){var d,e=b.lastIndexOf("."),k=b.split("/")[0];if(-1!==
|
||||
e&&(!("."===k||".."===k)||1<e))d=b.substring(e,b.length),b=b.substring(0,e);return i.nameToUrl(c(b,a&&a.id,!0),d,!0)},defined:function(b){return t(r,p(b,a,!1,!0).id)},specified:function(b){b=p(b,a,!1,!0).id;return t(r,b)||t(h,b)}});a||(j.undef=function(b){x();var c=p(b,a,!0),e=m(h,b);d(b);delete r[b];delete S[c.url];delete $[b];T(A,function(a,c){a[0]===b&&A.splice(c,1)});e&&(e.events.defined&&($[b]=e.events),y(b))});return j},enable:function(a){m(h,a.id)&&s(a).enable()},completeLoad:function(a){var b,
|
||||
c,d=m(j.shim,a)||{},g=d.exports;for(x();A.length;){c=A.shift();if(null===c[0]){c[0]=a;if(b)break;b=!0}else c[0]===a&&(b=!0);E(c)}c=m(h,a);if(!b&&!t(r,a)&&c&&!c.inited){if(j.enforceDefine&&(!g||!da(g)))return e(a)?void 0:w(C("nodefine","No define call for "+a,null,[a]));E([a,d.deps||[],d.exportsFn])}D()},nameToUrl:function(a,b,c){var d,e,h;(d=m(j.pkgs,a))&&(a=d);if(d=m(aa,a))return i.nameToUrl(d,b,c);if(g.jsExtRegExp.test(a))d=a+(b||"");else{d=j.paths;a=a.split("/");for(e=a.length;0<e;e-=1)if(h=a.slice(0,
|
||||
e).join("/"),h=m(d,h)){H(h)&&(h=h[0]);a.splice(0,e,h);break}d=a.join("/");d+=b||(/^data\:|\?/.test(d)||c?"":".js");d=("/"===d.charAt(0)||d.match(/^[\w\+\.\-]+:/)?"":j.baseUrl)+d}return j.urlArgs?d+((-1===d.indexOf("?")?"?":"&")+j.urlArgs):d},load:function(a,b){g.load(i,a,b)},execCb:function(a,b,c,d){return b.apply(d,c)},onScriptLoad:function(a){if("load"===a.type||ja.test((a.currentTarget||a.srcElement).readyState))N=null,a=I(a),i.completeLoad(a.id)},onScriptError:function(a){var b=I(a);if(!e(b.id))return w(C("scripterror",
|
||||
"Script error for: "+b.id,a,[b.id]))}};i.require=i.makeRequire();return i}var g,x,y,D,I,E,N,J,s,O,ka=/(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,la=/[^.]\s*require\s*\(\s*["']([^'"\s]+)["']\s*\)/g,Q=/\.js$/,ia=/^\.\//;x=Object.prototype;var K=x.toString,fa=x.hasOwnProperty,ha=Array.prototype.splice,z=!!("undefined"!==typeof window&&"undefined"!==typeof navigator&&window.document),ea=!z&&"undefined"!==typeof importScripts,ja=z&&"PLAYSTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/,
|
||||
Y="undefined"!==typeof opera&&"[object Opera]"===opera.toString(),F={},q={},R=[],M=!1;if("undefined"===typeof define){if("undefined"!==typeof requirejs){if(G(requirejs))return;q=requirejs;requirejs=void 0}"undefined"!==typeof require&&!G(require)&&(q=require,require=void 0);g=requirejs=function(b,c,d,e){var n,p="_";!H(b)&&"string"!==typeof b&&(n=b,H(c)?(b=c,c=d,d=e):b=[]);n&&n.context&&(p=n.context);(e=m(F,p))||(e=F[p]=g.s.newContext(p));n&&e.configure(n);return e.require(b,c,d)};g.config=function(b){return g(b)};
|
||||
g.nextTick="undefined"!==typeof setTimeout?function(b){setTimeout(b,4)}:function(b){b()};require||(require=g);g.version="2.1.13";g.jsExtRegExp=/^\/|:|\?|\.js$/;g.isBrowser=z;x=g.s={contexts:F,newContext:ga};g({});v(["toUrl","undef","defined","specified"],function(b){g[b]=function(){var c=F._;return c.require[b].apply(c,arguments)}});if(z&&(y=x.head=document.getElementsByTagName("head")[0],D=document.getElementsByTagName("base")[0]))y=x.head=D.parentNode;g.onError=ca;g.createNode=function(b){var c=
|
||||
b.xhtml?document.createElementNS("http://www.w3.org/1999/xhtml","html:script"):document.createElement("script");c.type=b.scriptType||"text/javascript";c.charset="utf-8";c.async=!0;return c};g.load=function(b,c,d){var e=b&&b.config||{};if(z)return e=g.createNode(e,c,d),e.setAttribute("data-requirecontext",b.contextName),e.setAttribute("data-requiremodule",c),e.attachEvent&&!(e.attachEvent.toString&&0>e.attachEvent.toString().indexOf("[native code"))&&!Y?(M=!0,e.attachEvent("onreadystatechange",b.onScriptLoad)):
|
||||
(e.addEventListener("load",b.onScriptLoad,!1),e.addEventListener("error",b.onScriptError,!1)),e.src=d,J=e,D?y.insertBefore(e,D):y.appendChild(e),J=null,e;if(ea)try{importScripts(d),b.completeLoad(c)}catch(m){b.onError(C("importscripts","importScripts failed for "+c+" at "+d,m,[c]))}};z&&!q.skipDataMain&&T(document.getElementsByTagName("script"),function(b){y||(y=b.parentNode);if(I=b.getAttribute("data-main"))return s=I,q.baseUrl||(E=s.split("/"),s=E.pop(),O=E.length?E.join("/")+"/":"./",q.baseUrl=
|
||||
O),s=s.replace(Q,""),g.jsExtRegExp.test(s)&&(s=I),q.deps=q.deps?q.deps.concat(s):[s],!0});define=function(b,c,d){var e,g;"string"!==typeof b&&(d=c,c=b,b=null);H(c)||(d=c,c=null);!c&&G(d)&&(c=[],d.length&&(d.toString().replace(ka,"").replace(la,function(b,d){c.push(d)}),c=(1===d.length?["require"]:["require","exports","module"]).concat(c)));if(M){if(!(e=J))N&&"interactive"===N.readyState||T(document.getElementsByTagName("script"),function(b){if("interactive"===b.readyState)return N=b}),e=N;e&&(b||
|
||||
(b=e.getAttribute("data-requiremodule")),g=F[e.getAttribute("data-requirecontext")])}(g?g.defQueue:R).push([b,c,d])};define.amd={jQuery:!0};g.exec=function(b){return eval(b)};g(q)}})(this);
|
202
gulpfile.js
202
gulpfile.js
|
@ -1,38 +1,38 @@
|
|||
var fs = require('fs');
|
||||
var 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')
|
||||
)
|
||||
))
|
||||
|
|
2
index.js
2
index.js
|
@ -1 +1 @@
|
|||
module.exports = require('./src/js/JSONEditor');
|
||||
module.exports = require('./src/js/JSONEditor')
|
||||
|
|
File diff suppressed because it is too large
Load Diff
10
package.json
10
package.json
|
@ -21,7 +21,8 @@
|
|||
"build": "gulp",
|
||||
"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*"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 ▿";
|
||||
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 ▿'
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 + ' ▾';
|
||||
box.title = 'Switch editor mode';
|
||||
var box = document.createElement('button')
|
||||
box.type = 'button'
|
||||
box.className = 'jsoneditor-modes jsoneditor-separator'
|
||||
box.innerHTML = currentTitle + ' ▾'
|
||||
box.title = 'Switch editor mode'
|
||||
box.onclick = function () {
|
||||
var menu = new ContextMenu(items);
|
||||
menu.show(box, 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
|
||||
|
|
3907
src/js/Node.js
3907
src/js/Node.js
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
|||
'use strict';
|
||||
'use strict'
|
||||
|
||||
var util = require('./util');
|
||||
var util = require('./util')
|
||||
|
||||
/**
|
||||
* @constructor History
|
||||
|
@ -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
|
||||
|
|
|
@ -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 results";
|
||||
this.dom.results.innerHTML = 'no results'
|
||||
} else if (resultCount === 1) {
|
||||
this.dom.results.innerHTML = "1 result";
|
||||
this.dom.results.innerHTML = '1 result'
|
||||
} else if (resultCount > MAX_SEARCH_RESULTS) {
|
||||
this.dom.results.innerHTML = MAX_SEARCH_RESULTS + "+ results";
|
||||
this.dom.results.innerHTML = MAX_SEARCH_RESULTS + '+ results'
|
||||
} else {
|
||||
this.dom.results.innerHTML = resultCount + " results";
|
||||
this.dom.results.innerHTML = resultCount + ' 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
|
||||
|
|
|
@ -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 = '►';
|
||||
sepEl = document.createElement('span')
|
||||
sepEl.className = 'jsoneditor-treepath-seperator'
|
||||
sepEl.innerHTML = '►'
|
||||
|
||||
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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
return spacer.getBoundingClientRect().right;
|
||||
}
|
||||
|
||||
var rs = {
|
||||
onArrowDown: function () { }, // defaults to no action.
|
||||
onArrowUp: function () { }, // defaults to no action.
|
||||
onEnter: function () { }, // defaults to no action.
|
||||
onTab: function () { }, // defaults to no action.
|
||||
startFrom: 0,
|
||||
options: [],
|
||||
element: null,
|
||||
elementHint: null,
|
||||
elementStyle: null,
|
||||
wrapper: wrapper, // Only to allow easy access to the HTML elements to the final user (possibly for minor customizations)
|
||||
show: function (element, startPos, options) {
|
||||
this.startFrom = startPos;
|
||||
this.wrapper.remove();
|
||||
if (this.elementHint) {
|
||||
this.elementHint.remove();
|
||||
this.elementHint = null;
|
||||
}
|
||||
|
||||
if (fontSize == '') {
|
||||
fontSize = window.getComputedStyle(element).getPropertyValue('font-size');
|
||||
}
|
||||
if (fontFamily == '') {
|
||||
fontFamily = window.getComputedStyle(element).getPropertyValue('font-family');
|
||||
}
|
||||
|
||||
var w = element.getBoundingClientRect().right - element.getBoundingClientRect().left;
|
||||
dropDown.style.marginLeft = '0';
|
||||
dropDown.style.marginTop = element.getBoundingClientRect().height + 'px';
|
||||
this.options = options;
|
||||
|
||||
if (this.element != element) {
|
||||
this.element = element;
|
||||
this.elementStyle = {
|
||||
zIndex: this.element.style.zIndex,
|
||||
position: this.element.style.position,
|
||||
backgroundColor: this.element.style.backgroundColor,
|
||||
borderColor: this.element.style.borderColor
|
||||
}
|
||||
}
|
||||
|
||||
this.element.style.zIndex = 3;
|
||||
this.element.style.position = 'relative';
|
||||
this.element.style.backgroundColor = 'transparent';
|
||||
this.element.style.borderColor = 'transparent';
|
||||
|
||||
this.elementHint = element.cloneNode();
|
||||
this.elementHint.className = 'autocomplete hint';
|
||||
this.elementHint.style.zIndex = 2;
|
||||
this.elementHint.style.position = 'absolute';
|
||||
this.elementHint.onfocus = function () { this.element.focus(); }.bind(this);
|
||||
|
||||
|
||||
|
||||
if (this.element.addEventListener) {
|
||||
this.element.removeEventListener("keydown", keyDownHandler);
|
||||
this.element.addEventListener("keydown", keyDownHandler, false);
|
||||
this.element.removeEventListener("blur", onBlurHandler);
|
||||
this.element.addEventListener("blur", onBlurHandler, false);
|
||||
}
|
||||
|
||||
wrapper.appendChild(this.elementHint);
|
||||
wrapper.appendChild(dropDown);
|
||||
element.parentElement.appendChild(wrapper);
|
||||
|
||||
|
||||
this.repaint(element);
|
||||
},
|
||||
setText: function (text) {
|
||||
this.element.innerText = text;
|
||||
},
|
||||
getText: function () {
|
||||
return this.element.innerText;
|
||||
},
|
||||
hideDropDown: function () {
|
||||
this.wrapper.remove();
|
||||
if (this.elementHint) {
|
||||
this.elementHint.remove();
|
||||
this.elementHint = null;
|
||||
dropDownController.hide();
|
||||
this.element.style.zIndex = this.elementStyle.zIndex;
|
||||
this.element.style.position = this.elementStyle.position;
|
||||
this.element.style.backgroundColor = this.elementStyle.backgroundColor;
|
||||
this.element.style.borderColor = this.elementStyle.borderColor;
|
||||
}
|
||||
|
||||
},
|
||||
repaint: function (element) {
|
||||
var text = element.innerText;
|
||||
text = text.replace('\n', '');
|
||||
|
||||
var startFrom = this.startFrom;
|
||||
var options = this.options;
|
||||
var optionsLength = this.options.length;
|
||||
|
||||
// breaking text in leftSide and token.
|
||||
|
||||
var token = text.substring(this.startFrom);
|
||||
leftSide = text.substring(0, this.startFrom);
|
||||
|
||||
for (var i = 0; i < optionsLength; i++) {
|
||||
var opt = this.options[i];
|
||||
if ( (!config.caseSensitive && opt.toLowerCase().indexOf(token.toLowerCase()) === 0)
|
||||
|| (config.caseSensitive && opt.indexOf(token) === 0)) { // <-- how about upperCase vs. lowercase
|
||||
this.elementHint.innerText = leftSide + token + opt.substring(token.length);
|
||||
this.elementHint.realInnerText = leftSide + opt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// moving the dropDown and refreshing it.
|
||||
dropDown.style.left = calculateWidthForText(leftSide) + 'px';
|
||||
dropDownController.refresh(token, this.options);
|
||||
this.elementHint.style.width = calculateWidthForText(this.elementHint.innerText) + 10 + 'px'
|
||||
var wasDropDownHidden = (dropDown.style.visibility == 'hidden');
|
||||
if (!wasDropDownHidden)
|
||||
this.elementHint.style.width = calculateWidthForText(this.elementHint.innerText) + dropDown.clientWidth + 'px';
|
||||
}
|
||||
};
|
||||
|
||||
var dropDownController = createDropDownController(dropDown, rs);
|
||||
|
||||
var keyDownHandler = function (e) {
|
||||
//console.log("Keydown:" + e.keyCode);
|
||||
e = e || window.event;
|
||||
var keyCode = e.keyCode;
|
||||
|
||||
if (this.elementHint == null) return;
|
||||
|
||||
if (keyCode == 33) { return; } // page up (do nothing)
|
||||
if (keyCode == 34) { return; } // page down (do nothing);
|
||||
|
||||
if (keyCode == 27) { //escape
|
||||
rs.hideDropDown();
|
||||
rs.element.focus();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
var text = this.element.innerText;
|
||||
text = text.replace('\n', '');
|
||||
var startFrom = this.startFrom;
|
||||
|
||||
if (config.confirmKeys.indexOf(keyCode) >= 0) { // (autocomplete triggered)
|
||||
if (keyCode == 9) {
|
||||
if (this.elementHint.innerText.length == 0) {
|
||||
rs.onTab();
|
||||
}
|
||||
}
|
||||
if (this.elementHint.innerText.length > 0) { // if there is a hint
|
||||
if (this.element.innerText != this.elementHint.realInnerText) {
|
||||
this.element.innerText = this.elementHint.realInnerText;
|
||||
rs.hideDropDown();
|
||||
setEndOfContenteditable(this.element);
|
||||
if (keyCode == 9) {
|
||||
rs.element.focus();
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (keyCode == 13) { // enter (autocomplete triggered)
|
||||
if (this.elementHint.innerText.length == 0) { // if there is a hint
|
||||
rs.onEnter();
|
||||
} else {
|
||||
var wasDropDownHidden = (dropDown.style.visibility == 'hidden');
|
||||
dropDownController.hide();
|
||||
|
||||
if (wasDropDownHidden) {
|
||||
rs.hideDropDown();
|
||||
rs.element.focus();
|
||||
rs.onEnter();
|
||||
return;
|
||||
}
|
||||
|
||||
this.element.innerText = this.elementHint.realInnerText;
|
||||
rs.hideDropDown();
|
||||
setEndOfContenteditable(this.element);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (keyCode == 40) { // down
|
||||
var token = text.substring(this.startFrom);
|
||||
var m = dropDownController.move(+1);
|
||||
if (m == '') { rs.onArrowDown(); }
|
||||
this.elementHint.innerText = leftSide + token + m.substring(token.length);
|
||||
this.elementHint.realInnerText = leftSide + m;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (keyCode == 38) { // up
|
||||
var token = text.substring(this.startFrom);
|
||||
var m = dropDownController.move(-1);
|
||||
if (m == '') { rs.onArrowUp(); }
|
||||
this.elementHint.innerText = leftSide + token + m.substring(token.length);
|
||||
this.elementHint.realInnerText = leftSide + m;
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
}.bind(rs);
|
||||
|
||||
var onBlurHandler = function (e) {
|
||||
rs.hideDropDown();
|
||||
//console.log("Lost focus.");
|
||||
}.bind(rs);
|
||||
|
||||
dropDownController.onmouseselection = function (text, rs) {
|
||||
rs.element.innerText = rs.elementHint.innerText = leftSide + text;
|
||||
rs.hideDropDown();
|
||||
window.setTimeout(function () {
|
||||
rs.element.focus();
|
||||
setEndOfContenteditable(rs.element);
|
||||
}, 1);
|
||||
};
|
||||
|
||||
return rs;
|
||||
}
|
||||
|
||||
module.exports = completely;
|
||||
function completely (config) {
|
||||
config = config || {}
|
||||
config.filter = config.filter || 'start'
|
||||
config.trigger = config.trigger || 'keydown'
|
||||
config.confirmKeys = config.confirmKeys || [39, 35, 9] // right, end, tab
|
||||
config.caseSensitive = config.caseSensitive || false // autocomplete case sensitive
|
||||
|
||||
var fontSize = ''
|
||||
var fontFamily = ''
|
||||
|
||||
var wrapper = document.createElement('div')
|
||||
wrapper.style.position = 'relative'
|
||||
wrapper.style.outline = '0'
|
||||
wrapper.style.border = '0'
|
||||
wrapper.style.margin = '0'
|
||||
wrapper.style.padding = '0'
|
||||
|
||||
var dropDown = document.createElement('div')
|
||||
dropDown.className = 'autocomplete dropdown'
|
||||
dropDown.style.position = 'absolute'
|
||||
dropDown.style.visibility = 'hidden'
|
||||
|
||||
var spacer
|
||||
var leftSide // <-- it will contain the leftSide part of the textfield (the bit that was already autocompleted)
|
||||
var createDropDownController = function (elem, rs) {
|
||||
var rows = []
|
||||
var ix = 0
|
||||
var oldIndex = -1
|
||||
|
||||
var onMouseOver = function () { this.style.outline = '1px solid #ddd' }
|
||||
var onMouseOut = function () { this.style.outline = '0' }
|
||||
var onMouseDown = function () { p.hide(); p.onmouseselection(this.__hint, p.rs) }
|
||||
|
||||
var p = {
|
||||
rs: rs,
|
||||
hide: function () {
|
||||
elem.style.visibility = 'hidden'
|
||||
// rs.hideDropDown();
|
||||
},
|
||||
refresh: function (token, array) {
|
||||
elem.style.visibility = 'hidden'
|
||||
ix = 0
|
||||
elem.innerHTML = ''
|
||||
var vph = (window.innerHeight || document.documentElement.clientHeight)
|
||||
var rect = elem.parentNode.getBoundingClientRect()
|
||||
var distanceToTop = rect.top - 6 // heuristic give 6px
|
||||
var distanceToBottom = vph - rect.bottom - 6 // distance from the browser border.
|
||||
|
||||
rows = []
|
||||
var filterFn = typeof config.filter === 'function' ? config.filter : defaultFilterFunction[config.filter]
|
||||
|
||||
var filtered = !filterFn ? [] : array.filter(function (match) {
|
||||
return filterFn(config.caseSensitive ? token : token.toLowerCase(), config.caseSensitive ? match : match.toLowerCase(), config)
|
||||
})
|
||||
|
||||
rows = filtered.map(function (row) {
|
||||
var divRow = document.createElement('div')
|
||||
divRow.className = 'item'
|
||||
// divRow.style.color = config.color;
|
||||
divRow.onmouseover = onMouseOver
|
||||
divRow.onmouseout = onMouseOut
|
||||
divRow.onmousedown = onMouseDown
|
||||
divRow.__hint = row
|
||||
divRow.innerHTML = row.substring(0, token.length) + '<b>' + row.substring(token.length) + '</b>'
|
||||
elem.appendChild(divRow)
|
||||
return divRow
|
||||
})
|
||||
|
||||
if (rows.length === 0) {
|
||||
return // nothing to show.
|
||||
}
|
||||
if (rows.length === 1 && ((token.toLowerCase() === rows[0].__hint.toLowerCase() && !config.caseSensitive) ||
|
||||
(token === rows[0].__hint && config.caseSensitive))) {
|
||||
return // do not show the dropDown if it has only one element which matches what we have just displayed.
|
||||
}
|
||||
|
||||
if (rows.length < 2) return
|
||||
p.highlight(0)
|
||||
|
||||
if (distanceToTop > distanceToBottom * 3) { // Heuristic (only when the distance to the to top is 4 times more than distance to the bottom
|
||||
elem.style.maxHeight = distanceToTop + 'px' // we display the dropDown on the top of the input text
|
||||
elem.style.top = ''
|
||||
elem.style.bottom = '100%'
|
||||
} else {
|
||||
elem.style.top = '100%'
|
||||
elem.style.bottom = ''
|
||||
elem.style.maxHeight = distanceToBottom + 'px'
|
||||
}
|
||||
elem.style.visibility = 'visible'
|
||||
},
|
||||
highlight: function (index) {
|
||||
if (oldIndex !== -1 && rows[oldIndex]) {
|
||||
rows[oldIndex].className = 'item'
|
||||
}
|
||||
rows[index].className = 'item hover'
|
||||
oldIndex = index
|
||||
},
|
||||
move: function (step) { // moves the selection either up or down (unless it's not possible) step is either +1 or -1.
|
||||
if (elem.style.visibility === 'hidden') return '' // nothing to move if there is no dropDown. (this happens if the user hits escape and then down or up)
|
||||
if (ix + step === -1 || ix + step === rows.length) return rows[ix].__hint // NO CIRCULAR SCROLLING.
|
||||
ix += step
|
||||
p.highlight(ix)
|
||||
return rows[ix].__hint// txtShadow.value = uRows[uIndex].__hint ;
|
||||
},
|
||||
onmouseselection: function () { } // it will be overwritten.
|
||||
}
|
||||
return p
|
||||
}
|
||||
|
||||
function setEndOfContenteditable (contentEditableElement) {
|
||||
var range, selection
|
||||
if (document.createRange) {
|
||||
// Firefox, Chrome, Opera, Safari, IE 9+
|
||||
range = document.createRange()// Create a range (a range is a like the selection but invisible)
|
||||
range.selectNodeContents(contentEditableElement)// Select the entire contents of the element with the range
|
||||
range.collapse(false)// collapse the range to the end point. false means collapse to end rather than the start
|
||||
selection = window.getSelection()// get the selection object (allows you to change selection)
|
||||
selection.removeAllRanges()// remove any selections already made
|
||||
selection.addRange(range)// make the range you have just created the visible selection
|
||||
} else if (document.selection) {
|
||||
// IE 8 and lower
|
||||
range = document.body.createTextRange()// Create a range (a range is a like the selection but invisible)
|
||||
range.moveToElementText(contentEditableElement)// Select the entire contents of the element with the range
|
||||
range.collapse(false)// collapse the range to the end point. false means collapse to end rather than the start
|
||||
range.select()// Select the range (make it the visible selection
|
||||
}
|
||||
}
|
||||
|
||||
function calculateWidthForText (text) {
|
||||
if (spacer === undefined) { // on first call only.
|
||||
spacer = document.createElement('span')
|
||||
spacer.style.visibility = 'hidden'
|
||||
spacer.style.position = 'fixed'
|
||||
spacer.style.outline = '0'
|
||||
spacer.style.margin = '0'
|
||||
spacer.style.padding = '0'
|
||||
spacer.style.border = '0'
|
||||
spacer.style.left = '0'
|
||||
spacer.style.whiteSpace = 'pre'
|
||||
spacer.style.fontSize = fontSize
|
||||
spacer.style.fontFamily = fontFamily
|
||||
spacer.style.fontWeight = 'normal'
|
||||
document.body.appendChild(spacer)
|
||||
}
|
||||
|
||||
// Used to encode an HTML string into a plain text.
|
||||
// taken from http://stackoverflow.com/questions/1219860/javascript-jquery-html-encoding
|
||||
spacer.innerHTML = String(text).replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
return spacer.getBoundingClientRect().right
|
||||
}
|
||||
|
||||
var rs = {
|
||||
onArrowDown: function () { }, // defaults to no action.
|
||||
onArrowUp: function () { }, // defaults to no action.
|
||||
onEnter: function () { }, // defaults to no action.
|
||||
onTab: function () { }, // defaults to no action.
|
||||
startFrom: 0,
|
||||
options: [],
|
||||
element: null,
|
||||
elementHint: null,
|
||||
elementStyle: null,
|
||||
wrapper: wrapper, // Only to allow easy access to the HTML elements to the final user (possibly for minor customizations)
|
||||
show: function (element, startPos, options) {
|
||||
this.startFrom = startPos
|
||||
this.wrapper.remove()
|
||||
if (this.elementHint) {
|
||||
this.elementHint.remove()
|
||||
this.elementHint = null
|
||||
}
|
||||
|
||||
if (fontSize === '') {
|
||||
fontSize = window.getComputedStyle(element).getPropertyValue('font-size')
|
||||
}
|
||||
if (fontFamily === '') {
|
||||
fontFamily = window.getComputedStyle(element).getPropertyValue('font-family')
|
||||
}
|
||||
|
||||
dropDown.style.marginLeft = '0'
|
||||
dropDown.style.marginTop = element.getBoundingClientRect().height + 'px'
|
||||
this.options = options
|
||||
|
||||
if (this.element !== element) {
|
||||
this.element = element
|
||||
this.elementStyle = {
|
||||
zIndex: this.element.style.zIndex,
|
||||
position: this.element.style.position,
|
||||
backgroundColor: this.element.style.backgroundColor,
|
||||
borderColor: this.element.style.borderColor
|
||||
}
|
||||
}
|
||||
|
||||
this.element.style.zIndex = 3
|
||||
this.element.style.position = 'relative'
|
||||
this.element.style.backgroundColor = 'transparent'
|
||||
this.element.style.borderColor = 'transparent'
|
||||
|
||||
this.elementHint = element.cloneNode()
|
||||
this.elementHint.className = 'autocomplete hint'
|
||||
this.elementHint.style.zIndex = 2
|
||||
this.elementHint.style.position = 'absolute'
|
||||
this.elementHint.onfocus = function () { this.element.focus() }.bind(this)
|
||||
|
||||
if (this.element.addEventListener) {
|
||||
this.element.removeEventListener('keydown', keyDownHandler)
|
||||
this.element.addEventListener('keydown', keyDownHandler, false)
|
||||
this.element.removeEventListener('blur', onBlurHandler)
|
||||
this.element.addEventListener('blur', onBlurHandler, false)
|
||||
}
|
||||
|
||||
wrapper.appendChild(this.elementHint)
|
||||
wrapper.appendChild(dropDown)
|
||||
element.parentElement.appendChild(wrapper)
|
||||
|
||||
this.repaint(element)
|
||||
},
|
||||
setText: function (text) {
|
||||
this.element.innerText = text
|
||||
},
|
||||
getText: function () {
|
||||
return this.element.innerText
|
||||
},
|
||||
hideDropDown: function () {
|
||||
this.wrapper.remove()
|
||||
if (this.elementHint) {
|
||||
this.elementHint.remove()
|
||||
this.elementHint = null
|
||||
dropDownController.hide()
|
||||
this.element.style.zIndex = this.elementStyle.zIndex
|
||||
this.element.style.position = this.elementStyle.position
|
||||
this.element.style.backgroundColor = this.elementStyle.backgroundColor
|
||||
this.element.style.borderColor = this.elementStyle.borderColor
|
||||
}
|
||||
},
|
||||
repaint: function (element) {
|
||||
var text = element.innerText
|
||||
text = text.replace('\n', '')
|
||||
|
||||
var optionsLength = this.options.length
|
||||
|
||||
// breaking text in leftSide and token.
|
||||
|
||||
var token = text.substring(this.startFrom)
|
||||
leftSide = text.substring(0, this.startFrom)
|
||||
|
||||
for (var i = 0; i < optionsLength; i++) {
|
||||
var opt = this.options[i]
|
||||
if ((!config.caseSensitive && opt.toLowerCase().indexOf(token.toLowerCase()) === 0) ||
|
||||
(config.caseSensitive && opt.indexOf(token) === 0)) { // <-- how about upperCase vs. lowercase
|
||||
this.elementHint.innerText = leftSide + token + opt.substring(token.length)
|
||||
this.elementHint.realInnerText = leftSide + opt
|
||||
break
|
||||
}
|
||||
}
|
||||
// moving the dropDown and refreshing it.
|
||||
dropDown.style.left = calculateWidthForText(leftSide) + 'px'
|
||||
dropDownController.refresh(token, this.options)
|
||||
this.elementHint.style.width = calculateWidthForText(this.elementHint.innerText) + 10 + 'px'
|
||||
var wasDropDownHidden = (dropDown.style.visibility === 'hidden')
|
||||
if (!wasDropDownHidden) { this.elementHint.style.width = calculateWidthForText(this.elementHint.innerText) + dropDown.clientWidth + 'px' }
|
||||
}
|
||||
}
|
||||
|
||||
var dropDownController = createDropDownController(dropDown, rs)
|
||||
|
||||
var keyDownHandler = function (e) {
|
||||
// console.log("Keydown:" + e.keyCode);
|
||||
e = e || window.event
|
||||
var keyCode = e.keyCode
|
||||
|
||||
if (this.elementHint == null) return
|
||||
|
||||
if (keyCode === 33) { return } // page up (do nothing)
|
||||
if (keyCode === 34) { return } // page down (do nothing);
|
||||
|
||||
if (keyCode === 27) { // escape
|
||||
rs.hideDropDown()
|
||||
rs.element.focus()
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
return
|
||||
}
|
||||
|
||||
var text = this.element.innerText
|
||||
text = text.replace('\n', '')
|
||||
|
||||
if (config.confirmKeys.indexOf(keyCode) >= 0) { // (autocomplete triggered)
|
||||
if (keyCode === 9) {
|
||||
if (this.elementHint.innerText.length === 0) {
|
||||
rs.onTab()
|
||||
}
|
||||
}
|
||||
if (this.elementHint.innerText.length > 0) { // if there is a hint
|
||||
if (this.element.innerText !== this.elementHint.realInnerText) {
|
||||
this.element.innerText = this.elementHint.realInnerText
|
||||
rs.hideDropDown()
|
||||
setEndOfContenteditable(this.element)
|
||||
if (keyCode === 9) {
|
||||
rs.element.focus()
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
}
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (keyCode === 13) { // enter (autocomplete triggered)
|
||||
if (this.elementHint.innerText.length === 0) { // if there is a hint
|
||||
rs.onEnter()
|
||||
} else {
|
||||
var wasDropDownHidden = (dropDown.style.visibility === 'hidden')
|
||||
dropDownController.hide()
|
||||
|
||||
if (wasDropDownHidden) {
|
||||
rs.hideDropDown()
|
||||
rs.element.focus()
|
||||
rs.onEnter()
|
||||
return
|
||||
}
|
||||
|
||||
this.element.innerText = this.elementHint.realInnerText
|
||||
rs.hideDropDown()
|
||||
setEndOfContenteditable(this.element)
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
if (keyCode === 40) { // down
|
||||
const token = text.substring(this.startFrom)
|
||||
const m = dropDownController.move(+1)
|
||||
if (m === '') { rs.onArrowDown() }
|
||||
this.elementHint.innerText = leftSide + token + m.substring(token.length)
|
||||
this.elementHint.realInnerText = leftSide + m
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
return
|
||||
}
|
||||
|
||||
if (keyCode === 38) { // up
|
||||
const token = text.substring(this.startFrom)
|
||||
const m = dropDownController.move(-1)
|
||||
if (m === '') { rs.onArrowUp() }
|
||||
this.elementHint.innerText = leftSide + token + m.substring(token.length)
|
||||
this.elementHint.realInnerText = leftSide + m
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
}
|
||||
}.bind(rs)
|
||||
|
||||
var onBlurHandler = function (e) {
|
||||
rs.hideDropDown()
|
||||
// console.log("Lost focus.");
|
||||
}
|
||||
|
||||
dropDownController.onmouseselection = function (text, rs) {
|
||||
rs.element.innerText = rs.elementHint.innerText = leftSide + text
|
||||
rs.hideDropDown()
|
||||
window.setTimeout(function () {
|
||||
rs.element.focus()
|
||||
setEndOfContenteditable(rs.element)
|
||||
}, 1)
|
||||
}
|
||||
|
||||
return rs
|
||||
}
|
||||
|
||||
module.exports = completely
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
|
||||
exports.DEFAULT_MODAL_ANCHOR = document.body;
|
||||
exports.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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -26,4 +26,4 @@
|
|||
* @author Jos de Jong, <wjosdejong@gmail.com>
|
||||
* @version @@version
|
||||
* @date @@date
|
||||
*/
|
||||
*/
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
'use strict';
|
||||
'use strict'
|
||||
|
||||
require('./polyfills');
|
||||
/* eslint-disable no-template-curly-in-string */
|
||||
|
||||
var _locales = ['en', 'pt-BR', 'zh-CN', 'tr'];
|
||||
require('./polyfills')
|
||||
|
||||
var _locales = ['en', 'pt-BR', 'zh-CN', 'tr']
|
||||
var _defs = {
|
||||
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
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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, '')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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'
|
||||
}
|
||||
];
|
||||
]
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
1533
src/js/treemode.js
1533
src/js/treemode.js
File diff suppressed because it is too large
Load Diff
1115
src/js/util.js
1115
src/js/util.js
File diff suppressed because it is too large
Load Diff
|
@ -1,6 +1,6 @@
|
|||
var isPromise = require('./util').isPromise;
|
||||
var 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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -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)
|
||||
});
|
||||
|
||||
});
|
||||
})
|
||||
})
|
||||
|
|
|
@ -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 })
|
||||
}
|
||||
|
|
|
@ -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
|
||||
});
|
||||
})
|
||||
|
|
Loading…
Reference in New Issue