From b9bb5426fc78af77f1ecd6711776fa179d3cc093 Mon Sep 17 00:00:00 2001 From: GB <12993901+grub-basket@users.noreply.github.com> Date: Sun, 19 Jul 2026 20:45:04 -0700 Subject: [PATCH] 0.188.1: copy commands prefix task checkboxes + color/alias metadata; tight task-list copy --- main.js | 13 ++++++++----- manifest.json | 2 +- package.json | 2 +- release-notes/0.188.0.md | 16 ++++++++++++++++ release-notes/0.188.1.md | 8 ++++++++ src/commands/clipboard-cmds.ts | 28 ++++++++++++++++++++++++---- src/view.ts | 24 ++++++++++++++++++++++++ 7 files changed, 82 insertions(+), 11 deletions(-) create mode 100644 release-notes/0.188.0.md create mode 100644 release-notes/0.188.1.md diff --git a/main.js b/main.js index e25692e..8433e30 100644 --- a/main.js +++ b/main.js @@ -32,14 +32,17 @@ `)}renderSuggestion(e,t){if(t.addClass("stashpad-suggest-item"),e.kind==="create"){t.createDiv({cls:"stashpad-suggest-create",text:e.label});return}if(e.kind==="folder-open"){t.addClass("is-folder-open"),t.createDiv({cls:"stashpad-suggest-title",text:e.label}),e.folder?t.createDiv({cls:"stashpad-suggest-preview",text:e.folder}):t.createDiv({cls:"stashpad-suggest-preview",text:"Click to choose a folder\u2026"});return}if(e.kind==="search-excluded"){t.addClass("is-search-excluded");let f=t.createDiv({cls:"stashpad-suggest-title stashpad-search-excluded-row"}),u=f.createSpan({cls:"stashpad-search-excluded-icon"});(0,Ie.setIcon)(u,"folder-search"),f.createSpan({text:e.label}),t.createDiv({cls:"stashpad-suggest-preview",text:"Include folders you've excluded from search (e.g. to move a note there)."});return}if(e.locked){t.addClass("stashpad-suggest-row","is-locked");let f=t.createDiv({cls:"stashpad-suggest-body"}),u=f.createDiv({cls:"stashpad-suggest-title stashpad-suggest-locked"});(0,Ie.setIcon)(u.createSpan({cls:"stashpad-suggest-locked-icon"}),"lock");let g=na(this.inputEl?.value??"").text;this.highlightInto(u.createSpan(),e.label,g),f.createDiv({cls:"stashpad-suggest-preview",text:e.locked.count>1?`${e.locked.count} notes \xB7 locked`:"Encrypted \u2014 locked"});return}e.crossFolder&&t.addClass("is-cross-folder"),t.addClass("stashpad-suggest-row");let i=t.createDiv({cls:"stashpad-suggest-body"}),s=this.notes.find(f=>e.crossFolder?f.cross?.folder===e.crossFolder&&f.cross?.id===e.crossId:f.node?.id===e.id),n=na(this.inputEl?.value??"").text,o=this.firstLineOfBody(s?.body??"")||e.label.trim(),a=i.createDiv({cls:"stashpad-suggest-title"});this.highlightInto(a,o,n);let l=e.crossFolder??this.opts.localFolder??null;if(e.bodyPreview&&e.matchLine!=null&&e.matchLine>=0){let f=i.createDiv({cls:"stashpad-suggest-preview stashpad-suggest-snippet"});this.highlightInto(f,e.bodyPreview,n)}let c="";if(e.crossFolder?c=s?.cross?.parentBlurb??"":c=this.parentBlurbFor(e.node),c){let f=i.createDiv({cls:"stashpad-suggest-preview"});f.appendText("Parent: "),this.highlightInto(f,c,n)}let A=e.crossFolder?this.buildCrossBreadcrumb(e):this.buildLocalBreadcrumb(e.node),h=e.crossFolder??this.opts.localFolder??null;if(h||A){let f=i.createDiv({cls:"stashpad-suggest-breadcrumb"}),g=[h?h.split("/").pop()||h:"",A].filter(I=>I&&I.length>0).join(" \u203A ");g&&f.setText(g)}let p=s?this.createdMsFor(s):null;if(p!=null||l){let f=t.createDiv({cls:"stashpad-suggest-rail"});if(p!=null){let u=f.createDiv({cls:"stashpad-suggest-time"});u.setText(this.formatRelativeTime(p)),u.title=ye(p).format("YYYY-MM-DD HH:mm")}l&&f.createDiv({cls:"stashpad-suggest-folder-badge",text:l.split("/").pop()||l})}}formatRelativeTime(e){let t=ye(e),i=ye().startOf("day").diff(ye(e).startOf("day"),"days");return i===0?t.format("h:mm a"):i===1?"yesterday":i>1&&i<7?`${i}d ago`:i>=7&&i<30?`${Math.floor(i/7)}w ago`:i>=30&&i<365?t.format("MMM D"):t.format("MMM D, YYYY")}highlightInto(e,t,i){if(!t)return;let s=i.filter(c=>c&&c.length>0);if(!s.length){e.appendText(t);return}let n=t.toLowerCase(),o=[];for(let c of s){let A=0;for(;(A=n.indexOf(c,A))!==-1;)o.push([A,A+c.length]),A+=1}if(!o.length){e.appendText(t);return}o.sort((c,A)=>c[0]-A[0]);let a=[];for(let c of o){let A=a[a.length-1];A&&c[0]<=A[1]?A[1]=Math.max(A[1],c[1]):a.push([c[0],c[1]])}let l=0;for(let[c,A]of a)c>l&&e.appendText(t.slice(l,c)),e.createSpan({cls:"stashpad-suggest-match",text:t.slice(c,A)}),l=A;ls.node?.id===t.id);return i?this.firstLineOfBody(i.body):""}onOpen(){if(super.onOpen(),this.opts.showFilterChips&&!Ie.Platform.isMobile){let e=this.inputEl,t=this.resultContainerEl;if(!e||!t)return;this.mountFilterChipRow(e,t);return}if(Ie.Platform.isMobile){let e=this.inputEl;e&&e.focus()}}mountFilterChipRow(e,t){e.addEventListener("keydown",c=>{if(c.key==="["){c.preventDefault();let A=e.selectionStart??e.value.length,h=e.selectionEnd??A,p=e.value.slice(0,A),f=e.value.slice(A,h),u=e.value.slice(h);e.value=`${p}[${f}]${u}`;let g=A+1+f.length;e.setSelectionRange(g,g),e.dispatchEvent(new Event("input",{bubbles:!0}));return}if(c.key==="]"){let A=e.selectionStart??-1;A>=0&&e.value[A]==="]"&&(c.preventDefault(),e.setSelectionRange(A+1,A+1));return}if(c.key==="Backspace"&&!c.metaKey&&!c.ctrlKey&&!c.altKey&&e.selectionStart===e.selectionEnd){let A=e.selectionStart??-1;if(A>0&&e.value[A-1]==="["&&e.value[A]==="]"){c.preventDefault();let h=e.value.slice(0,A-1),p=e.value.slice(A+1);e.value=`${h}${p}`,e.setSelectionRange(A-1,A-1),e.dispatchEvent(new Event("input",{bubbles:!0}))}}});let i=document.createElement("div");i.className="stashpad-search-filter-row";let s=document.createElement("span");s.className="stashpad-search-filter-label",s.textContent="Filters:",i.appendChild(s);let n=document.createElement("button");n.className="stashpad-search-filter-chip",n.type="button",n.textContent="in:[parent note]",n.title='Insert "in:" \u2014 filter by parent note.',n.addEventListener("mousedown",c=>{c.preventDefault()}),n.addEventListener("click",c=>{c.preventDefault(),this.appendFilterToInput(e,"in","")}),n.addEventListener("keydown",c=>{(c.key==="Enter"||c.key===" ")&&(c.preventDefault(),c.stopPropagation(),n.click())}),i.appendChild(n);let o=document.createElement("button");o.className="stashpad-search-filter-chip stashpad-search-filter-when",o.type="button",o.textContent="when:[date / day / timeframe]",o.title="Open the time-filter builder (Before / On / After / Between).",o.addEventListener("mousedown",c=>{c.preventDefault()}),o.addEventListener("click",c=>{c.preventDefault(),this.toggleWhenBuilder(e,i)}),o.addEventListener("keydown",c=>{(c.key==="Enter"||c.key===" ")&&(c.preventDefault(),c.stopPropagation(),o.click())}),i.appendChild(o),t.parentElement?.insertBefore(i,t);let a=new Ie.Scope(this.scope),l=c=>{let A=document.activeElement;return A?.classList?.contains("stashpad-search-filter-chip")?(c.preventDefault(),A.click(),!1):c.key==="Enter"&&!c.isComposing?(c.preventDefault(),this.selectActiveSuggestion?.(c),!1):!0};a.register([],"Enter",l),a.register([]," ",l),a.register(["Mod"],"f",c=>{c.preventDefault();let A=this.inputEl;return A&&(A.focus(),A.select()),!1}),a.register([],"Tab",c=>{let A=this.modalEl,h=this.inputEl;if(!A)return!0;let p=Array.from(A.querySelectorAll('input, button, select, textarea, a[href], [tabindex]:not([tabindex="-1"])')).filter(g=>!g.hasAttribute("disabled")&&g.tabIndex!==-1&&g.offsetParent!==null);if(p.length===0)return!0;let f=document.activeElement,u=f?p.indexOf(f):-1;if(c.shiftKey){if(u<=0)return c.preventDefault(),p[p.length-1].focus(),!1}else if(u===p.length-1)return c.preventDefault(),(h??p[0]).focus(),!1;return!0}),this.app.keymap?.pushScope(a),this.pendingCleanups.push(()=>{try{this.app.keymap?.popScope(a)}catch{}})}appendFilterToInput(e,t,i){let s=e.value,o=`${s.length>0&&!/\s$/.test(s)?" ":""}${t}: [`,a="]",l=i;e.value=`${s}${o}${l}${a}`;let c=s.length+o.length+l.length;if(e.setSelectionRange(c,c+0),!l){let A=s.length+o.length;e.setSelectionRange(A,A)}e.focus(),e.dispatchEvent(new Event("input",{bubbles:!0}))}toggleWhenBuilder(e,t){let i=this.modalEl;if(this.whenBuilderEl){this.whenBuilderEl.remove(),this.whenBuilderEl=null,i?.removeClass("is-when-builder-open");return}i?.addClass("is-when-builder-open");let s=document.createElement("div");s.className="stashpad-when-builder";let n=document.createElement("div");n.className="stashpad-when-tabs";let o=[{id:"before",label:"Before"},{id:"on",label:"On"},{id:"after",label:"After"},{id:"between",label:"Between"}],a={};for(let g of o){let I=document.createElement("button");I.type="button",I.className="stashpad-when-tab",I.textContent=g.label,this.whenMode===g.id&&I.addClass("is-active"),I.addEventListener("mousedown",m=>m.preventDefault()),I.addEventListener("click",m=>{if(m.preventDefault(),this.whenMode===g.id)return;let C=this.whenMode;C!=="between"&&g.id==="between"?this.whenBetweenEndText="":C==="between"&&g.id!=="between"&&(!this.whenSingleText&&this.whenBetweenEndText&&(this.whenSingleText=this.whenBetweenEndText),this.whenBetweenEndText=""),this.whenMode=g.id;for(let B in a)a[B].toggleClass("is-active",B===g.id);u()}),a[g.id]=I,n.appendChild(I)}s.appendChild(n);let l=document.createElement("div");l.className="stashpad-when-body",s.appendChild(l);let c=(g,I,m="single")=>{let C=ye().format("YYYY-MM-DD"),B=!I||I===C;if(m==="betweenStart")return"00:00";if(m==="betweenEnd")return"23:59";switch(g){case"after":return"00:00";case"on":return B?ye().format("HH:mm"):"23:59";case"before":return B?ye().format("HH:mm"):"23:59";default:return"23:59"}},A=(g,I)=>{g.addEventListener("keydown",m=>{m.key==="Enter"?(m.preventDefault(),m.stopPropagation(),I()):m.key==="Escape"&&(m.preventDefault(),m.stopPropagation(),this.closeWhenBuilder())})},h=(g,I)=>{let m=g.selectionStart??g.value.length,C=g.selectionEnd??g.value.length,E=`${m>0&&!/\s$/.test(g.value.slice(0,m))?" ":""}${I}`,y=g.value.slice(0,m)+E+g.value.slice(C);g.value=y;let v=m+E.length;g.setSelectionRange(v,v),g.focus(),g.dispatchEvent(new Event("input",{bubbles:!0}))},p=(g,I)=>{let C=g.slice(0,I).match(/(\d{4}-\d{2}-\d{2})(?!.*\d{4}-\d{2}-\d{2})/);return C?C[1]:null},f=(g,I,m,C)=>{let B=l.createDiv({cls:"stashpad-when-input-wrap has-icons"}),E=B.createDiv({cls:"stashpad-when-icon-slot"}),y=E.createEl("button",{cls:"stashpad-when-icon stashpad-when-icon-cal"});y.type="button",y.title="Pick date",(0,Ie.setIcon)(y,"calendar-days");let v=E.createEl("input",{cls:"stashpad-when-native",attr:{type:"date"}});v.tabIndex=-1;let Q=B.createDiv({cls:"stashpad-when-icon-slot"}),w=Q.createEl("button",{cls:"stashpad-when-icon stashpad-when-icon-clock"});w.type="button",w.title="Pick time",(0,Ie.setIcon)(w,"clock");let F=B.createDiv({cls:"stashpad-when-icon-slot"}),D=F.createEl("button",{cls:"stashpad-when-icon stashpad-when-icon-day"});D.type="button",D.title="Pick day",(0,Ie.setIcon)(D,"calendar");let H=B.createDiv({cls:"stashpad-when-icon-slot"}),R=H.createEl("button",{cls:"stashpad-when-icon stashpad-when-icon-tf"});R.type="button",R.title="Pick timeframe",(0,Ie.setIcon)(R,"history");let L=B.createEl("input",{cls:"stashpad-when-input",attr:{type:"text",placeholder:g}});L.value=I(),L.addEventListener("input",()=>m(L.value));let x=B.createEl("button",{cls:"stashpad-when-clear"});x.type="button",x.textContent="\xD7",x.title="Clear";for(let O of[y,w,D,R,x])O.addEventListener("mousedown",K=>K.preventDefault());let U=null,T=(O,K)=>{U&&U();let $=O.createDiv({cls:"stashpad-when-popover"}),Z=O.ownerDocument??document,V=new Ie.Scope(this.scope),J=null,ee=te=>{J=te},ue=!1,oe=te=>{!$.contains(te.target)&&te.target!==O&&!O.contains(te.target)&&ie()},ie=()=>{if(!ue){ue=!0,$.remove(),Z.removeEventListener("mousedown",oe,!0);try{this.app.keymap?.popScope(V)}catch{}U===ie&&(U=null)}};U=ie,V.register([],"Escape",te=>(te.preventDefault(),ie(),!1)),V.register([],"Enter",te=>(te.preventDefault(),J&&J(),!1));try{K($,ie,ee)}catch(te){console.error("[stashpad] popover fill threw:",te),$.remove(),U=null;return}this.app.keymap?.pushScope(V),this.pendingCleanups.push(ie),setTimeout(()=>Z.addEventListener("mousedown",oe,!0),0)};R.addEventListener("click",O=>{O.preventDefault(),T(H,(K,$,Z)=>{let V=this.whenMode==="on",J=(se,Ae)=>{if(!V)return`${se}${Ae}`;let Xe={d:"days",w:"weeks",m:"months",y:"years"}[Ae];return ye().subtract(se,Xe).format("YYYY-MM-DD")},ee=K.createDiv({cls:"stashpad-when-pop-row"}),ue=[{label:"Last 7d",n:7,unit:"d"},{label:"Last 30d",n:30,unit:"d"},{label:"This week",n:1,unit:"w"},{label:"This month",n:1,unit:"m"}];for(let se of ue){let Ae=ee.createEl("button",{cls:"stashpad-when-pop-chip",text:se.label});Ae.type="button",Ae.addEventListener("mousedown",Xe=>Xe.preventDefault()),Ae.addEventListener("click",Xe=>{Xe.preventDefault(),h(L,J(se.n,se.unit)),$()})}let oe=K.createDiv({cls:"stashpad-when-pop-row stashpad-when-pop-builder"});oe.createSpan({text:"Last",cls:"stashpad-when-pop-label"});let ie=oe.createEl("input",{cls:"stashpad-when-pop-number",attr:{type:"number",min:"1",max:"999",value:"7"}}),te=oe.createEl("select",{cls:"stashpad-when-pop-unit"});for(let se of[{v:"d",label:"days"},{v:"w",label:"weeks"},{v:"m",label:"months"},{v:"y",label:"years"}]){let Ae=te.createEl("option",{text:se.label});Ae.value=se.v}let fe=oe.createEl("button",{cls:"stashpad-when-pop-chip stashpad-when-pop-go",text:"Insert"});fe.type="button";let we=()=>{let se=parseInt(ie.value,10);!Number.isFinite(se)||se<1||(h(L,J(se,te.value)),$())};fe.addEventListener("mousedown",se=>se.preventDefault()),fe.addEventListener("click",se=>{se.preventDefault(),we()}),Z(we),ie.focus(),ie.select()})});let b=(O,K,$,Z,V)=>{T(K,(J,ee,ue)=>{$s(J,{seedH:$,seedM:Z,seedPeriod:V,close:ee,setOnEnter:ue,onFinalize:oe=>h(O,nr(oe))})})};D.addEventListener("click",O=>{O.preventDefault(),T(F,(K,$,Z)=>{let V=K.createDiv({cls:"stashpad-when-pop-row"});for(let ie of["Today","Yesterday"]){let te=V.createEl("button",{cls:"stashpad-when-pop-chip",text:ie});te.type="button",te.addEventListener("mousedown",fe=>fe.preventDefault()),te.addEventListener("click",fe=>{fe.preventDefault(),h(L,ie),$()})}let J=K.createDiv({cls:"stashpad-when-pop-row stashpad-when-pop-days"}),ee=["Monday","Tuesday","Wednesday","Thursday","Friday","Saturday","Sunday"],oe=(ye().day()+6)%7;for(let ie=0;iewe.preventDefault()),fe.addEventListener("click",we=>{if(we.preventDefault(),C==="betweenEnd"){let se=ie,Ae=ye().startOf("day"),Xe=(Ae.day()+6)%7,ai=(se-Xe+7)%7;ai===0&&(ai=7);let Us=Ae.clone().add(ai,"days").format("YYYY-MM-DD");h(L,Us)}else h(L,te);$()})}})});let M=(O,K)=>{O.value||(O.value=K);let $=O;if(typeof $.showPicker=="function")try{$.showPicker();return}catch{}O.focus(),O.click()};return y.addEventListener("click",O=>{O.preventDefault(),M(v,ye().format("YYYY-MM-DD"))}),v.addEventListener("change",()=>{v.value&&h(L,v.value)}),w.addEventListener("click",O=>{O.preventDefault();let K=L.selectionStart??L.value.length,$=p(L.value,K),Z=c(this.whenMode,$,C),[V,J]=Z.split(":"),ee=parseInt(V,10),ue=parseInt(J,10),oe=ee%12;oe===0&&(oe=12);let ie=ee>=12?"pm":"am";b(L,Q,oe,ue,ie)}),x.addEventListener("click",O=>{O.preventDefault(),L.value="",m(""),L.focus()}),L},u=()=>{if(l.empty(),this.whenMode==="between"){let g=f("start (date / day / timeframe)",()=>this.whenSingleText,y=>{this.whenSingleText=y},"betweenStart"),I=f("end (date / day / timeframe)",()=>this.whenBetweenEndText,y=>{this.whenBetweenEndText=y},"betweenEnd"),m=l.createDiv({cls:"stashpad-when-actions"}),C=m.createEl("button",{cls:"stashpad-when-insert",text:"Insert"});C.type="button",C.addEventListener("mousedown",y=>y.preventDefault());let B=()=>{let y=g.value.trim(),v=I.value.trim();y&&this.appendFilterToInput(e,"after",y),v&&this.appendFilterToInput(e,"before",v),this.closeWhenBuilder()};C.addEventListener("click",y=>{y.preventDefault(),B()});let E=m.createEl("button",{cls:"stashpad-when-cancel",text:"Cancel"});E.type="button",E.addEventListener("mousedown",y=>y.preventDefault()),E.addEventListener("click",y=>{y.preventDefault(),this.closeWhenBuilder()}),A(g,B),A(I,B),g.focus(),g.setSelectionRange(g.value.length,g.value.length)}else{let g=f("date / day / timeframe",()=>this.whenSingleText,E=>{this.whenSingleText=E},"single"),I=l.createDiv({cls:"stashpad-when-actions"}),m=I.createEl("button",{cls:"stashpad-when-insert",text:"Insert"});m.type="button",m.addEventListener("mousedown",E=>E.preventDefault());let C=()=>{let E=g.value.trim();E&&this.appendFilterToInput(e,this.whenMode,E),this.closeWhenBuilder()};m.addEventListener("click",E=>{E.preventDefault(),C()});let B=I.createEl("button",{cls:"stashpad-when-cancel",text:"Cancel"});B.type="button",B.addEventListener("mousedown",E=>E.preventDefault()),B.addEventListener("click",E=>{E.preventDefault(),this.closeWhenBuilder()}),A(g,C),g.focus(),g.setSelectionRange(g.value.length,g.value.length)}};u(),t.parentElement?.insertBefore(s,t.nextSibling),this.whenBuilderEl=s}closeWhenBuilder(){if(!this.whenBuilderEl)return;this.whenBuilderEl.remove(),this.whenBuilderEl=null,this.modalEl?.removeClass("is-when-builder-open")}selectSuggestion(e,t){if(e&&e.kind==="search-excluded"){this.loadExcludedNotes();return}super.selectSuggestion(e,t)}onChooseSuggestion(e){if(e.kind==="create"&&this.opts.onCreate){let t=this.inputEl?.value??"",i=t.replace(/(?{s=!0;let f=p.split("/").pop()??p;this.opts.onPick({id:`folder:${p}`,label:`Open folder \u201C${f}\u201D in a new tab`,node:null,kind:"folder-open",folder:p})},o=new oa(this.app,t,n),a=o.onClose.bind(o),l=this.tree,c=this.titleFn,A=this.opts,h=this.app;o.onClose=()=>{a(),setTimeout(()=>{if(s)return;let p=new d(h,l,c,A);p.open(),setTimeout(()=>{let f=p.inputEl;f&&(i&&(f.value=i,f.dispatchEvent(new Event("input",{bubbles:!0}))),f.focus(),f.setSelectionRange(f.value.length,f.value.length))},0)},0)},o.open();return}if(e.node?.file&&!this.app.vault.getAbstractFileByPath(e.node.file.path)){new Ie.Notice("That note no longer exists.");return}this.opts.onPick(e)}},oa=class extends Ie.FuzzySuggestModal{constructor(e,t,i){super(e);this.folders=t;this.onChosen=i;this.setPlaceholder("Open which folder?")}getItems(){return this.folders}getItemText(e){let t=e.split("/").pop()??e;return t===e?e:`${t} \u2014 ${e}`}onChooseItem(e){this.onChosen(e)}};var ys="stashpad";function Dn(d){let r=[];d.vault&&r.push(`vault=${encodeURIComponent(d.vault)}`),r.push(`folder=${encodeURIComponent(d.folder)}`),d.note&&r.push(`note=${encodeURIComponent(d.note)}`);let e=d.run&&d.run.length?d.run:["reveal"];return r.push(`run=${encodeURIComponent(e.join(","))}`),`obsidian://${ys}?${r.join("&")}`}function Zr(d){let r=(d||"").trim();if(!r)return null;let e;if(/^obsidian:\/\//i.test(r)){let c=r.match(/^obsidian:\/\/([^?]*)(?:\?(.*))?$/i);if(!c||decodeURIComponent(c[1].replace(/\/+$/,"")).toLowerCase()!==ys)return null;e=c[2]??""}else e=r.replace(/^\?/,"");let t=new URLSearchParams(e),i=t.get("folder");if(!i)return null;let s={folder:i},n=t.get("vault");n&&(s.vault=n);let o=t.get("note");o&&(s.note=o);let a=t.get("run");a&&(s.run=a);let l=t.get("action");return l&&(s.action=l),s}function jr(d){let r=d.run;!r&&d.action&&d.action!==ys&&(r=d.action);let e=(r||"reveal").split(",").map(t=>t.trim().toLowerCase()).filter(Boolean);return e.length?e:["reveal"]}var Ge=require("obsidian");ve();async function _r(d,r,e,t){let i=e.blob,s=i.replace(/\.stashenc$/,".stashmeta"),n=d.vault.adapter,o=null,a=null;try{o=await n.readBinary(i)}catch{o=null}if(!o){new Ge.Notice("Couldn't read the encrypted file to delete it.");return}try{await n.exists(s)&&(a=await n.read(s))}catch{a=null}let l=(r.settings.lockedSubtrees??[]).find(p=>p.blob===i)??null,c=async p=>{let f=d.vault.getAbstractFileByPath(p);if(f)try{await d.fileManager.trashFile(f);return}catch{}try{await n.exists(p)&&await n.remove(p)}catch{}},A=async()=>{await c(i),await c(s),r.settings.lockedSubtrees=(r.settings.lockedSubtrees??[]).filter(p=>p.blob!==i),await r.saveSettings(),t()},h=async()=>{if(await n.writeBinary(i,o),a!=null)try{await n.write(s,a)}catch{}l&&!(r.settings.lockedSubtrees??[]).some(p=>p.blob===i)&&(r.settings.lockedSubtrees=[...r.settings.lockedSubtrees??[],l],await r.saveSettings()),t()};await A(),r.getUndoStack(e.folder).push({label:e.count>1?"Delete encrypted notes":"Delete encrypted note",undo:h,redo:A}),new Ge.Notice(e.count>1?"Encrypted notes deleted \u2014 undo to restore.":"Encrypted note deleted \u2014 undo to restore.")}function xn(d,r){let{app:e,plugin:t,descriptor:i}=r,s=p=>new Ge.Notice(`Unlock this note first to ${p}.`),n=p=>{if(Ge.Platform.isMobile)return p;try{return e.vault.adapter?.getFullPath?.(p)||p}catch{return p}},o=()=>{let p=Dn({vault:e.vault.getName(),folder:i.folder,note:i.rootId,run:["reveal"]});navigator.clipboard.writeText(p).then(()=>new Ge.Notice("Stashpad link copied."),()=>new Ge.Notice("Couldn't copy the link."))},a=()=>{d.addItem(p=>{p.setTitle("Share & export").setIcon("share-2");let f=typeof p.setSubmenu=="function"?p.setSubmenu():null;f&&typeof f.addItem=="function"?(f.addItem(u=>{u.setTitle("Copy Stashpad link").setIcon("link"),i.rootId?u.onClick(()=>o()):u.setDisabled(!0)}),f.addItem(u=>u.setTitle("Export to .stash\u2026").setIcon("package").onClick(()=>{t.exportLockedSubtree(i.blob)})),t.settings.okfEnabled&&f.addItem(u=>u.setTitle("Export as OKF\u2026").setIcon("book-marked").onClick(()=>s("export it as OKF")))):i.rootId?p.onClick(()=>o()):p.setDisabled(!0)})},l=()=>{d.addItem(p=>p.setTitle(r.unlockLabel).setIcon("unlock").onClick(()=>r.onUnlock()))},c=()=>{if(Ge.Platform.isMobile)return;let p=Ge.Platform.isMacOS?"Finder":Ge.Platform.isWin?"File Explorer":"file manager";d.addItem(f=>f.setTitle(`Show in ${p}`).setIcon("folder-search").onClick(()=>{try{let u=window.require?.("electron")?.shell,g=e.vault.adapter?.getFullPath?.(i.blob);g&&u?.showItemInFolder&&u.showItemInFolder(g)}catch(u){console.warn("[Stashpad] showItemInFolder failed",u)}}))},A=()=>{d.addItem(p=>p.setTitle("Copy encrypted file path").setIcon("copy").onClick(()=>{navigator.clipboard.writeText(n(i.blob)),new Ge.Notice("Path copied.")}))},h=()=>{d.addItem(p=>{p.setTitle(i.count>1?"Delete encrypted notes\u2026":"Delete encrypted note\u2026").setIcon("trash-2"),p.setWarning?.(!0),p.onClick(()=>{r.confirmDelete?new j(e,i.count>1?`Delete ${i.count} encrypted notes?`:"Delete encrypted note?","The encrypted file moves to Obsidian's trash (recoverable there). You'll still need your password to read it if you restore it.","Delete",async f=>{f&&await _r(e,t,i,r.onChange)}).open():_r(e,t,i,r.onChange)})})};r.fullParity?(d.addItem(p=>p.setTitle("Open in new Stashpad tab").setIcon("layout-grid").onClick(()=>s("open it in a tab"))),d.addItem(p=>p.setTitle("Open in Obsidian editor").setIcon("file-text").onClick(()=>s("open it in the editor"))),d.addItem(p=>p.setTitle("Focus in Stashpad").setIcon("arrow-right").onClick(()=>s("focus it"))),d.addSeparator(),d.addItem(p=>p.setTitle("Split note\u2026").setIcon("split").onClick(()=>s("split it"))),d.addItem(p=>p.setTitle("Copy text").setIcon("copy").onClick(()=>s("copy its text"))),d.addItem(p=>p.setTitle("Clone (duplicate / copy)").setIcon("files").onClick(()=>s("clone it"))),d.addItem(p=>p.setTitle("Fork into a separate note\u2026").setIcon("git-branch").onClick(()=>s("fork it"))),a(),l(),c(),A(),d.addSeparator(),d.addItem(p=>p.setTitle("Move to\u2026").setIcon("move").onClick(()=>s("move it"))),d.addItem(p=>p.setTitle("Move to Home").setIcon("home").onClick(()=>s("move it"))),d.addItem(p=>p.setTitle("Pin to sidebar").setIcon("pin").onClick(()=>s("pin it"))),d.addItem(p=>p.setTitle("Pin to top of list").setIcon("arrow-up-to-line").onClick(()=>s("pin it"))),d.addItem(p=>p.setTitle("Set color\u2026").setIcon("palette").onClick(()=>s("set its color"))),d.addItem(p=>p.setTitle("Task").setIcon("check-circle-2").onClick(()=>s("change its task state"))),d.addSeparator(),h()):(l(),a(),d.addSeparator(),c(),A(),d.addSeparator(),h())}var el=require("obsidian");ce();var Nn=class extends el.SuggestModal{constructor(r){super(r),this.setPlaceholder("Run a Stashpad command\u2026");let e=this.app.commands?.commands??{};this.commands=Object.keys(e).filter(t=>t.startsWith("stashpad:")).filter(t=>t!=="stashpad:stashpad-command-palette").map(t=>({id:t,name:cd(e[t]?.name??t)})).sort((t,i)=>t.name.localeCompare(i.name))}getSuggestions(r){return this.commands.filter(e=>qs(r,e.name))}renderSuggestion(r,e){e.createDiv({text:r.name,cls:"stashpad-cmd-palette-name"})}onChooseSuggestion(r){this.app.commands?.executeCommandById?.(r.id)}};function cd(d){return d.replace(/^(?:\s*Stashpad:\s*)+/i,"").trim()||d}An();ve();un();var aa=require("obsidian");function tl(d){let r=d.code||"",e=/^Key([A-Z])$/.exec(r);if(e)return e[1].toLowerCase();let t=/^Digit(\d)$/.exec(r);return t?t[1]:(d.key||"").toLowerCase()}function dd(d,r){return!r||d.metaKey||d.ctrlKey||d.altKey?!1:r.length===1&&!/[a-z0-9]/i.test(r)?d.key===r:tl(d)===r.toLowerCase()}function Hi(d,r){return r?r.includes("+")?Ad(d,r):dd(d,r):!1}function q(d,r){if(!r)return!1;let{primary:e,secondary:t,preferRight:i,useBoth:s}=r;return e&&t?s?Hi(d,e)||Hi(d,t):i?Hi(d,t):Hi(d,e):Hi(d,e)||Hi(d,t)}function ws(d){if(!d)return"";let r=aa.Platform.isMacOS;return d.split("+").map(e=>{let t=e.trim();return t?t.toLowerCase()==="mod"?r?"Cmd":"Ctrl":t.toLowerCase()==="alt"?r?"Opt":"Alt":t.length===1?t.toUpperCase():t:""}).filter(Boolean).join("+")}function Ad(d,r){if(!r)return!1;let e=r.split("+").map(h=>h.trim()).filter(Boolean);if(e.length<2)return!1;let t=e[e.length-1].toLowerCase(),i=new Set(e.slice(0,-1).map(h=>h.toLowerCase())),s=i.has("mod"),n=i.has("ctrl")||i.has("control"),o=i.has("cmd")||i.has("meta")||i.has("command"),a=i.has("alt")||i.has("option"),l=i.has("shift"),A=aa.Platform.isMacOS?d.metaKey:d.ctrlKey;return s&&!A||n&&!d.ctrlKey||o&&!d.metaKey||a!==d.altKey||l!==d.shiftKey||!s&&(!n&&d.ctrlKey||!o&&d.metaKey)?!1:tl(d)===t}var ae=require("obsidian");ce();var il=require("obsidian"),hd="byfolder";function Tn(d,r,e,t){let i=d.createDiv({cls:"stashpad-trash-modes"}),s=i.createEl("button",{cls:"stashpad-agg-reset",attr:{"aria-label":"Reset to default view"}});(0,il.setIcon)(s,"rotate-ccw"),s.onclick=()=>t(hd);let n=[{key:"byfolder",label:"By folder",count:e.total},{key:"separated",label:"Separated",count:e.total},{key:"mixed",label:"Mixed (by date)",count:e.total},{key:"encrypted",label:"Encrypted",count:e.enc},{key:"unencrypted",label:"Unencrypted",count:e.dec}];for(let o of n){let a=i.createEl("button",{cls:"stashpad-triage-chip"});r===o.key&&a.addClass("is-active"),a.createSpan({text:o.label}),a.createSpan({cls:"stashpad-triage-chip-count",text:String(o.count)}),a.onclick=()=>t(o.key)}}function yt(d,r,e,t){if(!e||e===r)return;let i=o=>{let a=!1;return d.iterateAllLeaves(l=>{l===o&&(a=!0)}),a},s=r,n=d.on("active-leaf-change",()=>{if(i(r)){s=d.activeLeaf??s;return}d.offref(n),s===r&&i(e)&&(d.setActiveLeaf(e,{focus:!0}),d.revealLeaf(e))});t?.(n)}var Mn=ae.moment,Pn=class extends ae.ItemView{constructor(e,t){super(e);this.plugin=t;this.mode="encrypted";this.taskState=mn();this.archiveSubMode="byfolder";this.renderPending=!1;this.watchFolderFilter="";this.watchViaFilter="";this.watchQuery=""}getViewType(){return ci}getDisplayText(){return this.mode==="archived"?"All archived":this.mode==="tasks"?"All tasks":this.mode==="watch"?"Previously encrypted":"All encrypted"}getIcon(){return this.mode==="archived"?"archive":this.mode==="tasks"?"check-square":this.mode==="watch"?"history":"lock"}getState(){return{...super.getState(),mode:this.mode}}async setState(e,t){(e?.mode==="archived"||e?.mode==="encrypted"||e?.mode==="tasks"||e?.mode==="watch")&&(this.mode=e.mode),await super.setState(e,t),await this.render()}async onOpen(){this.containerEl.addClass("stashpad-aggregate-view");let e=s=>s.endsWith(".stashenc")&&!s.startsWith("_deleted/"),t=s=>s.endsWith(".md")&&/(^|\/)archive\//.test(s),i=s=>e(s)||t(s);this.registerEvent(this.app.vault.on("create",s=>{i(s.path)&&this.scheduleRender()})),this.registerEvent(this.app.vault.on("delete",s=>{i(s.path)&&this.scheduleRender()})),this.registerEvent(this.app.vault.on("rename",(s,n)=>{(i(s.path)||i(n))&&this.scheduleRender()})),await this.render()}scheduleRender(){this.renderPending||(this.renderPending=!0,window.setTimeout(()=>{this.renderPending=!1,this.render()},150))}cleanFolder(e){return(e||"").replace(/\/+$/,"")}archiveFolders(){let e=new Set;for(let i of this.plugin.discoverStashpadFolders()){let s=Dt(i);this.plugin.app.vault.getAbstractFileByPath(s)&&e.add(s)}for(let i of this.plugin.settings.archiveFolders??[])e.add(this.cleanFolder(i));let t=this.plugin.settings.folderEncPrefs??{};for(let[i,s]of Object.entries(t))s?.archive&&e.add(this.cleanFolder(i));return[...e].sort((i,s)=>i.localeCompare(s))}async render(){let e=this.contentEl;e.empty(),e.addClass("stashpad-aggregate-body");let t=e.createDiv({cls:"stashpad-aggregate-header"});t.createEl("h3",{text:this.getDisplayText()});let i=t.createEl("button",{cls:"stashpad-trash-iconbtn"});if((0,ae.setIcon)(i,"refresh-cw"),i.setAttr("aria-label","Refresh"),i.onclick=()=>void this.render(),this.mode==="tasks"){Cs(e.createDiv(),this.app,this.plugin,this.taskState,{onOpen:(s,n)=>void this.plugin.revealNoteByRef(s,n)});return}if(this.mode==="archived"){this.renderArchived(e);return}if(this.mode==="watch"){this.renderWatch(e);return}this.renderEncrypted(e)}renderEncrypted(e){let t=this.plugin.settings.lockedSubtrees??[];if(t.length===0){e.createDiv({cls:"stashpad-trash-empty",text:"Nothing is encrypted yet. Lock a note or folder and it shows up here."});return}let i=new Map;for(let n of t){let o=this.cleanFolder(n.folder)||"(vault root)";(i.get(o)??i.set(o,[]).get(o)).push(n)}let s=[...i.keys()].sort((n,o)=>n.localeCompare(o));e.createDiv({cls:"stashpad-aggregate-sub",text:`${t.length} locked ${t.length===1?"item":"items"} in ${s.length} ${s.length===1?"folder":"folders"}.`});for(let n of s){let o=e.createDiv({cls:"stashpad-trash-group"}),a=o.createDiv({cls:"stashpad-trash-group-head"});(0,ae.setIcon)(a.createSpan({cls:"stashpad-trash-group-icon"}),"folder"),a.createSpan({text:n.split("/").pop()||n}),a.createSpan({cls:"stashpad-trash-group-count",text:String(i.get(n).length)});let l=a.createEl("button",{cls:"stashpad-trash-iconbtn",text:"Open"});l.onclick=()=>void this.plugin.activateViewForFolder(n);for(let c of i.get(n)){let A=o.createDiv({cls:"stashpad-trash-row"}),h=A.createDiv({cls:"stashpad-trash-row-main"});h.createSpan({cls:"stashpad-trash-title",text:c.title||"Locked note"});let p=c.created?`locked ${Mn(c.created).fromNow()}`:"locked",f=c.count>1?` \xB7 ${c.count} notes`:"";h.createSpan({cls:"stashpad-trash-sub",text:p+f});let u=A.createEl("button",{cls:"stashpad-trash-iconbtn",text:"Export"});u.setAttr("aria-label","Export to .stash (encrypted with a password you choose)"),u.onclick=()=>void this.plugin.exportLockedSubtree(c.blob);let g=A.createSpan({cls:"stashpad-aggregate-lockbadge"});(0,ae.setIcon)(g,"lock"),this.attachLockedRowMenu(A,c,{archived:!1})}}}renderArchived(e){let t=this.archiveFolders();if(t.length===0){e.createDiv({cls:"stashpad-trash-empty",text:"No archive folders yet. Toggle Archive on a folder to collect it here."});return}let i=new Set(t),s=this.plugin.settings.lockedSubtrees??[],n=new Map;for(let g of s){let I=this.cleanFolder(g.folder);i.has(I)&&(n.get(I)??n.set(I,[]).get(I)).push(g)}let o=new Map,a=0;for(let g of t){let I=this.plugin.archivedPlainNotesIn(g);o.set(g,I),a+=I.length}let l=[...n.values()].reduce((g,I)=>g+I.length,0),c=a+l,A=t.flatMap(g=>o.get(g)??[]),h=t.flatMap(g=>n.get(g)??[]);e.createDiv({cls:"stashpad-aggregate-sub",text:`${t.length} archive ${t.length===1?"folder":"folders"}, ${c} archived ${c===1?"item":"items"} (${a} plain \xB7 ${l} locked).`}),Tn(e,this.archiveSubMode,{total:c,enc:l,dec:a},g=>{this.archiveSubMode=g,this.render()});let p=this.archiveSubMode;if(p==="mixed"){let g=[];for(let m of A)g.push({ts:m.stat.mtime||0,kind:"plain",f:m});for(let m of h)g.push({ts:m.created&&Date.parse(m.created)||0,kind:"locked",e:m});g.sort((m,C)=>C.ts-m.ts);let I=e.createDiv({cls:"stashpad-trash-group"});for(let m of g)m.kind==="plain"&&m.f?this.archivePlainRow(I,m.f):m.e&&this.archiveLockedRow(I,m.e);return}if(p==="byfolder"){for(let g of t){let I=n.get(g)??[],m=o.get(g)??[],C=e.createDiv({cls:"stashpad-trash-group"}),B=C.createDiv({cls:"stashpad-trash-group-head"});(0,ae.setIcon)(B.createSpan({cls:"stashpad-trash-group-icon"}),"archive"),B.createSpan({text:g.split("/").pop()||g}),B.createSpan({cls:"stashpad-trash-group-count",text:String(I.length+m.length)});let E=B.createEl("button",{cls:"stashpad-trash-iconbtn",text:"Open"});if(E.onclick=()=>void this.plugin.activateViewForFolder(g),I.length===0&&m.length===0){C.createDiv({cls:"stashpad-trash-sub",text:"No archived items."});continue}for(let y of m)this.archivePlainRow(C,y);for(let y of I)this.archiveLockedRow(C,y)}return}let f=p!=="encrypted"&&A.length>0,u=p!=="unencrypted"&&h.length>0;if(!f&&!u){e.createDiv({cls:"stashpad-trash-empty",text:"Nothing in this view."});return}if(f){let g=e.createDiv({cls:"stashpad-trash-group"}),I=g.createDiv({cls:"stashpad-trash-group-head"});(0,ae.setIcon)(I.createSpan({cls:"stashpad-trash-group-icon"}),"file-text"),I.createSpan({text:"Plain notes"}),I.createSpan({cls:"stashpad-trash-group-count",text:String(A.length)});for(let m of A)this.archivePlainRow(g,m)}if(u){let g=e.createDiv({cls:"stashpad-trash-group"}),I=g.createDiv({cls:"stashpad-trash-group-head"});(0,ae.setIcon)(I.createSpan({cls:"stashpad-trash-group-icon"}),"lock"),I.createSpan({text:"Locked (encrypted)"}),I.createSpan({cls:"stashpad-trash-group-count",text:String(h.length)});for(let m of h)this.archiveLockedRow(g,m)}}archivePlainRow(e,t){let i=e.createDiv({cls:"stashpad-trash-row"}),s=i.createDiv({cls:"stashpad-trash-row-main"});s.createSpan({cls:"stashpad-trash-title",text:t.basename.replace(/-[a-z0-9]{4,12}$/,"").replace(/-/g," ").trim()||t.basename}),s.createSpan({cls:"stashpad-trash-sub",text:`archived ${Mn(t.stat.mtime).fromNow()}`});let n=i.createEl("button",{cls:"stashpad-trash-restore",text:"Restore"});(0,ae.setIcon)(n.createSpan({cls:"stashpad-btn-icon"}),"rotate-ccw"),n.onclick=async()=>{n.disabled=!0,await this.plugin.unarchiveNote(t)?this.render():n.disabled=!1},this.attachPlainRowMenu(i,t,n)}attachPlainRowMenu(e,t,i){let s=()=>{let o=new ae.Menu;return o.addItem(a=>a.setTitle("Open note").setIcon("file-text").onClick(()=>void this.app.workspace.getLeaf(!1).openFile(t))),o.addItem(a=>a.setTitle("Restore (un-archive)").setIcon("rotate-ccw").onClick(()=>i.click())),o.addSeparator(),ae.Platform.isMobile||o.addItem(a=>a.setTitle("Show in Finder").setIcon("folder-open").onClick(()=>{try{let l=window.require?.("electron")?.shell,c=this.app.vault.adapter?.getFullPath?.(t.path);c&&l?.showItemInFolder&&l.showItemInFolder(c)}catch(l){console.warn("[Stashpad] showItemInFolder failed",l)}})),o.addItem(a=>a.setTitle("Copy file path").setIcon("copy").onClick(()=>{let l=t.path;if(!ae.Platform.isMobile)try{l=this.app.vault.adapter?.getFullPath?.(t.path)||t.path}catch{}navigator.clipboard.writeText(l),new ae.Notice("Path copied.")})),o};e.oncontextmenu=o=>{o.preventDefault(),s().showAtMouseEvent(o)};let n=e.createEl("button",{cls:"stashpad-trash-iconbtn stashpad-agg-more"});(0,ae.setIcon)(n,"ellipsis-vertical"),n.setAttr("aria-label","More actions"),n.onclick=o=>{o.stopPropagation(),s().showAtMouseEvent(o)}}archiveLockedRow(e,t){let i=e.createDiv({cls:"stashpad-trash-row"}),s=i.createDiv({cls:"stashpad-trash-row-main"});s.createSpan({cls:"stashpad-trash-title",text:t.title||"Locked note"});let n=t.created?`archived ${Mn(t.created).fromNow()}`:"archived",o=(t.count??0)>1?` \xB7 ${t.count} notes`:"";s.createSpan({cls:"stashpad-trash-sub",text:n+o});let a=i.createEl("button",{cls:"stashpad-trash-restore",text:"Restore"});(0,ae.setIcon)(a.createSpan({cls:"stashpad-btn-icon"}),"rotate-ccw"),a.setAttr("aria-label","Unlock and restore (needs the password)"),a.onclick=async()=>{a.disabled=!0;let A=t.blob.split("/"),h=A.lastIndexOf("archive"),p=h>0?A.slice(0,h).join("/"):void 0;await this.plugin.unlockBundleAt(t.blob,p?{destFolder:p}:{})?this.render():a.disabled=!1};let l=i.createEl("button",{cls:"stashpad-trash-iconbtn",text:"Export"});l.setAttr("aria-label","Export to .stash (encrypted with a password you choose)"),l.onclick=()=>void this.plugin.exportLockedSubtree(t.blob);let c=i.createSpan({cls:"stashpad-aggregate-lockbadge"});(0,ae.setIcon)(c,"lock"),this.attachLockedRowMenu(i,t,{archived:!0})}attachLockedRowMenu(e,t,i){let s=()=>{let o=new ae.Menu;return xn(o,{app:this.app,plugin:this.plugin,descriptor:{blob:t.blob,rootId:t.rootId,count:t.count??1,folder:this.cleanFolder(t.folder)},unlockLabel:i.archived?"Unlock & restore":"Decrypt (unlock)",onUnlock:async()=>{let a;if(i.archived){let c=t.blob.split("/"),A=c.lastIndexOf("archive");a=A>0?c.slice(0,A).join("/"):void 0}await this.plugin.unlockBundleAt(t.blob,a?{destFolder:a}:{})&&this.render()},onChange:()=>void this.render(),fullParity:!1,confirmDelete:!1}),o};e.oncontextmenu=o=>{o.preventDefault(),s().showAtMouseEvent(o)};let n=e.createEl("button",{cls:"stashpad-trash-iconbtn stashpad-agg-more"});(0,ae.setIcon)(n,"ellipsis-vertical"),n.setAttr("aria-label","More actions"),n.onclick=o=>{o.stopPropagation(),s().showAtMouseEvent(o)}}renderWatch(e){this.plugin.pruneReEncryptWatch()&&this.plugin.saveSettings();let t=this.plugin.settings.reEncryptWatch??[],i=t.filter(g=>!g.removed),s=t.filter(g=>g.removed);if(t.length===0){e.createDiv({cls:"stashpad-trash-empty",text:"Nothing here yet. When you unlock an encrypted note (or restore one from the trash), it shows up here so you can re-encrypt it later."});return}let n=e.createDiv({cls:"stashpad-trash-modes"}),o=n.createEl("select",{cls:"dropdown"});o.createEl("option",{value:"",text:"All folders"});for(let g of[...new Set(i.map(I=>I.folder))].sort())o.createEl("option",{value:g,text:g});o.value=this.watchFolderFilter,o.onchange=()=>{this.watchFolderFilter=o.value,this.render()};let a=n.createEl("select",{cls:"dropdown"});a.createEl("option",{value:"",text:"Unlocked + restored"}),a.createEl("option",{value:"unlock",text:"Unlocked"}),a.createEl("option",{value:"restore",text:"Restored from trash"}),a.value=this.watchViaFilter,a.onchange=()=>{this.watchViaFilter=a.value,this.render()};let l=n.createEl("input",{type:"text",attr:{placeholder:"Search\u2026"}});l.value=this.watchQuery,l.oninput=()=>{this.watchQuery=l.value,u()};let c=(g,I)=>g.toLowerCase().split(/\s+/).filter(Boolean).every(m=>I.toLowerCase().includes(m)),A=g=>(!this.watchFolderFilter||g.folder===this.watchFolderFilter)&&(!this.watchViaFilter||g.via===this.watchViaFilter)&&(!this.watchQuery.trim()||c(this.watchQuery,`${g.title} ${g.folder}`)),h=async()=>{await this.plugin.saveSettings(),this.render()},p=(g,I,m)=>{let C=g.createDiv({cls:"stashpad-trash-row"}),B=C.createDiv({cls:"stashpad-trash-row-main"});B.createSpan({cls:"stashpad-trash-title",text:this.plugin.reEncryptDisplayTitle(I)});let E=Mn(I.unlockedAt).fromNow(),y=I.count>1?` \xB7 ${I.count} notes`:"";if(B.createSpan({cls:"stashpad-trash-sub",text:`${I.via==="restore"?"restored":"unlocked"} ${E} \xB7 ${I.folder.split("/").pop()||I.folder}${y}`}),m){let v=C.createEl("button",{cls:"stashpad-trash-iconbtn",text:"Un-remove"});v.onclick=()=>{delete I.removed,delete I.removedAt,h()}}else{let v=C.createEl("button",{cls:"stashpad-trash-restore",text:"Re-encrypt"});(0,ae.setIcon)(v.createSpan({cls:"stashpad-btn-icon"}),"lock"),v.onclick=async()=>{v.disabled=!0,await this.plugin.lockNoteSubtree(I.folder,I.rootId,null,{})||(v.disabled=!1),this.render()};let Q=C.createEl("input",{type:"number",cls:"stashpad-watch-peek",attr:{placeholder:"auto",title:"Auto re-encrypt after N idle minutes (blank = folder/global default, 0 = off)",min:"0"}});Q.value=I.peekMin==null?"":String(I.peekMin),Q.onchange=()=>{let F=Q.value.trim(),D=Number(F);if(F==="")delete I.peekMin;else if(Number.isFinite(D)&&D>=0)I.peekMin=Math.floor(D);else{Q.value=I.peekMin==null?"":String(I.peekMin);return}this.plugin.saveSettings()};let w=C.createEl("button",{cls:"stashpad-trash-iconbtn"});(0,ae.setIcon)(w,"x"),w.setAttr("aria-label","Remove from watchlist (recoverable below)"),w.onclick=()=>{I.removed=!0,I.removedAt=new Date().toISOString(),h()}}},f=e.createDiv(),u=()=>{f.empty();let g=i.filter(A).sort((C,B)=>(B.unlockedAt||"").localeCompare(C.unlockedAt||"")),I=f.createDiv({cls:"stashpad-trash-group-head"});if((0,ae.setIcon)(I.createSpan({cls:"stashpad-trash-group-icon"}),"history"),I.createSpan({text:"Watching"}),I.createSpan({cls:"stashpad-trash-group-count",text:String(g.length)}),i.length>0){let C=I.createEl("button",{cls:"stashpad-trash-iconbtn",text:"Re-encrypt all applicable"});C.onclick=()=>void this.plugin.encryptEverythingApplicable()}g.length===0&&f.createDiv({cls:"stashpad-trash-sub",text:i.length?"No matches for the current filters.":"Nothing being watched."});let m=f.createDiv({cls:"stashpad-trash-group"});for(let C of g)p(m,C,!1);if(s.length>0){let C=f.createEl("details",{cls:"stashpad-watch-removed"});C.createEl("summary",{text:`Removed from watchlist (${s.length})`});let B=C.createDiv({cls:"stashpad-trash-group"});for(let E of s.filter(A))p(B,E,!0)}};u()}async onClose(){this.contentEl.empty()}};async function He(d,r){let{workspace:e}=d.app,t=e.getLeavesOfType(ci).find(n=>n.getViewState()?.state?.mode===r);if(t){e.revealLeaf(t);return}let i=e.getMostRecentLeaf(),s=e.getLeaf("tab");await s.setViewState({type:ci,active:!0,state:{mode:r}}),e.revealLeaf(s),yt(e,s,i,n=>d.registerEvent(n))}var ti=require("obsidian");ve();var Oe=class Oe{constructor(r){this.host=r;this.knownBodies=new Map;this.contribTimers=new Map;this.recentSelfWrites=new Map;this.lastExternalModify=new Map}dispose(){for(let r of this.contribTimers.values())clearTimeout(r);this.contribTimers.clear(),this.knownBodies.clear(),this.recentSelfWrites.clear(),this.lastExternalModify.clear()}currentAuthorLink(){let r=(this.host.plugin.settings.authorName??"").trim(),e=(this.host.plugin.settings.authorId??"").trim();if(!r||!e)return null;let t=r.replace(/[^\w\- ]+/g,"").trim().replace(/\s+/g,"-")||"author",i=`${this.host.noteFolder}/_authors/${t}-${e}.md`,s=r.replace(/[\[\]|]/g,"").trim()||t;return{link:`[[${i}|${s}]]`,path:i,name:r,id:e}}claimSelectedAsAuthor(){this.claimAuthorship({scope:"selection",contributorMode:!1})}claimFolderAsAuthor(){this.claimAuthorship({scope:"folder",contributorMode:!1})}claimSelectedWithContributor(){this.claimAuthorship({scope:"selection",contributorMode:!0})}claimFolderWithContributor(){this.claimAuthorship({scope:"folder",contributorMode:!0})}fileBackedNotesInFolder(){let r=this.host.noteFolder.replace(/\/+$/,"");return this.host.app.vault.getMarkdownFiles().filter(e=>{let t=e.parent?.path?.replace(/\/+$/,"")??"";if(t!==r&&!t.startsWith(r+"/")||e.path.includes("/_authors/"))return!1;let i=this.host.app.metadataCache.getFileCache(e)?.frontmatter;return typeof i?.id=="string"&&!!i.id})}async pacedFrontmatter(r,e){for(let s=0;se(o,r[s]))}catch(o){console.warn("[Stashpad] claim: frontmatter write failed",r[s],o)}}(s+1)%25===0&&await new Promise(o=>setTimeout(o,30))}}async claimAuthorship(r){let e=this.currentAuthorLink();if(!e){new ti.Notice("Set your author name in Stashpad settings first.");return}let t=`-${e.id}`,i=r.scope==="selection"?this.host.getActionTargets().map(p=>p.file).filter(p=>!!p):this.fileBackedNotesInFolder();if(i.length===0){new ti.Notice(r.scope==="selection"?"No notes selected.":"No notes in this folder.");return}let s=[],n=[];for(let p of i){let f=this.host.app.metadataCache.getFileCache(p)?.frontmatter,u=typeof f?.author=="string"?f.author:"";if(!u.trim()){s.push(p.path);continue}if(u.includes(t)||!r.contributorMode)continue;(Array.isArray(f?.contributors)?f.contributors.filter(I=>typeof I=="string"):[]).some(I=>I.includes(t))||n.push(p.path)}let o=s.length+n.length;if(o===0){new ti.Notice("Nothing to claim \u2014 those notes are already authored by you.");return}if(r.scope==="folder"){let p=[`Stamp yourself as author on ${s.length} unauthored note(s)`];if(n.length&&p.push(`and as a contributor on ${n.length} already-authored note(s)`),!await new Promise(u=>{new j(this.host.app,"Claim authorship",`${p.join(" ")}? Existing authors are never overwritten. This can be undone.`,"Claim",u).open()}))return}let a=this.host.noteFolder,l=e.link,c=new Set,A=async()=>{await this.pacedFrontmatter(s,(p,f)=>{typeof p.author=="string"&&p.author.trim()||(p.author=l),Array.isArray(p.contributors)&&p.contributors.some(u=>typeof u=="string"&&u.includes(t))&&(p.contributors=p.contributors.filter(u=>!(typeof u=="string"&&u.includes(t))),c.add(f))}),await this.pacedFrontmatter(n,p=>{let f=Array.isArray(p.contributors)?p.contributors.filter(u=>typeof u=="string"):[];f.some(u=>u.includes(t))||f.push(l),p.contributors=f})};this.ensureAuthorFile(e),await A(),this.host.plugin.getUndoStack(a).push({label:`Claim authorship (${o} note${o===1?"":"s"})`,undo:async()=>{await this.pacedFrontmatter(s,(p,f)=>{if(typeof p.author=="string"&&p.author.includes(t)&&delete p.author,c.has(f)){let u=Array.isArray(p.contributors)?p.contributors.filter(g=>typeof g=="string"):[];u.some(g=>g.includes(t))||u.push(l),p.contributors=u}}),await this.pacedFrontmatter(n,p=>{Array.isArray(p.contributors)&&(p.contributors=p.contributors.filter(f=>!(typeof f=="string"&&f.includes(t))))}),this.host.debouncedRender()},redo:async()=>{c.clear(),await A(),this.host.debouncedRender()}});let h=[];s.length&&h.push(`authored ${s.length}`),n.length&&h.push(`contributing to ${n.length}`),new ti.Notice(`Claimed authorship: ${h.join(", ")}. Undo available.`),this.host.debouncedRender()}async ensureAuthorFile(r){try{r.id&&this.host.plugin.authorRegistry.record({id:r.id,name:r.name});let e=`${this.host.noteFolder}/_authors`;if(await this.host.ensureFolder(e),await this.host.app.vault.adapter.exists(r.path))return;let t=r.id===(this.host.plugin.settings.authorId??"").trim(),i=this.host.plugin.buildAuthorStub({id:r.id,name:r.name,role:t?this.host.plugin.settings.authorRole:void 0,department:t?this.host.plugin.settings.authorDepartment:void 0},new Date().toISOString());await this.host.app.vault.create(r.path,i)}catch(e){console.warn("[Stashpad] ensureAuthorFile failed",e)}}collectAuthorIds(r){let e=new Set,t=i=>{if(typeof i!="string")return null;let s=i.match(/-([a-z0-9]{4,12})(?:\.md)?(?:\||\]\])/i);return s?s[1]:null};for(let i of r){if(!i.file)continue;let s=this.host.app.metadataCache.getFileCache(i.file)?.frontmatter;if(!s)continue;let n=t(s.author);if(n&&e.add(n),Array.isArray(s.contributors))for(let o of s.contributors){let a=t(o);a&&e.add(a)}}return Array.from(e)}pruneContribMaps(){let r=Date.now(),e=Oe.EXTERNAL_WRITE_GRACE_MS*20,t=Oe.EXTERNAL_QUIESCENCE_MS*12;for(let[i,s]of this.recentSelfWrites)r-s>e&&this.recentSelfWrites.delete(i);for(let[i,s]of this.lastExternalModify)r-s>t&&this.lastExternalModify.delete(i);if(this.knownBodies.size>64)for(let i of this.knownBodies.keys())this.host.tree.idForPath(i)||this.knownBodies.delete(i)}noteModify(r){let e=Date.now(),t=this.recentSelfWrites.get(r.path);t!==void 0&&e-t{if(this.contribTimers.delete(r.path),this.isFileActivelyEdited(r)){this.scheduleContribution(r);return}let n=this.lastExternalModify.get(r.path);if(n!==void 0&&Date.now()-n{o.modified=n;let a=typeof o.author=="string"?o.author:"",l=Array.isArray(o.contributors)?o.contributors.filter(p=>typeof p=="string"):[],c=`-${s.id}`,A=a.includes(c),h=l.some(p=>p.includes(c));!A&&!h&&l.push(s.link),o.contributors=l})}catch(o){console.warn("[Stashpad] maybeRecordContribution failed",o)}}};Oe.CONTRIB_DEBOUNCE_MS=4e3,Oe.CONTRIB_ACTIVE_EDITOR_BONUS_MS=2e3,Oe.EXTERNAL_WRITE_GRACE_MS=1500,Oe.EXTERNAL_QUIESCENCE_MS=5e3;var Hn=Oe;var Rn=class{constructor(r){this.host=r;this.dragSourceIds=null;this.dragPlaceholder=null;this.dragRowHeight=0}attachRowDnD(r,e,t){r.addEventListener("dragstart",i=>{let s=this.host.selection.has(e.id)&&this.host.selection.size>1?[...this.host.selection]:[e.id];if(this.dragSourceIds=s,this.dragRowHeight=r.offsetHeight,r.addClass("is-dragging"),this.host.listEl&&(this.dragPlaceholder=this.host.listEl.createDiv({cls:"stashpad-drop-placeholder"}),this.dragPlaceholder.setCssStyles({height:"0px"}),this.dragPlaceholder.addEventListener("dragover",n=>{this.dragSourceIds&&(n.preventDefault(),n.dataTransfer&&(n.dataTransfer.dropEffect="move"))}),this.dragPlaceholder.addEventListener("drop",n=>{if(!this.dragSourceIds||!this.dragPlaceholder)return;n.preventDefault(),n.stopPropagation();let o=this.dragSourceIds.slice();this.dragSourceIds=null;let a=this.dragPlaceholder.nextElementSibling,l=this.dragPlaceholder.previousElementSibling;this.removeDragPlaceholder();let c,A="before";a&&a.classList.contains("stashpad-note")?(c=a.dataset.id,A="before"):l&&l.classList.contains("stashpad-note")&&(c=l.dataset.id,A="after"),c&&this.host.reorderToTarget(o,c,A)}),this.dragPlaceholder.remove()),i.dataTransfer?.setData("text/plain",s.join(",")),i.dataTransfer){i.dataTransfer.effectAllowed="move";try{i.dataTransfer.setDragImage(r,12,12)}catch{}}}),r.addEventListener("dragend",()=>{r.removeClass("is-dragging"),this.clearDropIndicators(),this.removeDragPlaceholder(),this.dragSourceIds=null}),r.addEventListener("dragover",i=>{if(!this.dragSourceIds)return;i.preventDefault(),i.dataTransfer&&(i.dataTransfer.dropEffect="move");let s=this.dropZone(i,r);this.clearDropIndicators(),s==="drop-into"?(this.removeDragPlaceholder(),r.addClass("drop-into")):(r.removeClass("drop-into"),this.placePlaceholder(r,s==="drop-above"?"before":"after"))}),r.addEventListener("dragleave",i=>{let s=r.getBoundingClientRect();(i.clientXs.right||i.clientYs.bottom)&&r.removeClass("drop-into")}),r.addEventListener("drop",i=>{if(!this.dragSourceIds)return;i.preventDefault(),i.stopPropagation();let s=this.dragSourceIds.slice();this.dragSourceIds=null;let n=this.dropZone(i,r);this.clearDropIndicators(),this.removeDragPlaceholder(),r.removeClass("is-dragging"),n==="drop-into"?this.host.reorderToTarget(s,e.id,"into"):this.host.reorderToTarget(s,e.id,n==="drop-above"?"before":"after")})}attachListDnD(r){r.addEventListener("dragover",e=>{if(!this.dragSourceIds)return;let t=e.target;if(t&&t.closest&&t.closest(".stashpad-note"))return;e.preventDefault(),e.dataTransfer&&(e.dataTransfer.dropEffect="move");let i=Array.from(r.querySelectorAll(".stashpad-note"));if(i.length!==0){for(let s of i){let n=s.getBoundingClientRect();if(e.clientY{if(!this.dragSourceIds)return;e.preventDefault();let t=this.dragSourceIds.slice();if(this.dragSourceIds=null,!this.dragPlaceholder)return;let i=this.dragPlaceholder.nextElementSibling,s=this.dragPlaceholder.previousElementSibling;if(this.removeDragPlaceholder(),i&&i.classList.contains("stashpad-note")){let n=i.dataset.id;n&&this.host.reorderToTarget(t,n,"before")}else if(s&&s.classList.contains("stashpad-note")){let n=s.dataset.id;n&&this.host.reorderToTarget(t,n,"after")}})}placePlaceholder(r,e){if(!this.dragPlaceholder||!this.host.listEl)return;let t=e==="before"?r:r.nextSibling;if(e==="before"&&this.dragPlaceholder.nextSibling===r||e==="after"&&this.dragPlaceholder.previousSibling===r)return;let i=!!this.dragPlaceholder.parentElement;this.host.listEl.insertBefore(this.dragPlaceholder,t),this.dragPlaceholder.setCssStyles({opacity:"1"}),i?this.dragPlaceholder.setCssStyles({height:`${this.dragRowHeight}px`}):(this.dragPlaceholder.setCssStyles({height:"0px"}),this.dragPlaceholder.offsetHeight,this.dragPlaceholder.setCssStyles({height:`${this.dragRowHeight}px`}))}removeDragPlaceholder(){if(!this.dragPlaceholder?.parentElement)return;let r=this.dragPlaceholder;r.setCssStyles({height:"0px",opacity:"0"}),setTimeout(()=>{r.parentElement&&r.remove()},150)}dropZone(r,e){let t=e.getBoundingClientRect(),i=r.clientY-t.top;return it.height*.7?"drop-below":"drop-into"}clearDropIndicators(){if(this.host.listEl)for(let r of Array.from(this.host.listEl.querySelectorAll(".drop-into")))r.removeClass("drop-into")}};var ra=require("obsidian");var Un=class{constructor(r,e,t){this.host=r;this.component=e;this.bodyObserver=null;this.lazyBodies=new WeakMap;this.renderCache=t??new Map}async getOrComputeRender(r){let e=this.renderCache.get(r.path);if(e&&e.mtime===r.stat.mtime)return Te.record("render.row.cacheHit",0),e;let t=await Te.timeAsync("render.row.read",()=>this.host.app.vault.cachedRead(r)),i=this.host.stripFrontmatter(t),{text:s,attachments:n}=this.splitAttachments(i),o=createDiv({cls:"stashpad-note-text"});await Te.timeAsync("render.row.markdown",()=>ra.MarkdownRenderer.render(this.host.app,s,o,r.path,this.component));let a=o.innerHTML,l={mtime:r.stat.mtime,text:s,attachments:n,html:a};return this.renderCache.set(r.path,l),l}async primeRender(r,e){try{let{text:t,attachments:i}=this.splitAttachments(this.host.stripFrontmatter(e)),s=createDiv({cls:"stashpad-note-text"});await ra.MarkdownRenderer.render(this.host.app,t,s,r.path,this.component);let n={mtime:r.stat.mtime,text:t,attachments:i,html:s.innerHTML};this.renderCache.set(r.path,n)}catch(t){console.warn("[Stashpad] primeRender failed",t)}}arm(){this.bodyObserver?.disconnect(),this.lazyBodies=new WeakMap,this.bodyObserver=new IntersectionObserver(r=>{for(let e of r){if(!e.isIntersecting)continue;let t=e.target,i=this.lazyBodies.get(t);this.bodyObserver?.unobserve(t),this.lazyBodies.delete(t),i&&i()}},{root:this.host.contentEl,rootMargin:"1400px 0px"})}dispose(){this.bodyObserver?.disconnect(),this.bodyObserver=null}isArmed(){return!!this.bodyObserver}hasFreshRenderCache(r){let e=this.renderCache.get(r.path);return!!e&&e.mtime===r.stat.mtime}peekCache(r){return this.renderCache.get(r.path)}evict(r){let e=this.renderCache;e.evict?e.evict(r.path):e.delete&&e.delete(r.path)}retagMtime(r,e){let t=this.renderCache.get(r);t&&t.mtime!==e&&this.renderCache.set(r,{...t,mtime:e})}defer(r,e){this.lazyBodies.set(r,e),this.bodyObserver?.observe(r)}splitAttachments(r){let e=[];return{text:r.replace(/!\[\[([^\]\|]+)(?:\|[^\]]+)?\]\]/g,(i,s)=>(e.push(s),"")).replace(/\n{3,}/g,` -`).trim(),attachments:e}}};function nl(d,r,e){return d.tree.getChildren(r).slice().sort((i,s)=>pd(d,i,s,e)).map(i=>i.id)}function pd(d,r,e,t){switch(t){case"created-asc":return(r.created||"").localeCompare(e.created||"");case"created-desc":return(e.created||"").localeCompare(r.created||"");case"modified-asc":case"modified-desc":{let i=sl(d,r)||r.created||"",s=sl(d,e)||e.created||"";return t==="modified-asc"?i.localeCompare(s):s.localeCompare(i)}case"title-az":case"title-za":{let i=d.titleForNode(r),s=d.titleForNode(e),n={numeric:!0,sensitivity:"base"};return t==="title-az"?i.localeCompare(s,void 0,n):s.localeCompare(i,void 0,n)}default:return 0}}function sl(d,r){if(!r.file)return"";let e=d.app.metadataCache.getFileCache(r.file)?.frontmatter;return(typeof e?.modified=="string"?e.modified:"")||""}var Ri=require("obsidian");Qi();Zi();async function la(d){let r=d.getActionTargets();if(!r.length)return;let e=X().prefixTimestampsOnCopy,t=[];for(let i of r){if(!i.file)continue;let s=await d.app.vault.cachedRead(i.file),n=d.stripFrontmatter(s).trim();t.push(e?`${d.formatTimeInline(i.created)} ${n}`:n)}await navigator.clipboard.writeText(t.join(` +`).trim(),attachments:e}}};function nl(d,r,e){return d.tree.getChildren(r).slice().sort((i,s)=>pd(d,i,s,e)).map(i=>i.id)}function pd(d,r,e,t){switch(t){case"created-asc":return(r.created||"").localeCompare(e.created||"");case"created-desc":return(e.created||"").localeCompare(r.created||"");case"modified-asc":case"modified-desc":{let i=sl(d,r)||r.created||"",s=sl(d,e)||e.created||"";return t==="modified-asc"?i.localeCompare(s):s.localeCompare(i)}case"title-az":case"title-za":{let i=d.titleForNode(r),s=d.titleForNode(e),n={numeric:!0,sensitivity:"base"};return t==="title-az"?i.localeCompare(s,void 0,n):s.localeCompare(i,void 0,n)}default:return 0}}function sl(d,r){if(!r.file)return"";let e=d.app.metadataCache.getFileCache(r.file)?.frontmatter;return(typeof e?.modified=="string"?e.modified:"")||""}var Ri=require("obsidian");Qi();Zi();async function la(d){let r=d.getActionTargets();if(!r.length)return;let e=X().prefixTimestampsOnCopy,t=[];for(let s of r){if(!s.file)continue;let n=await d.app.vault.cachedRead(s.file),o=d.stripFrontmatter(n).trim(),{needsDash:a,checkbox:l,meta:c}=d.copyMetaPrefix(s),A=`${a?"- ":""}${l}${c}`,h=e?`${d.formatTimeInline(s.created)} `:"";t.push(`${A}${h}${o}`)}let i=t[0]??"";for(let s=1;si.id),folder:d.noteFolder})}async function ol(d){let r=d.getActionTargets();if(!r.length||!r[0].file){new Ri.Notice("Nothing to copy from.");return}let e=r[0],t=await d.app.vault.cachedRead(e.file),i=d.stripFrontmatter(t),s=er(i);if(s.length===0){d.plugin.notifications.show({message:`No codeblock found in "${d.titleForNode(e)}".`,kind:"info",category:"system",affectedIds:[e.id],folder:d.noteFolder});return}if(s.length===1){await navigator.clipboard.writeText(s[0].code),d.plugin.notifications.show({message:`Copied codeblock${s[0].lang?` (${s[0].lang})`:""} from "${d.titleForNode(e)}".`,kind:"success",category:"system",affectedIds:[e.id],folder:d.noteFolder});return}let n=s.map((a,l)=>({kind:"one",idx:l,label:`${l+1}. ${a.lang||"(no language)"} \u2014 ${a.code.split(` +`:` +`;i+=n+t[s]}await navigator.clipboard.writeText(i),d.plugin.notifications.show({message:`Copied ${d.titleList(r)} to clipboard`,kind:"success",category:"system",affectedIds:r.map(s=>s.id),folder:d.noteFolder})}async function ol(d){let r=d.getActionTargets();if(!r.length||!r[0].file){new Ri.Notice("Nothing to copy from.");return}let e=r[0],t=await d.app.vault.cachedRead(e.file),i=d.stripFrontmatter(t),s=er(i);if(s.length===0){d.plugin.notifications.show({message:`No codeblock found in "${d.titleForNode(e)}".`,kind:"info",category:"system",affectedIds:[e.id],folder:d.noteFolder});return}if(s.length===1){await navigator.clipboard.writeText(s[0].code),d.plugin.notifications.show({message:`Copied codeblock${s[0].lang?` (${s[0].lang})`:""} from "${d.titleForNode(e)}".`,kind:"success",category:"system",affectedIds:[e.id],folder:d.noteFolder});return}let n=s.map((a,l)=>({kind:"one",idx:l,label:`${l+1}. ${a.lang||"(no language)"} \u2014 ${a.code.split(` `)[0].slice(0,60)}${a.code.includes(` `)?"\u2026":""}`}));n.push({kind:"all",idx:-1,label:`Copy all ${s.length} blocks (joined with blank lines)`});let o=new class extends Ri.SuggestModal{getSuggestions(a){let l=a.trim().toLowerCase();if(!l)return n;let c=l.split(/\s+/).filter(Boolean);return n.filter(A=>{let h=A.label.toLowerCase();return c.every(p=>h.includes(p))})}renderSuggestion(a,l){l.createDiv({cls:"stashpad-suggest-title",text:a.label})}async onChooseSuggestion(a){let l=a.kind==="all"?s.map(c=>c.code).join(` -`):s[a.idx].code;await navigator.clipboard.writeText(l),d.plugin.notifications.show({message:a.kind==="all"?`Copied all ${s.length} codeblocks from "${d.titleForNode(e)}".`:`Copied codeblock${s[a.idx].lang?` (${s[a.idx].lang})`:""} from "${d.titleForNode(e)}".`,kind:"success",category:"system",affectedIds:[e.id],folder:d.noteFolder})}}(d.app);o.setPlaceholder(`${s.length} codeblocks in "${d.titleForNode(e)}" \u2014 pick one to copy.`),o.open()}async function al(d){let r=d.getActionTargets();if(r.length===0){let n=d.tree.get(d.focusId);n?.file&&(r=[n])}if(r.length===0){new Ri.Notice("Nothing to copy.");return}let e=X().prefixTimestampsOnCopy,t=[],i=async(n,o)=>{if(n.file){let a=await d.app.vault.cachedRead(n.file),l=d.stripFrontmatter(a).trim().split(/\r?\n/).join(" "),c=e?`${d.formatTimeInline(n.created)} `:"";t.push(`${" ".repeat(o)}- ${c}${l}`)}for(let a of d.tree.getChildren(n.id))await i(a,o+1)};for(let n of r)await i(n,0);let s=t.join(` -`);await navigator.clipboard.writeText(s),d.plugin.clearNoteClipboard(),d.plugin.noteClipboard={mode:"copy",folder:d.noteFolder,ids:r.map(n=>n.id),text:s},d.render(),d.plugin.notifications.show({message:`Copied tree of ${d.titleList(r)} (${t.length} entries) \u2014 paste in the list to clone, in a note to drop the outline in`,kind:"success",category:"system",affectedIds:r.map(n=>n.id),folder:d.noteFolder})}async function rl(d){let r=d.getActionTargets();if(r.length===0){let i=d.tree.get(d.focusId);i?.file&&(r=[i])}if(r.length===0){new Ri.Notice("Nothing to copy.");return}let e=[],t=(i,s)=>{if(!i.file)return;let n=" ".repeat(s);e.push(`${n}- ![[${i.file.basename}]]`);for(let o of d.tree.getChildren(i.id))t(o,s+1)};for(let i of r)t(i,0);await navigator.clipboard.writeText(e.join(` +`):s[a.idx].code;await navigator.clipboard.writeText(l),d.plugin.notifications.show({message:a.kind==="all"?`Copied all ${s.length} codeblocks from "${d.titleForNode(e)}".`:`Copied codeblock${s[a.idx].lang?` (${s[a.idx].lang})`:""} from "${d.titleForNode(e)}".`,kind:"success",category:"system",affectedIds:[e.id],folder:d.noteFolder})}}(d.app);o.setPlaceholder(`${s.length} codeblocks in "${d.titleForNode(e)}" \u2014 pick one to copy.`),o.open()}async function al(d){let r=d.getActionTargets();if(r.length===0){let n=d.tree.get(d.focusId);n?.file&&(r=[n])}if(r.length===0){new Ri.Notice("Nothing to copy.");return}let e=X().prefixTimestampsOnCopy,t=[],i=async(n,o)=>{if(n.file){let a=await d.app.vault.cachedRead(n.file),l=d.stripFrontmatter(a).trim().split(/\r?\n/).join(" "),c=e?`${d.formatTimeInline(n.created)} `:"",{checkbox:A,meta:h}=d.copyMetaPrefix(n);t.push(`${" ".repeat(o)}- ${A}${h}${c}${l}`)}for(let a of d.tree.getChildren(n.id))await i(a,o+1)};for(let n of r)await i(n,0);let s=t.join(` +`);await navigator.clipboard.writeText(s),d.plugin.clearNoteClipboard(),d.plugin.noteClipboard={mode:"copy",folder:d.noteFolder,ids:r.map(n=>n.id),text:s},d.render(),d.plugin.notifications.show({message:`Copied tree of ${d.titleList(r)} (${t.length} entries) \u2014 paste in the list to clone, in a note to drop the outline in`,kind:"success",category:"system",affectedIds:r.map(n=>n.id),folder:d.noteFolder})}async function rl(d){let r=d.getActionTargets();if(r.length===0){let i=d.tree.get(d.focusId);i?.file&&(r=[i])}if(r.length===0){new Ri.Notice("Nothing to copy.");return}let e=[],t=(i,s)=>{if(!i.file)return;let n=" ".repeat(s),{checkbox:o,meta:a}=d.copyMetaPrefix(i);e.push(`${n}- ${o}${a}![[${i.file.basename}]]`);for(let l of d.tree.getChildren(i.id))t(l,s+1)};for(let i of r)t(i,0);await navigator.clipboard.writeText(e.join(` `)),d.plugin.notifications.show({message:`Copied outline of ${d.titleList(r)} (${e.length} entr${e.length===1?"y":"ies"})`,kind:"success",category:"system",affectedIds:r.map(i=>i.id),folder:d.noteFolder})}var Me=require("obsidian");ce();var Jn=require("obsidian");qn();pt();ce();var ct="stash",Sl=1;function wa(d){let e=(d.split(/[\\/]/).pop()??"").trim();return!e||e==="."||e===".."||e.includes("/")||e.includes("\\")||e.includes("..")?"":e}var Ea=/!\[\[([^\]\|]+)(?:\|[^\]]+)?\]\]/g;async function vt(d,r){let e=[],t=Rd([...r.rootNotes,...r.allDescendants]),i=new Map,s=[];for(let o of t){let a=await d.vault.read(o.file),l=a,c=va(a);for(let A of c){let h=d.metadataCache.getFirstLinkpathDest(A,o.file.path);if(!h){s.push(`Missing attachment "${A}" in ${o.file.path}`);continue}let p=h.name;i.has(p)||i.set(p,await d.vault.readBinary(h)),l=Dl(l,A,p)}l=xl(l,d,o.file.path),e.push({name:`notes/${o.file.name}`,data:l})}for(let[o,a]of i)e.push({name:`attachments/${o}`,data:a});let n={stashSchema:Sl,exportedAt:new Date().toISOString(),sourceFolder:r.sourceFolder,noteCount:t.length,rootIds:r.rootNotes.map(o=>o.id)};return e.push({name:"manifest.json",data:JSON.stringify(n,null,2)}),s.length&&e.push({name:"warnings.txt",data:s.join(` `)}),Ui(e,6)}async function bl(d,r,e){let t=[],i=new Map,s=[],n=new Set;for(let o of r){let a=await d.vault.read(o.file);if(e!=="frontmatter"){for(let A of va(a)){let h=d.metadataCache.getFirstLinkpathDest(A,o.file.path);if(!h){s.push(`Missing attachment "${A}" in ${o.file.path}`);continue}let p=h.name;i.has(p)||i.set(p,await d.vault.readBinary(h)),a=Dl(a,A,p)}a=xl(a,d,o.file.path)}let l=Kd(a,e),c=o.file.name;for(;n.has(c);)c=`${o.file.basename}-${he(4)}.md`;n.add(c),t.push({name:`notes/${c}`,data:l})}for(let[o,a]of i)t.push({name:`attachments/${o}`,data:a});return s.length&&t.push({name:"warnings.txt",data:s.join(` `)}),Ui(t,6)}async function We(d,r,e,t,i={}){let s=await Li(r),n=s["manifest.json"];if(!n)throw new Error("Not a valid .stash package: missing manifest.json");let o=JSON.parse(Kn(n));if(typeof o.stashSchema!="number"||o.stashSchema>Sl)throw new Error(`Unsupported .stash schema: v${o.stashSchema}`);await kl(d,e);let a=Object.entries(s).filter(([v])=>v.startsWith("notes/")&&v.endsWith(".md")),l=[];for(let[v,Q]of a){let w=Kn(Q),{fm:F,body:D}=ge(w),H=wa(v.slice(6))||wa(`${F.id||"imported-"+he(4)}.md`)||`imported-${he(4)}.md`;l.push({originalName:H,fm:F,body:D})}let c=new Map,A=0;for(let v of l){let Q=v.fm.id;Q&&(i.forceNewIds?c.set(Q,he(6)):t.has(Q)||c.has(Q)?(c.set(Q,`${Q}-${he(4)}-Imported`),A++):c.set(Q,Q))}let h=new Date().toISOString(),p=[],f=`${e}/_attachments`,u=0,g=Object.entries(s).filter(([v])=>v.startsWith("attachments/")),I=new Map,m=null;if(i.dedupeExisting){m=new Map;for(let v of d.vault.getFiles())m.has(v.name)||m.set(v.name,v.path)}let C=(v,Q)=>{if(v.length!==Q.length)return!1;for(let w=0;w{let M=Nl(Jt(b));return tt(I.get(M)??`${f}/${M}`)}));let x=Ot(L,H),U=w===Q?v.originalName:Od(v.originalName,Q,w),T=`${e}/${U}`;await d.vault.adapter.exists(T)&&(U=`${U.replace(/\.md$/,"")}-${he(4)}.md`,T=`${e}/${U}`),await d.vault.create(T,x),E++}let y;if(o.colorAliases&&typeof o.colorAliases=="object"){let v={};for(let[Q,w]of Object.entries(o.colorAliases)){let F=String(Q).trim().toLowerCase(),D=String(w??"").trim();/^#([0-9a-f]{6})$/.test(F)&&D&&(v[F]=D.slice(0,60))}Object.keys(v).length&&(y=v)}return{notesWritten:E,attachmentsWritten:u,collisionsRenamed:A,warnings:p,colorAliases:y,idRemap:Object.fromEntries(c)}}function Rd(d){let r=new Set,e=[];for(let t of d)r.has(t.id)||(r.add(t.id),e.push(t));return e}function va(d){let r=new Set,e;for(Ea.lastIndex=0;(e=Ea.exec(d))!==null;)r.add(e[1]);return[...r]}async function ii(d,r){let e=await d.vault.read(r),t=[],i=new Set;for(let s of va(e)){let n=d.metadataCache.getFirstLinkpathDest(s,r.path);n&&!i.has(n.path)&&(i.add(n.path),t.push(n))}return t}function Dl(d,r,e){return d.replace(new RegExp(`!\\[\\[${Gd(r)}(\\|[^\\]]+)?\\]\\]`,"g"),(t,i)=>`![[${e}${i??""}]]`)}function Ud(d,r){let e=d.lastIndexOf(".");return e>0?`${d.slice(0,e)}-${r}${d.slice(e)}`:`${d}-${r}`}function Ld(d,r,e){return d.replace(Ea,(t,i,s)=>{if(i.includes("/"))return t;let n=r.get(i)??`${e}/${i}`;return t.replace(i,n)})}function xl(d,r,e){let t=ge(d);if(!t.fm.attachments||!Array.isArray(t.fm.attachments))return d;let i=t.fm.attachments.map(n=>{let o=r.metadataCache.getFirstLinkpathDest(n,e);return o?o.name:Nl(n)}),s={...t.fm,attachments:i};return Ot(s,t.body)}function Gd(d){return d.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}function Nl(d){let r=d.lastIndexOf("/");return r<0?d:d.slice(r+1)}function Od(d,r,e){return d.includes(r)?d.replace(r,e):d.replace(/\.md$/,`-${e}.md`)}function ge(d){if(!d.startsWith("---"))return{fm:{},body:d};let r=d.indexOf(` @@ -74,7 +77,7 @@ Tap to switch / create.`,this.folderOverride&&i.addClass("is-active"),i.onmoused `),c=await this.app.vault.read(t.file),A=c.startsWith("---")?c.indexOf(` ---`,3):-1;if(c.startsWith("---")&&A<0){this.plugin.notifications.show({message:"Can't merge \u2014 the kept note's frontmatter is malformed (no closing ---).",kind:"warning",category:"merge",folder:this.noteFolder});return}let h=c.startsWith("---")?A+4:0,f=`${c.slice(0,h)} ${l} -`;await this.app.vault.modify(t.file,f);for(let I=1;II.id),folder:this.noteFolder}),this.tree.rebuild(this.noteFolder),this.render({kind:"follow-cursor"});{let I=t.id,m=this.selectionGuardKey,C=()=>{if(this.selectionGuardKey!==m||this.selection.has(I))return;let B=this.currentChildren.findIndex(E=>E.id===I);B<0||(this.selection.add(I),this.cursorIdx=B,this.render({kind:"follow-cursor"}))};setTimeout(C,120),setTimeout(C,400)}let g=this.noteFolder;this.plugin.getUndoStack(g).push({label:`Merge ${e.length} notes`,undo:async()=>{await this.restoreSnapshots(n,e.map(m=>m.id));let I=this.fileForNote(t.id,i);I&&await this.app.vault.modify(I,s);for(let m of o){let C=this.fileForNote(m.childId,m.childPath);C&&await this.app.fileManager.processFrontMatter(C,B=>{B.parent=m.oldParent})}this.pendingFocusIds=e.map(m=>m.id),this.tree.rebuild(g),this.render({kind:"follow-cursor"})},redo:async()=>{await this.trashNotesAndAttachments(n);let I=this.fileForNote(t.id,i);I&&await this.app.vault.modify(I,f);for(let m of o){let C=this.fileForNote(m.childId,m.childPath);C&&await this.app.fileManager.processFrontMatter(C,B=>{B.parent=m.newParent})}this.tree.rebuild(g),this.render()}})}cmdCopy(){return la(this)}cmdCopyCodeBlock(){return ol(this)}cmdCopyTree(){return al(this)}cmdCopyOutline(){return rl(this)}cmdToggleExpand(){let e=this.getActionTargets();if(!e.length)return;let t=e.some(i=>!this.isNoteExpanded(i.id));for(let i of e)this.setNoteExpanded(i.id,t);this.render()}isNoteExpanded(e){let t=this.expandedNotes.has(e);return this.plugin.settings.expandBodiesByDefault?!t:t}setNoteExpanded(e,t){let i=this.plugin.settings.expandBodiesByDefault;t===i?this.expandedNotes.delete(e):this.expandedNotes.add(e)}cmdExpandAll(){for(let e of this.currentChildren)this.setNoteExpanded(e.id,!0);this.render()}cmdCollapseAll(){for(let e of this.currentChildren)this.setNoteExpanded(e.id,!1);this.render()}async cloneSubtree(e,t,i,s={}){if(!e.file)return null;if(e.id===t||this.isDescendant(t,e.id))return new k.Notice(`Can't insert "${this.titleForNode(e)}" into itself or a descendant \u2014 that would loop forever.`),null;let n=this.tree.getChildren(e.id).slice(),o=e.file,a=await this.app.vault.read(o),l=this.stripFrontmatter(a),c=this.app.metadataCache.getFileCache(o)?.frontmatter??{},A=this.plugin.mintNoteId(),h=xe(l,this.activeStopwords()),p=Ne(h,A),f=`${this.noteFolder}/${p}`,u=new Date().toISOString(),g=s.preserveCreated&&e.created?e.created:u,I=this.extractAttachments(l),m=["---",`id: ${A}`,`parent: ${t}`,`created: ${g}`];if(I.length>0){m.push("attachments:");for(let B of I)m.push(` - "${B.replace(/"/g,'\\"')}"`)}else m.push("attachments: []");m.push("---",l),await this.ensureFolder(this.noteFolder),await this.app.vault.create(f,m.join(` +`;await this.app.vault.modify(t.file,f);for(let I=1;II.id),folder:this.noteFolder}),this.tree.rebuild(this.noteFolder),this.render({kind:"follow-cursor"});{let I=t.id,m=this.selectionGuardKey,C=()=>{if(this.selectionGuardKey!==m||this.selection.has(I))return;let B=this.currentChildren.findIndex(E=>E.id===I);B<0||(this.selection.add(I),this.cursorIdx=B,this.render({kind:"follow-cursor"}))};setTimeout(C,120),setTimeout(C,400)}let g=this.noteFolder;this.plugin.getUndoStack(g).push({label:`Merge ${e.length} notes`,undo:async()=>{await this.restoreSnapshots(n,e.map(m=>m.id));let I=this.fileForNote(t.id,i);I&&await this.app.vault.modify(I,s);for(let m of o){let C=this.fileForNote(m.childId,m.childPath);C&&await this.app.fileManager.processFrontMatter(C,B=>{B.parent=m.oldParent})}this.pendingFocusIds=e.map(m=>m.id),this.tree.rebuild(g),this.render({kind:"follow-cursor"})},redo:async()=>{await this.trashNotesAndAttachments(n);let I=this.fileForNote(t.id,i);I&&await this.app.vault.modify(I,f);for(let m of o){let C=this.fileForNote(m.childId,m.childPath);C&&await this.app.fileManager.processFrontMatter(C,B=>{B.parent=m.newParent})}this.tree.rebuild(g),this.render()}})}cmdCopy(){return la(this)}cmdCopyCodeBlock(){return ol(this)}cmdCopyTree(){return al(this)}cmdCopyOutline(){return rl(this)}copyMetaPrefix(e){let t=this.isTask(e),i=t?this.isCompleted(e)?"[x] ":"[ ] ":"",s=this.colorForNode(e),n="";if(s){let o=this.plugin.getColorAlias(this.noteFolder,s);n=o?`[color: ${s} | alias: ${o}] `:`[color: ${s}] `}return{needsDash:t,checkbox:i,meta:n}}cmdToggleExpand(){let e=this.getActionTargets();if(!e.length)return;let t=e.some(i=>!this.isNoteExpanded(i.id));for(let i of e)this.setNoteExpanded(i.id,t);this.render()}isNoteExpanded(e){let t=this.expandedNotes.has(e);return this.plugin.settings.expandBodiesByDefault?!t:t}setNoteExpanded(e,t){let i=this.plugin.settings.expandBodiesByDefault;t===i?this.expandedNotes.delete(e):this.expandedNotes.add(e)}cmdExpandAll(){for(let e of this.currentChildren)this.setNoteExpanded(e.id,!0);this.render()}cmdCollapseAll(){for(let e of this.currentChildren)this.setNoteExpanded(e.id,!1);this.render()}async cloneSubtree(e,t,i,s={}){if(!e.file)return null;if(e.id===t||this.isDescendant(t,e.id))return new k.Notice(`Can't insert "${this.titleForNode(e)}" into itself or a descendant \u2014 that would loop forever.`),null;let n=this.tree.getChildren(e.id).slice(),o=e.file,a=await this.app.vault.read(o),l=this.stripFrontmatter(a),c=this.app.metadataCache.getFileCache(o)?.frontmatter??{},A=this.plugin.mintNoteId(),h=xe(l,this.activeStopwords()),p=Ne(h,A),f=`${this.noteFolder}/${p}`,u=new Date().toISOString(),g=s.preserveCreated&&e.created?e.created:u,I=this.extractAttachments(l),m=["---",`id: ${A}`,`parent: ${t}`,`created: ${g}`];if(I.length>0){m.push("attachments:");for(let B of I)m.push(` - "${B.replace(/"/g,'\\"')}"`)}else m.push("attachments: []");m.push("---",l),await this.ensureFolder(this.noteFolder),await this.app.vault.create(f,m.join(` `)),i.push(f);let C=this.app.vault.getAbstractFileByPath(f);if(C){try{await this.app.fileManager.processFrontMatter(C,B=>{for(let[E,y]of Object.entries(c))et.includes(E)||fo.includes(E)||(B[E]=y);s.preserveCreated&&(B.modified=u),s.copyKind==="fork"&&(B[uo]=u)})}catch(B){console.warn("[Stashpad] cloneSubtree: processFrontMatter failed",B)}try{this.tree.insertSynthetic({id:A,parent:t,children:[],file:C,created:g})}catch{}this.fmSync.scheduleParentChange(A,null,t)}for(let B of n)await this.cloneSubtree(B,A,i,s);return A}async cmdClone(){let e=this.getActionTargets();if(!e.length){new k.Notice("Nothing to clone.");return}let t=new Set(e.map(A=>A.id)),i=e.filter(A=>{let h=A.parent;for(;h;){if(t.has(h))return!1;h=this.tree.get(h)?.parent??null}return!0}),s=this.noteFolder,n=[],o=[];try{for(let A of i){if(!A.file)continue;let h=A.parent??this.focusId,p=await this.cloneSubtree(A,h,n);p&&o.push(p)}}catch(A){console.warn("[Stashpad] clone failed partway",A),new k.Notice(`Clone stopped early: ${A.message}`)}if(!o.length)return;this.tree.rebuild(s),this.pendingFocusIds=o.slice(),this.render();let a=n.map(A=>this.app.vault.getAbstractFileByPath(A)).filter(A=>!!A&&A.extension==="md").map(A=>({id:nt(A.basename)??A.basename,parent:null,children:[],file:A,created:new Date().toISOString()})),l=await this.snapshotNotes(a,!1);this.plugin.getUndoStack(s).push({label:`Clone ${o.length} note${o.length===1?"":"s"}`,undo:async()=>{for(let A of[...n].reverse()){let h=this.app.vault.getAbstractFileByPath(A);if(h)try{await this.app.fileManager.trashFile(h)}catch{}}this.tree.rebuild(s),this.render()},redo:async()=>{await this.restoreSnapshots(l,o)}});let c=o.map(A=>this.tree.get(A)).filter(A=>!!A);this.plugin.notifications.show({message:this.bulkActionMessage({verb:"Cloned",nodes:c,suffix:`(${n.length} file${n.length===1?"":"s"} total)`}),kind:"success",category:"clone",affectedIds:o,folder:this.noteFolder})}cmdForkNote(){let e=this.getActionTargets()[0];if(!e?.file){new k.Notice("Nothing to fork.");return}let t=e.parent??S,i=t===S?null:this.tree.get(t),s=i?this.titleForNode(i):"Home";new at(this.app,this.tree,n=>this.titleForNode(n),{mode:"pick",allowCreate:!0,placeholder:`Fork "${this.titleForNode(e)}" under\u2026 (default: ${s})`,onPick:n=>{if(n.crossFolder){new k.Notice("Fork stays in this folder for now.");return}this.forkNoteUnder(e,n.id)},onCreate:n=>{(async()=>{let o=await this.createNoteUnder(n,this.focusId);o&&await this.forkNoteUnder(e,o)})()}}).open()}async forkNoteUnder(e,t){if(!e.file)return;let i=this.noteFolder,s=[],n=await this.cloneSubtree(e,t,s,{preserveCreated:!0,copyKind:"fork"});if(!n)return;let o=s[0]?this.app.vault.getAbstractFileByPath(s[0]):null;if(o)try{await this.app.fileManager.processFrontMatter(o,A=>{A[zi]=`[[${e.file.basename}]]`})}catch{}this.tree.rebuild(i),this.pendingFocusIds=[n],this.render(),await this.syncForkSiblings(this.forkFamilyFiles({originName:e.file.basename,include:[e.file,o]}));let a=s.map(A=>this.app.vault.getAbstractFileByPath(A)).filter(A=>!!A&&A.extension==="md").map(A=>({id:nt(A.basename)??A.basename,parent:null,children:[],file:A,created:new Date().toISOString()})),l=await this.snapshotNotes(a,!1);this.plugin.getUndoStack(i).push({label:"Fork note",undo:async()=>{for(let A of[...s].reverse()){let h=this.app.vault.getAbstractFileByPath(A);if(h)try{await this.app.fileManager.trashFile(h)}catch{}}this.tree.rebuild(i),this.render()},redo:async()=>{await this.restoreSnapshots(l,[n])}});let c=this.tree.get(n);this.plugin.notifications.show({message:c?`Forked "${this.titleForNode(e)}" \u2192 "${this.titleForNode(c)}" (${s.length} file${s.length===1?"":"s"})`:"Forked note",kind:"success",category:"clone",affectedIds:[n],folder:i})}async ensureSheetGroup(e){let t=_e(this.app.metadataCache.getFileCache(e)?.frontmatter);if(t)return t;let i=Ka();return await this.app.fileManager.processFrontMatter(e,s=>{s[$i]=i,typeof s[ht]!="number"&&(s[ht]=0),s[Yi]=!0}),i}forkFamilyFiles(e){let t=new Map,i=s=>{s&&t.set(s.path,s)};for(let s of this.app.vault.getMarkdownFiles()){let n=this.app.metadataCache.getFileCache(s)?.frontmatter;e.gid&&_e(n)===e.gid&&i(s),e.originName&&(s.basename===e.originName||Oa(n)===e.originName)&&i(s)}for(let s of e.include??[])i(s);return[...t.values()]}async syncForkSiblings(e){for(let t of e){let i=e.filter(s=>s.path!==t.path).map(s=>`[[${s.basename}]]`);await this.app.fileManager.processFrontMatter(t,s=>{i.length?s[je]=i:delete s[je]})}}async cmdForkVersion(e){this.plugin.settings.enableSheetVersions||(this.plugin.settings.enableSheetVersions=!0,await this.plugin.saveSettings(),new k.Notice("Sheet versions enabled."));let t=e??this.getActionTargets()[0];if(!t?.file){new k.Notice("Select a note to version.");return}let i=this.noteFolder,s={...this.app.metadataCache.getFileCache(t.file)?.frontmatter??{}},n=await this.ensureSheetGroup(t.file),o=t.parent??this.focusId,a=typeof s[ht]=="number"?s[ht]:0;for(let u of this.tree.getChildren(o)){if(u.id===t.id)continue;let g=ke(this.app,u);if(_e(g)!==n)continue;let I=g?.[ht];typeof I=="number"&&I>a&&(a=I)}let l=a+1,c=[],A=await this.cloneSubtree(t,o,c,{preserveCreated:!0,copyKind:"fork"});if(!A||!c.length){new k.Notice("Sheets: could not create version.");return}let h=this.app.vault.getAbstractFileByPath(c[0]);h&&await this.app.fileManager.processFrontMatter(h,u=>{u[$i]=n,u[ht]=l,delete u[ri],delete u[Yi],u[zi]=`[[${t.file.basename}]]`}),this.tree.rebuild(i),this.activeVersionByGroup.set(n,A),this.plugin.saveActiveVersion(i,n,A),this.render();let p=this.app.vault.getAbstractFileByPath(c[0]);await this.syncForkSiblings(this.forkFamilyFiles({gid:n,include:[t.file,p]})),this.plugin.getUndoStack(i).push({label:"Fork version",undo:async()=>{for(let u of[...c].reverse()){let g=this.app.vault.getAbstractFileByPath(u);if(g)try{await this.app.fileManager.trashFile(g)}catch{}}this.activeVersionByGroup.delete(n),this.tree.rebuild(i),this.render()},redo:async()=>{}});let f=c.length;new k.Notice(`Forked a new version${f>1?` (${f} notes)`:""}`)}async cmdMarkVersionFinal(e){this.plugin.settings.enableSheetVersions||(this.plugin.settings.enableSheetVersions=!0,await this.plugin.saveSettings());let t=e??this.getActionTargets()[0];if(!t?.file)return;let i=_e(ke(this.app,t));if(!i){new k.Notice("Not a versioned note.");return}let s=!Wi(ke(this.app,t)),n=t.parent??this.focusId,o=this.tree.getChildren(n).filter(a=>_e(ke(this.app,a))===i);for(let a of o){if(!a.file)continue;let l=Wi(ke(this.app,a)),c=s&&a.id===t.id;l!==c&&await this.app.fileManager.processFrontMatter(a.file,A=>{c?A[ri]=!0:delete A[ri]})}this.render()}async cmdCopyNotes(){let e=this.getActionTargets();if(!e.length){new k.Notice("Nothing to copy.");return}await la(this),this.plugin.clearNoteClipboard(),this.plugin.noteClipboard={mode:"copy",folder:this.noteFolder,ids:e.map(t=>t.id)},this.render()}isCutPending(e){let t=this.plugin.noteClipboard;return!!t&&t.mode==="cut"&&t.folder===this.noteFolder&&t.ids.includes(e)}isCopyPending(e){let t=this.plugin.noteClipboard;return!!t&&t.mode==="copy"&&t.folder===this.noteFolder&&t.ids.includes(e)}insertIntoComposer(e){let t=this.composerInputEl;if(!t){this.composerDraft=this.composerDraft?`${this.composerDraft} ${e}`:e;return}let i=t.selectionStart??t.value.length,s=t.selectionEnd??t.value.length;t.value=t.value.slice(0,i)+e+t.value.slice(s);let n=i+e.length;try{t.setSelectionRange(n,n)}catch{}this.composerDraft=t.value}focusedInsideCut(e){let t=new Set(e),i=this.focusId,s=0;for(;i&&i!==S&&s++<1e3;){if(t.has(i))return!0;i=this.tree.get(i)?.parent??null}return!1}async cmdCutNotes(){let e=this.getActionTargets();if(!e.length){new k.Notice("Nothing to cut.");return}let t=[];for(let s of e)s.file&&t.push(this.stripFrontmatter(await this.app.vault.cachedRead(s.file)).trim());let i=t.join(` diff --git a/manifest.json b/manifest.json index 801a39e..2cce2f2 100644 --- a/manifest.json +++ b/manifest.json @@ -1,7 +1,7 @@ { "id": "stashpad", "name": "Stashpad", - "version": "0.187.0", + "version": "0.188.1", "minAppVersion": "1.13.0", "description": "A chat-style, nested-notes workspace: rapid capture, outliner navigation, fast search, tasks, and per-folder templates, with one-click Open Knowledge Format (OKF) export for LLMs and agents.", "author": "Human", diff --git a/package.json b/package.json index df4278a..1bd64f3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "stashpad-obsidian", - "version": "0.187.0", + "version": "0.188.1", "private": true, "scripts": { "dev": "node esbuild.config.mjs", diff --git a/release-notes/0.188.0.md b/release-notes/0.188.0.md new file mode 100644 index 0000000..b28d286 --- /dev/null +++ b/release-notes/0.188.0.md @@ -0,0 +1,16 @@ +# 0.188.0 + +## Copying + +- **Copies now carry task checkboxes and colour metadata.** Copying notes — plain + **Copy**, **Copy tree** (indented list), or **Copy outline** (`![[embed]]` links) — + prefixes each note so it renders and round-trips in a regular Obsidian note: + - A task becomes a checkbox: `- [ ]` (incomplete) or `- [x]` (completed). The + leading dash is added so the checkbox renders, and the empty checkbox keeps its + inner space. + - A coloured note carries its colour inline: `[color: #ffe243 | alias: boogers]` + (the alias appears only when you've named that colour). + + Put together: `- [x] [color: #ffe243 | alias: boogers] the note text`. On the + list/link formats the checkbox and metadata sit right after the bullet dash. Notes + that aren't tasks and have no colour copy exactly as before. diff --git a/release-notes/0.188.1.md b/release-notes/0.188.1.md new file mode 100644 index 0000000..04dc26f --- /dev/null +++ b/release-notes/0.188.1.md @@ -0,0 +1,8 @@ +# 0.188.1 + +## Copying + +- **Copied task lists stay tight.** Plain **Copy** no longer puts a blank line + between every copied note — consecutive single-line items (like tasks) now join + with a single newline, so a copied checklist reads as one list. The blank-line + separator is kept only around a multi-line note, where the gap still helps. diff --git a/src/commands/clipboard-cmds.ts b/src/commands/clipboard-cmds.ts index 250985e..0874caa 100644 --- a/src/commands/clipboard-cmds.ts +++ b/src/commands/clipboard-cmds.ts @@ -19,9 +19,24 @@ export async function cmdCopy(view: StashpadView): Promise { if (!t.file) continue; const raw = await view.app.vault.cachedRead(t.file); const body = view.stripFrontmatter(raw).trim(); - out.push(prefix ? `${view.formatTimeInline(t.created)} ${body}` : body); + // 0.188.0: task checkbox + color/alias metadata prefix. Plain-copy has no + // leading dash, so add one ("- ") ONLY for a task (a checkbox needs it to + // render); a colour-only prefix renders fine inline without a dash. + const { needsDash, checkbox, meta } = view.copyMetaPrefix(t); + const lead = `${needsDash ? "- " : ""}${checkbox}${meta}`; + const ts = prefix ? `${view.formatTimeInline(t.created)} ` : ""; + out.push(`${lead}${ts}${body}`); } - await navigator.clipboard.writeText(out.join("\n\n")); + // 0.188.1: join consecutive SINGLE-LINE items (tasks / short notes) with a + // single newline so a copied task list stays a tight checklist — the old blank + // line between every item split the checkboxes into a loose list. The blank-line + // separator is kept only around a multi-line item, where prose wants the gap. + let joined = out[0] ?? ""; + for (let i = 1; i < out.length; i++) { + const gap = out[i - 1].includes("\n") || out[i].includes("\n") ? "\n\n" : "\n"; + joined += gap + out[i]; + } + await navigator.clipboard.writeText(joined); view.plugin.notifications.show({ message: `Copied ${view.titleList(targets)} to clipboard`, kind: "success", @@ -122,7 +137,10 @@ export async function cmdCopyTree(view: StashpadView): Promise { const raw = await view.app.vault.cachedRead(node.file); const body = view.stripFrontmatter(raw).trim().split(/\r?\n/).join(" "); const ts = prefix ? `${view.formatTimeInline(node.created)} ` : ""; - lines.push(`${" ".repeat(depth)}- ${ts}${body}`); + // 0.188.0: checkbox + colour metadata go AFTER the bullet dash this format + // already emits (needsDash ignored — the "- " is always present here). + const { checkbox, meta } = view.copyMetaPrefix(node); + lines.push(`${" ".repeat(depth)}- ${checkbox}${meta}${ts}${body}`); } for (const c of view.tree.getChildren(node.id)) await walk(c, depth + 1); }; @@ -159,7 +177,9 @@ export async function cmdCopyOutline(view: StashpadView): Promise { const walk = (node: TreeNode, depth: number) => { if (!node.file) return; const indent = " ".repeat(depth); - lines.push(`${indent}- ![[${node.file.basename}]]`); + // 0.188.0: checkbox + colour metadata after the bullet dash, before the embed. + const { checkbox, meta } = view.copyMetaPrefix(node); + lines.push(`${indent}- ${checkbox}${meta}![[${node.file.basename}]]`); for (const c of view.tree.getChildren(node.id)) walk(c, depth + 1); }; for (const r of roots) walk(r, 0); diff --git a/src/view.ts b/src/view.ts index 352dbba..441e3d5 100644 --- a/src/view.ts +++ b/src/view.ts @@ -8221,6 +8221,30 @@ export class StashpadView extends ItemView { cmdCopyTree(): Promise { return clipboardCmds.cmdCopyTree(this); } cmdCopyOutline(): Promise { return clipboardCmds.cmdCopyOutline(this); } + /** 0.188.0: inline task/color metadata prefix for a COPIED note, so a task + * pastes as a real Obsidian checkbox and a note's color (+ its alias) survive + * as inline metadata in a plain note. Public so the clipboard commands can + * reuse the private task/color getters. Returns the pieces so each copy + * format places them correctly relative to its own leading dash: + * - `needsDash` — true when the note is a task (a checkbox needs a "- " to + * render as a checkbox). Formats that ALREADY emit "- " ignore this. + * - `checkbox` — "[ ] " (incomplete) / "[x] " (completed), or "". + * - `meta` — "[color: #hex | alias: name] " (alias only when the color + * has one), or "". + * Compose as ``; empty-checkbox keeps the space + * between brackets so Obsidian renders it. */ + copyMetaPrefix(node: TreeNode): { needsDash: boolean; checkbox: string; meta: string } { + const task = this.isTask(node); + const checkbox = task ? (this.isCompleted(node) ? "[x] " : "[ ] ") : ""; + const color = this.colorForNode(node); + let meta = ""; + if (color) { + const alias = this.plugin.getColorAlias(this.noteFolder, color); + meta = alias ? `[color: ${color} | alias: ${alias}] ` : `[color: ${color}] `; + } + return { needsDash: task, checkbox, meta }; + } + /** Toggle the "Show more / show less" clamp for the current target(s). * Targets follow getActionTargets (selection > cursor row). Each * target's id is added to or removed from this.expandedNotes; if any