generated at
scrapbox-commit-viewer@0.2.0
deprecatd

hr

commit history (scrapbox)をとても見やすく表示してくれるUserScript

sh
deno run --allow-net --allow-read --allow-write --allow-run --allow-env --unstable https://scrapbox.io/api/code/takker/UserScriptをbundleするDeno_script/build.ts "https://scrapbox.io/api/code/programming-notes/scrapbox-history-slider@0.2.0/script.js" --bundle --minify --charset=utf8 --external=../htm@3.0.4%2Fpreact/script.js --external=../preact@10.5.13/hooks.js | xsel
script.js
import{html as f,render as w}from"../htm@3.0.4%2Fpreact/script.js";import{useState as h,useEffect as v}from"../preact@10.5.13/hooks.js";import{useState as _,useEffect as E,useCallback as I}from"../preact@10.5.13/hooks.js";function k(o,{delay:c},e){let[s,p]=_(!1),a=I(o,e);return E(()=>{(async()=>{let l=setTimeout(()=>p(!0),c);await a(),clearTimeout(l),p(!1)})()},[a,c,...e]),{loading:s}}var S=()=>{let[o,c]=h(!1),[e,s]=h(0),[p,a]=h(0),[l,u]=h(()=>()=>""),{loading:g}=k(async()=>{if(!o)return;let{length:r,getSnapshot:i}=await $();s(r-1),a(r-1),u(()=>i)},{delay:1e3},[o]);v(()=>{scrapbox.PageMenu.addItem({title:"open commit viewer",image:"https://1.bp.blogspot.com/-UZtkSEX0wh4/U5l5_dNcEsI/AAAAAAAAhWs/UzJGVzyiX8Y/s800/kaichu_dokei.png",onClick:()=>c(!0)})},[]);let t=()=>c(!1);return f` <style> :host { color: var(--page-text-color, #fefefe); } .background { position: fixed; top: 0; right: 0; width: 100%; height: 100%; background-color: rgba(255, 255, 255, 0.4); z-index: 89999; } .container { position: fixed; top: 5px; left: 5px; width: calc(100% - 10px); max-height: 80vh; background-color: #555555; border: 3px solid #22cc77; z-index: 90000; } .close-button { font-size: 30px; line-height: 1em; padding: 0; width: 30px; height: 30px; } pre { width: 100%; max-height: 70vh; /* なぜか100%だとはみ出てしまった */ overflow-y: auto; font-family: var(--history-slider-pre-font, Menlo,Monaco,Consolas,"Courier New",monospace); word-break: break-all; word-wrap: break-word; white-space: pre-wrap; } input { width: 90%; } </style> ${o&&f` <div class="background" onClick="${t}"/> <div class="container"> ${g?"Loading...":f` <div style="display: inline"> <input type="range" max="${e}" min="0" step="1" value="${p}" onInput="${({target:{value:r}})=>a(r)}" /> <button class="close-button" onClick="${t}">x</button> </div> <pre>${l(parseInt(p,10))}</pre> `} </div> `} `},m=document.createElement("div");m.dataset.userscriptName="history-slider";m.attachShadow({mode:"open"});document.body.append(m);w(f`<${S} />`,m.shadowRoot);var x="_insert",b="_update",y="_delete";async function $(){let o=await fetch(`/api/commits/${scrapbox.Project.name}/${scrapbox.Page.id}`),{commits:c}=await o.json(),e=c.flatMap(({changes:t,created:n})=>t.flatMap(r=>{let i=T(r,n);return i?[i]:[]})),s=[],p,[a,...l]=e;switch(console.debug({initChange:a,restChanges:l,changes:e}),a.type){case x:s.push(a.lines.text),p={id:a.lines.id,updatedAt:[0]};break;case b:s.push(a.lines.text),p={id:a.targetId,updatedAt:[0]};break;default:console.error("init change neither _insert nor _update")}let u=l.reduce((t,n,r)=>{let i=t.findIndex(d=>d.id===n.targetId);switch(n.type){case x:s.push(n.lines.text);let d={id:n.lines.id,updatedAt:[s.length-1]};if(n.targetId==="_end"){t.push(d);break}if(i===-1)return t;t.splice(i,0,d);break;case b:if(s.push(n.lines.text),i===-1)return t;t[i].updatedAt.push(s.length-1);break;case y:if(s.push(null),i===-1)return t;t[i].deletedAt=s.length-1;break;default:break}return t},[p]);console.debug({allHistory:u});let g=t=>u.flatMap(({updatedAt:n,deletedAt:r,id:i})=>{let d=n.filter(A=>A<=t).pop();return d===void 0||r!==void 0&&r<=t?[]:[{id:i,textIndex:d}]});return{length:s.length,getSnapshot:t=>g(t).map(n=>s[n.textIndex]).join(` `)}}function T(o,c){let e={created:c};if(o.lines&&(e.lines=o.lines),o._insert)e.type=x,e.targetId=o[e.type];else if(o._update)e.type=b,e.targetId=o[e.type];else if(o._delete)e.type=y,e.targetId=o[e.type];else return;return e}

#2022-06-19 20:13:08
#2021-06-10 16:37:21