markdown-actions 1.0.3 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/markdown-actions.esm.js +59 -78
- package/dist/markdown-actions.esm.js.map +3 -3
- package/dist/markdown-actions.js +59 -78
- package/dist/markdown-actions.js.map +3 -3
- package/dist/markdown-actions.min.js +20 -22
- package/package.json +1 -1
- package/src/core/selection.js +10 -2
- package/src/index.js +76 -117
|
@@ -1,22 +1,20 @@
|
|
|
1
|
-
var markdownActions=(()=>{var
|
|
2
|
-
`).length>1}function Oe(e,n){let t=n;for(;e[t]&&e[t-1]!=null&&!e[t-1].match(/\s/);)t--;return t}function
|
|
3
|
-
`),t=0;for(let
|
|
4
|
-
`.repeat(2-
|
|
5
|
-
`.repeat(2-d)),{newlinesToAppend:
|
|
6
|
-
`;)
|
|
7
|
-
`;)
|
|
8
|
-
`:
|
|
9
|
-
${
|
|
10
|
-
`);if(
|
|
11
|
-
`),
|
|
12
|
-
`),
|
|
13
|
-
`),t=/^\d+\.\s+/,
|
|
14
|
-
`),processed:
|
|
15
|
-
`),t="- ",
|
|
16
|
-
`),processed:
|
|
17
|
-
`).map((S
|
|
18
|
-
`)+
|
|
19
|
-
`),d=0,
|
|
20
|
-
`),
|
|
21
|
-
`;)r--;for(;u<c.length&&c[u]!==`
|
|
22
|
-
`;)u++;e.selectionStart=r,e.selectionEnd=u;let f=c.slice(r,u),p=f.match(/^(#{1,6})\s*/),E=p?p[0].length:0,L=p?p[1].length:0,S=f.replace(/^#{1,6}\s*/,""),h,b=!1;t&&L===n?(h=S,b=!0):h=o.prefix+S;let g,a;if(s){let m=l-r;if(b)m<E?g=r:g=l-E;else if(E>0)if(m<E)g=r+Math.min(m,o.prefix.length);else{let M=o.prefix.length-E;g=l+M}else g=l+o.prefix.length;g=Math.min(g,r+h.length),a=g}else{if(b)g=Math.max(l-E,r),a=Math.max(i-E,r);else if(E>0){let m=o.prefix.length-E;g=l+m,a=i+m}else g=l+o.prefix.length,a=i+o.prefix.length;g=Math.min(g,r+h.length),a=Math.min(a,r+h.length)}y(e,{text:h,selectionStart:g,selectionEnd:a})}function de(e){$(e,1,!0)}function ge(e){$(e,2,!0)}function pe(e){$(e,3,!0)}function he(e){return j(e)}function Se(e,n){return ne(e,n)}function me(e,n={}){te(e,n)}function Ee(e,n){if(!e||e.disabled||e.readOnly)return;let t=v(n),l;if(t.multiline){let i=e.value.slice(e.selectionStart,e.selectionEnd);w(i)?l=F(e,t):l=x(e,t)}else l=x(e,t);y(e,l)}var We={toggleBold:le,toggleItalic:ie,toggleCode:oe,insertLink:se,toggleBulletList:ce,toggleNumberedList:re,toggleQuote:ue,toggleTaskList:fe,insertHeader:$,toggleH1:de,toggleH2:ge,toggleH3:pe,getActiveFormats:he,hasFormat:Se,expandSelection:me,applyCustomFormat:Ee,preserveSelection:V,setUndoMethod:U,setDebugMode:B,getDebugMode:W};return ye(Ne);})();
|
|
1
|
+
var markdownActions=(()=>{var A=Object.defineProperty;var be=Object.getOwnPropertyDescriptor;var ae=Object.getOwnPropertyNames,K=Object.getOwnPropertySymbols;var G=Object.prototype.hasOwnProperty,Le=Object.prototype.propertyIsEnumerable;var z=(e,n,t)=>n in e?A(e,n,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[n]=t,B=(e,n)=>{for(var t in n||(n={}))G.call(n,t)&&z(e,t,n[t]);if(K)for(var t of K(n))Le.call(n,t)&&z(e,t,n[t]);return e};var ve=(e,n)=>{for(var t in n)A(e,t,{get:n[t],enumerable:!0})},Te=(e,n,t,i)=>{if(n&&typeof n=="object"||typeof n=="function")for(let l of ae(n))!G.call(e,l)&&l!==t&&A(e,l,{get:()=>n[l],enumerable:!(i=be(n,l))||i.enumerable});return e};var ye=e=>Te(A({},"__esModule",{value:!0}),e);var Ne={};ve(Ne,{applyCustomFormat:()=>me,default:()=>We,expandSelection:()=>Se,getActiveFormats:()=>pe,getDebugMode:()=>k,hasFormat:()=>he,insertHeader:()=>R,insertLink:()=>se,preserveSelection:()=>H,setDebugMode:()=>U,setUndoMethod:()=>J,toggleBold:()=>te,toggleBulletList:()=>oe,toggleCode:()=>le,toggleH1:()=>de,toggleH2:()=>fe,toggleH3:()=>ge,toggleItalic:()=>ie,toggleNumberedList:()=>ce,toggleQuote:()=>re,toggleTaskList:()=>ue});var T={bold:{prefix:"**",suffix:"**",trimFirst:!0},italic:{prefix:"_",suffix:"_",trimFirst:!0},code:{prefix:"`",suffix:"`",blockPrefix:"```",blockSuffix:"```"},link:{prefix:"[",suffix:"](url)",replaceNext:"url",scanFor:"https?://"},bulletList:{prefix:"- ",multiline:!0,unorderedList:!0},numberedList:{prefix:"1. ",multiline:!0,orderedList:!0},quote:{prefix:"> ",multiline:!0,surroundWithNewlines:!0},taskList:{prefix:"- [ ] ",multiline:!0,surroundWithNewlines:!0},header1:{prefix:"# "},header2:{prefix:"## "},header3:{prefix:"### "},header4:{prefix:"#### "},header5:{prefix:"##### "},header6:{prefix:"###### "}};function xe(){return{prefix:"",suffix:"",blockPrefix:"",blockSuffix:"",multiline:!1,replaceNext:"",prefixSpace:!1,scanFor:"",surroundWithNewlines:!1,orderedList:!1,unorderedList:!1,trimFirst:!1}}function y(e){return B(B({},xe()),e)}var w=!1;function U(e){w=e}function k(){return w}function I(e,n,t){w&&(console.group(`\u{1F50D} ${e}`),console.log(n),t&&console.log("Data:",t),console.groupEnd())}function W(e,n){if(!w)return;let t=e.value.slice(e.selectionStart,e.selectionEnd);console.group(`\u{1F4CD} Selection: ${n}`),console.log("Position:",`${e.selectionStart}-${e.selectionEnd}`),console.log("Selected text:",JSON.stringify(t)),console.log("Length:",t.length);let i=e.value.slice(Math.max(0,e.selectionStart-10),e.selectionStart),l=e.value.slice(e.selectionEnd,Math.min(e.value.length,e.selectionEnd+10));console.log("Context:",JSON.stringify(i)+"[SELECTION]"+JSON.stringify(l)),console.groupEnd()}function D(e){w&&(console.group("\u{1F4DD} Result"),console.log("Text to insert:",JSON.stringify(e.text)),console.log("New selection:",`${e.selectionStart}-${e.selectionEnd}`),console.groupEnd())}var L=null;function v(e,{text:n,selectionStart:t,selectionEnd:i}){let l=k();l&&(console.group("\u{1F527} insertText"),console.log("Current selection:",`${e.selectionStart}-${e.selectionEnd}`),console.log("Text to insert:",JSON.stringify(n)),console.log("New selection to set:",t,"-",i)),e.focus();let o=e.selectionStart,d=e.selectionEnd,c=e.value.slice(0,o),s=e.value.slice(d);l&&(console.log("Before text (last 20):",JSON.stringify(c.slice(-20))),console.log("After text (first 20):",JSON.stringify(s.slice(0,20))),console.log("Selected text being replaced:",JSON.stringify(e.value.slice(o,d))));let f=e.value,u=o!==d;if(!u&&(L===null||L===!0)){e.contentEditable="true";try{L=document.execCommand("insertText",!1,n)}catch(r){L=!1}e.contentEditable="false"}else u&&(l&&console.log("Has selection, skipping execCommand and using manual mode"),L=!1);if(l&&(console.log("canInsertText before:",L),console.log("execCommand result:",L)),L){let r=c+n+s,g=e.value;l&&(console.log("Expected length:",r.length),console.log("Actual length:",g.length)),g!==r&&l&&(console.log("execCommand changed the value but not as expected"),console.log("Expected:",JSON.stringify(r.slice(0,100))),console.log("Actual:",JSON.stringify(g.slice(0,100))))}if(!L)if(l&&console.log("Using manual insertion"),e.value===f){l&&console.log("Value unchanged, doing manual replacement");try{document.execCommand("ms-beginUndoUnit")}catch(r){}e.value=c+n+s;try{document.execCommand("ms-endUndoUnit")}catch(r){}e.dispatchEvent(new CustomEvent("input",{bubbles:!0,cancelable:!0}))}else l&&console.log("Value was changed by execCommand, skipping manual insertion");l&&console.log("Setting selection range:",t,i),t!=null&&i!=null?e.setSelectionRange(t,i):e.setSelectionRange(o,e.selectionEnd),l&&(console.log("Final value length:",e.value.length),console.groupEnd())}function J(e){switch(e){case"native":L=!0;break;case"manual":L=!1;break;case"auto":L=null;break}}function N(e){return e.trim().split(`
|
|
2
|
+
`).length>1}function Oe(e,n){let t=n;for(;e[t]&&e[t-1]!=null&&!e[t-1].match(/\s/);)t--;return t}function Me(e,n,t){let i=n,l=t?/\n/:/\s/;for(;e[i]&&!e[i].match(l);)i++;return i}function j(e){let n=e.value.split(`
|
|
3
|
+
`),t=0;for(let i=0;i<n.length;i++){let l=n[i].length+1;e.selectionStart>=t&&e.selectionStart<t+l&&(e.selectionStart=t),e.selectionEnd>=t&&e.selectionEnd<t+l&&(i===n.length-1?e.selectionEnd=Math.min(t+n[i].length,e.value.length):e.selectionEnd=t+l-1),t+=l}}function X(e,n,t,i=!1){if(e.selectionStart===e.selectionEnd)e.selectionStart=Oe(e.value,e.selectionStart),e.selectionEnd=Me(e.value,e.selectionEnd,i);else{let l=e.selectionStart-n.length,o=e.selectionEnd+t.length,d=e.value.slice(l,e.selectionStart)===n,c=e.value.slice(e.selectionEnd,o)===t;d&&c&&(e.selectionStart=l,e.selectionEnd=o)}return e.value.slice(e.selectionStart,e.selectionEnd)}function C(e){let n=e.value.slice(0,e.selectionStart),t=e.value.slice(e.selectionEnd),i=n.match(/\n*$/),l=t.match(/^\n*/),o=i?i[0].length:0,d=l?l[0].length:0,c="",s="";return n.match(/\S/)&&o<2&&(c=`
|
|
4
|
+
`.repeat(2-o)),t.match(/\S/)&&d<2&&(s=`
|
|
5
|
+
`.repeat(2-d)),{newlinesToAppend:c,newlinesToPrepend:s}}function H(e,n){let t=e.selectionStart,i=e.selectionEnd,l=e.scrollTop;n(),e.selectionStart=t,e.selectionEnd=i,e.scrollTop=l}function $(e,n,t={}){let i=e.selectionStart,l=e.selectionEnd,o=i===l,d=e.value,c=i;for(;c>0&&d[c-1]!==`
|
|
6
|
+
`;)c--;if(o){let f=i;for(;f<d.length&&d[f]!==`
|
|
7
|
+
`;)f++;e.selectionStart=c,e.selectionEnd=f}else j(e);let s=n(e);if(t.adjustSelection){let u=e.value.slice(e.selectionStart,e.selectionEnd).startsWith(t.prefix),r=t.adjustSelection(u,i,l,c);s.selectionStart=r.start,s.selectionEnd=r.end}else if(t.prefix){let u=e.value.slice(e.selectionStart,e.selectionEnd).startsWith(t.prefix);o?u?(s.selectionStart=Math.max(i-t.prefix.length,c),s.selectionEnd=s.selectionStart):(s.selectionStart=i+t.prefix.length,s.selectionEnd=s.selectionStart):u?(s.selectionStart=Math.max(i-t.prefix.length,c),s.selectionEnd=Math.max(l-t.prefix.length,c)):(s.selectionStart=i+t.prefix.length,s.selectionEnd=l+t.prefix.length)}return s}function M(e,n){let t,i,{prefix:l,suffix:o,blockPrefix:d,blockSuffix:c,replaceNext:s,prefixSpace:f,scanFor:u,surroundWithNewlines:r,trimFirst:g}=n,h=e.selectionStart,E=e.selectionEnd,p=e.value.slice(e.selectionStart,e.selectionEnd),S=N(p)&&d&&d.length>0?`${d}
|
|
8
|
+
`:l,m=N(p)&&c&&c.length>0?`
|
|
9
|
+
${c}`:o;if(f){let b=e.value[e.selectionStart-1];e.selectionStart!==0&&b!=null&&!b.match(/\s/)&&(S=` ${S}`)}p=X(e,S,m,n.multiline);let a=e.selectionStart,x=e.selectionEnd,Ee=s&&s.length>0&&m.indexOf(s)>-1&&p.length>0;if(r){let b=C(e);t=b.newlinesToAppend,i=b.newlinesToPrepend,S=t+l,m+=i}if(p.startsWith(S)&&p.endsWith(m)){let b=p.slice(S.length,p.length-m.length);if(h===E){let O=h-S.length;O=Math.max(O,a),O=Math.min(O,a+b.length),a=x=O}else x=a+b.length;return{text:b,selectionStart:a,selectionEnd:x}}else if(Ee)if(u&&u.length>0&&p.match(u)){m=m.replace(s,p);let b=S+m;return a=x=a+S.length,{text:b,selectionStart:a,selectionEnd:x}}else{let b=S+p+m;return a=a+S.length+p.length+m.indexOf(s),x=a+s.length,{text:b,selectionStart:a,selectionEnd:x}}else{let b=S+p+m;a=h+S.length,x=E+S.length;let O=p.match(/^\s*|\s*$/g);if(g&&O){let q=O[0]||"",Q=O[1]||"";b=q+S+p.trim()+m+Q,a+=q.length,x-=Q.length}return{text:b,selectionStart:a,selectionEnd:x}}}function P(e,n){let{prefix:t,suffix:i,surroundWithNewlines:l}=n,o=e.value.slice(e.selectionStart,e.selectionEnd),d=e.selectionStart,c=e.selectionEnd,s=o.split(`
|
|
10
|
+
`);if(s.every(u=>u.startsWith(t)&&(!i||u.endsWith(i))))o=s.map(u=>{let r=u.slice(t.length);return i&&(r=r.slice(0,r.length-i.length)),r}).join(`
|
|
11
|
+
`),c=d+o.length;else if(o=s.map(u=>t+u+(i||"")).join(`
|
|
12
|
+
`),l){let{newlinesToAppend:u,newlinesToPrepend:r}=C(e);d+=u.length,c=d+o.length,o=u+o+r}return{text:o,selectionStart:d,selectionEnd:c}}function Y(e){let n=e.split(`
|
|
13
|
+
`),t=/^\d+\.\s+/,i=n.every(o=>t.test(o)),l=n;return i&&(l=n.map(o=>o.replace(t,""))),{text:l.join(`
|
|
14
|
+
`),processed:i}}function Z(e){let n=e.split(`
|
|
15
|
+
`),t="- ",i=n.every(o=>o.startsWith(t)),l=n;return i&&(l=n.map(o=>o.slice(t.length))),{text:l.join(`
|
|
16
|
+
`),processed:i}}function F(e,n){return n?"- ":`${e+1}. `}function we(e,n){let t,i,l;return e.orderedList?(t=Y(n),i=Z(t.text),l=i.text):(t=Z(n),i=Y(t.text),l=i.text),[t,i,l]}function ke(e,n){let t=e.selectionStart===e.selectionEnd,i=e.selectionStart,l=e.selectionEnd;j(e);let o=e.value.slice(e.selectionStart,e.selectionEnd),[d,c,s]=we(n,o),f=s.split(`
|
|
17
|
+
`).map((p,S)=>`${F(S,n.unorderedList)}${p}`),u=f.reduce((p,S,m)=>p+F(m,n.unorderedList).length,0),r=f.reduce((p,S,m)=>p+F(m,!n.unorderedList).length,0);if(d.processed)return t?(i=Math.max(i-F(0,n.unorderedList).length,0),l=i):(i=e.selectionStart,l=e.selectionEnd-u),{text:s,selectionStart:i,selectionEnd:l};let{newlinesToAppend:g,newlinesToPrepend:h}=C(e),E=g+f.join(`
|
|
18
|
+
`)+h;return t?(i=Math.max(i+F(0,n.unorderedList).length+g.length,0),l=i):c.processed?(i=Math.max(e.selectionStart+g.length,0),l=e.selectionEnd+g.length+u-r):(i=Math.max(e.selectionStart+g.length,0),l=e.selectionEnd+g.length+u),{text:E,selectionStart:i,selectionEnd:l}}function V(e,n){let t=e.selectionStart,i=e.selectionEnd,l=ke(e,n);v(e,l)}function _(e){if(!e)return[];let n=[],{selectionStart:t,selectionEnd:i,value:l}=e,o=l.split(`
|
|
19
|
+
`),d=0,c="";for(let r of o){if(t>=d&&t<=d+r.length){c=r;break}d+=r.length+1}c.startsWith("- ")&&(c.startsWith("- [ ] ")||c.startsWith("- [x] ")?n.push("task-list"):n.push("bullet-list")),/^\d+\.\s/.test(c)&&n.push("numbered-list"),c.startsWith("> ")&&n.push("quote"),c.startsWith("# ")&&n.push("header"),c.startsWith("## ")&&n.push("header-2"),c.startsWith("### ")&&n.push("header-3");let s=Math.max(0,t-10),f=Math.min(l.length,i+10),u=l.slice(s,f);if(u.includes("**")){let r=l.slice(Math.max(0,t-100),t),g=l.slice(i,Math.min(l.length,i+100)),h=r.lastIndexOf("**"),E=g.indexOf("**");h!==-1&&E!==-1&&n.push("bold")}if(u.includes("_")){let r=l.slice(Math.max(0,t-100),t),g=l.slice(i,Math.min(l.length,i+100)),h=r.lastIndexOf("_"),E=g.indexOf("_");h!==-1&&E!==-1&&n.push("italic")}if(u.includes("`")){let r=l.slice(Math.max(0,t-100),t),g=l.slice(i,Math.min(l.length,i+100));r.includes("`")&&g.includes("`")&&n.push("code")}if(u.includes("[")&&u.includes("]")){let r=l.slice(Math.max(0,t-100),t),g=l.slice(i,Math.min(l.length,i+100)),h=r.lastIndexOf("["),E=g.indexOf("]");h!==-1&&E!==-1&&l.slice(i+E+1,i+E+10).startsWith("(")&&n.push("link")}return n}function ee(e,n){return _(e).includes(n)}function ne(e,n={}){if(!e)return;let{toWord:t,toLine:i,toFormat:l}=n,{selectionStart:o,selectionEnd:d,value:c}=e;if(i){let s=c.split(`
|
|
20
|
+
`),f=0,u=0,r=0;for(let g of s){if(o>=r&&o<=r+g.length){f=r,u=r+g.length;break}r+=g.length+1}e.selectionStart=f,e.selectionEnd=u}else if(t&&o===d){let s=o,f=d;for(;s>0&&!/\s/.test(c[s-1]);)s--;for(;f<c.length&&!/\s/.test(c[f]);)f++;e.selectionStart=s,e.selectionEnd=f}}function te(e){if(!e||e.disabled||e.readOnly)return;I("toggleBold","Starting"),W(e,"Before");let n=y(T.bold),t=M(e,n);D(t),v(e,t),W(e,"After")}function ie(e){if(!e||e.disabled||e.readOnly)return;let n=y(T.italic),t=M(e,n);v(e,t)}function le(e){if(!e||e.disabled||e.readOnly)return;let n=y(T.code),t=M(e,n);v(e,t)}function se(e,n={}){if(!e||e.disabled||e.readOnly)return;let t=e.value.slice(e.selectionStart,e.selectionEnd),i=y(T.link);if(t&&t.match(/^https?:\/\//)&&!n.url?(i.suffix=`](${t})`,i.replaceNext=""):n.url&&(i.suffix=`](${n.url})`,i.replaceNext=""),n.text&&!t){let d=e.selectionStart;e.value=e.value.slice(0,d)+n.text+e.value.slice(d),e.selectionStart=d,e.selectionEnd=d+n.text.length}let o=M(e,i);v(e,o)}function oe(e){if(!e||e.disabled||e.readOnly)return;let n=y(T.bulletList);V(e,n)}function ce(e){if(!e||e.disabled||e.readOnly)return;let n=y(T.numberedList);V(e,n)}function re(e){if(!e||e.disabled||e.readOnly)return;I("toggleQuote","Starting"),W(e,"Initial");let n=y(T.quote),t=$(e,i=>P(i,n),{prefix:n.prefix});D(t),v(e,t),W(e,"Final")}function ue(e){if(!e||e.disabled||e.readOnly)return;let n=y(T.taskList),t=$(e,i=>P(i,n),{prefix:n.prefix});v(e,t)}function R(e,n=1,t=!1){if(!e||e.disabled||e.readOnly)return;(n<1||n>6)&&(n=1);let i=`header${n===1?"1":n}`,l=y(T[i]||T.header1),o=e.selectionStart,d=e.selectionEnd,c=$(e,s=>{let f=s.value.slice(s.selectionStart,s.selectionEnd),u=f.match(/^(#{1,6})\s*/),r=u?u[1].length:0,g=f.replace(/^#{1,6}\s*/,""),h;return t&&r===n?h=g:h=l.prefix+g,{text:h,selectionStart:s.selectionStart,selectionEnd:s.selectionEnd}},{prefix:l.prefix,adjustSelection:(s,f,u,r)=>{let h=e.value.slice(r,e.selectionEnd).match(/^(#{1,6})\s*/),E=h?h[0].length:0,p=h?h[1].length:0;if(t&&p===n)return{start:Math.max(f-E,r),end:Math.max(u-E,r)};if(E>0){let m=l.prefix.length-E;return{start:f+m,end:u+m}}else return{start:f+l.prefix.length,end:u+l.prefix.length}}});v(e,c)}function de(e){R(e,1,!0)}function fe(e){R(e,2,!0)}function ge(e){R(e,3,!0)}function pe(e){return _(e)}function he(e,n){return ee(e,n)}function Se(e,n={}){ne(e,n)}function me(e,n){if(!e||e.disabled||e.readOnly)return;let t=y(n),i;if(t.multiline){let l=e.value.slice(e.selectionStart,e.selectionEnd);N(l)?i=P(e,t):i=M(e,t)}else i=M(e,t);v(e,i)}var We={toggleBold:te,toggleItalic:ie,toggleCode:le,insertLink:se,toggleBulletList:oe,toggleNumberedList:ce,toggleQuote:re,toggleTaskList:ue,insertHeader:R,toggleH1:de,toggleH2:fe,toggleH3:ge,getActiveFormats:pe,hasFormat:he,expandSelection:Se,applyCustomFormat:me,preserveSelection:H,setUndoMethod:J,setDebugMode:U,getDebugMode:k};return ye(Ne);})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "markdown-actions",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "A lightweight, zero-dependency JavaScript library for adding markdown formatting functionality to any textarea element",
|
|
5
5
|
"main": "dist/markdown-actions.js",
|
|
6
6
|
"module": "dist/markdown-actions.esm.js",
|
package/src/core/selection.js
CHANGED
|
@@ -123,6 +123,7 @@ export function preserveSelection(textarea, callback) {
|
|
|
123
123
|
* @param {Function} operation - The operation to perform (receives textarea and returns result)
|
|
124
124
|
* @param {Object} options - Options for the operation
|
|
125
125
|
* @param {string} options.prefix - The prefix being added/removed (for cursor adjustment)
|
|
126
|
+
* @param {Function} options.adjustSelection - Custom selection adjustment function
|
|
126
127
|
* @returns {Object} The result from the operation with adjusted cursor position
|
|
127
128
|
*/
|
|
128
129
|
export function applyLineOperation(textarea, operation, options = {}) {
|
|
@@ -161,8 +162,15 @@ export function applyLineOperation(textarea, operation, options = {}) {
|
|
|
161
162
|
const result = operation(textarea)
|
|
162
163
|
|
|
163
164
|
// Restore original selection/cursor with prefix adjustment
|
|
164
|
-
if (options.
|
|
165
|
-
//
|
|
165
|
+
if (options.adjustSelection) {
|
|
166
|
+
// Use custom selection adjustment logic
|
|
167
|
+
const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)
|
|
168
|
+
const isRemoving = selectedText.startsWith(options.prefix)
|
|
169
|
+
const adjusted = options.adjustSelection(isRemoving, originalStart, originalEnd, lineStart)
|
|
170
|
+
result.selectionStart = adjusted.start
|
|
171
|
+
result.selectionEnd = adjusted.end
|
|
172
|
+
} else if (options.prefix) {
|
|
173
|
+
// Use default prefix-based adjustment
|
|
166
174
|
const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)
|
|
167
175
|
const isRemoving = selectedText.startsWith(options.prefix)
|
|
168
176
|
|
package/src/index.js
CHANGED
|
@@ -45,23 +45,10 @@ export function toggleItalic(textarea) {
|
|
|
45
45
|
*/
|
|
46
46
|
export function toggleCode(textarea) {
|
|
47
47
|
if (!textarea || textarea.disabled || textarea.readOnly) return
|
|
48
|
-
const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)
|
|
49
|
-
const style = mergeWithDefaults(FORMATS.code)
|
|
50
|
-
|
|
51
|
-
// Use block style for single line, multiline style for multiple lines
|
|
52
|
-
let result
|
|
53
|
-
if (isMultipleLines(selectedText)) {
|
|
54
|
-
// For multiline, we want code blocks
|
|
55
|
-
const blockStyle = {
|
|
56
|
-
prefix: '```\n',
|
|
57
|
-
suffix: '\n```',
|
|
58
|
-
surroundWithNewlines: true
|
|
59
|
-
}
|
|
60
|
-
result = multilineStyle(textarea, mergeWithDefaults(blockStyle))
|
|
61
|
-
} else {
|
|
62
|
-
result = blockStyle(textarea, style)
|
|
63
|
-
}
|
|
64
48
|
|
|
49
|
+
// blockStyle already handles both inline and block code correctly
|
|
50
|
+
const style = mergeWithDefaults(FORMATS.code)
|
|
51
|
+
const result = blockStyle(textarea, style)
|
|
65
52
|
insertText(textarea, result)
|
|
66
53
|
}
|
|
67
54
|
|
|
@@ -74,8 +61,16 @@ export function insertLink(textarea, options = {}) {
|
|
|
74
61
|
const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)
|
|
75
62
|
let style = mergeWithDefaults(FORMATS.link)
|
|
76
63
|
|
|
77
|
-
//
|
|
78
|
-
|
|
64
|
+
// Check if selected text is a URL
|
|
65
|
+
const isURL = selectedText && selectedText.match(/^https?:\/\//)
|
|
66
|
+
|
|
67
|
+
if (isURL && !options.url) {
|
|
68
|
+
// If selected text is a URL, use it as both link text and URL
|
|
69
|
+
style.suffix = `](${selectedText})`
|
|
70
|
+
style.replaceNext = ''
|
|
71
|
+
// Don't change the selected text, it becomes the link text
|
|
72
|
+
} else if (options.url) {
|
|
73
|
+
// Override with custom URL if provided
|
|
79
74
|
style.suffix = `](${options.url})`
|
|
80
75
|
style.replaceNext = ''
|
|
81
76
|
}
|
|
@@ -161,113 +156,77 @@ export function insertHeader(textarea, level = 1, toggle = false) {
|
|
|
161
156
|
if (!textarea || textarea.disabled || textarea.readOnly) return
|
|
162
157
|
if (level < 1 || level > 6) level = 1
|
|
163
158
|
|
|
164
|
-
// Save original cursor position before any expansion
|
|
165
|
-
const originalStart = textarea.selectionStart
|
|
166
|
-
const originalEnd = textarea.selectionEnd
|
|
167
|
-
const noInitialSelection = originalStart === originalEnd
|
|
168
|
-
|
|
169
159
|
const headerKey = `header${level === 1 ? '1' : level}`
|
|
170
160
|
const style = mergeWithDefaults(FORMATS[headerKey] || FORMATS.header1)
|
|
171
161
|
|
|
172
|
-
//
|
|
173
|
-
const
|
|
174
|
-
|
|
175
|
-
let lineEnd = originalStart
|
|
176
|
-
|
|
177
|
-
// Find line boundaries
|
|
178
|
-
while (lineStart > 0 && value[lineStart - 1] !== '\n') {
|
|
179
|
-
lineStart--
|
|
180
|
-
}
|
|
181
|
-
while (lineEnd < value.length && value[lineEnd] !== '\n') {
|
|
182
|
-
lineEnd++
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
textarea.selectionStart = lineStart
|
|
186
|
-
textarea.selectionEnd = lineEnd
|
|
187
|
-
|
|
188
|
-
const currentLine = value.slice(lineStart, lineEnd)
|
|
189
|
-
|
|
190
|
-
// Check if we're removing or changing existing header
|
|
191
|
-
const existingHeaderMatch = currentLine.match(/^(#{1,6})\s*/)
|
|
192
|
-
const existingPrefixLength = existingHeaderMatch ? existingHeaderMatch[0].length : 0
|
|
193
|
-
const existingLevel = existingHeaderMatch ? existingHeaderMatch[1].length : 0
|
|
194
|
-
|
|
195
|
-
// Remove any existing header formatting
|
|
196
|
-
const cleanedLine = currentLine.replace(/^#{1,6}\s*/, '')
|
|
197
|
-
|
|
198
|
-
let newLine
|
|
199
|
-
let isRemoving = false
|
|
200
|
-
|
|
201
|
-
// If toggle mode and current line has the same header level, remove it
|
|
202
|
-
if (toggle && existingLevel === level) {
|
|
203
|
-
newLine = cleanedLine
|
|
204
|
-
isRemoving = true
|
|
205
|
-
} else {
|
|
206
|
-
// Apply new header
|
|
207
|
-
newLine = style.prefix + cleanedLine
|
|
208
|
-
}
|
|
209
|
-
|
|
210
|
-
let selectionStart, selectionEnd
|
|
162
|
+
// Save original positions before any operations
|
|
163
|
+
const originalStart = textarea.selectionStart
|
|
164
|
+
const originalEnd = textarea.selectionEnd
|
|
211
165
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
if
|
|
219
|
-
|
|
220
|
-
|
|
166
|
+
// Use applyLineOperation for consistent behavior
|
|
167
|
+
const result = applyLineOperation(
|
|
168
|
+
textarea,
|
|
169
|
+
(ta) => {
|
|
170
|
+
const currentLine = ta.value.slice(ta.selectionStart, ta.selectionEnd)
|
|
171
|
+
|
|
172
|
+
// Check if we're removing or changing existing header
|
|
173
|
+
const existingHeaderMatch = currentLine.match(/^(#{1,6})\s*/)
|
|
174
|
+
const existingLevel = existingHeaderMatch ? existingHeaderMatch[1].length : 0
|
|
175
|
+
|
|
176
|
+
// Remove any existing header formatting
|
|
177
|
+
const cleanedLine = currentLine.replace(/^#{1,6}\s*/, '')
|
|
178
|
+
|
|
179
|
+
let newLine
|
|
180
|
+
|
|
181
|
+
// If toggle mode and current line has the same header level, remove it
|
|
182
|
+
if (toggle && existingLevel === level) {
|
|
183
|
+
newLine = cleanedLine
|
|
221
184
|
} else {
|
|
222
|
-
//
|
|
223
|
-
|
|
185
|
+
// Apply new header
|
|
186
|
+
newLine = style.prefix + cleanedLine
|
|
224
187
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
188
|
+
|
|
189
|
+
return {
|
|
190
|
+
text: newLine,
|
|
191
|
+
selectionStart: ta.selectionStart,
|
|
192
|
+
selectionEnd: ta.selectionEnd
|
|
193
|
+
}
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
prefix: style.prefix,
|
|
197
|
+
// Custom handler for header-specific logic
|
|
198
|
+
adjustSelection: (isRemoving, selStart, selEnd, lineStart) => {
|
|
199
|
+
const currentLine = textarea.value.slice(lineStart, textarea.selectionEnd)
|
|
200
|
+
const existingHeaderMatch = currentLine.match(/^(#{1,6})\s*/)
|
|
201
|
+
const existingPrefixLength = existingHeaderMatch ? existingHeaderMatch[0].length : 0
|
|
202
|
+
const existingLevel = existingHeaderMatch ? existingHeaderMatch[1].length : 0
|
|
203
|
+
|
|
204
|
+
// Check if we're actually removing (toggle off)
|
|
205
|
+
const actuallyRemoving = toggle && existingLevel === level
|
|
206
|
+
|
|
207
|
+
if (actuallyRemoving) {
|
|
208
|
+
// Removing the header entirely
|
|
209
|
+
return {
|
|
210
|
+
start: Math.max(selStart - existingPrefixLength, lineStart),
|
|
211
|
+
end: Math.max(selEnd - existingPrefixLength, lineStart)
|
|
212
|
+
}
|
|
213
|
+
} else if (existingPrefixLength > 0) {
|
|
214
|
+
// Replacing existing header with new one
|
|
215
|
+
const prefixDiff = style.prefix.length - existingPrefixLength
|
|
216
|
+
return {
|
|
217
|
+
start: selStart + prefixDiff,
|
|
218
|
+
end: selEnd + prefixDiff
|
|
219
|
+
}
|
|
220
|
+
} else {
|
|
221
|
+
// Adding new header
|
|
222
|
+
return {
|
|
223
|
+
start: selStart + style.prefix.length,
|
|
224
|
+
end: selEnd + style.prefix.length
|
|
225
|
+
}
|
|
226
|
+
}
|
|
234
227
|
}
|
|
235
|
-
} else {
|
|
236
|
-
// We're adding a new header
|
|
237
|
-
// Move cursor by the length of the new prefix
|
|
238
|
-
selectionStart = originalStart + style.prefix.length
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// Ensure cursor doesn't go past end of line
|
|
242
|
-
selectionStart = Math.min(selectionStart, lineStart + newLine.length)
|
|
243
|
-
selectionEnd = selectionStart
|
|
244
|
-
} else {
|
|
245
|
-
// Had a selection - preserve it with adjustment
|
|
246
|
-
if (isRemoving) {
|
|
247
|
-
// When removing header, shift selection back
|
|
248
|
-
selectionStart = Math.max(originalStart - existingPrefixLength, lineStart)
|
|
249
|
-
selectionEnd = Math.max(originalEnd - existingPrefixLength, lineStart)
|
|
250
|
-
} else if (existingPrefixLength > 0) {
|
|
251
|
-
// We're replacing an existing header
|
|
252
|
-
const prefixDiff = style.prefix.length - existingPrefixLength
|
|
253
|
-
selectionStart = originalStart + prefixDiff
|
|
254
|
-
selectionEnd = originalEnd + prefixDiff
|
|
255
|
-
} else {
|
|
256
|
-
// We're adding a new header
|
|
257
|
-
selectionStart = originalStart + style.prefix.length
|
|
258
|
-
selectionEnd = originalEnd + style.prefix.length
|
|
259
228
|
}
|
|
260
|
-
|
|
261
|
-
// Ensure selection doesn't go past end of line
|
|
262
|
-
selectionStart = Math.min(selectionStart, lineStart + newLine.length)
|
|
263
|
-
selectionEnd = Math.min(selectionEnd, lineStart + newLine.length)
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
const result = {
|
|
267
|
-
text: newLine,
|
|
268
|
-
selectionStart,
|
|
269
|
-
selectionEnd
|
|
270
|
-
}
|
|
229
|
+
)
|
|
271
230
|
|
|
272
231
|
insertText(textarea, result)
|
|
273
232
|
}
|