From 0d052a20c301de460d6750f777ccdfc76f2f3642 Mon Sep 17 00:00:00 2001 From: ZDDC Date: Mon, 8 Jun 2026 15:19:43 -0500 Subject: [PATCH] chore(embedded): cut v0.0.27-beta --- zddc/internal/apps/embedded/archive.html | 2 +- zddc/internal/apps/embedded/browse.html | 1889 ++++++++++++------ zddc/internal/apps/embedded/classifier.html | 2 +- zddc/internal/apps/embedded/index.html | 11 +- zddc/internal/apps/embedded/transmittal.html | 2 +- zddc/internal/apps/embedded/versions.txt | 14 +- zddc/internal/handler/tables.html | 2 +- 7 files changed, 1278 insertions(+), 644 deletions(-) diff --git a/zddc/internal/apps/embedded/archive.html b/zddc/internal/apps/embedded/archive.html index f202881..4afc32e 100644 --- a/zddc/internal/apps/embedded/archive.html +++ b/zddc/internal/apps/embedded/archive.html @@ -2665,7 +2665,7 @@ td[data-field="trackingNumber"] {
ZDDC Archive - v0.0.27-beta · 2026-06-08 13:10:35 · 48b8199 + v0.0.27-beta · 2026-06-08 20:19:35 · ec9c9c7
diff --git a/zddc/internal/apps/embedded/browse.html b/zddc/internal/apps/embedded/browse.html index 3c5cce3..317cbe0 100644 --- a/zddc/internal/apps/embedded/browse.html +++ b/zddc/internal/apps/embedded/browse.html @@ -977,6 +977,7 @@ body.help-open .app-header { background-color: rgba(255, 211, 0, 0.1); } +.CodeMirror-hints{position:absolute;z-index:10;overflow:hidden;list-style:none;margin:0;padding:2px;-webkit-box-shadow:2px 3px 5px rgba(0,0,0,.2);-moz-box-shadow:2px 3px 5px rgba(0,0,0,.2);box-shadow:2px 3px 5px rgba(0,0,0,.2);border-radius:3px;border:1px solid silver;background:#fff;font-size:90%;font-family:monospace;max-height:20em;overflow-y:auto;box-sizing:border-box}.CodeMirror-hint{margin:0;padding:0 4px;border-radius:2px;white-space:pre;color:#000;cursor:pointer}li.CodeMirror-hint-active{background:#08f;color:#fff} /* shared/context-menu.css — generic styles for window.zddc.menu. Mirrors the look-and-feel of native context menus: tight rows, five-column grid (check | icon | label | accel | arrow), subtle @@ -1575,6 +1576,7 @@ body { content's natural size (which clips the YAML editor's bottom when there are many lines, even with the editor's own scroll) */ + min-width: 0; overflow: auto; display: flex; flex-direction: column; @@ -1582,10 +1584,16 @@ body { } /* The body's children fill the available space. Plugins inject - different content here — img, iframe, pre, custom markdown editor. */ + different content here — img, iframe, pre, custom markdown editor. + min-width:0 is load-bearing: a flex item defaults to min-width:auto + (its min-content width), so the markdown editor's wide internal + min-content would push the whole pane past the viewport's right edge + instead of shrinking. With min-width:0 the editor shrinks and its own + (and the grid's minmax(0)) scrolling takes over. */ .preview-pane__body > * { flex: 1; min-height: 0; + min-width: 0; } .preview-empty { @@ -2222,39 +2230,55 @@ body { /* ── Front matter editor ────────────────────────────────────────────────── */ .md-fm__body { - /* Body cell owns the textarea; sized by the sidebar's grid row. */ + /* Body cell owns the CodeMirror editor; sized by the sidebar's grid row. */ padding: 0; display: block; overflow: hidden; } -.md-fm__textarea { - width: 100%; +/* Recognised-keys caption under the header (tooltip carries the full list). */ +.md-fm__hint { + padding: 2px 0.6rem 4px; + font-size: 0.72rem; + color: var(--text-muted); + cursor: help; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +/* CodeMirror YAML front-matter editor — fills the body cell + scrolls + internally, matching the .zddc previewer's editor styling. */ +.md-fm__editor, +.md-fm__editor .CodeMirror { height: 100%; - box-sizing: border-box; - margin: 0; - padding: 0.4rem 0.6rem; - border: 0; - background: transparent; - color: var(--text); +} +.md-fm__editor .CodeMirror { font-family: var(--font-mono, ui-monospace, SFMono-Regular, Consolas, monospace); font-size: 0.8rem; line-height: 1.45; - resize: none; - outline: none; - white-space: pre; - overflow: auto; - tab-size: 2; + background: transparent; + color: var(--text); } -.md-fm__textarea::placeholder { - color: var(--text-muted); - font-style: italic; +.md-fm__editor .CodeMirror-gutters { + background: var(--bg-secondary); + border-right: 1px solid var(--border); } -.md-fm__textarea:focus { - background: var(--surface-2, rgba(0, 0, 0, 0.025)); +/* Schema-completion dropdown (show-hint add-on) — theme it to the app + palette so it reads in dark mode; show-hint.css ships light-only. */ +.CodeMirror-hints { + z-index: 9600; + font-family: var(--font-mono, ui-monospace, SFMono-Regular, Consolas, monospace); + font-size: 0.78rem; + background: var(--bg-elevated, var(--bg, #fff)); + border: 1px solid var(--border, #ccc); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.28); } -.md-fm__textarea[readonly] { - color: var(--text-muted); - cursor: not-allowed; +.CodeMirror-hint { + color: var(--text, #222); + padding: 2px 8px; +} +li.CodeMirror-hint-active { + background: var(--primary, #2868c8); + color: #fff; } /* Older .md-fm-section / .fm-list / .md-toc-resizer rules were replaced @@ -2413,6 +2437,24 @@ body { outline: none; } +/* Hover-doc tooltip (yaml-complete.js) — appended to document.body, so it's + styled globally. Carries a key's schema description on hover. */ +.cm-doc-tip { + position: fixed; + z-index: 9700; + max-width: 360px; + padding: 6px 9px; + font-size: 0.75rem; + line-height: 1.4; + background: var(--bg-elevated, var(--bg, #fff)); + color: var(--text, #222); + border: 1px solid var(--border, #ccc); + border-radius: 4px; + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.28); + pointer-events: none; + white-space: normal; +} + /* CodeMirror has to fill the grid cell. The vendored CSS sets `height: 300px` by default — we override to 100% so it grows with the preview pane. */ @@ -2624,6 +2666,97 @@ body { margin-top: 0.85rem; } +/* manage-access.js — guided "who can do what here" dialog. */ +.ma-overlay { + position: fixed; + inset: 0; + z-index: 9800; + display: flex; + align-items: center; + justify-content: center; + background: rgba(0, 0, 0, 0.4); +} +.ma-box { + background: var(--bg-elevated, var(--bg, #fff)); + color: var(--text, #222); + border: 1px solid var(--border, #ccc); + border-radius: 8px; + box-shadow: 0 12px 40px rgba(0, 0, 0, 0.32); + padding: 1.1rem 1.25rem; + width: min(34rem, 94vw); + max-height: 90vh; + overflow: auto; +} +.ma-title { margin: 0 0 0.2rem; font-size: 1.15rem; } +.ma-sub { + margin: 0 0 0.8rem; + font-size: 0.82rem; + color: var(--text-muted, #777); + word-break: break-all; +} +.ma-list { display: flex; flex-direction: column; gap: 0.4rem; } +/* who fills the row and shrinks (min-width:0); level + delete size to content + so nothing overflows the dialog regardless of email/principal length. */ +.ma-row { + display: grid; + grid-template-columns: minmax(0, 1fr) max-content max-content; + gap: 0.5rem; + align-items: center; +} +.ma-who, +.ma-level { + box-sizing: border-box; + padding: 0.4rem 0.5rem; + font: inherit; + border: 1px solid var(--border, #ccc); + border-radius: 4px; + background: var(--bg, #fff); + color: var(--text, #222); +} +.ma-who { width: 100%; min-width: 0; } +.ma-level { width: 8.5rem; cursor: pointer; } +.ma-legend { + margin: 0.5rem 0 0; + font-size: 0.74rem; + color: var(--text-muted, #888); +} +.ma-del { + border: none; + background: transparent; + color: var(--text-muted, #999); + cursor: pointer; + font-size: 1rem; + padding: 0.2rem 0.4rem; + border-radius: 4px; +} +.ma-del:hover { background: var(--bg-secondary, rgba(0, 0, 0, 0.06)); color: var(--danger, #c14242); } +.ma-add { + margin: 0.6rem 0 0; + border: 1px dashed var(--border, #bbb); + background: transparent; + color: var(--primary, #2868c8); + cursor: pointer; + padding: 0.35rem 0.6rem; + border-radius: 4px; + font: inherit; +} +.ma-add:hover { background: var(--bg-secondary, rgba(0, 0, 0, 0.04)); } +.ma-inherit { + display: flex; + align-items: center; + gap: 0.3rem; + margin: 0.9rem 0 0; + font-size: 0.88rem; +} +.ma-err { color: var(--danger, #c14242); font-size: 0.82rem; margin: 0.5rem 0 0; min-height: 0; } +.ma-err:empty { display: none; } +.ma-actions { + display: flex; + justify-content: flex-end; + gap: 0.5rem; + margin-top: 1rem; +} + @@ -2639,7 +2772,7 @@ body {
ZDDC Browse - v0.0.27-beta · 2026-06-08 13:10:36 · 48b8199 + v0.0.27-beta · 2026-06-08 20:19:36 · ec9c9c7
@@ -4007,6 +4140,7 @@ X.B(E,Y);return E}return J}()) !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).jsyaml={})}(this,(function(e){"use strict";function t(e){return null==e}var n={isNothing:t,isObject:function(e){return"object"==typeof e&&null!==e},toArray:function(e){return Array.isArray(e)?e:t(e)?[]:[e]},repeat:function(e,t){var n,i="";for(n=0;nl&&(t=i-l+(o=" ... ").length),n-i>l&&(n=i+l-(a=" ...").length),{str:o+e.slice(t,n).replace(/\t/g,"→")+a,pos:i-t+o.length}}function l(e,t){return n.repeat(" ",t-e.length)+e}var c=function(e,t){if(t=Object.create(t||null),!e.buffer)return null;t.maxLength||(t.maxLength=79),"number"!=typeof t.indent&&(t.indent=1),"number"!=typeof t.linesBefore&&(t.linesBefore=3),"number"!=typeof t.linesAfter&&(t.linesAfter=2);for(var i,r=/\r?\n|\r|\0/g,o=[0],c=[],s=-1;i=r.exec(e.buffer);)c.push(i.index),o.push(i.index+i[0].length),e.position<=i.index&&s<0&&(s=o.length-2);s<0&&(s=o.length-1);var u,p,f="",d=Math.min(e.line+t.linesAfter,c.length).toString().length,h=t.maxLength-(t.indent+d+3);for(u=1;u<=t.linesBefore&&!(s-u<0);u++)p=a(e.buffer,o[s-u],c[s-u],e.position-(o[s]-o[s-u]),h),f=n.repeat(" ",t.indent)+l((e.line-u+1).toString(),d)+" | "+p.str+"\n"+f;for(p=a(e.buffer,o[s],c[s],e.position,h),f+=n.repeat(" ",t.indent)+l((e.line+1).toString(),d)+" | "+p.str+"\n",f+=n.repeat("-",t.indent+d+3+p.pos)+"^\n",u=1;u<=t.linesAfter&&!(s+u>=c.length);u++)p=a(e.buffer,o[s+u],c[s+u],e.position-(o[s]-o[s+u]),h),f+=n.repeat(" ",t.indent)+l((e.line+u+1).toString(),d)+" | "+p.str+"\n";return f.replace(/\n$/,"")},s=["kind","multi","resolve","construct","instanceOf","predicate","represent","representName","defaultStyle","styleAliases"],u=["scalar","sequence","mapping"];var p=function(e,t){if(t=t||{},Object.keys(t).forEach((function(t){if(-1===s.indexOf(t))throw new o('Unknown option "'+t+'" is met in definition of "'+e+'" YAML type.')})),this.options=t,this.tag=e,this.kind=t.kind||null,this.resolve=t.resolve||function(){return!0},this.construct=t.construct||function(e){return e},this.instanceOf=t.instanceOf||null,this.predicate=t.predicate||null,this.represent=t.represent||null,this.representName=t.representName||null,this.defaultStyle=t.defaultStyle||null,this.multi=t.multi||!1,this.styleAliases=function(e){var t={};return null!==e&&Object.keys(e).forEach((function(n){e[n].forEach((function(e){t[String(e)]=n}))})),t}(t.styleAliases||null),-1===u.indexOf(this.kind))throw new o('Unknown kind "'+this.kind+'" is specified for "'+e+'" YAML type.')};function f(e,t){var n=[];return e[t].forEach((function(e){var t=n.length;n.forEach((function(n,i){n.tag===e.tag&&n.kind===e.kind&&n.multi===e.multi&&(t=i)})),n[t]=e})),n}function d(e){return this.extend(e)}d.prototype.extend=function(e){var t=[],n=[];if(e instanceof p)n.push(e);else if(Array.isArray(e))n=n.concat(e);else{if(!e||!Array.isArray(e.implicit)&&!Array.isArray(e.explicit))throw new o("Schema.extend argument should be a Type, [ Type ], or a schema definition ({ implicit: [...], explicit: [...] })");e.implicit&&(t=t.concat(e.implicit)),e.explicit&&(n=n.concat(e.explicit))}t.forEach((function(e){if(!(e instanceof p))throw new o("Specified list of YAML types (or a single Type object) contains a non-Type object.");if(e.loadKind&&"scalar"!==e.loadKind)throw new o("There is a non-scalar type in the implicit list of a schema. Implicit resolving of such types is not supported.");if(e.multi)throw new o("There is a multi type in the implicit list of a schema. Multi tags can only be listed as explicit.")})),n.forEach((function(e){if(!(e instanceof p))throw new o("Specified list of YAML types (or a single Type object) contains a non-Type object.")}));var i=Object.create(d.prototype);return i.implicit=(this.implicit||[]).concat(t),i.explicit=(this.explicit||[]).concat(n),i.compiledImplicit=f(i,"implicit"),i.compiledExplicit=f(i,"explicit"),i.compiledTypeMap=function(){var e,t,n={scalar:{},sequence:{},mapping:{},fallback:{},multi:{scalar:[],sequence:[],mapping:[],fallback:[]}};function i(e){e.multi?(n.multi[e.kind].push(e),n.multi.fallback.push(e)):n[e.kind][e.tag]=n.fallback[e.tag]=e}for(e=0,t=arguments.length;e=0?"0b"+e.toString(2):"-0b"+e.toString(2).slice(1)},octal:function(e){return e>=0?"0o"+e.toString(8):"-0o"+e.toString(8).slice(1)},decimal:function(e){return e.toString(10)},hexadecimal:function(e){return e>=0?"0x"+e.toString(16).toUpperCase():"-0x"+e.toString(16).toUpperCase().slice(1)}},defaultStyle:"decimal",styleAliases:{binary:[2,"bin"],octal:[8,"oct"],decimal:[10,"dec"],hexadecimal:[16,"hex"]}}),x=new RegExp("^(?:[-+]?(?:[0-9][0-9_]*)(?:\\.[0-9_]*)?(?:[eE][-+]?[0-9]+)?|\\.[0-9_]+(?:[eE][-+]?[0-9]+)?|[-+]?\\.(?:inf|Inf|INF)|\\.(?:nan|NaN|NAN))$");var I=/^[-+]?[0-9]+e/;var S=new p("tag:yaml.org,2002:float",{kind:"scalar",resolve:function(e){return null!==e&&!(!x.test(e)||"_"===e[e.length-1])},construct:function(e){var t,n;return n="-"===(t=e.replace(/_/g,"").toLowerCase())[0]?-1:1,"+-".indexOf(t[0])>=0&&(t=t.slice(1)),".inf"===t?1===n?Number.POSITIVE_INFINITY:Number.NEGATIVE_INFINITY:".nan"===t?NaN:n*parseFloat(t,10)},predicate:function(e){return"[object Number]"===Object.prototype.toString.call(e)&&(e%1!=0||n.isNegativeZero(e))},represent:function(e,t){var i;if(isNaN(e))switch(t){case"lowercase":return".nan";case"uppercase":return".NAN";case"camelcase":return".NaN"}else if(Number.POSITIVE_INFINITY===e)switch(t){case"lowercase":return".inf";case"uppercase":return".INF";case"camelcase":return".Inf"}else if(Number.NEGATIVE_INFINITY===e)switch(t){case"lowercase":return"-.inf";case"uppercase":return"-.INF";case"camelcase":return"-.Inf"}else if(n.isNegativeZero(e))return"-0.0";return i=e.toString(10),I.test(i)?i.replace("e",".e"):i},defaultStyle:"lowercase"}),O=b.extend({implicit:[A,v,C,S]}),j=O,T=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9])-([0-9][0-9])$"),N=new RegExp("^([0-9][0-9][0-9][0-9])-([0-9][0-9]?)-([0-9][0-9]?)(?:[Tt]|[ \\t]+)([0-9][0-9]?):([0-9][0-9]):([0-9][0-9])(?:\\.([0-9]*))?(?:[ \\t]*(Z|([-+])([0-9][0-9]?)(?::([0-9][0-9]))?))?$");var F=new p("tag:yaml.org,2002:timestamp",{kind:"scalar",resolve:function(e){return null!==e&&(null!==T.exec(e)||null!==N.exec(e))},construct:function(e){var t,n,i,r,o,a,l,c,s=0,u=null;if(null===(t=T.exec(e))&&(t=N.exec(e)),null===t)throw new Error("Date resolve error");if(n=+t[1],i=+t[2]-1,r=+t[3],!t[4])return new Date(Date.UTC(n,i,r));if(o=+t[4],a=+t[5],l=+t[6],t[7]){for(s=t[7].slice(0,3);s.length<3;)s+="0";s=+s}return t[9]&&(u=6e4*(60*+t[10]+ +(t[11]||0)),"-"===t[9]&&(u=-u)),c=new Date(Date.UTC(n,i,r,o,a,l,s)),u&&c.setTime(c.getTime()-u),c},instanceOf:Date,represent:function(e){return e.toISOString()}});var E=new p("tag:yaml.org,2002:merge",{kind:"scalar",resolve:function(e){return"<<"===e||null===e}}),M="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=\n\r";var L=new p("tag:yaml.org,2002:binary",{kind:"scalar",resolve:function(e){if(null===e)return!1;var t,n,i=0,r=e.length,o=M;for(n=0;n64)){if(t<0)return!1;i+=6}return i%8==0},construct:function(e){var t,n,i=e.replace(/[\r\n=]/g,""),r=i.length,o=M,a=0,l=[];for(t=0;t>16&255),l.push(a>>8&255),l.push(255&a)),a=a<<6|o.indexOf(i.charAt(t));return 0===(n=r%4*6)?(l.push(a>>16&255),l.push(a>>8&255),l.push(255&a)):18===n?(l.push(a>>10&255),l.push(a>>2&255)):12===n&&l.push(a>>4&255),new Uint8Array(l)},predicate:function(e){return"[object Uint8Array]"===Object.prototype.toString.call(e)},represent:function(e){var t,n,i="",r=0,o=e.length,a=M;for(t=0;t>18&63],i+=a[r>>12&63],i+=a[r>>6&63],i+=a[63&r]),r=(r<<8)+e[t];return 0===(n=o%3)?(i+=a[r>>18&63],i+=a[r>>12&63],i+=a[r>>6&63],i+=a[63&r]):2===n?(i+=a[r>>10&63],i+=a[r>>4&63],i+=a[r<<2&63],i+=a[64]):1===n&&(i+=a[r>>2&63],i+=a[r<<4&63],i+=a[64],i+=a[64]),i}}),_=Object.prototype.hasOwnProperty,D=Object.prototype.toString;var U=new p("tag:yaml.org,2002:omap",{kind:"sequence",resolve:function(e){if(null===e)return!0;var t,n,i,r,o,a=[],l=e;for(t=0,n=l.length;t>10),56320+(e-65536&1023))}for(var ie=new Array(256),re=new Array(256),oe=0;oe<256;oe++)ie[oe]=te(oe)?1:0,re[oe]=te(oe);function ae(e,t){this.input=e,this.filename=t.filename||null,this.schema=t.schema||K,this.onWarning=t.onWarning||null,this.legacy=t.legacy||!1,this.json=t.json||!1,this.listener=t.listener||null,this.implicitTypes=this.schema.compiledImplicit,this.typeMap=this.schema.compiledTypeMap,this.length=e.length,this.position=0,this.line=0,this.lineStart=0,this.lineIndent=0,this.firstTabInLine=-1,this.documents=[]}function le(e,t){var n={name:e.filename,buffer:e.input.slice(0,-1),position:e.position,line:e.line,column:e.position-e.lineStart};return n.snippet=c(n),new o(t,n)}function ce(e,t){throw le(e,t)}function se(e,t){e.onWarning&&e.onWarning.call(null,le(e,t))}var ue={YAML:function(e,t,n){var i,r,o;null!==e.version&&ce(e,"duplication of %YAML directive"),1!==n.length&&ce(e,"YAML directive accepts exactly one argument"),null===(i=/^([0-9]+)\.([0-9]+)$/.exec(n[0]))&&ce(e,"ill-formed argument of the YAML directive"),r=parseInt(i[1],10),o=parseInt(i[2],10),1!==r&&ce(e,"unacceptable YAML version of the document"),e.version=n[0],e.checkLineBreaks=o<2,1!==o&&2!==o&&se(e,"unsupported YAML version of the document")},TAG:function(e,t,n){var i,r;2!==n.length&&ce(e,"TAG directive accepts exactly two arguments"),i=n[0],r=n[1],G.test(i)||ce(e,"ill-formed tag handle (first argument) of the TAG directive"),P.call(e.tagMap,i)&&ce(e,'there is a previously declared suffix for "'+i+'" tag handle'),V.test(r)||ce(e,"ill-formed tag prefix (second argument) of the TAG directive");try{r=decodeURIComponent(r)}catch(t){ce(e,"tag prefix is malformed: "+r)}e.tagMap[i]=r}};function pe(e,t,n,i){var r,o,a,l;if(t1&&(e.result+=n.repeat("\n",t-1))}function be(e,t){var n,i,r=e.tag,o=e.anchor,a=[],l=!1;if(-1!==e.firstTabInLine)return!1;for(null!==e.anchor&&(e.anchorMap[e.anchor]=a),i=e.input.charCodeAt(e.position);0!==i&&(-1!==e.firstTabInLine&&(e.position=e.firstTabInLine,ce(e,"tab characters must not be used in indentation")),45===i)&&z(e.input.charCodeAt(e.position+1));)if(l=!0,e.position++,ge(e,!0,-1)&&e.lineIndent<=t)a.push(null),i=e.input.charCodeAt(e.position);else if(n=e.line,we(e,t,3,!1,!0),a.push(e.result),ge(e,!0,-1),i=e.input.charCodeAt(e.position),(e.line===n||e.lineIndent>t)&&0!==i)ce(e,"bad indentation of a sequence entry");else if(e.lineIndentt?g=1:e.lineIndent===t?g=0:e.lineIndentt?g=1:e.lineIndent===t?g=0:e.lineIndentt)&&(y&&(a=e.line,l=e.lineStart,c=e.position),we(e,t,4,!0,r)&&(y?g=e.result:m=e.result),y||(de(e,f,d,h,g,m,a,l,c),h=g=m=null),ge(e,!0,-1),s=e.input.charCodeAt(e.position)),(e.line===o||e.lineIndent>t)&&0!==s)ce(e,"bad indentation of a mapping entry");else if(e.lineIndent=0))break;0===o?ce(e,"bad explicit indentation width of a block scalar; it cannot be less than one"):u?ce(e,"repeat of an indentation width identifier"):(p=t+o-1,u=!0)}if(Q(a)){do{a=e.input.charCodeAt(++e.position)}while(Q(a));if(35===a)do{a=e.input.charCodeAt(++e.position)}while(!J(a)&&0!==a)}for(;0!==a;){for(he(e),e.lineIndent=0,a=e.input.charCodeAt(e.position);(!u||e.lineIndentp&&(p=e.lineIndent),J(a))f++;else{if(e.lineIndent0){for(r=a,o=0;r>0;r--)(a=ee(l=e.input.charCodeAt(++e.position)))>=0?o=(o<<4)+a:ce(e,"expected hexadecimal character");e.result+=ne(o),e.position++}else ce(e,"unknown escape sequence");n=i=e.position}else J(l)?(pe(e,n,i,!0),ye(e,ge(e,!1,t)),n=i=e.position):e.position===e.lineStart&&me(e)?ce(e,"unexpected end of the document within a double quoted scalar"):(e.position++,i=e.position)}ce(e,"unexpected end of the stream within a double quoted scalar")}(e,d)?y=!0:!function(e){var t,n,i;if(42!==(i=e.input.charCodeAt(e.position)))return!1;for(i=e.input.charCodeAt(++e.position),t=e.position;0!==i&&!z(i)&&!X(i);)i=e.input.charCodeAt(++e.position);return e.position===t&&ce(e,"name of an alias node must contain at least one character"),n=e.input.slice(t,e.position),P.call(e.anchorMap,n)||ce(e,'unidentified alias "'+n+'"'),e.result=e.anchorMap[n],ge(e,!0,-1),!0}(e)?function(e,t,n){var i,r,o,a,l,c,s,u,p=e.kind,f=e.result;if(z(u=e.input.charCodeAt(e.position))||X(u)||35===u||38===u||42===u||33===u||124===u||62===u||39===u||34===u||37===u||64===u||96===u)return!1;if((63===u||45===u)&&(z(i=e.input.charCodeAt(e.position+1))||n&&X(i)))return!1;for(e.kind="scalar",e.result="",r=o=e.position,a=!1;0!==u;){if(58===u){if(z(i=e.input.charCodeAt(e.position+1))||n&&X(i))break}else if(35===u){if(z(e.input.charCodeAt(e.position-1)))break}else{if(e.position===e.lineStart&&me(e)||n&&X(u))break;if(J(u)){if(l=e.line,c=e.lineStart,s=e.lineIndent,ge(e,!1,-1),e.lineIndent>=t){a=!0,u=e.input.charCodeAt(e.position);continue}e.position=o,e.line=l,e.lineStart=c,e.lineIndent=s;break}}a&&(pe(e,r,o,!1),ye(e,e.line-l),r=o=e.position,a=!1),Q(u)||(o=e.position+1),u=e.input.charCodeAt(++e.position)}return pe(e,r,o,!1),!!e.result||(e.kind=p,e.result=f,!1)}(e,d,1===i)&&(y=!0,null===e.tag&&(e.tag="?")):(y=!0,null===e.tag&&null===e.anchor||ce(e,"alias node should not have any properties")),null!==e.anchor&&(e.anchorMap[e.anchor]=e.result)):0===g&&(y=c&&be(e,h))),null===e.tag)null!==e.anchor&&(e.anchorMap[e.anchor]=e.result);else if("?"===e.tag){for(null!==e.result&&"scalar"!==e.kind&&ce(e,'unacceptable node kind for ! tag; it should be "scalar", not "'+e.kind+'"'),s=0,u=e.implicitTypes.length;s"),null!==e.result&&f.kind!==e.kind&&ce(e,"unacceptable node kind for !<"+e.tag+'> tag; it should be "'+f.kind+'", not "'+e.kind+'"'),f.resolve(e.result,e.tag)?(e.result=f.construct(e.result,e.tag),null!==e.anchor&&(e.anchorMap[e.anchor]=e.result)):ce(e,"cannot resolve a node with !<"+e.tag+"> explicit tag")}return null!==e.listener&&e.listener("close",e),null!==e.tag||null!==e.anchor||y}function ke(e){var t,n,i,r,o=e.position,a=!1;for(e.version=null,e.checkLineBreaks=e.legacy,e.tagMap=Object.create(null),e.anchorMap=Object.create(null);0!==(r=e.input.charCodeAt(e.position))&&(ge(e,!0,-1),r=e.input.charCodeAt(e.position),!(e.lineIndent>0||37!==r));){for(a=!0,r=e.input.charCodeAt(++e.position),t=e.position;0!==r&&!z(r);)r=e.input.charCodeAt(++e.position);for(i=[],(n=e.input.slice(t,e.position)).length<1&&ce(e,"directive name must not be less than one character in length");0!==r;){for(;Q(r);)r=e.input.charCodeAt(++e.position);if(35===r){do{r=e.input.charCodeAt(++e.position)}while(0!==r&&!J(r));break}if(J(r))break;for(t=e.position;0!==r&&!z(r);)r=e.input.charCodeAt(++e.position);i.push(e.input.slice(t,e.position))}0!==r&&he(e),P.call(ue,n)?ue[n](e,n,i):se(e,'unknown document directive "'+n+'"')}ge(e,!0,-1),0===e.lineIndent&&45===e.input.charCodeAt(e.position)&&45===e.input.charCodeAt(e.position+1)&&45===e.input.charCodeAt(e.position+2)?(e.position+=3,ge(e,!0,-1)):a&&ce(e,"directives end mark is expected"),we(e,e.lineIndent-1,4,!1,!0),ge(e,!0,-1),e.checkLineBreaks&&H.test(e.input.slice(o,e.position))&&se(e,"non-ASCII line breaks are interpreted as content"),e.documents.push(e.result),e.position===e.lineStart&&me(e)?46===e.input.charCodeAt(e.position)&&(e.position+=3,ge(e,!0,-1)):e.position=55296&&i<=56319&&t+1=56320&&n<=57343?1024*(i-55296)+n-56320+65536:i}function Re(e){return/^\n* /.test(e)}function Be(e,t,n,i,r,o,a,l){var c,s,u=0,p=null,f=!1,d=!1,h=-1!==i,g=-1,m=De(s=Ye(e,0))&&s!==Oe&&!_e(s)&&45!==s&&63!==s&&58!==s&&44!==s&&91!==s&&93!==s&&123!==s&&125!==s&&35!==s&&38!==s&&42!==s&&33!==s&&124!==s&&61!==s&&62!==s&&39!==s&&34!==s&&37!==s&&64!==s&&96!==s&&function(e){return!_e(e)&&58!==e}(Ye(e,e.length-1));if(t||a)for(c=0;c=65536?c+=2:c++){if(!De(u=Ye(e,c)))return 5;m=m&&qe(u,p,l),p=u}else{for(c=0;c=65536?c+=2:c++){if(10===(u=Ye(e,c)))f=!0,h&&(d=d||c-g-1>i&&" "!==e[g+1],g=c);else if(!De(u))return 5;m=m&&qe(u,p,l),p=u}d=d||h&&c-g-1>i&&" "!==e[g+1]}return f||d?n>9&&Re(e)?5:a?2===o?5:2:d?4:3:!m||a||r(e)?2===o?5:2:1}function Ke(e,t,n,i,r){e.dump=function(){if(0===t.length)return 2===e.quotingType?'""':"''";if(!e.noCompatMode&&(-1!==Te.indexOf(t)||Ne.test(t)))return 2===e.quotingType?'"'+t+'"':"'"+t+"'";var a=e.indent*Math.max(1,n),l=-1===e.lineWidth?-1:Math.max(Math.min(e.lineWidth,40),e.lineWidth-a),c=i||e.flowLevel>-1&&n>=e.flowLevel;switch(Be(t,c,e.indent,l,(function(t){return function(e,t){var n,i;for(n=0,i=e.implicitTypes.length;n"+Pe(t,e.indent)+We(Me(function(e,t){var n,i,r=/(\n+)([^\n]*)/g,o=(l=e.indexOf("\n"),l=-1!==l?l:e.length,r.lastIndex=l,He(e.slice(0,l),t)),a="\n"===e[0]||" "===e[0];var l;for(;i=r.exec(e);){var c=i[1],s=i[2];n=" "===s[0],o+=c+(a||n||""===s?"":"\n")+He(s,t),a=n}return o}(t,l),a));case 5:return'"'+function(e){for(var t,n="",i=0,r=0;r=65536?r+=2:r++)i=Ye(e,r),!(t=je[i])&&De(i)?(n+=e[r],i>=65536&&(n+=e[r+1])):n+=t||Fe(i);return n}(t)+'"';default:throw new o("impossible error: invalid scalar style")}}()}function Pe(e,t){var n=Re(e)?String(t):"",i="\n"===e[e.length-1];return n+(i&&("\n"===e[e.length-2]||"\n"===e)?"+":i?"":"-")+"\n"}function We(e){return"\n"===e[e.length-1]?e.slice(0,-1):e}function He(e,t){if(""===e||" "===e[0])return e;for(var n,i,r=/ [^ ]/g,o=0,a=0,l=0,c="";n=r.exec(e);)(l=n.index)-o>t&&(i=a>o?a:l,c+="\n"+e.slice(o,i),o=i+1),a=l;return c+="\n",e.length-o>t&&a>o?c+=e.slice(o,a)+"\n"+e.slice(a+1):c+=e.slice(o),c.slice(1)}function $e(e,t,n,i){var r,o,a,l="",c=e.tag;for(r=0,o=n.length;r tag resolver accepts not "'+s+'" style');i=c.represent[s](t,s)}e.dump=i}return!0}return!1}function Ve(e,t,n,i,r,a,l){e.tag=null,e.dump=n,Ge(e,n,!1)||Ge(e,n,!0);var c,s=Ie.call(e.dump),u=i;i&&(i=e.flowLevel<0||e.flowLevel>t);var p,f,d="[object Object]"===s||"[object Array]"===s;if(d&&(f=-1!==(p=e.duplicates.indexOf(n))),(null!==e.tag&&"?"!==e.tag||f||2!==e.indent&&t>0)&&(r=!1),f&&e.usedDuplicates[p])e.dump="*ref_"+p;else{if(d&&f&&!e.usedDuplicates[p]&&(e.usedDuplicates[p]=!0),"[object Object]"===s)i&&0!==Object.keys(e.dump).length?(!function(e,t,n,i){var r,a,l,c,s,u,p="",f=e.tag,d=Object.keys(n);if(!0===e.sortKeys)d.sort();else if("function"==typeof e.sortKeys)d.sort(e.sortKeys);else if(e.sortKeys)throw new o("sortKeys must be a boolean or a function");for(r=0,a=d.length;r1024)&&(e.dump&&10===e.dump.charCodeAt(0)?u+="?":u+="? "),u+=e.dump,s&&(u+=Le(e,t)),Ve(e,t+1,c,!0,s)&&(e.dump&&10===e.dump.charCodeAt(0)?u+=":":u+=": ",p+=u+=e.dump));e.tag=f,e.dump=p||"{}"}(e,t,e.dump,r),f&&(e.dump="&ref_"+p+e.dump)):(!function(e,t,n){var i,r,o,a,l,c="",s=e.tag,u=Object.keys(n);for(i=0,r=u.length;i1024&&(l+="? "),l+=e.dump+(e.condenseFlow?'"':"")+":"+(e.condenseFlow?"":" "),Ve(e,t,a,!1,!1)&&(c+=l+=e.dump));e.tag=s,e.dump="{"+c+"}"}(e,t,e.dump),f&&(e.dump="&ref_"+p+" "+e.dump));else if("[object Array]"===s)i&&0!==e.dump.length?(e.noArrayIndent&&!l&&t>0?$e(e,t-1,e.dump,r):$e(e,t,e.dump,r),f&&(e.dump="&ref_"+p+e.dump)):(!function(e,t,n){var i,r,o,a="",l=e.tag;for(i=0,r=n.length;i",e.dump=c+" "+e.dump)}return!0}function Ze(e,t){var n,i,r=[],o=[];for(Je(e,r,o),n=0,i=o.length;nt)return i;o.to==t&&(o.from!=o.to&&"before"==n?r=i:Fe=i),o.from==t&&(o.from!=o.to&&"before"!=n?r=i:Fe=i)}return null!=r?r:Fe}Ee=/[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/,Re=/[stwN]/,ze=/[LRr]/,Ie=/[Lb1n]/,Be=/[1n]/;var Ee,Re,ze,Ie,Be,Ge=function(e,t){var n="ltr"==t?"L":"R";if(0==e.length||"ltr"==t&&!Ee.test(e))return!1;for(var r,i=e.length,o=[],l=0;l=e.size)throw new Error("There is no line "+(t+e.first)+" in the document.");for(var n=e;!n.lines;)for(var r=0;;++r){var i=n.children[r],o=i.chunkSize();if(t=e.first&&tn?F(n,W(e,n).text.length):(e=W(e,(n=t).line).text.length,null==(t=n.ch)||e=this.string.length},g.prototype.sol=function(){return this.pos==this.lineStart},g.prototype.peek=function(){return this.string.charAt(this.pos)||void 0},g.prototype.next=function(){if(this.post},g.prototype.eatSpace=function(){for(var e=this.pos;/[\s\u00a0]/.test(this.string.charAt(this.pos));)++this.pos;return this.pos>e},g.prototype.skipToEnd=function(){this.pos=this.string.length},g.prototype.skipTo=function(e){e=this.string.indexOf(e,this.pos);if(-1e.options.maxHighlightLength&&ft(e.doc.mode,r.state),o=At(e,t,r),i&&(r.state=i),t.stateAfter=r.save(!i),t.styles=o.styles,o.classes?t.styleClasses=o.classes:t.styleClasses&&(t.styleClasses=null),n===e.doc.highlightFrontier&&(e.doc.modeFrontier=Math.max(e.doc.modeFrontier,++e.doc.highlightFrontier))),t.styles}function Wt(n,r,e){var t=n.doc,i=n.display;if(!t.mode.startState)return new Ot(t,!0,r);var o=function(e,t,n){for(var r,i,o=e.doc,l=n?-1:t-(e.doc.mode.innerMode?1e3:100),s=t;lt.first&&W(t,o-1).stateAfter,s=l?Ot.fromSaved(t,l,o):new Ot(t,gt(t.mode),o);return t.iter(o,r,function(e){Ht(n,e.text,s);var t=s.line;e.stateAfter=t==r-1||t%5==0||t>=i.viewFrom&&tt.start)return o}throw new Error("Mode "+e.name+" failed to advance stream.")}Ot.prototype.lookAhead=function(e){var t=this.doc.getLine(this.line+e);return null!=t&&e>this.maxLookAhead&&(this.maxLookAhead=e),t},Ot.prototype.baseToken=function(e){if(!this.baseTokens)return null;for(;this.baseTokens[this.baseTokenPos]<=e;)this.baseTokenPos+=2;var t=this.baseTokens[this.baseTokenPos+1];return{type:t&&t.replace(/( |^)overlay .*/,""),size:this.baseTokens[this.baseTokenPos]-e}},Ot.prototype.nextLine=function(){this.line++,0e.options.maxHighlightLength?(s=!1,l&&Ht(e,t,r,c.pos),c.pos=t.length,null):zt(Pt(n,c,r.state,h),o);if(!h||(d=h[0].name)&&(f="m-"+(f?d+" "+f:d)),!s||u!=f){for(;a=t:l.to>t),(r=r||[]).push(new Ut(s,l.from,o?null:l.to)))}return r}(n,r,o),s=function(e,t,n){var r;if(e)for(var i=0;i=t:l.to>t))&&(l.from!=t||"bookmark"!=s.type||n&&!l.marker.insertLeft)||(o=null==l.from||(s.inclusiveLeft?l.from<=t:l.frome.lastLine())return t;var n,r=W(e,t);if(!on(e,r))return t;for(;n=Jt(r);)r=n.find(1,!0).line;return H(r)+1}function on(e,t){var n=Gt&&t.markedSpans;if(n)for(var r,i=0;in.maxLineLength&&(n.maxLineLength=t,n.maxLine=e)})}var un=function(e,t,n){this.text=e,Yt(this,t),this.height=n?n(this):1};un.prototype.lineNo=function(){return H(this)},$e(un);var cn={},hn={};function dn(e,t){if(!e||/^\s*$/.test(e))return null;t=t.addModeClass?hn:cn;return t[e]||(t[e]=e.replace(/\S+/g,"cm-$&"))}function fn(e,t){var n=ne("span",null,null,x?"padding-right: .1px":null),r={pre:ne("pre",[n],"CodeMirror-line"),content:n,col:0,pos:0,cm:e,trailingSpace:!1,splitSpaces:e.getOption("lineWrapping")};t.measure={};for(var i=0;i<=(t.rest?t.rest.length:0);i++){var o=i?t.rest[i-1]:t.line,l=void 0,l=(r.pos=0,r.addToken=gn,function(e){if(null!=tt)return tt;var t=y(e,document.createTextNode("AخA")),n=le(t,0,1).getBoundingClientRect(),t=le(t,1,2).getBoundingClientRect();return te(e),n&&n.left!=n.right&&(tt=t.right-n.right<3)}(e.display.measure)&&(l=Ve(o,e.doc.direction))&&(r.addToken=function(h,d){return function(e,t,n,r,i,o,l){n=n?n+" cm-force-border":"cm-force-border";for(var s=e.pos,a=s+t.length;;){for(var u=void 0,c=0;cs&&u.from<=s);c++);if(u.to>=a)return h(e,t,n,r,i,o,l);h(e,t.slice(0,u.to-s),n,r,null,o,l),r=null,t=t.slice(u.to-s),s=u.to}}}(r.addToken,l)),r.map=[],t!=e.display.externalMeasured&&H(o));!function(e,t,n){var r=e.markedSpans,i=e.text,o=0;if(r)for(var l,s,a,u,c,h,d,f=i.length,p=0,g=1,m="",v=0;;){if(v==p){a=u=c=s="",h=d=null,v=1/0;for(var y=[],b=void 0,w=0;wp||C.collapsed&&x.to==p&&x.from==p)){if(null!=x.to&&x.to!=p&&v>x.to&&(v=x.to,u=""),C.className&&(a+=" "+C.className),C.css&&(s=(s?s+";":"")+C.css),C.startStyle&&x.from==p&&(c+=" "+C.startStyle),C.endStyle&&x.to==v&&(b=b||[]).push(C.endStyle,x.to),C.title&&((d=d||{}).title=C.title),C.attributes)for(var S in C.attributes)(d=d||{})[S]=C.attributes[S];C.collapsed&&(!h||qt(h.marker,C)<0)&&(h=x)}else x.from>p&&v>x.from&&(v=x.from)}if(b)for(var L=0;Ln)return{map:e.measure.maps[i],cache:e.measure.caches[i],before:!0}}}function zn(e,t,n,r){return Gn(e,Bn(e,t),n,r)}function In(e,t){if(t>=e.display.viewFrom&&t=e.lineN&&tt)&&(i=(o=a-s)-1,a<=t&&(l="right")),null!=i){if(r=e[u+2],s==a&&n==(r.insertLeft?"left":"right")&&(l=n),"left"==n&&0==i)for(;u&&e[u-2]==e[u-3]&&e[u-1].insertLeft;)r=e[2+(u-=3)],l="left";if("right"==n&&i==a-s)for(;u=i.text.length?(t=i.text.length,e="before"):t<=0&&(t=0,e="after"),!a)return s("before"==e?t-1:t,"before"==e);function u(e,t,n){return s(n?e-1:e,1==a[t].level!=n)}var c=Pe(a,t,e),h=Fe,c=u(t,c,"before"==e);return null!=h&&(c.other=u(t,h,"before"!=e)),c}function tr(e,t){var n=0,t=(t=E(e.doc,t),e.options.lineWrapping||(n=cr(e.display)*t.ch),W(e.doc,t.line)),e=ln(t)+Dn(e.display);return{left:n,right:n,top:e,bottom:e+t.height}}function nr(e,t,n,r,i){e=F(e,t,n);return e.xRel=i,r&&(e.outside=r),e}function rr(e,t,n){var r=e.doc;if((n+=e.display.viewOffset)<0)return nr(r.first,0,null,-1,-1);var i=bt(r,n),o=r.first+r.size-1;if(o=a.bottom?1:0)}return c=We(e.text,c,1),nr(t,c,g,f,r-p)}(e,l,i,t,n),a=function(e,t){var n,r=Gt&&e.markedSpans;if(r)for(var i=0;it)&&(!n||qt(n,o.marker)<0)&&(n=o.marker)}return n}(l,s.ch+(0r},i,e)}}function or(e,t,n,r){return ir(e,t,n=n||Bn(e,t),Zn(e,t,Gn(e,n,r),"line").top)}function lr(e,t,n,r){return!(e.bottom<=n)&&(e.top>n||(r?e.left:e.right)>t)}function sr(n,r,i,o,l,s,a){var e,t=He(function(e){var e=l[e],t=1!=e.level;return lr(er(n,F(i,t?e.to:e.from,t?"before":"after"),"line",r,o),s,a,!0)},0,l.length-1),u=l[t];return 0a&&(u=l[t-1])),u}function ar(e,t,n,r,i,o,l){for(var l=ir(e,t,r,l),s=l.begin,a=l.end,u=(/\s/.test(t.text.charAt(a-1))&&a--,null),c=null,h=0;h=a||f.to<=s||(d=(d=Gn(e,r,1!=f.level?Math.min(a,f.to)-1:Math.max(s,f.from)).right)a?{from:u.from,to:a,level:u.level}:u}function ur(e){if(null!=e.cachedTextHeight)return e.cachedTextHeight;if(null==Un){Un=M("pre",null,"CodeMirror-line-like");for(var t=0;t<49;++t)Un.appendChild(document.createTextNode("x")),Un.appendChild(M("br"));Un.appendChild(document.createTextNode("x"))}y(e.measure,Un);var n=Un.offsetHeight/50;return 3=e.display.viewTo)return null;if((t-=e.display.viewFrom)<0)return null;for(var n=e.display.view,r=0;rt)&&(o.updateLineNumbers=t),e.curOp.viewChanged=!0,t>=o.viewTo?Gt&&nn(e.doc,t)o.viewFrom?yr(e):(o.viewFrom+=r,o.viewTo+=r):t<=o.viewFrom&&n>=o.viewTo?yr(e):t<=o.viewFrom?(l=br(e,n,n+r,1))?(o.view=o.view.slice(l.index),o.viewFrom=l.lineN,o.viewTo+=r):yr(e):n>=o.viewTo?(l=br(e,t,t,-1))?(o.view=o.view.slice(0,l.index),o.viewTo=l.lineN):yr(e):(l=br(e,t,t,-1),i=br(e,n,n+r,1),l&&i?(o.view=o.view.slice(0,l.index).concat(yn(e,l.lineN,i.lineN)).concat(o.view.slice(i.index)),o.viewTo+=r):yr(e)),o.externalMeasured);l&&(n=i.lineN&&t=r.viewTo||null!=(i=r.view[mr(e,t)]).node&&-1==L(r=i.changes||(i.changes=[]),n)&&r.push(n)}function yr(e){e.display.viewFrom=e.display.viewTo=e.doc.first,e.display.view=[],e.display.viewOffset=0}function br(e,t,n,r){var i,o=mr(e,t),l=e.display.view;if(!Gt||n==e.doc.first+e.doc.size)return{index:o,lineN:n};for(var s=e.display.viewFrom,a=0;a=e.display.viewTo||s.to().linet||t==n&&l.to==t)&&(r(Math.max(l.from,t),Math.min(l.to,n),1==l.level?"rtl":"ltr",o),i=!0)}i||r(t,n,"ltr")}(C,g||0,null==m?b:m,function(e,t,n,r){var i,o,l,s,a,u="ltr"==n,c=w(e,u?"left":"right"),h=w(t-1,u?"right":"left"),d=null==g&&0==e,f=null==m&&t==b,p=0==r,r=!C||r==C.length-1;h.top-c.top<=3?(i=(k?d:f)&&p?S:(u?c:h).left,a=(k?f:d)&&r?L:(u?h:c).right,T(i,c.top,a-i,c.bottom)):(a=u?(o=k&&d&&p?S:c.left,l=k?L:x(e,n,"before"),s=k?S:x(t,n,"after"),k&&f&&r?L:h.right):(o=k?x(e,n,"before"):S,l=!k&&d&&p?L:c.right,s=!k&&f&&r?S:h.left,k?x(t,n,"after"):L),T(o,c.top,l-o,c.bottom),c.bottome.display.sizerWidth&&((a=Math.ceil(c/cr(e.display)))>e.display.maxLineLength&&(e.display.maxLineLength=a,e.display.maxLine=s.line,e.display.maxLineChanged=!0))}}2=o&&(i=bt(t,ln(W(t,n))-e.wrapper.clientHeight),o=n)),{from:i,to:Math.max(o,i+1)}}function Hr(e,t){var n=e.display,r=ur(e.display),i=(t.top<0&&(t.top=0),(e.curOp&&null!=e.curOp.scrollTop?e.curOp:n.scroller).scrollTop),o=En(e),l={},s=(t.bottom-t.top>o&&(t.bottom=t.top+o),e.doc.height+Wn(n)),a=t.tops-r,r=(t.topi+o&&((a=Math.min(t.top,(r?s:t.bottom)-o))!=i&&(l.scrollTop=a)),e.options.fixedGutter?0:n.gutters.offsetWidth),s=e.curOp&&null!=e.curOp.scrollLeft?e.curOp.scrollLeft:n.scroller.scrollLeft-r,o=Pn(e)-n.gutters.offsetWidth,i=t.right-t.left>o;return i&&(t.right=t.left+o),t.left<10?l.scrollLeft=0:t.lefto+s-3&&(l.scrollLeft=t.right+(i?0:10)-o),l}function Fr(e,t){null!=t&&(Rr(e),e.curOp.scrollTop=(null==e.curOp.scrollTop?e.doc:e.curOp).scrollTop+t)}function Pr(e){Rr(e);var t=e.getCursor();e.curOp.scrollToPos={from:t,to:t,margin:e.options.cursorScrollMargin}}function Er(e,t,n){null==t&&null==n||Rr(e),null!=t&&(e.curOp.scrollLeft=t),null!=n&&(e.curOp.scrollTop=n)}function Rr(e){var t=e.curOp.scrollToPos;t&&(e.curOp.scrollToPos=null,zr(e,tr(e,t.from),tr(e,t.to),t.margin))}function zr(e,t,n,r){t=Hr(e,{left:Math.min(t.left,n.left),top:Math.min(t.top,n.top)-r,right:Math.max(t.right,n.right),bottom:Math.max(t.bottom,n.bottom)+r});Er(e,t.scrollLeft,t.scrollTop)}function Ir(e,t){Math.abs(e.doc.scrollTop-t)<2||(d||ri(e,{top:t}),Br(e,t,!0),d&&ri(e),Qr(e,100))}function Br(e,t,n){t=Math.max(0,Math.min(e.display.scroller.scrollHeight-e.display.scroller.clientHeight,t)),e.display.scroller.scrollTop==t&&!n||(e.doc.scrollTop=t,e.display.scrollbars.setScrollTop(t),e.display.scroller.scrollTop!=t&&(e.display.scroller.scrollTop=t))}function Gr(e,t,n,r){t=Math.max(0,Math.min(t,e.display.scroller.scrollWidth-e.display.scroller.clientWidth)),(n?t==e.doc.scrollLeft:Math.abs(e.doc.scrollLeft-t)<2)&&!r||(e.doc.scrollLeft=t,li(e),e.display.scroller.scrollLeft!=t&&(e.display.scroller.scrollLeft=t),e.display.scrollbars.setScrollLeft(t))}function Ur(e){var t=e.display,n=t.gutters.offsetWidth,r=Math.round(e.doc.height+Wn(e.display));return{clientHeight:t.scroller.clientHeight,viewHeight:t.wrapper.clientHeight,scrollWidth:t.scroller.scrollWidth,clientWidth:t.scroller.clientWidth,viewWidth:t.wrapper.clientWidth,barLeft:e.options.fixedGutter?n:0,docHeight:r,scrollHeight:r+Fn(e)+t.barHeight,nativeBarWidth:t.nativeBarWidth,gutterWidth:n}}function Vr(e,t,n){this.cm=n;var r=this.vert=M("div",[M("div",null,null,"min-width: 1px")],"CodeMirror-vscrollbar"),i=this.horiz=M("div",[M("div",null,null,"height: 100%; min-height: 1px")],"CodeMirror-hscrollbar");r.tabIndex=i.tabIndex=-1,e(r),e(i),k(r,"scroll",function(){r.clientHeight&&t(r.scrollTop,"vertical")}),k(i,"scroll",function(){i.clientWidth&&t(i.scrollLeft,"horizontal")}),this.checkedZeroWidth=!1,w&&v<8&&(this.horiz.style.minHeight=this.vert.style.minWidth="18px")}function Kr(){}Vr.prototype.update=function(e){var t,n=e.scrollWidth>e.clientWidth+1,r=e.scrollHeight>e.clientHeight+1,i=e.nativeBarWidth;return r?(this.vert.style.display="block",this.vert.style.bottom=n?i+"px":"0",t=e.viewHeight-(n?i:0),this.vert.firstChild.style.height=Math.max(0,e.scrollHeight-e.clientHeight+t)+"px"):(this.vert.scrollTop=0,this.vert.style.display="",this.vert.firstChild.style.height="0"),n?(this.horiz.style.display="block",this.horiz.style.right=r?i+"px":"0",this.horiz.style.left=e.barLeft+"px",t=e.viewWidth-e.barLeft-(r?i:0),this.horiz.firstChild.style.width=Math.max(0,e.scrollWidth-e.clientWidth+t)+"px"):(this.horiz.style.display="",this.horiz.firstChild.style.width="0"),!this.checkedZeroWidth&&0=l.viewTo)||l.maxLineChanged&&o.options.lineWrapping,i.update=i.mustUpdate&&new ei(o,i.mustUpdate&&{top:i.scrollTop,ensure:i.scrollToPos},i.forceUpdate)}for(var s=0;s(i.defaultView.innerHeight||i.documentElement.clientHeight)&&(r=!1),null==r||X||(o=M("div","​",null,"position: absolute;\n top: "+(t.top-n.viewOffset-Dn(e.display))+"px;\n height: "+(t.bottom-t.top+Fn(e)+n.barHeight)+"px;\n left: "+t.left+"px; width: "+Math.max(2,t.right-t.left)+"px;"),e.display.lineSpace.appendChild(o),o.scrollIntoView(r),e.display.lineSpace.removeChild(o)))}(w,v));var S=b.maybeHiddenMarkers,L=b.maybeUnhiddenMarkers;if(S)for(var k=0;k=l.display.viewTo||(s=+new Date+l.options.workTime,a=Wt(l,c.highlightFrontier),u=[],c.iter(a.line,Math.min(c.first+c.size,l.display.viewTo+500),function(e){if(a.line>=l.display.viewFrom){for(var t=e.styles,n=e.text.length>l.options.maxHighlightLength?ft(c.mode,a.state):null,r=At(l,e,a,!0),n=(n&&(a.state=n),e.styles=r.styles,e.styleClasses),r=r.classes,i=(r?e.styleClasses=r:n&&(e.styleClasses=null),!t||t.length!=e.styles.length||n!=r&&(!n||!r||n.bgClass!=r.bgClass||n.textClass!=r.textClass)),o=0;!i&&os)return Qr(l,l.options.workDelay),!0}),c.highlightFrontier=a.line,c.modeFrontier=Math.max(c.modeFrontier,a.line),u.length&&h(l,function(){for(var e=0;e=n.viewFrom&&t.visible.to<=n.viewTo&&(null==n.updateLineNumbers||n.updateLineNumbers>=n.viewTo)&&n.renderedView==n.view&&0==wr(e))return!1;si(e)&&(yr(e),t.dims=hr(e));var i=r.first+r.size,o=Math.max(t.visible.from-e.options.viewportMargin,r.first),l=Math.min(i,t.visible.to+e.options.viewportMargin),r=(n.viewFroml&&n.viewTo-l<20&&(l=Math.min(i,n.viewTo)),Gt&&(o=nn(e.doc,o),l=rn(e.doc,l)),o!=n.viewFrom||l!=n.viewTo||n.lastWrapHeight!=t.wrapperHeight||n.lastWrapWidth!=t.wrapperWidth),i=(i=o,o=l,0==(c=(l=e).display).view.length||i>=c.viewTo||o<=c.viewFrom?(c.view=yn(l,i,o),c.viewFrom=i):(c.viewFrom>i?c.view=yn(l,i,c.viewFrom).concat(c.view):c.viewFromo&&(c.view=c.view.slice(0,mr(l,o)))),c.viewTo=o,n.viewOffset=ln(W(e.doc,n.viewFrom)),e.display.mover.style.top=n.viewOffset+"px",wr(e));if(!r&&0==i&&!t.force&&n.renderedView==n.view&&(null==n.updateLineNumbers||n.updateLineNumbers>=n.viewTo))return!1;var l=function(e){if(e.hasFocus())return null;if(!(n=N(ue(e)))||!re(e.display.lineDiv,n))return null;var t,n={activeElt:n};return window.getSelection&&(t=he(e).getSelection()).anchorNode&&t.extend&&re(e.display.lineDiv,t.anchorNode)&&(n.anchorNode=t.anchorNode,n.anchorOffset=t.anchorOffset,n.focusNode=t.focusNode,n.focusOffset=t.focusOffset),n}(e),s=(4=e.display.viewFrom&&t.visible.to<=e.display.viewTo)break;if(!ti(e,t))break;Ar(e);var i=Ur(e);xr(e),jr(e,i),oi(e,i),t.force=!1}t.signal(e,"update",e),e.display.viewFrom==e.display.reportedViewFrom&&e.display.viewTo==e.display.reportedViewTo||(t.signal(e,"viewportChange",e,e.display.viewFrom,e.display.viewTo),e.display.reportedViewFrom=e.display.viewFrom,e.display.reportedViewTo=e.display.viewTo)}function ri(e,t){var n,t=new ei(e,t);ti(e,t)&&(Ar(e),ni(e,t),n=Ur(e),xr(e),jr(e,n),oi(e,n),t.finish())}function ii(e){var t=e.gutters.offsetWidth;e.sizer.style.marginLeft=t+"px",b(e,"gutterChanged",e)}function oi(e,t){e.display.sizer.style.minHeight=t.docHeight+"px",e.display.heightForcer.style.top=t.docHeight+"px",e.display.gutters.style.height=t.docHeight+e.display.barHeight+Fn(e)+"px"}function li(e){var t=e.display,n=t.view;if(t.alignWidgets||t.gutters.firstChild&&e.options.fixedGutter){for(var r=dr(t)-t.scroller.scrollLeft+e.doc.scrollLeft,i=t.gutters.offsetWidth,o=r+"px",l=0;ll.clientWidth,a=l.scrollHeight>l.clientHeight;if(r&&s||n&&a){if(n&&C&&x)e:for(var u=t.target,c=o.view;u!=l;u=u.parentNode)for(var h=0;hs-(e.cm?e.cm.options.historyEventDelay:500)||"*"==t.origin.charAt(0)))&&(o=(o=l).lastOp==r?(Wi(o.done),z(o.done)):o.done.length&&!z(o.done).ranges?z(o.done):1l.undoDepth;)l.done.shift(),l.done[0].ranges||l.done.shift()}l.done.push(n),l.generation=++l.maxGeneration,l.lastModTime=l.lastSelTime=s,l.lastOp=l.lastSelOp=r,l.lastOrigin=l.lastSelOrigin=t.origin,i||O(e,"historyAdded")}function Fi(e,t,n,r){var i,o,l,s=e.history,a=r&&r.origin;n==s.lastSelOp||a&&s.lastSelOrigin==a&&(s.lastModTime==s.lastSelTime&&s.lastOrigin==a||(e=e,i=a,o=z(s.done),l=t,"*"==(i=i.charAt(0))||"+"==i&&o.ranges.length==l.ranges.length&&o.somethingSelected()==l.somethingSelected()&&new Date-e.history.lastSelTime<=(e.cm?e.cm.options.historyEventDelay:500)))?s.done[s.done.length-1]=t:Pi(t,s.done),s.lastSelTime=+new Date,s.lastSelOrigin=a,s.lastSelOp=n,r&&!1!==r.clearRedo&&Wi(s.undone)}function Pi(e,t){var n=z(t);n&&n.ranges&&n.equals(e)||t.push(e)}function Ei(t,n,e,r){var i=n["spans_"+t.id],o=0;t.iter(Math.max(t.first,e),Math.min(t.first+t.size,r),function(e){e.markedSpans&&((i=i||(n["spans_"+t.id]={}))[o]=e.markedSpans),++o})}function Ri(e,t){var n=t["spans_"+e.id];if(!n)return null;for(var r=[],i=0;i=t.ch:s.to>t.ch))){if(i&&(O(a,"beforeCursorEnter"),a.explicitlyCleared)){if(o.markedSpans){--l;continue}break}if(a.atomic){if(n){var s=a.find(r<0?1:-1),h=void 0;if((s=(r<0?c:u)?Qi(e,s,-r,s&&s.line==t.line?o:null):s)&&s.line==t.line&&(h=P(s,n))&&(r<0?h<0:0e.first?E(e,F(t.line-1)):null:0e.lastLine())){t.from.linei?{from:t.from,to:F(i,W(e,i).text.length),text:[t.text[0]],origin:t.origin}:t).removed=mt(e,t.from,t.to),n=n||xi(e,t),e.cm){var i=e.cm,o=t,l=r,s=i.doc,a=i.display,u=o.from,c=o.to,h=!1,d=u.line,f=(i.options.lineWrapping||(d=H(tn(W(s,u.line))),s.iter(d,c.line+1,function(e){if(e==a.maxLine)return h=!0})),-1a.maxLineLength&&(a.maxLine=e,a.maxLineLength=t,a.maxLineChanged=!0,h=!1)}),h&&(i.curOp.updateMaxLine=!0)),s),p=u.line;if(f.modeFrontier=Math.min(f.modeFrontier,p),!(f.highlightFrontiert.display.maxLineLength&&(t.display.maxLine=u,t.display.maxLineLength=c,t.display.maxLineChanged=!0)}null!=r&&t&&this.collapsed&&R(t,r,i+1),this.lines.length=0,this.explicitlyCleared=!0,this.atomic&&this.doc.cantEdit&&(this.doc.cantEdit=!1,t&&$i(t.doc)),t&&b(t,"markerCleared",t,this,r,i),n&&Zr(t),this.parent&&this.parent.clear()}},mo.prototype.find=function(e,t){var n,r;null==e&&"bookmark"==this.type&&(e=1);for(var i=0;i=e.ch)&&t.push(i.marker.parent||i.marker)}return t},findMarks:function(i,o,l){i=E(this,i),o=E(this,o);var s=[],a=i.line;return this.iter(i.line,o.line+1,function(e){var t=e.markedSpans;if(t)for(var n=0;n=r.to||null==r.from&&a!=i.line||null!=r.from&&a==o.line&&r.from>=o.ch||l&&!l(r.marker)||s.push(r.marker.parent||r.marker)}++a}),s},getAllMarks:function(){var r=[];return this.iter(function(e){var t=e.markedSpans;if(t)for(var n=0;nt&&(t=e.from),null!=e.to&&e.toe.text.length?null:t}function Ko(e,t,n){e=Vo(e,t.ch,n);return null==e?null:new F(t.line,e,n<0?"after":"before")}function jo(e,t,n,r,i){if(e){"rtl"==t.doc.direction&&(i=-i);var o,l,s,a,e=Ve(n,t.doc.direction);if(e)return o=i<0==(1==(e=i<0?z(e):e[0]).level)?"after":"before",0=n.text.length?(s.ch=n.text.length,s.sticky="before"):s.ch<=0&&(s.ch=0,s.sticky="after");var r=Pe(a,s.ch,s.sticky),i=a[r];if("ltr"==t.doc.direction&&i.level%2==0&&(0s.ch:i.from=i.from&&d>=c.begin))return new F(s.line,d,h?"before":"after")}function f(e,t,n){for(var r=function(e,t){return t?new F(s.line,u(e,1),"before"):new F(s.line,e,"after")};0<=e&&el.doc.first&&((n=W(l.doc,e.line-1).text)&&(e=new F(e.line,1),l.replaceRange(t.charAt(0)+l.doc.lineSeparator()+n.charAt(n.length-1),F(e.line-1,n.length-1),e,"+transpose")))),i.push(new G(e,e)));l.setSelections(i)})},newlineAndIndent:function(r){return h(r,function(){for(var e=(t=r.listSelections()).length-1;0<=e;e--)r.replaceRange(r.doc.lineSeparator(),t[e].anchor,t[e].head,"+input");for(var t=r.listSelections(),n=0;nc&&t.push(new G(F(s,c),F(s,we(u,l,n))))}t.length||t.push(new G(f,f)),U(g,vi(d,y.ranges.slice(0,v).concat(t),v),{origin:"*mouse",scroll:!1}),d.scrollIntoView(e)}else{var h,r=m,i=ul(d,e,p.unit),e=r.anchor,e=0=n.to||o.linea.bottom?20:0)&&setTimeout(I(d,function(){u==i&&(l.scroller.scrollTop+=r,e(t))}),50))}:n)(e)}),i=I(d,n);d.state.selectingText=i,k(l.wrapper.ownerDocument,"mousemove",r),k(l.wrapper.ownerDocument,"mouseup",i)})(i,s,o,a)):Qe(e)==h.scroller&&D(e):2==n?(t&&Gi(c.doc,t),setTimeout(function(){return h.input.focus()},20)):3==n&&(Q?c.display.input.onContextMenu(e):Mr(c)))))}function ul(e,t,n){if("char"==n)return new G(t,t);if("word"==n)return e.findWordAt(t);if("line"==n)return new G(F(t.line,0),E(e.doc,F(t.line+1,0)));n=n(e,t);return new G(n.from,n.to)}function cl(e,t,n,r){var i,o;if(t.touches)i=t.touches[0].clientX,o=t.touches[0].clientY;else try{i=t.clientX,o=t.clientY}catch(e){return!1}if(i>=Math.floor(e.display.gutters.getBoundingClientRect().right))return!1;r&&D(t);var l=e.display,r=l.lineDiv.getBoundingClientRect();if(o>r.bottom||!Ye(e,n))return qe(t);o-=r.top-l.viewOffset;for(var s=0;s=i)return O(e,n,e,bt(e.doc,o),e.display.gutterSpecs[s].className,t),qe(t)}}function hl(e,t){return cl(e,t,"gutterClick",!0)}function dl(e,t){var n,r;An(e.display,t)||(r=t,Ye(n=e,"gutterContextMenu")&&cl(n,r,"gutterContextMenu",!1))||A(e,t,"contextmenu")||Q||e.display.input.onContextMenu(t)}function fl(e){e.display.wrapper.className=e.display.wrapper.className.replace(/\s*cm-s-\S+/g,"")+e.options.theme.replace(/(^|\s)\s*/g," cm-s-"),Yn(e)}ol.prototype.compare=function(e,t,n){return this.time+400>e&&0==P(t,this.pos)&&n==this.button};var pl={toString:function(){return"CodeMirror.Init"}},gl={},ml={};function vl(e,t,n){!t!=!(n&&n!=pl)&&(n=e.display.dragFunctions,(t=t?k:T)(e.display.scroller,"dragstart",n.start),t(e.display.scroller,"dragenter",n.enter),t(e.display.scroller,"dragover",n.over),t(e.display.scroller,"dragleave",n.leave),t(e.display.scroller,"drop",n.drop))}function yl(e){e.options.lineWrapping?(ie(e.display.wrapper,"CodeMirror-wrap"),e.display.sizer.style.minWidth="",e.display.sizerWidth=null):(ee(e.display.wrapper,"CodeMirror-wrap"),an(e)),pr(e),R(e),Yn(e),setTimeout(function(){return jr(e)},100)}function p(e,t){var n=this;if(!(this instanceof p))return new p(e,t);this.options=t=t?fe(t):{},fe(gl,t,!1);var r,i=t.value,o=("string"==typeof i?i=new f(i,t.mode,null,t.lineSeparator,t.direction):t.mode&&(i.modeOption=t.mode),this.doc=i,new p.inputStyles[t.inputStyle](this)),e=this.display=new hi(e,i,o,t),l=(fl(e.wrapper.CodeMirror=this),t.lineWrapping&&(this.display.wrapper.className+=" CodeMirror-wrap"),$r(this),this.state={keyMaps:[],overlays:[],modeGen:0,overwrite:!1,delayingBlurEvent:!1,focused:!1,suppressEdits:!1,pasteIncoming:-1,cutIncoming:-1,selectingText:!1,draggingText:!1,highlight:new pe,keySeq:null,specialChars:null},t.autofocus&&!_&&e.input.focus(),w&&v<11&&setTimeout(function(){return n.display.input.reset(!0)},20),this),s=l.display;k(s.scroller,"mousedown",I(l,al)),k(s.scroller,"dblclick",w&&v<11?I(l,function(e){var t;A(l,e)||(!(t=gr(l,e))||hl(l,e)||An(l.display,e)||(D(e),e=l.findWordAt(t),Gi(l.doc,e.anchor,e.head)))}):function(e){return A(l,e)||D(e)}),k(s.scroller,"contextmenu",function(e){return dl(l,e)}),k(s.input.getField(),"contextmenu",function(e){s.scroller.contains(e.target)||dl(l,e)});var a,u={end:0};function c(){s.activeTouch&&(a=setTimeout(function(){return s.activeTouch=null},1e3),(u=s.activeTouch).end=+new Date)}function h(e,t){if(null==t.left)return 1;var n=t.left-e.left,t=t.top-e.top;return 400o.first?S(W(o,t-1).text,null,l):0:"add"==n?c=a+e.options.indentUnit:"subtract"==n?c=a-e.options.indentUnit:"number"==typeof n&&(c=a+n);var c=Math.max(0,c),h="",d=0;if(e.options.indentWithTabs)for(var f=Math.floor(c/l);f;--f)d+=l,h+="\t";if(dl,a=rt(t),u=null;if(s&&1l?"cut":"+input")});to(e.doc,f),b(e,"inputRead",e,f)}t&&!s&&kl(e,t),Pr(e),e.curOp.updateInput<2&&(e.curOp.updateInput=h),e.curOp.typing=!0,e.state.pasteIncoming=e.state.cutIncoming=-1}function Ll(e,t){var n=e.clipboardData&&e.clipboardData.getData("Text");return n&&(e.preventDefault(),t.isReadOnly()||t.options.disableInput||!t.hasFocus()||h(t,function(){return Sl(t,n,0,null,"paste")}),1)}function kl(e,t){if(e.options.electricChars&&e.options.smartIndent)for(var n=e.doc.sel,r=n.ranges.length-1;0<=r;r--){var i=n.ranges[r];if(!(100=n.first+n.size||(r=new F(e,r.ch,r.sticky),!(s=W(n,e))))return;r=jo(l,n.cm,s,r.line,a)}else r=t;return 1}if("char"==o||"codepoint"==o)u();else if("column"==o)u(!0);else if("word"==o||"group"==o)for(var c=null,h="group"==o,d=n.cm&&n.cm.getHelper(r,"wordChars"),f=!0;!(i<0)||u(!f);f=!1){var p=s.text.charAt(r.ch)||"\n",p=Ne(p,d)?"w":h&&"\n"==p?"n":!h||/\s/.test(p)?null:"p";if(!h||f||p||(p="s"),c&&c!=p){i<0&&(i=1,u(),r.sticky="after");break}if(p&&(c=p),0=s.height){l.hitSide=!0;break}o+=5*n}return l}function r(e){this.cm=e,this.lastAnchorNode=this.lastAnchorOffset=this.lastFocusNode=this.lastFocusOffset=null,this.polling=new pe,this.composing=null,this.gracePeriod=!1,this.readDOMTimeout=null}function Dl(e,t){var n=In(e,t.line);if(!n||n.hidden)return null;var r=W(e.doc,t.line),n=Rn(n,r,t.line),r=Ve(r,e.doc.direction),e="left",r=(r&&(e=Pe(r,t.ch)%2?"right":"left"),Kn(n.map,t.ch,e));return r.offset="right"==r.collapse?r.end:r.start,r}function Wl(e,t){return t&&(e.bad=!0),e}function Hl(e,t,n){var r;if(t==e.display.lineDiv){if(!(r=e.display.lineDiv.childNodes[n]))return Wl(e.clipPos(F(e.display.viewTo-1)),!0);t=null,n=0}else for(r=t;;r=r.parentNode){if(!r||r==e.display.lineDiv)return null;if(r.parentNode&&r.parentNode==e.display.lineDiv)break}for(var i=0;i=t.display.viewTo||n.line=t.display.viewFrom&&Dl(t,r)||{node:i[0].measure.map[2],offset:0},r=n.linet.firstLine()&&(i=F(i.line-1,W(t.doc,i.line-1).length)),r.ch==W(t.doc,r.line).text.length&&r.linen.viewTo-1)return!1;var o,l=i.line==n.viewFrom||0==(l=mr(t,i.line))?(e=H(n.view[0].line),n.view[0].node):(e=H(n.view[l].line),n.view[l-1].node.nextSibling),r=mr(t,r.line),n=r==n.view.length-1?(o=n.viewTo-1,n.lineDiv.lastChild):(o=H(n.view[r+1].line)-1,n.view[r+1].node.previousSibling);if(!l)return!1;for(var s=t.doc.splitLines(function(o,e,t,l,s){var n="",a=!1,u=o.doc.lineSeparator(),c=!1;function h(){a&&(n+=u,c&&(n+=u),a=c=!1)}function d(e){e&&(h(),n+=e)}for(;!function e(t){if(1==t.nodeType){var n=t.getAttribute("cm-text");if(n)d(n);else if(n=t.getAttribute("cm-marker"))(n=o.findMarks(F(l,0),F(s+1,0),(i=+n,function(e){return e.id==i}))).length&&(n=n[0].find(0))&&d(mt(o.doc,n.from,n.to).join(u));else if("false"!=t.getAttribute("contenteditable")&&(n=/^(pre|div|p|li|table|br)$/i.test(t.nodeName),/^br$/i.test(t.nodeName)||0!=t.textContent.length)){n&&h();for(var r=0;ri.ch&&p.charCodeAt(p.length-c-1)==g.charCodeAt(g.length-c-1);)u--,c++;s[s.length-1]=p.slice(0,p.length-c).replace(/^\u200b+/,""),s[0]=s[0].slice(u).replace(/\u200b+$/,"");r=F(e,u),l=F(o,a.length?z(a).length-c:0);return 1n&&(wl(this,i.head.line,e,!0),n=i.head.line,r==this.doc.sel.primIndex&&Pr(this));else{for(var o=i.from(),i=i.to(),l=Math.max(n,o.line),n=Math.min(this.lastLine(),i.line-(i.ch?0:1))+1,s=l;s>1;if((l?n[2*l-1]:0)>=o)i=l;else{if(!(n[2*l+1]l)&&e.top>t.offsetHeight?a=e.top-t.offsetHeight:e.bottom+t.offsetHeight<=l&&(a=e.bottom),u+t.offsetWidth>o&&(u=o-t.offsetWidth)),t.style.top=a+"px",t.style.left=t.style.right="","right"==i?(u=s.sizer.clientWidth-t.offsetWidth,t.style.right="0px"):("left"==i?u=0:"middle"==i&&(u=(s.sizer.clientWidth-t.offsetWidth)/2),t.style.left=u+"px"),n&&(r=this,l={left:u,top:a,right:u+t.offsetWidth,bottom:a+t.offsetHeight},null!=(l=Hr(r,l)).scrollTop&&Ir(r,l.scrollTop),null!=l.scrollLeft&&Gr(r,l.scrollLeft))},triggerOnKeyDown:t(nl),triggerOnKeyPress:t(il),triggerOnKeyUp:rl,triggerOnMouseDown:t(al),execCommand:function(e){if(Yo.hasOwnProperty(e))return Yo[e].call(null,this)},triggerElectric:t(function(e){kl(this,e)}),findPosH:function(e,t,n,r){for(var i=1,o=(t<0&&(i=-1,t=-t),E(this.doc,e)),l=0;li.keyCol)return e.skipToEnd(),"string";if(i.literal&&(i.literal=!1),e.sol()){if(i.keyCol=0,i.pair=!1,i.pairStart=!1,e.match("---"))return"def";if(e.match("..."))return"def";if(e.match(/\s*-\s+/))return"meta"}if(e.match(/^(\{|\}|\[|\])/))return"{"==t?i.inlinePairs++:"}"==t?i.inlinePairs--:"["==t?i.inlineList++:i.inlineList--,"meta";if(0)\s*/))return i.literal=!0,"meta";if(e.match(/^\s*(\&|\*)[a-z0-9\._-]+\b/i))return"variable-2";if(0==i.inlinePairs&&e.match(/^\s*-?[0-9\.\,]+\s?$/))return"number";if(0'"%@`][^\s'":]|[^\s,\[\]{}#&*!|>'"%@`])[^#:]*(?=:($|\s))/)?(i.pair=!0,i.keyCol=e.indentation(),"atom"):i.pair&&e.match(/^:\s*/)?(i.pairStart=!0,"meta"):(i.pairStart=!1,i.escaped="\\"==t,e.next(),null)},startState:function(){return{pair:!1,pairStart:!1,keyCol:0,inlinePairs:0,inlineList:0,literal:!1,escaped:!1}},lineComment:"#",fold:"indent"}}),e.defineMIME("text/x-yaml","yaml"),e.defineMIME("text/yaml","yaml")});!function(t){"object"==typeof exports&&"object"==typeof module?t(require("../../lib/codemirror")):"function"==typeof define&&define.amd?define(["../../lib/codemirror"],t):t(CodeMirror)}(function(p){"use strict";var h="CodeMirror-lint-markers",g="CodeMirror-lint-line-";function u(t){t.parentNode&&t.parentNode.removeChild(t)}function v(t,e,n,o){t=t,e=e,n=n,(i=document.createElement("div")).className="CodeMirror-lint-tooltip cm-s-"+t.options.theme,i.appendChild(n.cloneNode(!0)),(t.state.lint.options.selfContain?t.getWrapperElement():document.body).appendChild(i),p.on(document,"mousemove",a),a(e),null!=i.style.opacity&&(i.style.opacity=1);var i,r=i;function a(t){if(!i.parentNode)return p.off(document,"mousemove",a);var e=Math.max(0,t.clientY-i.offsetHeight-5),t=Math.max(0,Math.min(t.clientX+5,i.ownerDocument.defaultView.innerWidth-i.offsetWidth));i.style.top=e+"px",i.style.left=t+"px"}function l(){var t;p.off(o,"mouseout",l),r&&((t=r).parentNode&&(null==t.style.opacity&&u(t),t.style.opacity=0,setTimeout(function(){u(t)},600)),r=null)}var s=setInterval(function(){if(r)for(var t=o;;t=t.parentNode){if((t=t&&11==t.nodeType?t.host:t)==document.body)return;if(!t){l();break}}if(!r)return clearInterval(s)},400);p.on(o,"mouseout",l)}function a(s,t,e){for(var n in this.marked=[],(t=t instanceof Function?{getAnnotations:t}:t)&&!0!==t||(t={}),this.options={},this.linterOptions=t.options||{},o)this.options[n]=o[n];for(var n in t)o.hasOwnProperty(n)?null!=t[n]&&(this.options[n]=t[n]):t.options||(this.linterOptions[n]=t[n]);this.timeout=null,this.hasGutter=e,this.onMouseOver=function(t){var e=s,n=t.target||t.srcElement;if(/\bCodeMirror-lint-mark-/.test(n.className)){for(var n=n.getBoundingClientRect(),o=(n.left+n.right)/2,n=(n.top+n.bottom)/2,i=e.findMarksAt(e.coordsChar({left:o,top:n},"client")),r=[],a=0;al.clientHeight+1;setTimeout(function(){f=s.getScrollInfo()});0b&&(l.style.width=b-5+"px",k-=H.right-H.left-b),l.style.left=(m=Math.max(p.left-k-y,0))+"px"),e)for(var x=l.firstChild;x;x=x.nextSibling)x.style.paddingRight=s.display.nativeBarWidth+"px";s.addKeyMap(this.keyMap=function(t,n){var o={Up:function(){n.moveFocus(-1)},Down:function(){n.moveFocus(1)},PageUp:function(){n.moveFocus(1-n.menuSize(),!0)},PageDown:function(){n.moveFocus(n.menuSize()-1,!0)},Home:function(){n.setFocus(0)},End:function(){n.setFocus(n.length-1)},Enter:n.pick,Tab:n.pick,Esc:n.close},e=(/Mac/.test(navigator.platform)&&(o["Ctrl-P"]=function(){n.moveFocus(-1)},o["Ctrl-N"]=function(){n.moveFocus(1)}),t.options.customKeys),s=e?{}:o;function i(t,e){var i="string"!=typeof e?function(t){return e(t,n)}:o.hasOwnProperty(e)?o[e]:e;s[t]=i}if(e)for(var c in e)e.hasOwnProperty(c)&&i(c,e[c]);var r=t.options.extraKeys;if(r)for(var c in r)r.hasOwnProperty(c)&&i(c,r[c]);return s}(o,{moveFocus:function(t,e){i.changeActive(i.selectedHint+t,e)},setFocus:function(t){i.changeActive(t)},menuSize:function(){return i.screenAmount()},length:n.length,close:function(){o.close()},pick:function(){i.pick()},data:t})),o.options.closeOnUnfocus&&(s.on("blur",this.onBlur=function(){C=setTimeout(function(){o.close()},100)}),s.on("focus",this.onFocus=function(){clearTimeout(C)})),s.on("scroll",this.onScroll=function(){var t=s.getScrollInfo(),e=s.getWrapperElement().getBoundingClientRect(),i=(f=f||s.getScrollInfo(),g+f.top-t.top),n=i-(r.pageYOffset||(c.documentElement||c.body).scrollTop);if(v||(n+=l.offsetHeight),n<=e.top||n>=e.bottom)return o.close();l.style.top=i+"px",l.style.left=m+f.left-t.left+"px"}),T.on(l,"dblclick",function(t){t=O(l,t.target||t.srcElement);t&&null!=t.hintId&&(i.changeActive(t.hintId),i.pick())}),T.on(l,"click",function(t){t=O(l,t.target||t.srcElement);t&&null!=t.hintId&&(i.changeActive(t.hintId),o.options.completeOnSingleClick&&i.pick())}),T.on(l,"mousedown",function(){setTimeout(function(){s.focus()},20)});var S=this.getSelectedHintRange();return 0===S.from&&0===S.to||this.scrollToActive(),T.signal(t,"select",n[this.selectedHint],l.childNodes[this.selectedHint]),!0}function r(t,e,i,n){t.async?t(e,n,i):(t=t(e,i))&&t.then?t.then(n):n(t)}n.prototype={close:function(){this.active()&&(this.cm.state.completionActive=null,this.tick=null,this.options.updateOnCursorActivity&&this.cm.off("cursorActivity",this.activityFunc),this.widget&&this.data&&T.signal(this.data,"close"),this.widget&&this.widget.close(),T.signal(this.cm,"endCompletion",this.cm))},active:function(){return this.cm.state.completionActive==this},pick:function(t,e){var i=t.list[e],n=this;this.cm.operation(function(){i.hint?i.hint(n.cm,t,i):n.cm.replaceRange(M(i),i.from||t.from,i.to||t.to,"complete"),T.signal(t,"pick",i),n.cm.scrollIntoView()}),this.options.closeOnPick&&this.close()},cursorActivity:function(){this.debounce&&(s(this.debounce),this.debounce=0);var t,e=this.startPos,i=(this.data&&(e=this.data.from),this.cm.getCursor()),n=this.cm.getLine(i.line);i.line!=this.startPos.line||n.length-i.ch!=this.startLen-this.startPos.ch||i.ch=this.data.list.length?t=e?this.data.list.length-1:0:t<0&&(t=e?0:this.data.list.length-1),this.selectedHint!=t&&((e=this.hints.childNodes[this.selectedHint])&&(e.className=e.className.replace(" "+F,""),e.removeAttribute("aria-selected")),(e=this.hints.childNodes[this.selectedHint=t]).className+=" "+F,e.setAttribute("aria-selected","true"),this.completion.cm.getInputField().setAttribute("aria-activedescendant",e.id),this.scrollToActive(),T.signal(this.data,"select",this.data.list[this.selectedHint],e))},scrollToActive:function(){var t=this.getSelectedHintRange(),e=this.hints.childNodes[t.from],t=this.hints.childNodes[t.to],i=this.hints.firstChild;e.offsetTopthis.hints.scrollTop+this.hints.clientHeight&&(this.hints.scrollTop=t.offsetTop+t.offsetHeight-this.hints.clientHeight+i.offsetTop)},screenAmount:function(){return Math.floor(this.hints.clientHeight/this.hints.firstChild.offsetHeight)||1},getSelectedHintRange:function(){var t=this.completion.options.scrollMargin||0;return{from:Math.max(0,this.selectedHint-t),to:Math.min(this.data.list.length-1,this.selectedHint+t)}}},T.registerHelper("hint","auto",{resolve:function(t,e){var i,c=t.getHelpers(e,"hint");return c.length?((e=function(t,n,o){var s=function(t,e){if(!t.somethingSelected())return e;for(var i=[],n=0;n,]/,closeOnPick:!0,closeOnUnfocus:!0,updateOnCursorActivity:!0,completeOnSingleClick:!0,container:null,customKeys:null,extraKeys:null,paddingForScrollbar:!0,moveOnOverlap:!0};T.defineOption("hintOptions",null)}); /*! * @toast-ui/editor * @version 3.2.2 | Fri Feb 17 2023 @@ -7566,6 +7700,211 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr }; })(); +window.__ZDDC_SCHEMA__ = { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://zddc.varasys.io/schema/zddc.schema.json", + "title": ".zddc policy document", + "description": "Machine schema for the .zddc grammar (see GRAMMAR.md). Each property carries x-zddc-tier: 'structure' (the project shape an end user should not change — paths, WORM, tools, behaviors) or 'option' (the blanks an operator fills — role members, field-code vocabularies, names, labels). A form view renders option fields editable and structure fields read-only. NOTE: not all keys are valid at every level; the cascade + the per-location form decide relevance. Server-side validation still lives in validate.go (this draft-2020-12 schema uses $ref + patternProperties, which the in-tree validator does not yet support); the schema drives the form + client today.", + "type": "object", + "additionalProperties": false, + "properties": { + "title": { + "type": "string", + "description": "Human title for this directory.", + "x-zddc-tier": "option" + }, + "created_by": { + "type": "string", + "description": "Email of the user who created this folder. Set by the server; audit only.", + "x-zddc-tier": "structure" + }, + "admins": { + "type": "array", + "items": { "type": "string" }, + "description": "Principals (emails, globs, or role names) who administer this subtree. Root admins are super-admins; deeper entries are subtree admins. Elevation-gated full bypass over scope.", + "x-zddc-tier": "option" + }, + "roles": { + "type": "object", + "description": "Named principal groups referenced by acl/worm/admins. Membership UNIONS across the cascade. The operator fills the members.", + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "properties": { + "members": { + "type": "array", + "items": { "type": "string" }, + "description": "Email patterns (alice@x, *@acme.com, *) in this role." + }, + "reset": { + "type": "boolean", + "description": "Stop the membership union here: ancestor definitions above this level are excluded." + } + } + }, + "x-zddc-tier": "option" + }, + "acl": { + "type": "object", + "description": "Access control for this level. permissions maps a principal (email/glob/role) to a verb string from r w c d a (empty string = explicit deny). inherit:false clamps the ACL level-walk so ancestor levels' grants do not apply.", + "additionalProperties": false, + "properties": { + "inherit": { "type": "boolean", "description": "false = this level's ACL does not inherit ancestor levels." }, + "permissions": { + "type": "object", + "patternProperties": { + "^.+$": { "type": "string", "pattern": "^[rwcda]*$", "description": "Verb subset of r w c d a; empty = explicit deny." } + }, + "additionalProperties": false + } + }, + "x-zddc-tier": "structure" + }, + "worm": { + "type": "array", + "items": { "type": "string" }, + "description": "WORM zone: write/delete/admin stripped for all; create survives only for the listed principals; admins bypass. Unions across the cascade.", + "x-zddc-tier": "structure" + }, + "inherit": { + "type": "boolean", + "description": "false = stop the cascade here; everything below (ancestors + embedded defaults) is ignored. Makes a subtree a self-contained island.", + "x-zddc-tier": "structure" + }, + "default_tool": { + "type": "string", + "enum": ["archive", "transmittal", "classifier", "browse", "tables", "landing", "form"], + "description": "Tool served at (no trailing slash). Sugar for views.dir.tool.", + "x-zddc-tier": "structure" + }, + "dir_tool": { + "type": "string", + "enum": ["archive", "transmittal", "classifier", "browse", "tables", "landing", "form"], + "description": "Tool served at / (trailing slash). Sugar for views.dir_slash.tool; defaults to browse.", + "x-zddc-tier": "structure" + }, + "views": { + "type": "object", + "description": "Per-URL-shape tool + supporting-config mapping.", + "additionalProperties": { + "type": "object", + "additionalProperties": false, + "properties": { + "tool": { "type": "string", "enum": ["archive", "transmittal", "classifier", "browse", "tables", "landing", "form"] }, + "config": { "type": "string", "description": "Supporting-file name resolved under .zddc.d/ (no slashes)." } + } + }, + "x-zddc-tier": "structure" + }, + "available_tools": { + "type": "array", + "items": { "type": "string" }, + "description": "Tools the apps subsystem may auto-serve here and below. Concat-dedupe union across the cascade.", + "x-zddc-tier": "structure" + }, + "auto_own": { + "type": "boolean", + "description": "mkdir here writes a creator-owned .zddc (creator: rwcda).", + "x-zddc-tier": "structure" + }, + "auto_own_fenced": { + "type": "boolean", + "description": "The auto-own .zddc is written with acl.inherit:false (private to its creator).", + "x-zddc-tier": "structure" + }, + "auto_own_roles": { + "type": "array", + "items": { "type": "string" }, + "description": "Roles also granted rwcda in the auto-own .zddc, alongside the creator.", + "x-zddc-tier": "structure" + }, + "virtual": { + "type": "boolean", + "description": "Never materialise on disk; treat requests as virtual routes.", + "x-zddc-tier": "structure" + }, + "drop_target": { + "type": "boolean", + "description": "This directory accepts drag-drop uploads (browse drop-zone). Leaf-only.", + "x-zddc-tier": "structure" + }, + "party_source": { + "type": "string", + "description": "A new / here requires registration in /.yaml (e.g. 'ssr'). Leaf-only.", + "x-zddc-tier": "structure" + }, + "history": { + "type": "boolean", + "description": "Snapshot text (markdown) edits to .history/ in this subtree with a server-stamped audit line.", + "x-zddc-tier": "structure" + }, + "history_globs": { + "type": "array", + "items": { "type": "string" }, + "description": "Which basenames get edit history (default [\"*.md\"]).", + "x-zddc-tier": "structure" + }, + "convert": { + "type": "object", + "description": "Template variables for MD→{docx,html,pdf} conversion. Cascades leaf→root, per-key latest wins.", + "additionalProperties": false, + "properties": { + "client": { "type": "string" }, + "project": { "type": "string" }, + "contractor": { "type": "string" }, + "project_number": { "type": "string" } + }, + "x-zddc-tier": "option" + }, + "field_codes": { + "type": "object", + "description": "Vocabularies for tracking-number / record field components. Map-merged per code across the cascade.", + "additionalProperties": { "type": "object" }, + "x-zddc-tier": "option" + }, + "records": { + "type": "object", + "description": "Per-record-type rules keyed by filename pattern (filename_format, field_defaults, locked, row_field, row_scope_fields, folder_fields).", + "additionalProperties": { "type": "object" }, + "x-zddc-tier": "structure" + }, + "display": { + "type": "object", + "description": "Human labels for child entries (on-disk name → label). Leaf-only.", + "additionalProperties": { "type": "string" }, + "x-zddc-tier": "option" + }, + "tables": { + "type": "object", + "description": "Legacy directory-of-YAML table views (stem → spec path).", + "additionalProperties": { "type": "string" }, + "x-zddc-tier": "structure" + }, + "received_path": { + "type": "string", + "description": "Links a workflow folder back to its canonical submittal in received/. Set by Plan Review.", + "x-zddc-tier": "structure" + }, + "planned_review_date": { + "type": "string", + "description": "Doc-controller's committed review-completion date (YYYY-MM-DD), on the canonical submittal.", + "x-zddc-tier": "option" + }, + "planned_response_date": { + "type": "string", + "description": "Doc-controller's committed response-issuance date (YYYY-MM-DD), on the canonical submittal.", + "x-zddc-tier": "option" + }, + "paths": { + "type": "object", + "description": "Virtual sub-directory rules. Each key is a single path segment (literal or '*'); the value is a nested .zddc applied at the matching child directory. Recursive.", + "additionalProperties": { "$ref": "#" }, + "x-zddc-tier": "structure" + } + } +} +; + // util.js — small browse-local helpers shared across the tool's modules. // // Consolidates copies that had drifted across modules: escapeHtml (some @@ -7793,6 +8132,526 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr }; })(); +// yaml-complete.js — deterministic, schema-driven completion + hover docs for +// the browse YAML editors (markdown front matter + .zddc). NO heuristics, no +// AI: every candidate and doc string comes from a PROVIDER backed by the +// converter's field list or the .zddc JSON Schema. +// +// A provider answers three questions about a position, identified by its key +// PATH (the array of parent keys): +// keysAt(path) → [{name, hint, values}] valid child keys here +// valuesFor(path, key) → [string] | null enum/boolean values +// describe(path, key) → string | null doc text (for hover) +// The CodeMirror plumbing (indent→path, sibling scan, show-hint, hover) is +// shared; only the provider differs between the flat front matter and the +// nested .zddc schema. Requires CodeMirror 5 + the show-hint add-on. +(function () { + 'use strict'; + if (!window.app) window.app = {}; + if (!window.app.modules) window.app.modules = {}; + + function indentOf(line) { var m = line.match(/^(\s*)/); return m ? m[1].length : 0; } + function isBlankOrComment(line) { return /^\s*$/.test(line) || /^\s*#/.test(line); } + function truncate(s, n) { s = String(s); return s.length > n ? s.slice(0, n - 1) + '…' : s; } + + // Parent key-path for a line, derived from YAML indentation: walk upward + // collecting each "key:" line at a strictly smaller indent. + function pathAt(cm, lineNo) { + var path = []; + var target = indentOf(cm.getLine(lineNo)); + for (var ln = lineNo - 1; ln >= 0 && target > 0; ln--) { + var line = cm.getLine(ln); + if (isBlankOrComment(line)) continue; + var ind = indentOf(line); + if (ind < target) { + var m = line.match(/^\s*([\w.\-]+)\s*:/); + if (m) { path.unshift(m[1]); target = ind; } + } + } + return path; + } + + // Sibling keys already present at the same indent within this block, so we + // don't re-suggest a key the author already wrote. + function presentSiblings(cm, lineNo, indent) { + var present = {}; + [-1, 1].forEach(function (dir) { + for (var ln = lineNo + dir; ln >= 0 && ln < cm.lineCount(); ln += dir) { + var line = cm.getLine(ln); + if (isBlankOrComment(line)) continue; + var ind = indentOf(line); + if (ind < indent) break; // left the block + if (ind === indent) { + var m = line.match(/^\s*([\w.\-]+)\s*:/); + if (m) present[m[1]] = true; + } + } + }); + return present; + } + + function keyItem(k, hinter) { + var item = { + text: k.name + ': ', + displayText: k.name + (k.hint ? ' — ' + truncate(k.hint, 64) : '') + }; + // An enum key inserts "key: " then immediately opens its value menu. + if (k.values && k.values.length) { + item.hint = function (cmi, data, comp) { + cmi.replaceRange(comp.text, data.from, data.to); + setTimeout(function () { cmi.showHint({ hint: hinter, completeSingle: false }); }, 0); + }; + } + return item; + } + + function makeHinter(provider) { + function hinter(cm) { + var CM = window.CodeMirror; + if (!CM) return null; + var cur = cm.getCursor(); + var before = cm.getLine(cur.line).slice(0, cur.ch); + var colon = before.indexOf(':'); + var path = pathAt(cm, cur.line); + + if (colon === -1) { + // KEY context. + var m = before.match(/^(\s*)([\w.\-]*)$/); + if (!m) return null; + var indent = m[1], typed = m[2]; + var keys = provider.keysAt(path) || []; + if (!keys.length) return null; + var present = presentSiblings(cm, cur.line, indent.length); + var list = []; + keys.forEach(function (k) { + if (present[k.name]) return; + if (typed && k.name.indexOf(typed) !== 0) return; + list.push(keyItem(k, hinter)); + }); + if (!list.length) return null; + return { list: list, from: CM.Pos(cur.line, indent.length), to: cur }; + } + + // VALUE context. + var key = before.slice(0, colon).trim(); + var values = provider.valuesFor(path, key) || []; + if (!values.length) return null; + var rest = before.slice(colon + 1); + var valTyped = rest.replace(/^\s*/, ''); + var valStart = colon + 1 + (rest.length - valTyped.length); + var vlist = []; + values.forEach(function (v) { + if (valTyped && v.indexOf(valTyped) !== 0) return; + vlist.push({ text: v, displayText: v }); + }); + if (!vlist.length) return null; + return { list: vlist, from: CM.Pos(cur.line, valStart), to: cur }; + } + return hinter; + } + + // Lightweight hover docs: hover a "key:" → its schema description. No + // add-on — a debounced mousemove over the editor + a fixed-position tip. + function attachHover(cm, provider) { + var tip = null, timer = null; + function hide() { if (tip && tip.parentNode) tip.parentNode.removeChild(tip); tip = null; } + function show(text, x, y) { + hide(); + tip = document.createElement('div'); + tip.className = 'cm-doc-tip'; + tip.textContent = text; + document.body.appendChild(tip); + tip.style.left = x + 'px'; + tip.style.top = (y + 16) + 'px'; + } + var wrap = cm.getWrapperElement(); + wrap.addEventListener('mousemove', function (e) { + if (timer) clearTimeout(timer); + var ex = e.clientX, ey = e.clientY; + timer = setTimeout(function () { + if (!wrap.isConnected) { hide(); return; } + try { + var pos = cm.coordsChar({ left: ex, top: ey }, 'window'); + var line = cm.getLine(pos.line) || ''; + var m = line.match(/^\s*([\w.\-]+)\s*:/); + if (!m) { hide(); return; } + var keyStart = line.indexOf(m[1]); + if (pos.ch < keyStart || pos.ch > keyStart + m[1].length) { hide(); return; } + var doc = provider.describe(pathAt(cm, pos.line), m[1]); + if (doc) show(doc, ex, ey); else hide(); + } catch (_e) { hide(); } + }, 350); + }); + wrap.addEventListener('mouseleave', function () { if (timer) clearTimeout(timer); hide(); }); + cm.on('cursorActivity', hide); + cm.on('changes', hide); + } + + // Wire completion (Ctrl-Space + auto-trigger as you type) and hover docs + // onto a CodeMirror instance. opts.readOnly skips the typing trigger; + // opts.hover:false skips hover. + function attach(cm, provider, opts) { + opts = opts || {}; + var hinter = makeHinter(provider); + var keys = Object.assign({}, cm.getOption('extraKeys') || {}, { + 'Ctrl-Space': function (c) { c.showHint({ hint: hinter, completeSingle: false }); } + }); + cm.setOption('extraKeys', keys); + if (!opts.readOnly) { + cm.on('inputRead', function (c, change) { + if (!change.text || change.text.length !== 1) return; // skip paste/delete + if (!/[\w.\-]/.test(change.text[0])) return; + c.showHint({ hint: hinter, completeSingle: false }); + }); + } + if (opts.hover !== false) attachHover(cm, provider); + return hinter; + } + + // ── Providers ─────────────────────────────────────────────────────────── + + // Flat: a fixed field list [{name, hint, values}] at the root, nothing + // nested (front matter). opts.exclude = names never suggested. + function flatProvider(getFields, opts) { + opts = opts || {}; + var exclude = {}; + (opts.exclude || []).forEach(function (n) { exclude[n] = true; }); + function fields() { return getFields() || []; } + function find(name) { + var fs = fields(); + for (var i = 0; i < fs.length; i++) if (fs[i].name === name) return fs[i]; + return null; + } + return { + keysAt: function (path) { + if (path.length) return []; + return fields().filter(function (f) { return !exclude[f.name]; }) + .map(function (f) { return { name: f.name, hint: f.hint, values: f.values }; }); + }, + valuesFor: function (path, key) { + if (path.length) return null; + var f = find(key); return f ? f.values : null; + }, + describe: function (path, key) { + if (path.length) return null; + var f = find(key); return f ? f.hint : null; + } + }; + } + + // Schema: a JSON Schema (draft-2020-12 subset). Resolves nested key-paths + // through properties / additionalProperties / patternProperties and the + // recursive $ref:"#" .zddc uses for paths:. Keys = object property names; + // values = enum / boolean. + function schemaProvider(getSchema) { + function root() { return getSchema(); } + function deref(node) { return (node && node.$ref === '#') ? root() : node; } + function stepInto(node, seg) { + node = deref(node); + if (!node || node.type !== 'object') return null; + if (node.properties && node.properties[seg]) return node.properties[seg]; + if (node.additionalProperties && typeof node.additionalProperties === 'object') { + return node.additionalProperties; + } + if (node.patternProperties) { + for (var p in node.patternProperties) { + if (Object.prototype.hasOwnProperty.call(node.patternProperties, p)) { + return node.patternProperties[p]; + } + } + } + return null; + } + function containerAt(path) { + var node = deref(root()); + for (var i = 0; i < path.length; i++) { + node = stepInto(node, path[i]); + if (!node) return null; + node = deref(node); + } + return node; + } + function valuesOf(node) { + node = deref(node); + if (!node) return null; + if (Array.isArray(node.enum)) return node.enum.map(String); + if (node.type === 'boolean') return ['true', 'false']; + return null; + } + function keyNodeAt(path, key) { + var c = containerAt(path); + if (!c || !c.properties) return null; + return c.properties[key] || null; + } + return { + keysAt: function (path) { + var c = containerAt(path); + if (!c || c.type !== 'object' || !c.properties) return []; + return Object.keys(c.properties).map(function (name) { + var n = deref(c.properties[name]) || {}; + return { name: name, hint: n.description, values: valuesOf(n) }; + }); + }, + valuesFor: function (path, key) { return valuesOf(keyNodeAt(path, key)); }, + describe: function (path, key) { + var n = deref(keyNodeAt(path, key)); + return n ? n.description : null; + } + }; + } + + window.app.modules.yamlComplete = { + attach: attach, + makeHinter: makeHinter, + flatProvider: flatProvider, + schemaProvider: schemaProvider + }; +})(); + +// manage-access.js — guided "who can do what here" dialog. A task-first +// front door for a folder's .zddc acl: the user picks people + friendly access +// levels; we read the on-disk .zddc, merge ONLY the access bits (preserving +// every other key), and PUT it. No YAML, no schema knowledge required. The raw +// editor stays as the "Advanced" escape hatch. +// +// Friendly level → verbs (r read, w overwrite, c create, d delete, a admin): +// View → r Contribute → rc +// Edit → rwc Manage → admins: membership (not a verb string) +// "Custom" preserves a hand-written verb string we don't recognise. +(function (app) { + 'use strict'; + if (!app || !app.modules) return; + var util = app.modules.util; + + var LEVELS = [ + { id: 'view', label: 'View', hint: 'read only', verbs: 'r' }, + { id: 'contribute', label: 'Contribute', hint: 'read + add new files', verbs: 'rc' }, + { id: 'edit', label: 'Edit', hint: 'read, overwrite, add', verbs: 'rwc' }, + { id: 'manage', label: 'Manage', hint: 'full config + (elevated) bypass', verbs: null } + ]; + function verbsOfLevel(id) { + for (var i = 0; i < LEVELS.length; i++) if (LEVELS[i].id === id) return LEVELS[i].verbs; + return null; + } + function levelOfVerbs(verbs) { + verbs = String(verbs || ''); + if (verbs.indexOf('a') !== -1) return 'manage'; + if (verbs.indexOf('w') !== -1) return 'edit'; + if (verbs.indexOf('c') !== -1) return 'contribute'; + if (verbs.indexOf('r') !== -1) return 'view'; + return 'custom'; // empty (explicit deny) or non-standard + } + + function dirUrl(dir) { + var u = dir || '/'; + if (u.charAt(0) !== '/') u = '/' + u; + if (u.charAt(u.length - 1) !== '/') u += '/'; + return u; + } + + function el(tag, cls, text) { + var e = document.createElement(tag); + if (cls) e.className = cls; + if (text != null) e.textContent = text; + return e; + } + + async function open(dir) { + if (!app.state || app.state.source !== 'server') { + toast('Access management needs the server.', 'error'); + return; + } + var base = dirUrl(dir); + var zddcUrl = base + '.zddc'; + var data = {}, etag = null; + try { + var r = await fetch(zddcUrl, { credentials: 'same-origin' }); + if (r.ok) { + etag = r.headers.get('ETag'); + var txt = await r.text(); + try { data = (window.jsyaml && window.jsyaml.load(txt)) || {}; } catch (_e) { data = {}; } + } else if (r.status !== 404) { + throw new Error('HTTP ' + r.status); + } + } catch (e) { + toast('Could not read access rules: ' + (e.message || e), 'error'); + return; + } + if (!data || typeof data !== 'object' || Array.isArray(data)) data = {}; + + // Build the principal → level model from admins (Manage) + acl.permissions. + var acl = (data.acl && typeof data.acl === 'object') ? data.acl : {}; + var perms = (acl.permissions && typeof acl.permissions === 'object') ? acl.permissions : {}; + var admins = Array.isArray(data.admins) ? data.admins : []; + var rows = []; + var seen = {}; + admins.forEach(function (p) { + if (typeof p === 'string' && !seen[p]) { seen[p] = 1; rows.push({ principal: p, level: 'manage', custom: '' }); } + }); + Object.keys(perms).forEach(function (p) { + if (seen[p]) return; + seen[p] = 1; + var lvl = levelOfVerbs(perms[p]); + rows.push({ principal: p, level: lvl, custom: lvl === 'custom' ? String(perms[p] || '') : '' }); + }); + var inherit = acl.inherit !== false; + + renderModal(base, zddcUrl, data, etag, rows, inherit); + } + + function toast(msg, kind) { if (window.zddc && window.zddc.toast) window.zddc.toast(msg, kind || 'info'); } + + function renderModal(base, zddcUrl, data, etag, rows, inherit) { + var overlay = el('div', 'ma-overlay'); + var box = el('div', 'ma-box'); + overlay.appendChild(box); + + box.appendChild(el('h2', 'ma-title', 'Manage access')); + var sub = el('p', 'ma-sub', 'Who can do what in ' + base + ' — changes here only.'); + box.appendChild(sub); + + var list = el('div', 'ma-list'); + box.appendChild(list); + + function addRow(model) { + var row = el('div', 'ma-row'); + var who = el('input', 'ma-who'); + who.type = 'text'; + who.value = model.principal || ''; + who.placeholder = 'email or *@domain or role name'; + who.addEventListener('input', function () { model.principal = who.value.trim(); }); + + var sel = el('select', 'ma-level'); + LEVELS.forEach(function (lv) { + var o = el('option', null, lv.label); + o.value = lv.id; + o.title = lv.hint; + sel.appendChild(o); + }); + if (model.level === 'custom') { + var o2 = el('option', null, 'Custom'); + o2.value = 'custom'; + o2.title = 'verbs: ' + model.custom; + sel.appendChild(o2); + } + sel.value = model.level; + sel.addEventListener('change', function () { model.level = sel.value; }); + + var del = el('button', 'ma-del', '✕'); + del.type = 'button'; + del.title = 'Remove'; + del.addEventListener('click', function () { row.remove(); model._removed = true; }); + + row.appendChild(who); + row.appendChild(sel); + row.appendChild(del); + list.appendChild(row); + return model; + } + rows.forEach(addRow); + + var addBtn = el('button', 'ma-add', '+ Add person or group'); + addBtn.type = 'button'; + addBtn.addEventListener('click', function () { + var m = { principal: '', level: 'view', custom: '' }; + rows.push(m); + addRow(m); + }); + box.appendChild(addBtn); + + var legend = el('p', 'ma-legend', + 'View = read · Contribute = add new files · Edit = overwrite + add · Manage = admin'); + box.appendChild(legend); + + // Inherit / make-private. + var inhWrap = el('label', 'ma-inherit'); + var inhBox = el('input'); + inhBox.type = 'checkbox'; + inhBox.checked = inherit; + inhWrap.appendChild(inhBox); + inhWrap.appendChild(el('span', null, ' Inherit access from parent folders')); + box.appendChild(inhWrap); + + var err = el('p', 'ma-err'); + box.appendChild(err); + + var actions = el('div', 'ma-actions'); + var cancel = el('button', 'btn btn-sm btn-secondary', 'Cancel'); + cancel.type = 'button'; + var save = el('button', 'btn btn-sm btn-primary', 'Save'); + save.type = 'button'; + actions.appendChild(cancel); + actions.appendChild(save); + box.appendChild(actions); + + function close() { + document.removeEventListener('keydown', onKey, true); + if (overlay.parentNode) overlay.parentNode.removeChild(overlay); + } + function onKey(e) { if (e.key === 'Escape') { e.preventDefault(); close(); } } + document.addEventListener('keydown', onKey, true); + overlay.addEventListener('mousedown', function (e) { if (e.target === overlay) close(); }); + cancel.addEventListener('click', close); + + save.addEventListener('click', function () { + err.textContent = ''; + // Rebuild perms + admins from the live rows (skip removed/blank). + var perms = {}, admins = [], bad = false; + rows.forEach(function (m) { + if (m._removed) return; + var p = (m.principal || '').trim(); + if (!p) return; + if (m.level === 'manage') { + if (admins.indexOf(p) === -1) admins.push(p); + } else if (m.level === 'custom') { + perms[p] = m.custom; // preserve the hand-written string + } else { + perms[p] = verbsOfLevel(m.level); + } + }); + + // Merge into the existing doc, preserving every unmanaged key. + var out = {}; + Object.keys(data).forEach(function (k) { out[k] = data[k]; }); + var acl = (out.acl && typeof out.acl === 'object') ? Object.assign({}, out.acl) : {}; + if (Object.keys(perms).length) acl.permissions = perms; else delete acl.permissions; + if (!inhBox.checked) acl.inherit = false; else delete acl.inherit; + if (Object.keys(acl).length) out.acl = acl; else delete out.acl; + if (admins.length) out.admins = admins; else delete out.admins; + + var content; + try { content = window.jsyaml.dump(out); } + catch (e2) { err.textContent = 'Could not serialize: ' + (e2.message || e2); return; } + + save.disabled = true; + save.textContent = 'Saving…'; + var node = { url: zddcUrl, name: '.zddc', ext: '' }; + util.saveFile(node, content, 'application/yaml; charset=utf-8', etag ? { etag: etag } : {}) + .then(function () { + toast('Access updated for ' + base, 'success'); + var ev = app.modules.events; + if (ev && ev.refreshListing) { try { ev.refreshListing(); } catch (_e) { /* ignore */ } } + close(); + }) + .catch(function (e3) { + save.disabled = false; + save.textContent = 'Save'; + if (e3 && e3.status === 412) { + err.textContent = 'These rules changed on the server since you opened this. Close and reopen to get the latest, then redo your change.'; + } else { + err.textContent = 'Save failed: ' + (e3 && e3.message ? e3.message : e3); + } + }); + }); + + document.body.appendChild(overlay); + var first = box.querySelector('.ma-who'); + if (first) first.focus(); + } + + app.modules.manageAccess = { open: open }; +})(window.app); + // conflict.js — shared conflict-resolution dialog for the browse tool. // // Surfaced when a save loses an optimistic-concurrency race: the file @@ -8351,13 +9210,30 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr // ── admin / sub-admin tier ── { - // HIDDEN unless the user can actually edit access rules here - // (admin verb 'a', or subtree/site admin) — not shown greyed. + // Guided "who can do what here" dialog — the front door for access. + // HIDDEN unless the user can administer here (admin verb 'a', or + // subtree/site admin). id: 'manage-access', group: 'admin', surfaces: ['row', 'pane'], - label: 'Edit access rules…', + label: 'Manage access…', appliesTo: function (ctx) { if (!isServer()) return false; // server-only tier var typeOk = ctx.surface === 'pane' || appliesToFolderLike(ctx.node); + return typeOk && manageAccessGate(ctx).enabled + && !!(window.app.modules.manageAccess); + }, + action: function (ctx) { + var m = window.app.modules.manageAccess; + if (m) m.open(ctx.dir); + } + }, + { + // The raw-YAML escape hatch — same authority gate, demoted to + // "advanced" since the guided dialog covers the common case. + id: 'edit-zddc-raw', group: 'admin', surfaces: ['row', 'pane'], + label: 'Edit raw policy (.zddc)…', + appliesTo: function (ctx) { + if (!isServer()) return false; + var typeOk = ctx.surface === 'pane' || appliesToFolderLike(ctx.node); return typeOk && manageAccessGate(ctx).enabled; }, action: function (ctx) { openZddcEditor(ctx.dir); } @@ -9506,7 +10382,7 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr function editorModules() { var m = window.app.modules; - return [m.markdown, m.yamledit, m.zddcform].filter(Boolean); + return [m.markdown, m.yamledit].filter(Boolean); } function disposeEditors() { @@ -9538,6 +10414,9 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr disposeEditors(); var container = document.getElementById('previewBody'); if (container) container.innerHTML = ''; + toggleTargetNode = null; + var tb = document.getElementById('previewViewToggle'); + if (tb) tb.classList.add('hidden'); } // Warn before a full page unload (reload / close / external nav) drops @@ -9547,6 +10426,41 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr if (dirtyEditor()) { e.preventDefault(); e.returnValue = ''; } }); + // ── Rendered ⇄ Source toggle ───────────────────────────────────────────── + // Some types we can RENDER, not just edit (.html). Those show rendered by + // default (sandboxed — no scripts, no same-origin) with a toggle to the + // CodeMirror source view. Markdown has its own rendered/source toggle, so + // it's not here. Extend RENDERABLE to add more (svg already previews as an + // image; csv could render as a table later). + var RENDERABLE = { html: 1, htm: 1 }; + function isRenderable(ext) { return !!RENDERABLE[(ext || '').toLowerCase()]; } + function nodeKey(node) { return (node && (node.url || node.name)) || ''; } + // Per-node mode; 'rendered' is the default. Only the node the user last + // toggled is remembered, so switching files resets to rendered. + var viewToggle = { key: null, mode: 'rendered' }; + var toggleTargetNode = null; + function effectiveMode(node) { + return (viewToggle.key && viewToggle.key === nodeKey(node)) ? viewToggle.mode : 'rendered'; + } + function ensureViewToggleBtn() { + var btn = document.getElementById('previewViewToggle'); + if (btn) return btn; + var popout = document.getElementById('previewPopout'); + if (!popout || !popout.parentNode) return null; + btn = document.createElement('button'); + btn.id = 'previewViewToggle'; + btn.type = 'button'; + btn.className = 'btn btn-sm btn-secondary hidden'; + popout.parentNode.insertBefore(btn, popout); + btn.addEventListener('click', function () { + if (!toggleTargetNode) return; + var next = effectiveMode(toggleTargetNode) === 'rendered' ? 'source' : 'rendered'; + viewToggle = { key: nodeKey(toggleTargetNode), mode: next }; + renderInline(toggleTargetNode, { toggle: true }); + }); + return btn; + } + // ── Inline rendering ──────────────────────────────────────────────────── // Bumped on every renderInline entry; a render that loses the race @@ -9575,9 +10489,10 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr var dm = dirtyEditor(); if (dm) { var cur = dm.currentNode ? dm.currentNode() : null; - if (samePreviewNode(cur, node)) { + if (samePreviewNode(cur, node) && !opts.toggle) { // Re-selecting the file we're already editing — don't reload - // and clobber the in-progress edits. + // and clobber the in-progress edits. (A deliberate view toggle + // falls through to the discard prompt below.) return; } if (opts.auto) { @@ -9605,6 +10520,32 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr var ext = (node.ext || '').toLowerCase(); + // Rendered ⇄ Source toggle button — shown only for renderable types. + var toggleBtn = ensureViewToggleBtn(); + if (toggleBtn) { + if (isRenderable(ext)) { + toggleTargetNode = node; + toggleBtn.classList.remove('hidden'); + toggleBtn.textContent = effectiveMode(node) === 'rendered' ? '⟨⟩ Source' : '◱ Preview'; + } else { + toggleBtn.classList.add('hidden'); + } + } + + // Renderable types (.html) — show rendered by default, sandboxed for + // safety (no scripts, no same-origin). The toggle flips to source. + if (isRenderable(ext) && effectiveMode(node) === 'rendered') { + try { + var rinfo = await getBlobUrl(node); + if (seq !== renderSeq) return; + container.innerHTML = ''; + } catch (e) { + renderError(container, e.message || String(e)); + } + return; + } + // Markdown plugin (if loaded) takes over for .md / .markdown. if ((ext === 'md' || ext === 'markdown') && window.app.modules.markdown && @@ -9617,39 +10558,27 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr return; } - // .zddc form view: a schema-driven form (option fields editable, - // structure read-only) is the PRIMARY editor for .zddc files. It hands - // off to the raw YAML editor on demand. Other YAML files skip it. - var zddcForm = window.app.modules.zddcform; - if (zddcForm && zddcForm.handles(node)) { - try { - await zddcForm.render(node, container, { getArrayBuffer: getArrayBuffer, getContentWithVersion: getContentWithVersion }); - } catch (e) { - renderError(container, '.zddc form render failed: ' + (e.message || e)); - } - return; - } - - // YAML plugin: .yaml / .yml / .zddc / *.zddc.yaml route to a - // CodeMirror 5 editor with js-yaml linting; .zddc files also - // get a schema-aware lint pass. + // CodeMirror editor: the general editor for editable text files that + // aren't markdown — yaml/.zddc (schema lint + completion + hover) plus + // txt/csv/tsv/json/xml/html/css/js/… as a plaintext code editor. + // Guided dialogs (Manage access, …) are the front door for the common + // .zddc tasks; this is the full/raw edit surface. var yamlMod = window.app.modules.yamledit; if (yamlMod && yamlMod.handles(node)) { try { await yamlMod.render(node, container, { getArrayBuffer: getArrayBuffer, getContentWithVersion: getContentWithVersion }); } catch (e) { - renderError(container, 'YAML render failed: ' + (e.message || e)); + renderError(container, 'Editor failed: ' + (e.message || e)); } return; } - // PDF / HTML → iframe. - if (ext === 'pdf' || ext === 'html' || ext === 'htm') { + // PDF → iframe (HTML now routes to the editor above). + if (ext === 'pdf') { try { var info = await getBlobUrl(node); if (seq !== renderSeq) return; - var sandbox = (ext === 'pdf') ? '' : ' sandbox="allow-same-origin allow-popups allow-popups-to-escape-sandbox"'; - container.innerHTML = ''; + container.innerHTML = ''; } catch (e) { renderError(container, e.message || String(e)); } @@ -9838,6 +10767,25 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr } async function renderInPopup(node) { + // Editor-type files (markdown, yaml/.zddc, code text) can't be hosted + // in the lightweight popup window — they need the bundled editor. Pop + // them out as the FULL browse app deep-linked to the file, which loads + // the real editor in a new window. Server mode only; HTML keeps its + // rendered popup. Falls through to the lightweight popup otherwise. + var pext = (node.ext || '').toLowerCase(); + var ym = window.app.modules.yamledit; + var isEditorType = pext === 'md' || pext === 'markdown' + || (ym && ym.handles && ym.handles(node) && pext !== 'html' && pext !== 'htm'); + if (isEditorType && window.app.state.source === 'server' && node.url) { + var slash = node.url.lastIndexOf('/'); + var pdir = slash >= 0 ? node.url.slice(0, slash + 1) : '/'; + var pbase = slash >= 0 ? node.url.slice(slash + 1) : node.url; + var pp = new URLSearchParams(); + try { pp.set('file', decodeURIComponent(pbase)); } catch (_e) { pp.set('file', pbase); } + if (window.app.state.showHidden) pp.set('hidden', '1'); + window.open(pdir + '?' + pp.toString(), '_blank', 'noopener'); + return; + } var info; try { info = await getBlobUrl(node); @@ -10012,30 +10960,38 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr // empty / unavailable. The promise dedupes concurrent fetches. var fmPlaceholder = null; var fmPlaceholderPromise = null; + // Recognised fields ([{name, hint, values}]) from the same /.api/frontmatter + // fetch — drives schema completion (keys + enum values). null = not loaded. + var fmFields = null; - // applyFrontMatterPlaceholder sets the textarea placeholder to the server's - // recognised-field hint, in server mode only. Async + best-effort: a failed - // fetch leaves the pane blank (no placeholder), never an error. - function applyFrontMatterPlaceholder(textarea) { + // applyFrontMatterHint populates a greyed caption (+ tooltip) with the + // server's recognised front-matter fields, in server mode only. Async + + // best-effort: a failed fetch leaves the caption hidden, never an error. + // (Replaces the old textarea placeholder — CodeMirror 5 has no built-in + // placeholder without an unvendored add-on. Arbitrary keys stay free.) + function applyFrontMatterHint(el) { var st = window.app && window.app.state; if (!st || st.source !== 'server') return; - if (fmPlaceholder !== null) { - textarea.placeholder = fmPlaceholder; - return; + function paint() { + if (!el.isConnected) return; // user switched files before resolve + if (!fmPlaceholder) { el.style.display = 'none'; return; } + el.textContent = 'ⓘ Recognised front-matter keys (hover) — any other key is allowed'; + el.title = fmPlaceholder; + el.style.display = ''; } + if (fmPlaceholder !== null) { paint(); return; } if (!fmPlaceholderPromise) { fmPlaceholderPromise = fetch('/.api/frontmatter', { headers: { 'Accept': 'application/json' }, credentials: 'same-origin' }).then(function (r) { return r.ok ? r.json() : null; }) - .then(function (j) { fmPlaceholder = (j && j.placeholder) || ''; }) - .catch(function () { fmPlaceholder = ''; }); + .then(function (j) { + fmPlaceholder = (j && j.placeholder) || ''; + fmFields = (j && j.fields) || []; + }) + .catch(function () { fmPlaceholder = ''; fmFields = []; }); } - fmPlaceholderPromise.then(function () { - // Only apply if this textarea is still in the DOM (user may have - // switched files before the fetch resolved). - if (textarea.isConnected) textarea.placeholder = fmPlaceholder; - }); + fmPlaceholderPromise.then(paint); } // Lightweight YAML front-matter parser. Same envelope as mdedit's: @@ -10357,22 +11313,19 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr fmHeader.textContent = 'YAML front matter'; var fmBody = document.createElement('div'); fmBody.className = 'md-side__body md-fm__body'; - var fmTextarea = document.createElement('textarea'); - fmTextarea.className = 'md-fm__textarea'; - fmTextarea.spellcheck = false; - fmTextarea.autocapitalize = 'off'; - fmTextarea.autocomplete = 'off'; - // Placeholder: in server mode, hint the recognised front-matter keys - // (doctype, numbering, …) as greyed text so authors can discover them. - // It's placeholder-only — inserts nothing, vanishes on the first - // keystroke — so arbitrary keys stay free and a file with no front - // matter still renders as a genuinely empty pane. The text is fetched - // from the server (/.api/frontmatter), the single source of truth, so - // it never drifts from what the converter honours. file:// mode shows - // no placeholder (conversion is server-only). - fmTextarea.placeholder = ''; - applyFrontMatterPlaceholder(fmTextarea); - fmBody.appendChild(fmTextarea); + // CodeMirror YAML editor host — mounted with the front-matter value + // once it's computed (sync-on-open) below. Same editor family as the + // .zddc previewer: syntax highlighting, line numbers, lint gutter. + var fmEditorHost = document.createElement('div'); + fmEditorHost.className = 'md-fm__editor'; + fmBody.appendChild(fmEditorHost); + // Recognised-keys hint (server mode): a greyed caption under the header + // whose tooltip carries the full "key: # hint" template from + // /.api/frontmatter. Replaces the old textarea placeholder. + var fmHint = document.createElement('div'); + fmHint.className = 'md-fm__hint'; + fmHint.style.display = 'none'; + applyFrontMatterHint(fmHint); // Rename cue: shown when the author edits an identity field // (tracking_number / revision / status / title) away from the // filename. The filename owns identity, so the cue offers an explicit @@ -10380,12 +11333,16 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr // discarding the value. Populated by renderIdentityCue(). var fmWarn = document.createElement('div'); fmWarn.className = 'md-fm__warn'; - fmWarn.hidden = true; + // Visibility is controlled via style.display (toggled in + // renderIdentityCue), NOT the `hidden` attribute: an inline + // display:flex outranks [hidden]{display:none}, which would leave an + // empty box on screen whenever the cue has nothing to say. fmWarn.style.cssText = 'color:#92400e;background:#fffbeb;border:1px solid ' + '#fcd34d;border-radius:4px;padding:6px 8px;margin:0 0 4px;font-size:' - + '0.78rem;line-height:1.5;display:flex;flex-wrap:wrap;align-items:' - + 'center;gap:6px;'; + + '0.78rem;line-height:1.5;flex-wrap:wrap;align-items:center;gap:6px;' + + 'display:none;'; fmSection.appendChild(fmHeader); + fmSection.appendChild(fmHint); fmSection.appendChild(fmWarn); fmSection.appendChild(fmBody); sidebar.appendChild(fmSection); @@ -10530,21 +11487,59 @@ var e=function(t,n){return e=Object.setPrototypeOf||{__proto__:[]}instanceof Arr // even if we tweak whitespace in the YAML lines. var initialParsed = parseFrontMatter(text); var bodyText = initialParsed.body; - // On open, mirror the filename-derived identity into the front matter - // (the filename is the single source of truth; this keeps the values - // baked in for the converter). No-op for non-ZDDC filenames. The dirty + // On open, RECONCILE existing front-matter identity keys with the + // filename (the single source of truth) — but never ADD them. A blank + // or new file opens blank (we don't inject a title etc.); a file whose + // author already wrote a now-stale title/revision/… gets corrected. + // The converter derives identity from the filename regardless, so + // there's nothing to "bake in" for an empty front matter. The dirty // baseline stays the ON-DISK state, so a correction opens the buffer // dirty and a save persists it. var onDiskFM = stringifyFrontMatter(initialParsed.data); var fid = filenameIdentity(node.name); if (fid) { for (var ik in fid) { - if (Object.prototype.hasOwnProperty.call(fid, ik)) initialParsed.data[ik] = fid[ik]; + if (Object.prototype.hasOwnProperty.call(fid, ik) + && Object.prototype.hasOwnProperty.call(initialParsed.data, ik)) { + initialParsed.data[ik] = fid[ik]; + } } } - fmTextarea.value = stringifyFrontMatter(initialParsed.data); + var syncedFM = stringifyFrontMatter(initialParsed.data); var initialHash = await hashContent(assembleContent(onDiskFM, bodyText)); var writableMode = canSave(node); + + // Front-matter YAML editor — CodeMirror, the same editor family as the + // .zddc previewer (syntax highlighting, line numbers, shared js-yaml + // lint gutter). Replaces the old