@pardnchiu/nanojson
Version:
A lightweight JSON editor built with pure JavaScript and native APIs. It features visual editing, dynamic type switching, and file import/export capabilities. Suitable for website embedding and JSON data editing.
1 lines • 14.2 kB
JavaScript
!function(){const e=/\.([\w_-]+)?/gi,t=/\#([\w_-]+)?/i,i=/^\w+(?=[\#\.]*)/i,n="pd-json-editor",s="pd-json-editor-nested-child",o="button:not(.collapsed), textarea, input, select",r="appendChild",l="array",a="body",c="boolean",h="display",d="temp",f="push",u="button",p="children",y="collapsed",m="setAttribute",v="dataset",b="true",_="disabled",g="type",k="editor",w="export",C="import",A="innerHTML",j="isArray",H="label",z="section",S="length",M="toLowerCase",N="match",O="nextElementSibling",V="querySelectorAll",x="number",D="object",L="option",T="parent",R="placeholder",E="render",U="replace",$="reset",B="selected",F="string",J="target",I="textarea",P="title",q="update",K="value",Y="readonly",G="lifecycle",Q="click",W="download",X={[D]:1,[l]:1};let Z="beforeRender",ee="beforeUpdate",te="beforeDestroy",ie="rendered",ne="updated",se="destroyed";let oe={[x]:"M5.5 15v-4.5H4V9h3v6H5.5zM9 15v-2.5c0-.283.096-.52.287-.713A.967.967 0 0110 11.5h2v-1H9V9h3.5c.283 0 .52.096.713.287.191.192.287.43.287.713v1.5c0 .283-.096.52-.287.713a.968.968 0 01-.713.287h-2v1h3V15H9zm6 0v-1.5h3v-1h-2v-1h2v-1h-3V9h3.5c.283 0 .52.096.712.287.192.192.288.43.288.713v4c0 .283-.096.52-.288.713A.968.968 0 0118.5 15H15z",[F]:"M17 15a.968.968 0 01-.712-.287A.968.968 0 0116 14v-4c0-.283.096-.52.288-.713A.968.968 0 0117 9h3c.283 0 .52.096.712.287.192.192.288.43.288.713v1h-1.5v-.5h-2v3h2V13H21v1c0 .283-.096.52-.288.713A.968.968 0 0120 15h-3zm-7.5 0V9h4c.283 0 .52.096.713.287.191.192.287.43.287.713v1c0 .283-.096.52-.287.713A.968.968 0 0113.5 12c.283 0 .52.096.713.287.191.192.287.43.287.713v1c0 .283-.096.52-.287.713A.968.968 0 0113.5 15h-4zm1.5-3.75h2v-.75h-2v.75zm0 2.25h2v-.75h-2v.75zM3 15v-5c0-.283.096-.52.288-.713A.968.968 0 014 9h3c.283 0 .52.096.713.287.191.192.287.43.287.713v5H6.5v-1.5h-2V15H3zm1.5-3h2v-1.5h-2V12z",[D]:"M13.5 18v-1.5h2.25c.213 0 .39-.072.534-.216a.726.726 0 00.216-.534v-1.5c0-.475.137-.906.413-1.294A2.233 2.233 0 0118 12.131v-.262a2.233 2.233 0 01-1.087-.825A2.184 2.184 0 0116.5 9.75v-1.5a.726.726 0 00-.216-.534.726.726 0 00-.534-.216H13.5V6h2.25a2.17 2.17 0 011.594.656c.437.438.656.969.656 1.594v1.5c0 .213.072.39.216.534a.726.726 0 00.534.216h.75v3h-.75a.726.726 0 00-.534.216.726.726 0 00-.216.534v1.5a2.17 2.17 0 01-.656 1.594A2.17 2.17 0 0115.75 18H13.5zm-5.25 0a2.17 2.17 0 01-1.594-.656A2.17 2.17 0 016 15.75v-1.5a.726.726 0 00-.216-.534.726.726 0 00-.534-.216H4.5v-3h.75c.213 0 .39-.072.534-.216A.726.726 0 006 9.75v-1.5c0-.625.219-1.156.656-1.594A2.17 2.17 0 018.25 6h2.25v1.5H8.25a.726.726 0 00-.534.216.726.726 0 00-.216.534v1.5c0 .475-.138.906-.412 1.294A2.233 2.233 0 016 11.869v.262c.45.163.813.438 1.088.825.274.388.412.819.412 1.294v1.5c0 .213.072.39.216.534a.726.726 0 00.534.216h2.25V18H8.25z",[l]:"M14.625 19v-1.75h2.625V6.75h-2.625V5H19v14h-4.375zM5 19V5h4.375v1.75H6.75v10.5h2.625V19H5z",[c]:"M7.91 16.818c-1.365 0-2.524-.477-3.478-1.432C3.477 14.432 3 13.273 3 11.91c0-1.364.477-2.523 1.432-3.477C5.386 7.477 6.545 7 7.909 7h8.182c1.363 0 2.523.477 3.477 1.432.955.954 1.432 2.114 1.432 3.477 0 1.364-.477 2.523-1.432 3.477-.954.955-2.114 1.432-3.477 1.432H7.909zm0-1.636h8.18c.9 0 1.671-.32 2.312-.962.641-.64.962-1.41.962-2.31 0-.9-.32-1.671-.962-2.312a3.151 3.151 0 00-2.311-.962H7.909c-.9 0-1.67.32-2.311.962a3.151 3.151 0 00-.962 2.311c0 .9.32 1.67.962 2.311.64.641 1.411.962 2.311.962zm8.18-.818c.683 0 1.262-.239 1.74-.716a2.367 2.367 0 00.716-1.739c0-.682-.24-1.261-.716-1.739a2.367 2.367 0 00-1.74-.715c-.68 0-1.26.238-1.738.716a2.367 2.367 0 00-.716 1.738c0 .682.239 1.261.716 1.739a2.367 2.367 0 001.739.716z",right:"M10 18V6l6 6-6 6z",folder:"M4 20c-.55 0-1.02-.196-1.413-.587A1.926 1.926 0 012 18V6c0-.55.196-1.02.587-1.412A1.926 1.926 0 014 4h6l2 2h8c.55 0 1.02.196 1.413.588.391.391.587.862.587 1.412H11.175l-2-2H4v12l2.4-8h17.1l-2.575 8.575a1.95 1.95 0 01-.738 1.038A1.985 1.985 0 0119 20H4zm2.1-2H19l1.8-6H7.9l-1.8 6z",add:"M11 13H5v-2h6V5h2v6h6v2h-6v6h-2v-6z",[W]:"M12 16l-5-5 1.4-1.45 2.6 2.6V4h2v8.15l2.6-2.6L17 11l-5 5zm-6 4c-.55 0-1.02-.196-1.412-.587A1.926 1.926 0 014 18v-3h2v3h12v-3h2v3c0 .55-.196 1.02-.587 1.413A1.926 1.926 0 0118 20H6z",clear:"M17.25 18H22v2h-6.75l2-2zm-12.5 2l-2.125-2.125c-.383-.383-.58-.858-.587-1.425-.009-.567.179-1.05.562-1.45l11-11.4c.383-.4.854-.6 1.412-.6.559 0 1.03.192 1.413.575L21.4 8.55c.383.383.575.858.575 1.425 0 .567-.192 1.042-.575 1.425L13 20H4.75zm7.4-2L20 9.95 15.05 5 4 16.4 5.6 18h6.55z"};for(let e of Object.keys(oe))oe[e]=`<svg width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="${oe[e]}" fill="#5F6368"/></svg>`;function re(e,t,i){if(X[e[g][M]()]&&!e[y])return(z+"."+s)._([...e[p].map((e,i)=>t(e,i)),(u+".child-add")._(oe.add)._({click:i})])}function le(e){const t=X[e[g][M]()];return(u+"."+y)._({[v]:{collapsable:t?1:0,[y]:e[y]?1:0}},t?oe.right:null)._({[Q]:t?t=>e.setCollapsed():e=>{}})}function ae(e){return new Promise(async(t,i)=>{if(null!=e)if(e instanceof File){const i=new FileReader;i.onload=i=>{try{const e=JSON.parse(i[J].result);t(e)}catch(i){console.error(`Failed to parse JSON from file ${e.name}: ${i}`),t()}},i.readAsText(e)}else if(typeof e===D)t(e);else if(typeof e===F)try{const i=await fetch(e);if(i.ok){const e=await i.text(),n=JSON.parse(e);t(n)}}catch(i){console.error(`Failed to fetch data from ${e}: ${i}`),t()}else console.error(`Invalid data [_type]: ${e} (${typeof e})`),t();else t()})}function ce(e){return Array[j](e)?l:typeof e===D?D:typeof e===c?c:typeof e===x?x:F}function he(e,t,i,n,s){function o(e){return e[U](/\n/g,"")}function r(t){const i=t[J];i[K]=i[O][A]=o(i[K]),e.key=o(i[K]).trim()}return i?"span.array-index"._(t):H._([(I+"#key-"+e.id)._({[R]:"KEY",[_]:n?"":null},e.key[U](/\n/g,""))._({input:e=>{r(e),s[q](()=>{})},change:e=>{r(e)}}),"pre"._(o(e.key))])}document.addEventListener("DOMContentLoaded",e=>{console.log("NanoJSON: https://github.com/pardnchiu/NanoJSON\nLicense: MIT\nCreator: Pardn Chiu")}),String.prototype._=function(n,s){const o=this.toString(),l=((o[N](i)||[])[0]||"").trim(),a=((o[N](t)||[])[1]||"").trim(),c=(e.test(o)?o[N](e):[]).map(e=>e[U](/^\./,""));if(l[S]<1)return;let f,u,p=o===d,y=p?document.createDocumentFragment():document.createElement(l);a[S]>0&&(y.id=a);for(const e of c)y.classList.add(e);if(null==n&&null!=s&&([n,s]=[s,null]),null!=n&&null!=s)[f,u]=[n,s];else if(null==s)typeof n===F||typeof n===x||Array[j](n)?u=n:f=n;else if(null==n)return y;return(()=>{if(typeof f===D&&null!=f)for(const e in f){if(!f.hasOwnProperty(e))continue;const t=f[e];if({[K]:1,innerText:1,[A]:1,textContent:1,contentEditable:1,[B]:1,checked:1}[e])y[e]=t;else if({[h]:1,color:1,backgroundColor:1,background:1,width:1,height:1,float:1}[e])y.style[e]=t;else if(e===v&&typeof t===D)for(const e of Object.keys(t))y[v][e]=t[e];else null!=t&&y[m](e,t)}})(),(()=>{if(null==u)return;if(Array[j](u)){for(let e of u)typeof e===F||typeof e===x?p?y[r](document.createTextNode(e)):y[A]+=e:e instanceof Element&&y[r](e);return}if(typeof u===D)return;const e=u;"img"===l||"source"===l?y.src=e:l===I||"input"===l?y[K]=e:p?y[r](document.createTextNode(u)):y[A]=e})(),y},HTMLElement.prototype._=function(e={}){if(typeof e!==D)return;let t=this;for(const i of Object.keys(e))t["on"+i]=t=>e[i](t);return t};new Map;function de(e,t){if(e[g][M]()===x){const s=/^-?\d+(\.\d+)?$/,o=parseFloat(e[K]);function i(e){return isNaN(e)?"":String(e)[U](/\s/g,"")[U](s,"")}return H._([(I+"#value-"+e.id)._({[R]:"NUM"},i(o))._({input:n=>{const s=n[J];s[K]=s[O][A]=i(s[K]),e[K]=i(s[K]),t[q](()=>{})},change:t=>{const n=t[J];n[K]=n[O][A]=i(n[K]),e[K]=i(n[K])}}),"pre"._(i(o))])}if(e[g][M]()===c)return e[K].trim()[S]<1&&(e[K]=b),("select#value-"+e.id)._([L._({[K]:b,[B]:e[K]===b},b),L._({[K]:"false",[B]:"false"===e[K]},"false")])._({change:i=>{e[K]=i[J][K],t[q](()=>{})}});{const r=X[e[g][M]()];function n(e){return e[U](/\n/g,"<br>")}return H._({[h]:r?"none":"block"},[(I+"#value-"+e.id)._({[R]:"VAL"},e[K])._({input:i=>{const s=i[J];s[O][A]=n(s[K]),e[K]=s[K],t[q](()=>{})},change:t=>{const i=t[J];i[O][A]=n(i[K]),e[K]=i[K]}}),"pre"._(n(e[K]))])}}window.JSONEditor=class{children=[];body;editor;button=[];#e;#t=!1;#i=D;get type(){return this.#i}constructor(e={}){if(typeof e!=D)return void console.error("Failed to load config.");let t=e.css;(null==t||typeof t!==F||t.length<1)&&(t="https://cdn.jsdelivr.net/npm/@pardnchiu/nanojson@1.1.5/dist/NanoJSON.css"),function(e){for(let t of["link"._({rel:"preload",href:e,as:"style"}),"link"._({rel:"stylesheet",href:e})])document.head[r](t)}(t),this.#n(e)}async#n(e={}){this[k]="section"._();const t=e.when??{},i=e[P]??"",s=e.description??"",l=Boolean(null==e.fill?1:e.fill)?1:0,c=e[Y]??!1;let f=null!=e[u]&&typeof e[u]===D?e[u]:{[C]:1,[w]:1,[$]:1};f[$]=f[$]??1,f[C]=f[C]??1,f[w]=f[w]??1,this.#e=new ue({beforeRender:t[Z],rendered:t[ie],beforeUpdate:t[ee],updated:t[ne],beforeDestroy:t[te],destroyed:t[se]});let y=await ae(e.file??e.json??e.path)??{};this[p]=this.#s(y);let A=d._([Math.max(i[S],s[S])>0?"header"._([i[S]>0?"strong"._(i):null,s[S]>0?"p"._(s):null]):null,this[k],"footer"._([u._({[P]:"Add"},oe.add)._({[Q]:e=>this.insert()}),Boolean(f[C])?u._({[P]:"Open"},oe.folder)._({[Q]:e=>e[J][O][Q]()}):null,Boolean(f[C])?"input"._({[g]:"file",accept:".json",[h]:"none"})._({change:e=>this[C](e[J].files[0])}):null,Boolean(f[w])?u._({[P]:"Download"},oe[W])._({[Q]:e=>{confirm(e[J][P]+"?")&&this[w]()}}):null,Boolean(f[$])?u._({[P]:"Reset"},oe.clear)._({[Q]:e=>{confirm(e[J][P]+"?")&&this[C]({})}}):null])]);null==e.id?(this[a]=(z+"."+n)._(),this[a][r](A)):(this[a]=document.getElementById(e.id),this[a].classList.add(n),this[a].replaceChildren(...A[p])),this[a][v].fill=l,this[p][S]<1&&this.insert(),this.#e[E](async()=>{if(this[E](),c){this[a][v][Y]=1;for(let e of[...this[a][V](o)])e[m](_,b)}this.#t=!0})}enable(){this[a][v][Y]=0;for(let e of[...this[a][V](o)])e.removeAttribute(_)}disable(){this[a][v][Y]=1;for(let e of[...this[a][V](o)])e[m](_,b)}#o(e){return e.render()}#s(e,t=null){const i=[];if(Array[j](e))for(let n of e){const e=ce(n),s=new fe({[g]:e,[T]:t??this,[k]:this,[G]:this.#e});e===D&&null!=n||e===l?s[p]=this.#s(n,s):s[K]=String(n),i[f](s)}else for(const[n,s]of Object.entries(e)){const e=ce(s),o=new fe({key:n,[g]:e,[T]:t??this,[k]:this,[G]:this.#e});e===D&&null!=s||e===l?o[p]=this.#s(s,o):null===s?(o[g]=_null,o[K]=null):o[K]=String(s),i[f](o)}return i}render(e=!1){let t=d._(this[p].map(e=>this.#o(e)));this[k].replaceChildren(...t[p]),this.#t&&e&&this.#e[q](()=>{})}insert(){this[p][f](new fe({[T]:this,[k]:this,[G]:this.#e})),this[E]()}get json(){const e={};for(let t of this[p])t.key&&(e[t.key||0]=t.json);return JSON.stringify(e,null,4)}async import(e){let t=await ae(e)??{};this[p]=this.#s(t),this[E](!0)}reset(){this[C]({})}export(){const e={};for(let t of this[p])(t.key||1===this[p][S])&&(e[t.key||0]=t.json);const t=new Blob([JSON.stringify(e,null,4)],{[g]:"application/json"}),i=URL.createObjectURL(t),n="a"._({href:i,[W]:`NanoJSON-${Date.now()}.json`});document[a][r](n),n[Q](),document[a].removeChild(n),URL.revokeObjectURL(i)}};class fe{key="";type="string";value="";parent;children=[];collapsed=!1;#r;#l;#e;constructor(e={}){typeof e==D?(this.id=function(e=64){let t="";for(let i=0;i<e;i++)t+="abcdefghijklmnopqrstuvwxyz0123456789".charAt(Math.floor(36*Math.random()));return t}(),this.key=e.key??this.key,this[g]=e[g]??this[g],this[K]=e[K]??this[K],this[T]=e[T]??this[T],this[p]=e[p]??this[p],this[y]=e[y]??this[y],this.#l=e[k],this.#e=e[G]):console.error("Failed to load config form editor node.")}render(){return this.#o()}addChild(){this.#a()}updateChild(){this.#o(),this.#c()}setCollapsed(){this[y]=!this[y],this.#o()}get json(){return this.#h()}#c(){this.#e[q](e=>{})}#o(){let e="section.pd-json-editor-child"._(["section.pair-wrapper"._([("section#"+this.id+".input-group")._([le(this),he(this,this[T][p].indexOf(this),this[T][g]===l,"1"===this.#l[a][v][Y],this.#e),"span"._(":"),(t=this,i="1"===this.#l[a][v][Y],H._([t[g][M]()===x?oe[x]:t[g][M]()===c?oe[c]:t[g][M]()===l?oe[l]:t[g][M]()===D?oe[D]:oe[F],"select"._({[_]:i?"":null},[...[F,x,c,l,D].map(e=>L._({[K]:e,[B]:e===t[g]},e))])._({change:e=>{if(t[g]=e[J][K],X[e[J][K][M]()])t[K]="",0===t[p][S]&&t.addChild();else if(e[J][K][M]()===x){const e=parseFloat(t[K]);t[K]=isNaN(e)?"":e}else t[K]="",t[p]=[];t.updateChild(),document.getElementById("value-"+t.id).focus()}})])),de(this,this.#e),u._(oe.add)._({[Q]:e=>{confirm("Remove?")&&this.#d()}})]),re(this,(e,t)=>{let i=e.#o();return i[v].last=t===this[p].length-1?1:0,i},()=>{this.#a()})])]);var t,i;return this.#r&&this.#r.parentElement.replaceChild(e,this.#r),this.#r=e,this.#r}#a(){const e=new fe({[T]:this,[k]:this.#l,[G]:this.#e});this[p][f](e);const t=this.#r.querySelector(z+"."+s);if(null!=t){const i=t[p][t[p].length-1];for(let e of i.parentElement[p])e[v].last=0;const n=e.#o();n[v].last=1,t.insertBefore(n,i)}this.#c()}#d(){if(!this[T])return;const e=this[T][p].indexOf(this);if(-1===e)return;const t=this.#r.previousElementSibling;"1"===this.#r[v].last&&null!=t&&(t[v].last=1),this[T][p].splice(e,1),this.#r.remove(),this.#c()}#h(){if(!this[T])return;if(this[g]===l)return this[p].map(e=>e.#h());if(this[g]===D){const e={};for(let t of this[p])(t.key||this[T][g]===l)&&(e[t.key||Object.keys(e)[S]]=t.#h());return e}let e=this[K];return this[g]===c?e=e[M]()===b:this[g]===x&&(e=Number(e)),e}}class ue{#f;#u;#p;#y;#m;#v;#b;#_;#g;constructor(e={}){this.#f=e[Z]||void 0,this.#u=e[ie]||void 0,this.#p=e[ee]||void 0,this.#y=e[ne]||void 0,this.#m=e[te]||void 0,this.#v=e[se]||void 0}async#k(e){return new Promise((t,i)=>{t(!1!==e())})}#w(e){e(!1)}async render(e){this.#b=Date.now(),null!=this.#f&&!1===await this.#k(this.#f)||(await e(),this.#_=Date.now()-this.#b,console.log(`Rendered in ${this.#_}ms.`),null!=this.#u&&this.#w(this.#u))}async update(e){clearTimeout(this.#g),this.#g=setTimeout(async()=>{this.#b=Date.now(),null!=this.#p&&!1===await this.#k(this.#p)||(await e(),this.#_=Date.now()-this.#b,console.log(`Updated in ${this.#_}ms.`),null!=this.#y&&this.#w(this.#y))},300)}async destroy(e){this.#b=Date.now(),null!=this.#m&&!1===await this.#k(this.#m)||(await e(),this.#_=Date.now()-this.#b,console.log(`Destroyed in ${this.#_}ms.`),null!=this.#v&&this.#w(this.#v))}}}("undefined"==typeof window?window={}:window);