diff --git a/ui/builder.html b/ui/builder.html index b3f3275..5d66cdd 100644 --- a/ui/builder.html +++ b/ui/builder.html @@ -105,8 +105,8 @@ input,textarea,button,select{font-family:inherit} .npl-inp:disabled{background:var(--surface-alt);color:var(--muted)} .opt-hint{font-size:10px;color:var(--muted)} -/* ── 구분자 설정 바 ───────────────────────── */ -.sep-bar{background:var(--surface-alt);border:1px solid var(--border);border-radius:5px;padding:5px 8px;display:flex;flex-direction:column;gap:4px} +/* ── 구분자/이름줄바꿈 설정 (노드 설정 내부) ─ */ +.struct-sep{display:flex;flex-direction:column;gap:4px;padding-bottom:6px;margin-bottom:6px;border-bottom:1px dashed var(--border)} .sep-bar-row{display:flex;align-items:center;gap:5px} .sep-bar-lbl{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.05em;color:var(--muted);width:52px;flex-shrink:0} @@ -283,7 +283,7 @@ function uid(){ return Math.random().toString(36).slice(2,9) } function mkNode(mark='', content=''){ return { id:uid(), mark, content, hidden:false, values:[], settings:{}, - nextSep:'blank', childSep:'blank' }; + nextSep:'blank', childSep:'blank', nameNewline:true }; } function mkListVal(names='', category=''){ return { id:uid(), type:'list', names, sep:' ', namesPerLine:0, category }; @@ -332,8 +332,9 @@ function load(){ } function normalizeNode(n){ - if(n.nextSep===undefined) n.nextSep='blank'; - if(n.childSep===undefined) n.childSep='blank'; + if(n.nextSep===undefined) n.nextSep='blank'; + if(n.childSep===undefined) n.childSep='blank'; + if(n.nameNewline===undefined) n.nameNewline=true; for(const v of n.values||[]) if(v.type==='node') normalizeNode(v.node); } function normalizeState(s){ @@ -523,7 +524,6 @@ function renderNode(node, nested){ ${!node.hidden?`
- ${renderSepBar(node)}
@@ -547,12 +547,12 @@ function renderNode(node, nested){ onchange="addSetting('${node.id}',this.value);this.selectedIndex=0"> ${setOpts} - ` - :`모두 설정됨`} + `:''} +
+
+ ${renderStructSettings(node)} + ${settingItems}
- ${settingItems - ?`
${settingItems}
` - :'
기본값 사용
'}
`:''} `; @@ -653,16 +653,28 @@ function renderSepChips(nid, field, current){ style="width:56px">`; } -function renderSepBar(node){ +function setNameNL(nid, val){ + const n=nodeMap[nid]; if(!n) return; + n.nameNewline=val; refresh(); +} + +function renderStructSettings(node){ + const nid=node.id; + const nl=node.nameNewline??true; return ` -
+
다음 노드 - ${renderSepChips(node.id,'nextSep', node.nextSep??'blank')} + ${renderSepChips(nid,'nextSep', node.nextSep??'blank')}
하위 노드 - ${renderSepChips(node.id,'childSep', node.childSep??'blank')} + ${renderSepChips(nid,'childSep', node.childSep??'blank')} +
+
+ 이름 뒤 + 줄바꿈 + 없음
`; } @@ -724,8 +736,10 @@ function toText(){ // 노드 하나를 문자열로 렌더링 function rNode(node){ let t=`${node.mark??''}${node.content||''}`; - let pendingSep=null; // 다음 child node 앞에 붙일 구분자 + const nl=(node.nameNewline??true)?'\n':''; // 이름 뒤 줄바꿈 여부 + let pendingSep=null; let prevWasList=false; + let firstContent=true; // 첫 번째 list/scalar 여부 (nameNewline 적용 대상) for(let i=0;i(j===0?pre:'')+n).join('\n'); else if(npl>0) lt=Array.from({length:Math.ceil(ns.length/npl)},(_,j)=>(j===0?pre:'')+ns.slice(j*npl,(j+1)*npl).join(lsep)).join('\n'); else lt=pre+ns.join(lsep); - t+='\n'+lt+'\n'; // list는 항상 줄 단위 - prevWasList=true; - pendingSep=null; + const pre2=firstContent?nl:'\n'; // 첫 list만 nameNewline 적용 + t+=pre2+lt+'\n'; + prevWasList=true; pendingSep=null; firstContent=false; } else if(v.type==='node'){ - // 이 child node 앞에 붙일 구분자 결정 if(!prevWasList){ t+=(pendingSep!==null) ? pendingSep : ss(node.childSep??'blank'); } t+=rNode(v.node); - prevWasList=false; - // 다음 형제가 노드면 nextSep을 예약 + prevWasList=false; firstContent=false; pendingSep=(nextV&&nextV.type==='node') ? ss(v.node.nextSep??'blank') : null; } else { - if(v.data) t+='\n'+String(v.data); - prevWasList=false; - pendingSep=null; + if(v.data){ + const pre2=firstContent?nl:'\n'; + t+=pre2+String(v.data); + firstContent=false; + } + prevWasList=false; pendingSep=null; } } return t;