md-editor-v3
Version:
Markdown editor for vue3, developed in jsx and typescript, dark theme、beautify content by prettier、render articles directly、paste or clip the picture and upload it...
2 lines (1 loc) • 9.25 kB
JavaScript
;const n=require("vue"),R=require("./config.cjs"),y=require("./event-bus.cjs"),G=require("./index5.cjs"),W=require("@vavt/util"),P=`.${R.prefix}-preview > [data-line]`,D=(e,l)=>+getComputedStyle(e).getPropertyValue(l).replace("px",""),j=(e,l)=>{const p=W.debounce(()=>{e.removeEventListener("scroll",c),e.addEventListener("scroll",c),l.removeEventListener("scroll",c),l.addEventListener("scroll",c)},50),c=I=>{const m=e.clientHeight,L=l.clientHeight,d=e.scrollHeight,s=l.scrollHeight,a=(d-m)/(s-L);I.target===e?(l.removeEventListener("scroll",c),l.scrollTo({top:e.scrollTop/a}),p()):(e.removeEventListener("scroll",c),e.scrollTo({top:l.scrollTop*a}),p())};return[()=>{p().finally(()=>{e.dispatchEvent(new Event("scroll"))})},()=>{e.removeEventListener("scroll",c),l.removeEventListener("scroll",c)}]},U=(e,l,p)=>{const{view:c}=p,I=W.createSmoothScroll(),m=r=>c.lineBlockAt(c.state.doc.line(r+1).from).top,L=r=>c.lineBlockAt(c.state.doc.line(r+1).from).bottom;let d=[],s=[],a=[];const N=()=>{d=[],s=Array.from(l.querySelectorAll(P)),a=s.map(o=>Number(o.dataset.line));const r=[...a],{lines:g}=c.state.doc;let H=r.shift()||0,t=r.shift()||g;for(let o=0;o<g;o++)o===t&&(H=o,t=r.shift()||g),d.push({start:H,end:t-1})},w=(r,g)=>{let H=1;for(let t=s.length-1;t-1>=0;t--){const o=s[t],f=s[t-1];if(o.offsetTop+o.offsetHeight>g&&f.offsetTop<g){H=Number(f.dataset.line);break}}for(let t=d.length-1;t>=0;t--){const o=L(d[t].end),f=m(d[t].start);if(o>r&&f<=r){H=H<d[t].start?H:d[t].start;break}}return H};let A=0,$=0;const V=()=>{if($!==0)return!1;A++;const{scrollDOM:r,contentHeight:g}=c;let H=D(l,"padding-block-start");const t=c.lineBlockAtHeight(r.scrollTop),{number:o}=c.state.doc.lineAt(t.from),f=d[o-1];if(!f)return!1;let v=1;const k=l.querySelector(`[data-line="${f.start}"]`)||l.firstElementChild?.firstElementChild,u=l.querySelector(`[data-line="${f.end+1}"]`)||l.lastElementChild?.lastElementChild,i=r.scrollHeight-r.clientHeight,b=l.scrollHeight-l.clientHeight;let T=m(f.start),h=L(f.end),x=k.offsetTop,S=u.offsetTop-x;T===0&&(x=0,k===u?(H=0,h=g-r.offsetHeight,S=b):S=u.offsetTop),v=(r.scrollTop-T)/(h-T);const M=u==l.lastElementChild?.lastElementChild?u.offsetTop+u.clientHeight:u.offsetTop;if(h>=i||M>b){const C=w(i,b);T=m(C),v=(r.scrollTop-T)/(i-T);const q=l.querySelector(`[data-line="${C}"]`);T>0&&q&&(x=q.offsetTop),S=b-x+D(l,"padding-block-start")}const E=x-H+S*v;I(l,E,()=>{A--})},B=()=>{if(A!==0)return;$++;const{scrollDOM:r}=c,g=l.scrollTop,H=l.scrollHeight,t=r.scrollHeight-r.clientHeight,o=l.scrollHeight-l.clientHeight;let f=l.firstElementChild?.firstElementChild,v=l.firstElementChild?.lastElementChild;if(a.length>0){let M=Math.ceil(a[a.length-1]*(g/H)),E=a.findLastIndex(C=>C<=M);E=E===-1?0:E,M=a[E];for(let C=E;C>=0&&C<a.length;)if(s[C].offsetTop>g){if(C-1>=0){C--;continue}M=-1,E=C;break}else{if(C+1<a.length&&s[C+1].offsetTop<g){C++;continue}M=a[C],E=C;break}switch(E){case-1:{f=l.firstElementChild?.firstElementChild,v=s[E];break}case a.length-1:{f=s[E],v=l.firstElementChild?.lastElementChild;break}default:f=s[E],v=s[E+1===s.length?E:E+1]}}let k=f===l.firstElementChild?.firstElementChild?0:f.offsetTop-D(f,"margin-block-start"),u=v.offsetTop,i=0;const{start:b,end:T}=d[Number(f.dataset.line||0)];let h=m(b);const x=m(T+1===c.state.doc.lines?T:T+1);let S=0;if(x>t||v.offsetTop+v.offsetHeight>o){const M=w(t,o),E=l.querySelector(`[data-line="${M}"]`);k=E?E.offsetTop-D(E,"margin-block-start"):k,h=m(M),i=(g-k)/(o-k),S=t-h}else f===l.firstElementChild?.firstElementChild?(f===v&&(u=v.offsetTop+v.offsetHeight+D(v,"margin-block-end")),S=x,i=Math.max(g/u,0)):(i=Math.max((g-k)/(u-k),0),S=x-h);I(e,h+S*i,()=>{$--})},O=r=>{const{scrollDOM:g,contentHeight:H}=c,t=g.clientHeight;if(H<=t||l.firstElementChild.clientHeight<=l.clientHeight||c.state.doc.lines<=d[d.length-1]?.end)return!1;r.target===e?V():B()};return[()=>{N(),e.addEventListener("scroll",O),l.addEventListener("scroll",O),e.dispatchEvent(new Event("scroll"))},()=>{e.removeEventListener("scroll",O),l.removeEventListener("scroll",O)}]},z={tocItem:{type:Object,default:()=>({})},mdHeadingId:{type:Function,default:()=>{}},onActive:{type:Function,default:()=>{}},onClick:{type:Function,default:()=>{}},scrollElementOffsetTop:{type:Number,default:0}},F=n.defineComponent({props:z,setup(e){const l=n.inject("scrollElementRef"),p=n.inject("roorNodeRef"),c=n.ref();n.watch(()=>e.tocItem.active,m=>{m&&e.onActive(e.tocItem,c.value)}),n.onMounted(()=>{e.tocItem.active&&e.onActive(e.tocItem,c.value)});const I=m=>{if(m.stopPropagation(),e.onClick(m,e.tocItem),m.defaultPrevented)return;const L=e.mdHeadingId({text:e.tocItem.text,level:e.tocItem.level,index:e.tocItem.index,currentToken:e.tocItem.currentToken,nextToken:e.tocItem.nextToken}),d=p.value.getElementById(L),s=l.value;if(d&&s){let a=d.offsetParent,N=d.offsetTop;if(s.contains(a))for(;a&&s!=a;)N+=a?.offsetTop,a=a?.offsetParent;const w=d.previousElementSibling;let A=0;w||(A=D(d,"margin-block-start")),s?.scrollTo({top:N-e.scrollElementOffsetTop-A,behavior:"smooth"})}};return()=>n.createVNode("div",{ref:c,class:[`${R.prefix}-catalog-link`,e.tocItem.active&&`${R.prefix}-catalog-active`],onClick:I},[n.createVNode("span",{title:e.tocItem.text},[e.tocItem.text]),e.tocItem.children&&e.tocItem.children.length>0&&n.createVNode("div",{class:`${R.prefix}-catalog-wrapper`},[e.tocItem.children.map(m=>n.createVNode(F,{mdHeadingId:e.mdHeadingId,key:`${e.tocItem.text}-link-${m.level}-${m.text}`,tocItem:m,onActive:e.onActive,onClick:e.onClick,scrollElementOffsetTop:e.scrollElementOffsetTop},null))])])}}),J={editorId:{type:String,default:void 0},class:{type:String,default:""},mdHeadingId:{type:Function,default:({text:e})=>e},scrollElement:{type:[String,Object],default:void 0},theme:{type:String,default:"light"},offsetTop:{type:Number,default:20},scrollElementOffsetTop:{type:Number,default:0},onClick:{type:Function,default:void 0},onActive:{type:Function,default:void 0},isScrollElementInShadow:{type:Boolean,default:!1},syncWith:{type:String,default:"preview"},catalogMaxDepth:{type:Number,default:void 0}},_=n.defineComponent({name:"MdCatalog",props:J,emits:["onClick","onActive"],setup(e,l){const p=e.editorId,c=`#${p}-preview-wrapper`,I=n.reactive({list:[],show:!1,scrollElement:e.scrollElement||c}),m=n.shallowRef(),L=n.ref(),d=n.ref(),s=n.ref(),a=n.ref(),N=n.shallowRef(),w=n.ref({});n.provide("scrollElementRef",d),n.provide("roorNodeRef",a);const A=n.computed(()=>{const t=[];return I.list.forEach((o,f)=>{if(e.catalogMaxDepth&&o.level>e.catalogMaxDepth)return;const{text:v,level:k,line:u}=o,i={level:k,text:v,line:u,index:f+1,active:m.value===o};if(t.length===0)t.push(i);else{let b=t[t.length-1];if(i.level>b.level)for(let T=b.level+1;T<=6;T++){const{children:h}=b;if(!h){b.children=[i];break}if(b=h[h.length-1],i.level<=b.level){h.push(i);break}}else t.push(i)}}),t}),$=()=>{if(I.scrollElement instanceof HTMLElement)return I.scrollElement;let t=document;return(I.scrollElement===c||e.isScrollElementInShadow)&&(t=L.value?.getRootNode()),t.querySelector(I.scrollElement)},V=t=>{if(t.length===0)return m.value=void 0,I.list=[],!1;const{activeHead:o,activeIndex:f}=t.reduce((u,i,b)=>{let T=0;if(e.syncWith==="preview"){const h=a.value?.getElementById(e.mdHeadingId({text:i.text,level:i.level,index:b+1,currentToken:i.currentToken,nextToken:i.nextToken}));h instanceof HTMLElement&&(T=G.getRelativeTop(h,d.value))}else{const h=N.value;if(h){const x=h.lineBlockAt(h.state.doc.line(i.line+1).from).top,S=h.scrollDOM.scrollTop;T=x-S}}return T<e.offsetTop&&T>u.minTop?{activeHead:i,activeIndex:b,minTop:T}:u},{activeHead:t[0],activeIndex:0,minTop:Number.MIN_SAFE_INTEGER});let v=o;const{catalogMaxDepth:k}=e;if(k&&v.level>k){for(let u=f;u>=0;u--){const i=t[u];if(i.level<=k){v=i;break}}if(v.level>k){const u=t.find(i=>i.level<=k);u&&(v=u)}}m.value=v,I.list=t},B=(t,o)=>{w.value.top=o.offsetTop+D(o,"padding-block-start")+"px",e.onActive?.(t,o),l.emit("onActive",t,o)},O=()=>{V(I.list)},r=t=>{if(s.value?.removeEventListener("scroll",O),e.syncWith==="editor")s.value=N.value?.scrollDOM;else{const o=$();d.value=o,s.value=o===document.documentElement?document:o}V(t),s.value?.addEventListener("scroll",O)},g=t=>{N.value=t};n.watch([()=>e.syncWith,N,()=>e.catalogMaxDepth],()=>{r(I.list)}),n.onMounted(()=>{a.value=L.value.getRootNode(),y.bus.on(p,{name:y.CATALOG_CHANGED,callback:r}),y.bus.on(p,{name:y.GET_EDITOR_VIEW,callback:g}),y.bus.emit(p,y.PUSH_CATALOG),y.bus.emit(p,y.SEND_EDITOR_VIEW)}),n.onBeforeUnmount(()=>{y.bus.remove(p,y.CATALOG_CHANGED,r),y.bus.remove(p,y.GET_EDITOR_VIEW,g),s.value?.removeEventListener("scroll",O)});const H=(t,o)=>{e.onClick?.(t,o),l.emit("onClick",t,o)};return()=>n.createVNode("div",{class:[`${R.prefix}-catalog`,e.theme==="dark"&&`${R.prefix}-catalog-dark`,e.class||""],ref:L},[A.value.length>0&&n.createVNode(n.Fragment,null,[n.createVNode("div",{class:`${R.prefix}-catalog-indicator`,style:w.value},null),n.createVNode("div",{class:`${R.prefix}-catalog-container`},[A.value.map(t=>n.createVNode(F,{mdHeadingId:e.mdHeadingId,tocItem:t,key:`link-${t.level}-${t.text}`,onActive:B,onClick:H,scrollElementOffsetTop:e.scrollElementOffsetTop},null))])])])}});_.install=e=>(e.component(_.name,_),e);exports.MdCatalog=_;exports.scrollAuto=U;exports.scrollAutoWithScale=j;