diff --git a/browser/min/pocketeditor.min.js b/browser/min/pocketeditor.min.js index f959795..a7ba7bf 100644 --- a/browser/min/pocketeditor.min.js +++ b/browser/min/pocketeditor.min.js @@ -5,4 +5,4 @@ `))n.appendChild(e.createLine({text:r,modif:D(r,e.mods)}))}return n}function w(e){function t(i){return i.dataset.list===""?"- ":i.dataset.h1===""?"# ":i.dataset.h2===""?"## ":i.dataset.h3===""?"### ":i.dataset.todoChecked===""?"[x] ":i.dataset.todo===""?"[ ] ":""}let n="",o="",r=i=>i?.dataset.list||i?.dataset.todo;return e.forEach((i,s)=>{o=t(i),n+=o+i.textContent;let f=r(e[s+1])&&r(i),c=e.length-1===s;n+=c?"":f?` `:` -`}),n}function L(e){let t=e;for(;t?.childNodes.length>0;){let n=Object.values(t.childNodes).reverse(),o=n.filter(r=>r.nodeName==="#text");if(o.length>0)return o[0];t=n[0]}return t}function b(e,t){let n=L(e),o=window.getSelection(),r=document.createRange(),i=n.nodeValue?.length||0;r.setStart(n,t?0:i),r.setEnd(n,t?0:i),o?.removeAllRanges(),o?.addRange(r),o?.collapseToEnd()}var H=[];function T(e,t){let n=e.lines,o=w(n),r=t?n.indexOf(t):0;o!==H[0]?.markdown&&(H.unshift({markdown:o,index:r}),H.length>50&&H.pop())}function I(e){let t;new MutationObserver(()=>{t&&clearTimeout(t)}).observe(e.container,{characterData:!0,subtree:!0}),e.container.addEventListener("keydown",o=>{(o.ctrlKey||o.metaKey)&&o.key==="z"&&(t=window.setTimeout(()=>{J(e)},1))})}function J(e){let{markdown:t,index:n}=H[0]??{};t&&(Object.values(e.container.children).forEach(o=>o.remove()),e.container.appendChild(C(e,t)),setTimeout(()=>{let o=e.container.querySelectorAll("[contenteditable]")[n];o&&(o.focus(),b(o,!1))},0),H.shift(),e.container.dispatchEvent(new InputEvent("input",{inputType:"insertText",bubbles:!0,data:""})))}function j(e,t){let n=e.getSelectedLines();n.length>0&&(t.clipboardData?.setData("text/plain",w(n)),t.preventDefault())}function V(e,t){let n=e.getSelectedLines();n.length>0&&(t.clipboardData?.setData("text/plain",w(n)),t.preventDefault(),e.removeLines(n),T(e,n[n.length-1]))}function F(e,t){t.preventDefault();let n=window.getSelection(),o=n?.getRangeAt(0),r=t.clipboardData?.getData("text")||"";if(D(r,e.mods)!==""){let i=t.target,s=C(e,r),f=s.childElementCount-1,c=e.getLineFromEditable(i),d=e.getSelectedLines();if(d.length>0&&(c=d[d.length-1]),!c?.parentElement?.dataset.pocketEditor)return;e.container.insertBefore(s,e.getNextLine(c));let u=c.nextSibling;for(let p=0;p{let m=c?.dataset[l]===l,h=e.getNextLine(c)?.dataset[l]===l;return m===h};(c||p("list")||p("todo")||p("todo-checked"))&&c.remove()}e.container.dispatchEvent(new InputEvent("input",{inputType:"insertText",bubbles:!0,data:""}));return}if(n?.rangeCount&&o){let i=n?.anchorOffset??0,s=n.focusNode?.nodeValue??"";s&&n.focusNode?(n.focusNode.nodeValue=s.slice(0,i)+r+s.slice(i),n.collapse(n.focusNode,i+r.length)):(o.insertNode(document.createTextNode(r)),b(o.endContainer))}e.container.dispatchEvent(new InputEvent("input",{inputType:"insertText",bubbles:!0,data:""}))}function S(e){let t=document.createElement("div"),n=e.parentElement;if(n)return delete n.dataset.list,delete n.dataset.todo,delete n.dataset.h1,delete n.dataset.h2,delete n.dataset.h3,delete n.dataset.todoChecked,t.textContent=n.textContent,t.setAttribute("contenteditable","true"),Object.values(n.childNodes).forEach(o=>o.remove()),n.appendChild(t),t.focus(),t}function M(e,t,n,o=!0){if(!n)return;let r=e.getLineFromEditable(t);if(!r||r?.dataset[n])return;switch(r.querySelector("span[data-list-marker]")?.remove(),r.querySelector("span[data-todo-marker]")?.remove(),delete r.dataset.h1,delete r.dataset.h2,delete r.dataset.h3,delete r.dataset.list,delete r.dataset.todo,delete r.dataset.todoChecked,n){case"h1":case"h2":case"h3":i(n);break;case"list":f();break;case"todo":s(!1);break;case"todo-checked":s(!0);break}function i(c){let d=document.createElement(c),u=c==="h1"?"#":c==="h2"?"##":"###";d.textContent=t.textContent?.replace(u,"").trimStart()||"",d.setAttribute("contenteditable","true"),r&&(r.dataset[c]="",t.replaceWith(d)),o&&b(d)}function s(c){let d=document.createElement("input"),u=document.createElement("span"),p=document.createElement("p"),l=e.getLineFromEditable(t),m=(t.textContent??"").replace(e.ZERO_WIDTH_WHITESPACE,"");!l||l.dataset.todo||((m.startsWith("[ ]")||m.startsWith("[x]"))&&(m=m.slice(4,m.length)),d.type="checkbox",d.name="checkbox",d.setAttribute("aria-label","todo list checkbox"),d.addEventListener("input",()=>{d.checked?(l.setAttribute("data-todo-checked",""),d.setAttribute("checked","")):(l.removeAttribute("data-todo-checked"),l.setAttribute("data-todo",""),d.removeAttribute("checked"))}),c&&(d.setAttribute("checked",""),l.dataset.todoChecked=""),l.dataset.todo="",u.dataset.todoMarker="",p.textContent=m,p.setAttribute("contenteditable","true"),t.replaceWith(p),u.appendChild(d),l.prepend(u),o&&b(p))}function f(){let c=document.createElement("span"),d=document.createElement("p"),u=(t.textContent??"").replace(e.ZERO_WIDTH_WHITESPACE,"");!r||r.dataset.list===""||(u.startsWith("-")&&(u=u?.replace("-","").trimStart()),r.dataset.list="",c.dataset.content="\u2022",c.dataset.listMarker="",d.textContent=u,d.setAttribute("contenteditable","true"),t.replaceWith(d),r.prepend(c),o&&b(d))}}function O(e,t){let n=e.container,o=t.target,r;try{let u=o?.hasAttribute("contenteditable"),p=o?.tagName==="INPUT";if(r=window.getSelection()?.getRangeAt(0),!r||!u||p)throw""}catch{return}let i=e.getLineFromEditable(o),s=Object.keys(i?.dataset??{}),f=t?.inputType==="insertParagraph",c=t?.inputType==="insertText",d;if(t.type==="beforeinput"&&f&&i){t.preventDefault(),T(e,i);let u=(o.textContent??"").replace(e.ZERO_WIDTH_WHITESPACE,""),p=u.slice(0,r.startOffset),l=u.slice(r.startOffset);if((r.startOffset===0||u===""&&r.startOffset===1)&&s.length>0){S(o);return}i.dataset.todo===""&&(d="todo"),i.dataset.list===""&&(d="list"),i.dataset.todoChecked===""&&(d="todo");let h=e.getNextLine(i),E=e.createLine({text:l,modif:d});h?n.insertBefore(E,h):n?.appendChild(E),E.querySelector("[contenteditable]")?.focus(),o.textContent=p,n.dispatchEvent(new InputEvent("input",{inputType:"insertText",bubbles:!0,data:""}));return}if(t.type==="input"&&c){let p=(o?.textContent??"").replace("\u200B","");for(let[l,m]of Object.entries(e.mods))(p.startsWith(m+" ")||p.startsWith(m+"\xA0"))&&(d=l,M(e,o,d))}}function P(e,t){if(!t.key.includes("Arrow")||!window.getSelection()?.anchorNode)return;let n=t.target,o=e.getLineFromEditable(n),r=window?.getSelection()?.getRangeAt(0),i=r?.startContainer?.nodeValue?.length??0;if(!r||!o)return;let s=e.getPrevLine(o),f=e.getNextLine(o),c=Math.min(r?.endOffset,r?.startOffset)===0,d=Math.max(r?.endOffset,r?.startOffset)===i;if(t.key==="ArrowLeft"&&c&&s)return{line:o,dir:"up"};if(t.key==="ArrowRight"&&d&&f)return{line:o,dir:"down"};let u=!1,p=!1,l=r?.getBoundingClientRect(),m=o?.getBoundingClientRect();if(!m||!l||l.y===0?(u=!0,p=!0):(u=m.top-l.top+l.height>0,p=l.bottom+l.height-m.bottom>0),t.key==="ArrowUp"&&s&&u)return{line:o,dir:"up"};if(t.key==="ArrowDown"&&f&&p)return{line:o,dir:"down"}}function W(e){let t=e.lines,n,o=[-1,-1],r=-1,i=-1;function s(a){clearTimeout(n),n=window.setTimeout(()=>{a()},200)}function f(a){if(a||(a=e.getSelectedLines()),a.length===0)return;document.querySelector("#pocket-editor-mock-sel")?.remove();let g=document.createElement("pre");g.id="pocket-editor-mock-sel",g.textContent="mock-selection",g.setAttribute("contenteditable","true"),e.container.appendChild(g);let v=window.getSelection(),k=document.createRange(),y=g.childNodes[0].nodeValue?.length||0;k.setStart(g.childNodes[0],0),k.setEnd(g.childNodes[0],y),v?.removeAllRanges(),v?.addRange(k)}function c(a){let g=e.getLineFromEditable(a);return g?t.indexOf(g):-1}function d(){let a=t[r];a?.querySelector("[contenteditable]")&&b(a),r=-1,i=-1,o=[-1,-1],document.querySelector("#pocket-editor-mock-sel")?.remove(),e.container.removeEventListener("mousemove",E)}function u(a){a>i&&(o[1]=a),a{v>=a[0]&&v<=a[1]?g.setAttribute("data-selected",""):g.removeAttribute("data-selected")}),s(()=>f())}function m(a){r=i=a,o=[a,a]}function h(a){t=e.lines;let g=e.getSelectedLines(),v=a.key.match(/([x|c|v])/g),k=a.key==="Control"||a.key==="Meta",y=g.length>0,R=a.ctrlKey||a.metaKey;if(k||R&&v&&y)return;if(R&&a.key==="a"){window.getSelection()?.removeAllRanges(),r=i=0,o=[0,t.length-1],l(o),a.preventDefault();return}if(y){if(window.getSelection()?.removeAllRanges(),a.key==="Escape"||a.key==="Tab"){d(),l(o),a.preventDefault();return}if(a.key.includes("Arrow")){a.key.includes("Down")&&(r=Math.min(r+1,t.length-1)),a.key.includes("Up")&&(r=Math.max(0,r-1)),a.shiftKey&&u(r),a.shiftKey||p(r),l(o),a.preventDefault();return}a.code.match(/Shift|Alt|Control|Caps/)||(d(),T(e,g[g.length- -1]),e.removeLines(g),a.code==="Enter"&&a.preventDefault())}if(!a.shiftKey)return;let{line:q}=P(e,a)??{};if(q){let Z=t.indexOf(q);m(Z),l(o),window.getSelection()?.removeAllRanges()}}function E(a){let g=a.target,v=e.getSelectedLines();v.length>0&&window.getSelection()?.removeAllRanges();let k=g.getAttribute("aria-label")==="todo list checkbox",y=g.dataset.listMarker,R=!!g.getAttribute("contenteditable");if(k||y||R){if(r=c(g),r===i&&v.length===0)return;u(r),l(o)}}function x(a){let g=a.target,v=a.button===2,k=a.button===0,y=e.getSelectedLines().length>0;t=e.lines,v&&a.preventDefault(),k&&(y&&(d(),l(o)),g.getAttribute("contenteditable")&&(m(c(g)),e.container.addEventListener("mousemove",E)))}function A(a){!a.composedPath().includes(e.container)&&(t=e.lines,d(),l(o)),e.container.removeEventListener("mousemove",E)}window.addEventListener("touchend",A),window.addEventListener("click",A),e.container.addEventListener("keydown",h),e.container.addEventListener("mousedown",x)}function z(e,t){b(t),e.parentElement?.remove()}function Y(e,t){let n=L(t),o=n.nodeType===3,r=n.nodeValue?.length||0,i=e?.textContent||"";n[o?"nodeValue":"textContent"]+=i;let s=window.getSelection(),f=document.createRange();f.setStart(n,o?r:0),f.setEnd(n,o?r:0),s?.removeAllRanges(),s?.addRange(f),e.parentElement.remove()}function _(e){let t="ontouchstart"in window||navigator.maxTouchPoints>0,n=navigator.userAgent.toLowerCase(),o=window.getSelection();function r(i){let s=i.target,f=e.getLineFromEditable(s),c="ontouchstart"in window||navigator.maxTouchPoints>0,d=!!s.getAttribute("contenteditable"),u=o?.getRangeAt(0)?.endOffset===0,p=i.inputType==="deleteContentBackward";if(i.type==="beforeinput"&&!p||!u||!d)return;if(i.preventDefault(),f&&T(e,f),Object.keys(f?.dataset??{}).length>0){let h=S(s);c&&h&&h.textContent===""&&(h.textContent=e.ZERO_WIDTH_WHITESPACE,b(h));return}let m=e.getPrevLine(f);m&&(s.textContent===""&&z(s,m),s.textContent!==""&&Y(s,m))}if(e.container.addEventListener("beforeinput",r),n.includes("safari")&&!n.match(/chrome|chromium/)&&e.container.addEventListener("keydown",i=>{try{let s=o?.getRangeAt(0),f=i.key==="Backspace",c=s?.startOffset===0;f&&c&&r(i)}catch{}}),t){let i=!1;e.container.addEventListener("beforeinput",s=>{let f=s.target,c=s.inputType==="deleteContentBackward",d=f.textContent===e.ZERO_WIDTH_WHITESPACE;c&&d&&(i=!0)}),e.container.addEventListener("keyup",s=>{let f=s.target;if(i){i=!1,r(s);return}f.textContent===""&&(f.textContent=e.ZERO_WIDTH_WHITESPACE,b(f))})}}function K(e){let t=0;function n(){let i=document.createElement("p"),s=document.createElement("span");i.id="pocket-editor-mock-p",s.textContent="abcdefghijklmnopqrstuvwxyz0123456789",i?.appendChild(s),e.container.querySelector(".line [contenteditable]")?.appendChild(i),t=s.offsetWidth/36/2,i.remove()}function o(i,s){let f=window.getSelection(),c=-1,d=U(f,i),u=e.caret_x??d.offset,p=i?.querySelector("[contenteditable]"),l=L(p),m=document.createRange();m.setStart(l,0),m.setEnd(l,0);let h=0;for(let E=0;E=u){c=E;break}}return c}function r(i){let s=i?.querySelector("[contenteditable]");if(!s)return console.warn("Couldn't get string[], no contenteditable found"),[];let f=0,c=0,d=0,u=[""],p=(s.textContent??"").split(" "),l=L(s),m=document.createRange();m.setStart(l,0),m.setEnd(l,0);let h=navigator.userAgent.includes("AppleWebKit");d=c=m.getBoundingClientRect().y;for(let E of p){E=E+" ",f+=E.length;try{m.setStart(l,f),m.setEnd(l,f),c=m.getBoundingClientRect().y}catch{}h&&(u[0]+=E),c>d&&(h&&(u[0]=u[0].trimEnd()),u.unshift(""),d=c),h===!1&&(u[0]+=E)}return u.reverse(),u}e.container.addEventListener("pointerdown",function(){e.caret_x=void 0}),e.container.addEventListener("keydown",function(i){if(!i.key.includes("Arrow"))return;let s=i.key==="ArrowRight",f=i.key==="ArrowLeft",{line:c,dir:d}=P(e,i)??{},u=window.getSelection(),p=document.createRange(),l=0,m;if(f||s?e.caret_x=void 0:e.caret_x===void 0&&(e.caret_x=U(u,c).offset),!!c){if(t===0&&n(),d==="down"){let h=e.getNextLine(c)??c;m=L(h);let E=m.nodeValue?.length||0;if(!s){let x=r(h);l=o(h,x[0])??-1,l<0&&(l=E)}}if(d==="up"){let h=e.getPrevLine(c)??c;m=L(h);let E=m.nodeValue?.length||0;if(l=E,!f){let x=r(h),A=x[x.length-1].trimEnd(),a=o(h,A)??E;l=E-(A.length-a),a<0&&(l=E)}}try{p.setStart(m,l),p.setEnd(m,l),u?.removeAllRanges(),u?.addRange(p),u?.collapseToEnd(),i.preventDefault()}catch{console.warn("Cannot set caret")}}})}function U(e,t){let n=!e?.anchorNode;if(!t||n)return{editable:0,range:0,offset:0};let r=t.querySelector("[contenteditable]")?.getBoundingClientRect().x??0,i=e?.getRangeAt(0)?.cloneRange()?.getBoundingClientRect().x??0;return{editable:r,range:i,offset:i-r}}async function B(e,t){let n=t.target,r=(t.ctrlKey||t.metaKey)&&t.shiftKey&&t.code.includes("Digit"),i=e.getLineFromEditable(n);if(r&&n){let s=parseInt(t.code.replace("Digit",""))-1,c=Object.keys(e.mods)[s];if(i?.hasAttribute(`data-${c}`)||s===5){t.preventDefault(),S(n);return}c in e.mods&&c!=="todo-checked"&&(t.preventDefault(),M(e,n,c))}}var N=class{container;lines;wrapper;caret_x;ZERO_WIDTH_WHITESPACE="\u200B";mods={h1:"#",h2:"##",h3:"###",list:"-",todo:"[ ]","todo-checked":"[x]"};constructor(t,n){let o=document.createElement("div"),{text:r,defer:i,id:s}=n??{};if(this.wrapper=document.querySelector(t),this.container=o,this.lines=[],this.wrapper===null)throw`Pocket editor: selector "${t}" was not found`;s&&(o.id=s),o.dataset.pocketEditor="",typeof i=="number"?setTimeout(()=>this.init(r),i):i===!0?setTimeout(()=>this.init(r)):this.init(r)}init(t){let n=this;t?this.container.appendChild(C(this,t)):this.container.appendChild(this.createLine({text:""})),this.wrapper&&this.wrapper.appendChild(this.container),this.container.addEventListener("beforeinput",i=>O(n,i)),this.container.addEventListener("input",i=>O(n,i)),this.container.addEventListener("keydown",i=>B(n,i)),this.container.addEventListener("paste",i=>F(n,i)),this.container.addEventListener("copy",i=>j(n,i)),this.container.addEventListener("cut",i=>V(n,i)),W(n),K(n),_(n),I(n);let o=()=>{this.lines=Object.values(this.container.children)};new MutationObserver(o).observe(this.container,{childList:!0}),this.lines=Object.values(this.container.children)}get value(){return w(this.lines)}set value(t){Object.values(this.container.children).forEach(n=>n.remove()),this.container.appendChild(C(this,t))}oninput(t){let n=this;return this.container.addEventListener("cut",o),this.container.addEventListener("paste",o),this.container.addEventListener("input",o),this.container.addEventListener("beforeinput",o),()=>{this.container.removeEventListener("cut",o),this.container.removeEventListener("paste",o),this.container.removeEventListener("input",o),this.container.removeEventListener("beforeinput",o)};function o(r){r.type==="beforeinput"&&!r.inputType.match(/(deleteContentBackward|insertParagraph)/g)||t(n.value)}}addEventListener(t,n){return this.oninput(n)}getSelectedLines(){return this.lines.filter(t=>t.dataset.selected!==void 0)??[]}getPrevLine(t){return this.lines[this.lines.indexOf(t)-1]}getNextLine(t){return this.lines[this.lines.indexOf(t)+1]}getLineFromEditable(t){for(;t?.parentElement;){let n=t.parentElement;if(n.tagName==="DIV")return n;t=n}return null}removeLines(t){let n=this.createLine(),o=this.getPrevLine(t[0]);t.forEach(r=>r.remove()),o?this.insertAfter(n,o):this.container.prepend(n),b(n),this.container.dispatchEvent(new InputEvent("input",{inputType:"deleteContent",bubbles:!0,data:""}))}createLine(t){let n=document.createElement("div"),o=document.createElement("p"),r=t?.modif??"",i=this.mods;return o.setAttribute("contenteditable","true"),n.appendChild(o),typeof t?.text=="string"&&(o.textContent=t.text),r in i&&M(this,o,r,!1),n}insertAfter(t,n){n?.parentNode?.insertBefore(t,n.nextSibling)}},Bt=N;globalThis.PocketEditor=N;})(); +`}),n}function L(e){let t=e;for(;t?.childNodes.length>0;){let n=Object.values(t.childNodes).reverse(),o=n.filter(r=>r.nodeName==="#text");if(o.length>0)return o[0];t=n[0]}return t}function b(e,t){let n=L(e),o=window.getSelection(),r=document.createRange(),i=n.nodeValue?.length||0;r.setStart(n,t?0:i),r.setEnd(n,t?0:i),o?.removeAllRanges(),o?.addRange(r),o?.collapseToEnd()}var H=[];function T(e,t){let n=e.lines,o=w(n),r=t?n.indexOf(t):0;o!==H[0]?.markdown&&(H.unshift({markdown:o,index:r}),H.length>50&&H.pop())}function I(e){let t;new MutationObserver(()=>{t&&clearTimeout(t)}).observe(e.container,{characterData:!0,subtree:!0}),e.container.addEventListener("keydown",o=>{(o.ctrlKey||o.metaKey)&&o.key==="z"&&(t=window.setTimeout(()=>{J(e)},1))})}function J(e){let{markdown:t,index:n}=H[0]??{};t&&(Object.values(e.container.children).forEach(o=>o.remove()),e.container.appendChild(C(e,t)),setTimeout(()=>{let o=e.container.querySelectorAll("[contenteditable]")[n];o&&(o.focus(),b(o,!1))},0),H.shift(),e.container.dispatchEvent(new InputEvent("input",{inputType:"insertText",bubbles:!0,data:""})))}function j(e,t){let n=e.getSelectedLines();n.length>0&&(t.clipboardData?.setData("text/plain",w(n)),t.preventDefault())}function V(e,t){let n=e.getSelectedLines();n.length>0&&(t.clipboardData?.setData("text/plain",w(n)),t.preventDefault(),e.removeLines(n),T(e,n[n.length-1]))}function F(e,t){t.preventDefault();let n=window.getSelection(),o=n?.getRangeAt(0),r=t.clipboardData?.getData("text")||"";if(D(r,e.mods)!==""){let i=t.target,s=C(e,r),f=s.childElementCount-1,c=e.getLineFromEditable(i),d=e.getSelectedLines();if(d.length>0&&(c=d[d.length-1]),!c?.parentElement?.dataset.pocketEditor)return;e.container.insertBefore(s,e.getNextLine(c));let u=c.nextSibling;for(let p=0;p{let m=c?.dataset[l]===l,h=e.getNextLine(c)?.dataset[l]===l;return m===h};(c||p("list")||p("todo")||p("todo-checked"))&&c.remove()}e.container.dispatchEvent(new InputEvent("input",{inputType:"insertText",bubbles:!0,data:""}));return}if(n?.rangeCount&&o){let i=n?.anchorOffset??0,s=n.focusNode?.nodeValue??"";s&&n.focusNode?(n.focusNode.nodeValue=s.slice(0,i)+r+s.slice(i),n.collapse(n.focusNode,i+r.length)):(o.insertNode(document.createTextNode(r)),b(o.endContainer))}e.container.dispatchEvent(new InputEvent("input",{inputType:"insertText",bubbles:!0,data:""}))}function M(e){let t=document.createElement("div"),n=e.parentElement;if(n)return delete n.dataset.list,delete n.dataset.todo,delete n.dataset.h1,delete n.dataset.h2,delete n.dataset.h3,delete n.dataset.todoChecked,t.textContent=n.textContent,t.setAttribute("contenteditable","true"),Object.values(n.childNodes).forEach(o=>o.remove()),n.appendChild(t),t.focus(),t}function S(e,t,n,o=!0){if(!n)return;let r=e.getLineFromEditable(t);if(!r||r?.dataset[n])return;switch(r.querySelector("span[data-list-marker]")?.remove(),r.querySelector("span[data-todo-marker]")?.remove(),delete r.dataset.h1,delete r.dataset.h2,delete r.dataset.h3,delete r.dataset.list,delete r.dataset.todo,delete r.dataset.todoChecked,n){case"h1":case"h2":case"h3":i(n);break;case"list":f();break;case"todo":s(!1);break;case"todo-checked":s(!0);break}function i(c){let d=document.createElement(c),u=c==="h1"?"#":c==="h2"?"##":"###";d.textContent=t.textContent?.replace(u,"").trimStart()||"",d.setAttribute("contenteditable","true"),r&&(r.dataset[c]="",t.replaceWith(d)),o&&b(d)}function s(c){let d=document.createElement("input"),u=document.createElement("span"),p=document.createElement("p"),l=e.getLineFromEditable(t),m=(t.textContent??"").replace(e.ZERO_WIDTH_WHITESPACE,"");!l||l.dataset.todo||((m.startsWith("[ ]")||m.startsWith("[x]"))&&(m=m.slice(4,m.length)),d.type="checkbox",d.name="checkbox",d.setAttribute("aria-label","todo list checkbox"),d.addEventListener("input",()=>{d.checked?(l.setAttribute("data-todo-checked",""),d.setAttribute("checked","")):(l.removeAttribute("data-todo-checked"),l.setAttribute("data-todo",""),d.removeAttribute("checked"))}),c&&(d.setAttribute("checked",""),l.dataset.todoChecked=""),l.dataset.todo="",u.dataset.todoMarker="",p.textContent=m,p.setAttribute("contenteditable","true"),t.replaceWith(p),u.appendChild(d),l.prepend(u),o&&b(p))}function f(){let c=document.createElement("span"),d=document.createElement("p"),u=(t.textContent??"").replace(e.ZERO_WIDTH_WHITESPACE,"");!r||r.dataset.list===""||(u.startsWith("-")&&(u=u?.replace("-","").trimStart()),r.dataset.list="",c.dataset.content="\u2022",c.dataset.listMarker="",d.textContent=u,d.setAttribute("contenteditable","true"),t.replaceWith(d),r.prepend(c),o&&b(d))}}function O(e,t){let n=e.container,o=t.target,r;try{let u=o?.hasAttribute("contenteditable"),p=o?.tagName==="INPUT";if(r=window.getSelection()?.getRangeAt(0),!r||!u||p)throw""}catch{return}let i=e.getLineFromEditable(o),s=Object.keys(i?.dataset??{}),f=t?.inputType==="insertParagraph",c=t?.inputType==="insertText",d;if(t.type==="beforeinput"&&f&&i){t.preventDefault(),T(e,i);let u=(o.textContent??"").replace(e.ZERO_WIDTH_WHITESPACE,""),p=u.slice(0,r.startOffset),l=u.slice(r.startOffset);if((r.startOffset===0||u===""&&r.startOffset===1)&&s.length>0){M(o);return}i.dataset.todo===""&&(d="todo"),i.dataset.list===""&&(d="list"),i.dataset.todoChecked===""&&(d="todo");let h=e.getNextLine(i),E=e.createLine({text:l,modif:d});h?n.insertBefore(E,h):n?.appendChild(E),E.querySelector("[contenteditable]")?.focus(),o.textContent=p,n.dispatchEvent(new InputEvent("input",{inputType:"insertText",bubbles:!0,data:""}));return}if(t.type==="input"&&c){let p=(o?.textContent??"").replace("\u200B","");for(let[l,m]of Object.entries(e.mods))(p.startsWith(m+" ")||p.startsWith(m+"\xA0"))&&(d=l,S(e,o,d))}}function P(e,t){if(!t.key.includes("Arrow")||!window.getSelection()?.anchorNode)return;let n=t.target,o=e.getLineFromEditable(n),r=window?.getSelection()?.getRangeAt(0),i=r?.startContainer?.nodeValue?.length??0;if(!r||!o)return;let s=e.getPrevLine(o),f=e.getNextLine(o),c=Math.min(r?.endOffset,r?.startOffset)===0,d=Math.max(r?.endOffset,r?.startOffset)===i;if(t.key==="ArrowLeft"&&c&&s)return{line:o,dir:"up"};if(t.key==="ArrowRight"&&d&&f)return{line:o,dir:"down"};let u=!1,p=!1,l=r?.getBoundingClientRect(),m=o?.getBoundingClientRect();if(!m||!l||l.y===0?(u=!0,p=!0):(u=m.top-l.top+l.height>0,p=l.bottom+l.height-m.bottom>0),t.key==="ArrowUp"&&s&&u)return{line:o,dir:"up"};if(t.key==="ArrowDown"&&f&&p)return{line:o,dir:"down"}}function W(e){let t=e.lines,n,o=[-1,-1],r=-1,i=-1;function s(a){clearTimeout(n),n=window.setTimeout(()=>{a()},200)}function f(a){if(a||(a=e.getSelectedLines()),a.length===0)return;document.querySelector("#pocket-editor-mock-sel")?.remove();let g=document.createElement("pre");g.id="pocket-editor-mock-sel",g.textContent="mock-selection",g.setAttribute("contenteditable","true"),e.container.appendChild(g);let v=window.getSelection(),k=document.createRange(),y=g.childNodes[0].nodeValue?.length||0;k.setStart(g.childNodes[0],0),k.setEnd(g.childNodes[0],y),v?.removeAllRanges(),v?.addRange(k)}function c(a){let g=e.getLineFromEditable(a);return g?t.indexOf(g):-1}function d(){let a=t[r];a?.querySelector("[contenteditable]")&&b(a),r=-1,i=-1,o=[-1,-1],document.querySelector("#pocket-editor-mock-sel")?.remove(),e.container.removeEventListener("mousemove",E)}function u(a){a>i&&(o[1]=a),a{v>=a[0]&&v<=a[1]?g.setAttribute("data-selected",""):g.removeAttribute("data-selected")}),s(()=>f())}function m(a){r=i=a,o=[a,a]}function h(a){t=e.lines;let g=e.getSelectedLines(),v=a.key.match(/([x|c|v])/g),k=a.key==="Control"||a.key==="Meta",y=g.length>0,R=a.ctrlKey||a.metaKey;if(k||R&&v&&y)return;if(R&&a.key==="a"){window.getSelection()?.removeAllRanges(),r=i=0,o=[0,t.length-1],l(o),a.preventDefault();return}if(y){if(window.getSelection()?.removeAllRanges(),a.key==="Escape"||a.key==="Tab"){d(),l(o),a.preventDefault();return}if(a.key.includes("Arrow")){a.key.includes("Down")&&(r=Math.min(r+1,t.length-1)),a.key.includes("Up")&&(r=Math.max(0,r-1)),a.shiftKey&&u(r),a.shiftKey||p(r),l(o),a.preventDefault();return}a.code.match(/Shift|Alt|Control|Caps/)||(d(),T(e,g[g.length- -1]),e.removeLines(g),a.code==="Enter"&&a.preventDefault())}if(!a.shiftKey)return;let{line:q}=P(e,a)??{};if(q){let Z=t.indexOf(q);m(Z),l(o),window.getSelection()?.removeAllRanges()}}function E(a){let g=a.target,v=e.getSelectedLines();v.length>0&&window.getSelection()?.removeAllRanges();let k=g.getAttribute("aria-label")==="todo list checkbox",y=g.dataset.listMarker,R=!!g.getAttribute("contenteditable");if(k||y||R){if(r=c(g),r===i&&v.length===0)return;u(r),l(o)}}function x(a){let g=a.target,v=a.button===2,k=a.button===0,y=e.getSelectedLines().length>0;t=e.lines,v&&a.preventDefault(),k&&(y&&(d(),l(o)),g.getAttribute("contenteditable")&&(m(c(g)),e.container.addEventListener("mousemove",E)))}function A(a){!a.composedPath().includes(e.container)&&(t=e.lines,d(),l(o)),e.container.removeEventListener("mousemove",E)}window.addEventListener("touchend",A),window.addEventListener("click",A),e.container.addEventListener("keydown",h),e.container.addEventListener("mousedown",x)}function z(e,t){b(t),e.parentElement?.remove()}function Y(e,t){let n=L(t),o=n.nodeType===3,r=n.nodeValue?.length||0,i=e?.textContent||"";n[o?"nodeValue":"textContent"]+=i;let s=window.getSelection(),f=document.createRange();f.setStart(n,o?r:0),f.setEnd(n,o?r:0),s?.removeAllRanges(),s?.addRange(f),e.parentElement.remove()}function _(e){let t="ontouchstart"in window||navigator.maxTouchPoints>0,n=navigator.userAgent.toLowerCase(),o=window.getSelection();function r(i){let s=i.target,f=e.getLineFromEditable(s),c="ontouchstart"in window||navigator.maxTouchPoints>0,d=!!s.getAttribute("contenteditable"),u=o?.getRangeAt(0)?.endOffset===0,p=i.inputType==="deleteContentBackward";if(i.type==="beforeinput"&&!p||!u||!d)return;if(i.preventDefault(),f&&T(e,f),Object.keys(f?.dataset??{}).length>0){let h=M(s);c&&h&&h.textContent===""&&(h.textContent=e.ZERO_WIDTH_WHITESPACE,b(h));return}let m=e.getPrevLine(f);m&&(s.textContent===""&&z(s,m),s.textContent!==""&&Y(s,m))}if(e.container.addEventListener("beforeinput",r),n.includes("safari")&&!n.match(/chrome|chromium/)&&e.container.addEventListener("keydown",i=>{try{let s=o?.getRangeAt(0),f=i.key==="Backspace",c=s?.startOffset===0;f&&c&&r(i)}catch{}}),t){let i=!1;e.container.addEventListener("beforeinput",s=>{let f=s.target,c=s.inputType==="deleteContentBackward",d=f.textContent===e.ZERO_WIDTH_WHITESPACE;c&&d&&(i=!0)}),e.container.addEventListener("keyup",s=>{let f=s.target;if(i){i=!1,r(s);return}f.textContent===""&&(f.textContent=e.ZERO_WIDTH_WHITESPACE,b(f))})}}function K(e){let t=0;function n(){let i=document.createElement("p"),s=document.createElement("span");i.id="pocket-editor-mock-p",s.textContent="abcdefghijklmnopqrstuvwxyz0123456789",i?.appendChild(s),e.container.querySelector(".line [contenteditable]")?.appendChild(i),t=s.offsetWidth/36/2,i.remove()}function o(i,s){let f=window.getSelection(),c=-1,d=U(f,i),u=e.caret_x??d.offset,p=i?.querySelector("[contenteditable]"),l=L(p),m=document.createRange();m.setStart(l,0),m.setEnd(l,0);let h=0;for(let E=0;E=u){c=E;break}}return c}function r(i){let s=i?.querySelector("[contenteditable]");if(!s)return console.warn("Couldn't get string[], no contenteditable found"),[];let f=0,c=0,d=0,u=[""],p=(s.textContent??"").split(" "),l=L(s),m=document.createRange();m.setStart(l,0),m.setEnd(l,0);let h=navigator.userAgent.includes("AppleWebKit");d=c=m.getBoundingClientRect().y;for(let E of p){E=E+" ",f+=E.length;try{m.setStart(l,f),m.setEnd(l,f),c=m.getBoundingClientRect().y}catch{}h&&(u[0]+=E),c>d&&(h&&(u[0]=u[0].trimEnd()),u.unshift(""),d=c),h===!1&&(u[0]+=E)}return u.reverse(),u}e.container.addEventListener("pointerdown",function(){e.caret_x=void 0}),e.container.addEventListener("keydown",function(i){if(!i.key.includes("Arrow"))return;let s=i.key==="ArrowRight",f=i.key==="ArrowLeft",{line:c,dir:d}=P(e,i)??{},u=window.getSelection(),p=document.createRange(),l=0,m;if(f||s?e.caret_x=void 0:e.caret_x===void 0&&(e.caret_x=U(u,c).offset),!!c){if(t===0&&n(),d==="down"){let h=e.getNextLine(c)??c;m=L(h);let E=m.nodeValue?.length||0;if(!s){let x=r(h);l=o(h,x[0])??-1,l<0&&(l=E)}}if(d==="up"){let h=e.getPrevLine(c)??c;m=L(h);let E=m.nodeValue?.length||0;if(l=E,!f){let x=r(h),A=x[x.length-1].trimEnd(),a=o(h,A)??E;l=E-(A.length-a),a<0&&(l=E)}}try{p.setStart(m,l),p.setEnd(m,l),u?.removeAllRanges(),u?.addRange(p),u?.collapseToEnd(),i.preventDefault()}catch{console.warn("Cannot set caret")}}})}function U(e,t){let n=!e?.anchorNode;if(!t||n)return{editable:0,range:0,offset:0};let r=t.querySelector("[contenteditable]")?.getBoundingClientRect().x??0,i=e?.getRangeAt(0)?.cloneRange()?.getBoundingClientRect().x??0;return{editable:r,range:i,offset:i-r}}async function B(e,t){let n=t.target,r=(t.ctrlKey||t.metaKey)&&t.shiftKey&&t.code.includes("Digit"),i=e.getLineFromEditable(n);if(r&&n){let s=parseInt(t.code.replace("Digit",""))-1,c=Object.keys(e.mods)[s];if(i?.hasAttribute(`data-${c}`)||s===5){t.preventDefault(),M(n);return}c in e.mods&&c!=="todo-checked"&&(t.preventDefault(),S(e,n,c))}}var N=class{container;lines;wrapper;caret_x;ZERO_WIDTH_WHITESPACE="\u200B";mods={h1:"#",h2:"##",h3:"###",list:"-",todo:"[ ]","todo-checked":"[x]"};constructor(t,n){let o=document.createElement("div"),{text:r,defer:i,id:s}=n??{};if(this.wrapper=typeof t=="string"?document.querySelector(t):t,this.container=o,this.lines=[],this.wrapper===null)throw new Error(`Pocket editor: parent "${t}" was not found`);s&&(o.id=s),o.dataset.pocketEditor="",typeof i=="number"?setTimeout(()=>this.init(r),i):i===!0?setTimeout(()=>this.init(r)):this.init(r)}init(t){let n=this;t?this.container.appendChild(C(this,t)):this.container.appendChild(this.createLine({text:""})),this.wrapper&&this.wrapper.appendChild(this.container),this.container.addEventListener("beforeinput",i=>O(n,i)),this.container.addEventListener("input",i=>O(n,i)),this.container.addEventListener("keydown",i=>B(n,i)),this.container.addEventListener("paste",i=>F(n,i)),this.container.addEventListener("copy",i=>j(n,i)),this.container.addEventListener("cut",i=>V(n,i)),W(n),K(n),_(n),I(n);let o=()=>{this.lines=Object.values(this.container.children)};new MutationObserver(o).observe(this.container,{childList:!0}),this.lines=Object.values(this.container.children)}get value(){return w(this.lines)}set value(t){Object.values(this.container.children).forEach(n=>n.remove()),this.container.appendChild(C(this,t))}oninput(t){let n=this;return this.container.addEventListener("cut",o),this.container.addEventListener("paste",o),this.container.addEventListener("input",o),this.container.addEventListener("beforeinput",o),()=>{this.container.removeEventListener("cut",o),this.container.removeEventListener("paste",o),this.container.removeEventListener("input",o),this.container.removeEventListener("beforeinput",o)};function o(r){r.type==="beforeinput"&&!r.inputType.match(/(deleteContentBackward|insertParagraph)/g)||t(n.value)}}addEventListener(t,n){return this.oninput(n)}getSelectedLines(){return this.lines.filter(t=>t.dataset.selected!==void 0)??[]}getPrevLine(t){return this.lines[this.lines.indexOf(t)-1]}getNextLine(t){return this.lines[this.lines.indexOf(t)+1]}getLineFromEditable(t){for(;t?.parentElement;){let n=t.parentElement;if(n.tagName==="DIV")return n;t=n}return null}removeLines(t){let n=this.createLine(),o=this.getPrevLine(t[0]);t.forEach(r=>r.remove()),o?this.insertAfter(n,o):this.container.prepend(n),b(n),this.container.dispatchEvent(new InputEvent("input",{inputType:"deleteContent",bubbles:!0,data:""}))}createLine(t){let n=document.createElement("div"),o=document.createElement("p"),r=t?.modif??"",i=this.mods;return o.setAttribute("contenteditable","true"),n.appendChild(o),typeof t?.text=="string"&&(o.textContent=t.text),r in i&&S(this,o,r,!1),n}insertAfter(t,n){n?.parentNode?.insertBefore(t,n.nextSibling)}},Bt=N;globalThis.PocketEditor=N;})(); diff --git a/browser/pocketeditor.js b/browser/pocketeditor.js index 2e10f95..abfb574 100644 --- a/browser/pocketeditor.js +++ b/browser/pocketeditor.js @@ -892,7 +892,7 @@ * This creates an editor. * You might also need to add the basic styling with "style.css" * - * @param {string} selector The selector of the parent in which to put the editor + * @param {string | HTMLElement} parent The wrapper in which to put the editor. Either an element or a CSS selector * @param {Object} [options] Pocket editor options * @param {string} [options.text] Default text to add when initializing pocket editor * @param {string} [options.id] Specify an id for this instance of the editor @@ -904,14 +904,14 @@ * * const editor = new pocketEditor("some-selector", { text: "Hello world" }) */ - constructor(selector, options) { + constructor(parent, options) { const div = document.createElement("div"); const { text, defer, id } = options ?? {}; - this.wrapper = document.querySelector(selector); + this.wrapper = typeof parent === "string" ? document.querySelector(parent) : parent; this.container = div; this.lines = []; if (this.wrapper === null) { - throw `Pocket editor: selector "${selector}" was not found`; + throw new Error(`Pocket editor: parent "${parent}" was not found`); } if (id) { div.id = id; diff --git a/package.json b/package.json index 6a30e44..9846d29 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "pocket-editor", "description": "Blazingly fast block style wysiwyg editor that returns markdown", - "version": "2.3.0", + "version": "2.4.0", "main": "dist/index.js", "types": "dist/index.d.ts", "author": "Victor Azevedo (https://victr.me)",