markdown-actions 1.0.1 → 1.0.3
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 +116 -66
- package/dist/markdown-actions.esm.js.map +4 -4
- package/dist/markdown-actions.js +116 -66
- package/dist/markdown-actions.js.map +4 -4
- package/dist/markdown-actions.min.js +22 -22
- package/package.json +1 -1
- package/src/core/insertion.js +37 -21
- package/src/core/selection.js +36 -21
- package/src/debug.js +25 -0
- package/src/index.js +26 -8
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
var markdownActions=(()=>{var
|
|
2
|
-
`).length>1}function
|
|
3
|
-
`),t=0;for(let l=0;l<n.length;l++){let i=n[l].length+1;e.selectionStart>=t&&e.selectionStart<t+i&&(e.selectionStart=t),e.selectionEnd>=t&&e.selectionEnd<t+i&&(l===n.length-1?e.selectionEnd=Math.min(t+n[l].length,e.value.length):e.selectionEnd=t+i-1),t+=i}}function
|
|
4
|
-
`.repeat(2-
|
|
5
|
-
`.repeat(2-
|
|
6
|
-
`;)r
|
|
7
|
-
`;)
|
|
8
|
-
`:i,
|
|
9
|
-
${
|
|
10
|
-
`);if(
|
|
11
|
-
`),
|
|
12
|
-
`),i){let{newlinesToAppend:
|
|
13
|
-
`),t=/^\d+\.\s+/,l=n.every(
|
|
14
|
-
`),processed:l}}function
|
|
15
|
-
`),t="- ",l=n.every(
|
|
16
|
-
`),processed:l}}function
|
|
17
|
-
`).map((S,
|
|
18
|
-
`)+
|
|
19
|
-
`),
|
|
20
|
-
`),r=0,
|
|
21
|
-
`;)r--;for(;c
|
|
22
|
-
`;)
|
|
1
|
+
var markdownActions=(()=>{var P=Object.defineProperty;var be=Object.getOwnPropertyDescriptor;var ae=Object.getOwnPropertyNames,z=Object.getOwnPropertySymbols;var X=Object.prototype.hasOwnProperty,Le=Object.prototype.propertyIsEnumerable;var G=(e,n,t)=>n in e?P(e,n,{enumerable:!0,configurable:!0,writable:!0,value:t}):e[n]=t,R=(e,n)=>{for(var t in n||(n={}))X.call(n,t)&&G(e,t,n[t]);if(z)for(var t of z(n))Le.call(n,t)&&G(e,t,n[t]);return e};var ve=(e,n)=>{for(var t in n)P(e,t,{get:n[t],enumerable:!0})},Te=(e,n,t,l)=>{if(n&&typeof n=="object"||typeof n=="function")for(let i of ae(n))!X.call(e,i)&&i!==t&&P(e,i,{get:()=>n[i],enumerable:!(l=be(n,i))||l.enumerable});return e};var ye=e=>Te(P({},"__esModule",{value:!0}),e);var Ne={};ve(Ne,{applyCustomFormat:()=>Ee,default:()=>We,expandSelection:()=>me,getActiveFormats:()=>he,getDebugMode:()=>W,hasFormat:()=>Se,insertHeader:()=>$,insertLink:()=>se,preserveSelection:()=>V,setDebugMode:()=>B,setUndoMethod:()=>U,toggleBold:()=>le,toggleBulletList:()=>ce,toggleCode:()=>oe,toggleH1:()=>de,toggleH2:()=>ge,toggleH3:()=>pe,toggleItalic:()=>ie,toggleNumberedList:()=>re,toggleQuote:()=>ue,toggleTaskList:()=>fe});var O={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 Me(){return{prefix:"",suffix:"",blockPrefix:"",blockSuffix:"",multiline:!1,replaceNext:"",prefixSpace:!1,scanFor:"",surroundWithNewlines:!1,orderedList:!1,unorderedList:!1,trimFirst:!1}}function v(e){return R(R({},Me()),e)}var k=!1;function B(e){k=e}function W(){return k}function I(e,n,t){k&&(console.group(`\u{1F50D} ${e}`),console.log(n),t&&console.log("Data:",t),console.groupEnd())}function N(e,n){if(!k)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 l=e.value.slice(Math.max(0,e.selectionStart-10),e.selectionStart),i=e.value.slice(e.selectionEnd,Math.min(e.value.length,e.selectionEnd+10));console.log("Context:",JSON.stringify(l)+"[SELECTION]"+JSON.stringify(i)),console.groupEnd()}function D(e){k&&(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 T=null;function y(e,{text:n,selectionStart:t,selectionEnd:l}){let i=W();i&&(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,"-",l)),e.focus();let s=e.selectionStart,d=e.selectionEnd,o=e.value.slice(0,s),c=e.value.slice(d);i&&(console.log("Before text (last 20):",JSON.stringify(o.slice(-20))),console.log("After text (first 20):",JSON.stringify(c.slice(0,20))),console.log("Selected text being replaced:",JSON.stringify(e.value.slice(s,d))));let r=e.value,u=s!==d;if(!u&&(T===null||T===!0)){e.contentEditable="true";try{T=document.execCommand("insertText",!1,n)}catch(f){T=!1}e.contentEditable="false"}else u&&(i&&console.log("Has selection, skipping execCommand and using manual mode"),T=!1);if(i&&(console.log("canInsertText before:",T),console.log("execCommand result:",T)),T){let f=o+n+c,p=e.value;i&&(console.log("Expected length:",f.length),console.log("Actual length:",p.length)),p!==f&&i&&(console.log("execCommand changed the value but not as expected"),console.log("Expected:",JSON.stringify(f.slice(0,100))),console.log("Actual:",JSON.stringify(p.slice(0,100))))}if(!T)if(i&&console.log("Using manual insertion"),e.value===r){i&&console.log("Value unchanged, doing manual replacement");try{document.execCommand("ms-beginUndoUnit")}catch(f){}e.value=o+n+c;try{document.execCommand("ms-endUndoUnit")}catch(f){}e.dispatchEvent(new CustomEvent("input",{bubbles:!0,cancelable:!0}))}else i&&console.log("Value was changed by execCommand, skipping manual insertion");i&&console.log("Setting selection range:",t,l),t!=null&&l!=null?e.setSelectionRange(t,l):e.setSelectionRange(s,e.selectionEnd),i&&(console.log("Final value length:",e.value.length),console.groupEnd())}function U(e){switch(e){case"native":T=!0;break;case"manual":T=!1;break;case"auto":T=null;break}}function w(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 xe(e,n,t){let l=n,i=t?/\n/:/\s/;for(;e[l]&&!e[l].match(i);)l++;return l}function J(e){let n=e.value.split(`
|
|
3
|
+
`),t=0;for(let l=0;l<n.length;l++){let i=n[l].length+1;e.selectionStart>=t&&e.selectionStart<t+i&&(e.selectionStart=t),e.selectionEnd>=t&&e.selectionEnd<t+i&&(l===n.length-1?e.selectionEnd=Math.min(t+n[l].length,e.value.length):e.selectionEnd=t+i-1),t+=i}}function Y(e,n,t,l=!1){if(e.selectionStart===e.selectionEnd)e.selectionStart=Oe(e.value,e.selectionStart),e.selectionEnd=xe(e.value,e.selectionEnd,l);else{let i=e.selectionStart-n.length,s=e.selectionEnd+t.length,d=e.value.slice(i,e.selectionStart)===n,o=e.value.slice(e.selectionEnd,s)===t;d&&o&&(e.selectionStart=i,e.selectionEnd=s)}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),l=n.match(/\n*$/),i=t.match(/^\n*/),s=l?l[0].length:0,d=i?i[0].length:0,o="",c="";return n.match(/\S/)&&s<2&&(o=`
|
|
4
|
+
`.repeat(2-s)),t.match(/\S/)&&d<2&&(c=`
|
|
5
|
+
`.repeat(2-d)),{newlinesToAppend:o,newlinesToPrepend:c}}function V(e,n){let t=e.selectionStart,l=e.selectionEnd,i=e.scrollTop;n(),e.selectionStart=t,e.selectionEnd=l,e.scrollTop=i}function _(e,n,t={}){let l=e.selectionStart,i=e.selectionEnd,s=l===i,d=e.value,o=l;for(;o>0&&d[o-1]!==`
|
|
6
|
+
`;)o--;if(s){let r=l;for(;r<d.length&&d[r]!==`
|
|
7
|
+
`;)r++;e.selectionStart=o,e.selectionEnd=r}else J(e);let c=n(e);if(t.prefix){let u=e.value.slice(e.selectionStart,e.selectionEnd).startsWith(t.prefix);s?u?(c.selectionStart=Math.max(l-t.prefix.length,o),c.selectionEnd=c.selectionStart):(c.selectionStart=l+t.prefix.length,c.selectionEnd=c.selectionStart):u?(c.selectionStart=Math.max(l-t.prefix.length,o),c.selectionEnd=Math.max(i-t.prefix.length,o)):(c.selectionStart=l+t.prefix.length,c.selectionEnd=i+t.prefix.length)}return c}function x(e,n){let t,l,{prefix:i,suffix:s,blockPrefix:d,blockSuffix:o,replaceNext:c,prefixSpace:r,scanFor:u,surroundWithNewlines:f,trimFirst:p}=n,E=e.selectionStart,L=e.selectionEnd,S=e.value.slice(e.selectionStart,e.selectionEnd),h=w(S)&&d&&d.length>0?`${d}
|
|
8
|
+
`:i,b=w(S)&&o&&o.length>0?`
|
|
9
|
+
${o}`:s;if(r){let m=e.value[e.selectionStart-1];e.selectionStart!==0&&m!=null&&!m.match(/\s/)&&(h=` ${h}`)}S=Y(e,h,b,n.multiline);let g=e.selectionStart,a=e.selectionEnd,q=c&&c.length>0&&b.indexOf(c)>-1&&S.length>0;if(f){let m=C(e);t=m.newlinesToAppend,l=m.newlinesToPrepend,h=t+i,b+=l}if(S.startsWith(h)&&S.endsWith(b)){let m=S.slice(h.length,S.length-b.length);if(E===L){let M=E-h.length;M=Math.max(M,g),M=Math.min(M,g+m.length),g=a=M}else a=g+m.length;return{text:m,selectionStart:g,selectionEnd:a}}else if(q)if(u&&u.length>0&&S.match(u)){b=b.replace(c,S);let m=h+b;return g=a=g+h.length,{text:m,selectionStart:g,selectionEnd:a}}else{let m=h+S+b;return g=g+h.length+S.length+b.indexOf(c),a=g+c.length,{text:m,selectionStart:g,selectionEnd:a}}else{let m=h+S+b;g=E+h.length,a=L+h.length;let M=S.match(/^\s*|\s*$/g);if(p&&M){let Q=M[0]||"",K=M[1]||"";m=Q+h+S.trim()+b+K,g+=Q.length,a-=K.length}return{text:m,selectionStart:g,selectionEnd:a}}}function F(e,n){let{prefix:t,suffix:l,surroundWithNewlines:i}=n,s=e.value.slice(e.selectionStart,e.selectionEnd),d=e.selectionStart,o=e.selectionEnd,c=s.split(`
|
|
10
|
+
`);if(c.every(u=>u.startsWith(t)&&(!l||u.endsWith(l))))s=c.map(u=>{let f=u.slice(t.length);return l&&(f=f.slice(0,f.length-l.length)),f}).join(`
|
|
11
|
+
`),o=d+s.length;else if(s=c.map(u=>t+u+(l||"")).join(`
|
|
12
|
+
`),i){let{newlinesToAppend:u,newlinesToPrepend:f}=C(e);d+=u.length,o=d+s.length,s=u+s+f}return{text:s,selectionStart:d,selectionEnd:o}}function Z(e){let n=e.split(`
|
|
13
|
+
`),t=/^\d+\.\s+/,l=n.every(s=>t.test(s)),i=n;return l&&(i=n.map(s=>s.replace(t,""))),{text:i.join(`
|
|
14
|
+
`),processed:l}}function ee(e){let n=e.split(`
|
|
15
|
+
`),t="- ",l=n.every(s=>s.startsWith(t)),i=n;return l&&(i=n.map(s=>s.slice(t.length))),{text:i.join(`
|
|
16
|
+
`),processed:l}}function A(e,n){return n?"- ":`${e+1}. `}function we(e,n){let t,l,i;return e.orderedList?(t=Z(n),l=ee(t.text),i=l.text):(t=ee(n),l=Z(t.text),i=l.text),[t,l,i]}function ke(e,n){let t=e.selectionStart===e.selectionEnd,l=e.selectionStart,i=e.selectionEnd;J(e);let s=e.value.slice(e.selectionStart,e.selectionEnd),[d,o,c]=we(n,s),r=c.split(`
|
|
17
|
+
`).map((S,h)=>`${A(h,n.unorderedList)}${S}`),u=r.reduce((S,h,b)=>S+A(b,n.unorderedList).length,0),f=r.reduce((S,h,b)=>S+A(b,!n.unorderedList).length,0);if(d.processed)return t?(l=Math.max(l-A(0,n.unorderedList).length,0),i=l):(l=e.selectionStart,i=e.selectionEnd-u),{text:c,selectionStart:l,selectionEnd:i};let{newlinesToAppend:p,newlinesToPrepend:E}=C(e),L=p+r.join(`
|
|
18
|
+
`)+E;return t?(l=Math.max(l+A(0,n.unorderedList).length+p.length,0),i=l):o.processed?(l=Math.max(e.selectionStart+p.length,0),i=e.selectionEnd+p.length+u-f):(l=Math.max(e.selectionStart+p.length,0),i=e.selectionEnd+p.length+u),{text:L,selectionStart:l,selectionEnd:i}}function H(e,n){let t=e.selectionStart,l=e.selectionEnd,i=ke(e,n);y(e,i)}function j(e){if(!e)return[];let n=[],{selectionStart:t,selectionEnd:l,value:i}=e,s=i.split(`
|
|
19
|
+
`),d=0,o="";for(let f of s){if(t>=d&&t<=d+f.length){o=f;break}d+=f.length+1}o.startsWith("- ")&&(o.startsWith("- [ ] ")||o.startsWith("- [x] ")?n.push("task-list"):n.push("bullet-list")),/^\d+\.\s/.test(o)&&n.push("numbered-list"),o.startsWith("> ")&&n.push("quote"),o.startsWith("# ")&&n.push("header"),o.startsWith("## ")&&n.push("header-2"),o.startsWith("### ")&&n.push("header-3");let c=Math.max(0,t-10),r=Math.min(i.length,l+10),u=i.slice(c,r);if(u.includes("**")){let f=i.slice(Math.max(0,t-100),t),p=i.slice(l,Math.min(i.length,l+100)),E=f.lastIndexOf("**"),L=p.indexOf("**");E!==-1&&L!==-1&&n.push("bold")}if(u.includes("_")){let f=i.slice(Math.max(0,t-100),t),p=i.slice(l,Math.min(i.length,l+100)),E=f.lastIndexOf("_"),L=p.indexOf("_");E!==-1&&L!==-1&&n.push("italic")}if(u.includes("`")){let f=i.slice(Math.max(0,t-100),t),p=i.slice(l,Math.min(i.length,l+100));f.includes("`")&&p.includes("`")&&n.push("code")}if(u.includes("[")&&u.includes("]")){let f=i.slice(Math.max(0,t-100),t),p=i.slice(l,Math.min(i.length,l+100)),E=f.lastIndexOf("["),L=p.indexOf("]");E!==-1&&L!==-1&&i.slice(l+L+1,l+L+10).startsWith("(")&&n.push("link")}return n}function ne(e,n){return j(e).includes(n)}function te(e,n={}){if(!e)return;let{toWord:t,toLine:l,toFormat:i}=n,{selectionStart:s,selectionEnd:d,value:o}=e;if(l){let c=o.split(`
|
|
20
|
+
`),r=0,u=0,f=0;for(let p of c){if(s>=f&&s<=f+p.length){r=f,u=f+p.length;break}f+=p.length+1}e.selectionStart=r,e.selectionEnd=u}else if(t&&s===d){let c=s,r=d;for(;c>0&&!/\s/.test(o[c-1]);)c--;for(;r<o.length&&!/\s/.test(o[r]);)r++;e.selectionStart=c,e.selectionEnd=r}}function le(e){if(!e||e.disabled||e.readOnly)return;I("toggleBold","Starting"),N(e,"Before");let n=v(O.bold),t=x(e,n);D(t),y(e,t),N(e,"After")}function ie(e){if(!e||e.disabled||e.readOnly)return;let n=v(O.italic),t=x(e,n);y(e,t)}function oe(e){if(!e||e.disabled||e.readOnly)return;let n=e.value.slice(e.selectionStart,e.selectionEnd),t=v(O.code),l;w(n)?l=F(e,v({prefix:"```\n",suffix:"\n```",surroundWithNewlines:!0})):l=x(e,t),y(e,l)}function se(e,n={}){if(!e||e.disabled||e.readOnly)return;let t=e.value.slice(e.selectionStart,e.selectionEnd),l=v(O.link);if(n.url&&(l.suffix=`](${n.url})`,l.replaceNext=""),n.text&&!t){let s=e.selectionStart;e.value=e.value.slice(0,s)+n.text+e.value.slice(s),e.selectionStart=s,e.selectionEnd=s+n.text.length}let i=x(e,l);y(e,i)}function ce(e){if(!e||e.disabled||e.readOnly)return;let n=v(O.bulletList);H(e,n)}function re(e){if(!e||e.disabled||e.readOnly)return;let n=v(O.numberedList);H(e,n)}function ue(e){if(!e||e.disabled||e.readOnly)return;I("toggleQuote","Starting"),N(e,"Initial");let n=v(O.quote),t=_(e,l=>F(l,n),{prefix:n.prefix});D(t),y(e,t),N(e,"Final")}function fe(e){if(!e||e.disabled||e.readOnly)return;let n=v(O.taskList),t=_(e,l=>F(l,n),{prefix:n.prefix});y(e,t)}function $(e,n=1,t=!1){if(!e||e.disabled||e.readOnly)return;(n<1||n>6)&&(n=1);let l=e.selectionStart,i=e.selectionEnd,s=l===i,d=`header${n===1?"1":n}`,o=v(O[d]||O.header1),c=e.value,r=l,u=l;for(;r>0&&c[r-1]!==`
|
|
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);})();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "markdown-actions",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.3",
|
|
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/insertion.js
CHANGED
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
* Extracted and adapted from GitHub's markdown-toolbar-element
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
import { getDebugMode } from '../debug.js'
|
|
7
|
+
|
|
6
8
|
let canInsertText = null
|
|
7
9
|
|
|
8
10
|
/**
|
|
@@ -14,10 +16,14 @@ let canInsertText = null
|
|
|
14
16
|
* @param {number} [options.selectionEnd] - New selection end
|
|
15
17
|
*/
|
|
16
18
|
export function insertText(textarea, { text, selectionStart, selectionEnd }) {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
19
|
+
const debugMode = getDebugMode();
|
|
20
|
+
|
|
21
|
+
if (debugMode) {
|
|
22
|
+
console.group('🔧 insertText');
|
|
23
|
+
console.log('Current selection:', `${textarea.selectionStart}-${textarea.selectionEnd}`);
|
|
24
|
+
console.log('Text to insert:', JSON.stringify(text));
|
|
25
|
+
console.log('New selection to set:', selectionStart, '-', selectionEnd);
|
|
26
|
+
}
|
|
21
27
|
|
|
22
28
|
// Make sure the textarea is focused
|
|
23
29
|
textarea.focus();
|
|
@@ -27,9 +33,11 @@ export function insertText(textarea, { text, selectionStart, selectionEnd }) {
|
|
|
27
33
|
const before = textarea.value.slice(0, originalSelectionStart)
|
|
28
34
|
const after = textarea.value.slice(originalSelectionEnd)
|
|
29
35
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
36
|
+
if (debugMode) {
|
|
37
|
+
console.log('Before text (last 20):', JSON.stringify(before.slice(-20)));
|
|
38
|
+
console.log('After text (first 20):', JSON.stringify(after.slice(0, 20)));
|
|
39
|
+
console.log('Selected text being replaced:', JSON.stringify(textarea.value.slice(originalSelectionStart, originalSelectionEnd)));
|
|
40
|
+
}
|
|
33
41
|
|
|
34
42
|
// Store the original value to check if execCommand actually changed it
|
|
35
43
|
const originalValue = textarea.value
|
|
@@ -47,35 +55,41 @@ export function insertText(textarea, { text, selectionStart, selectionEnd }) {
|
|
|
47
55
|
}
|
|
48
56
|
textarea.contentEditable = 'false'
|
|
49
57
|
} else if (hasSelection) {
|
|
50
|
-
console.log('Has selection, skipping execCommand and using manual mode');
|
|
58
|
+
if (debugMode) console.log('Has selection, skipping execCommand and using manual mode');
|
|
51
59
|
canInsertText = false
|
|
52
60
|
}
|
|
53
61
|
|
|
54
|
-
|
|
55
|
-
|
|
62
|
+
if (debugMode) {
|
|
63
|
+
console.log('canInsertText before:', canInsertText);
|
|
64
|
+
console.log('execCommand result:', canInsertText);
|
|
65
|
+
}
|
|
56
66
|
|
|
57
67
|
// Check if execCommand actually worked by comparing the value
|
|
58
68
|
if (canInsertText) {
|
|
59
69
|
const expectedValue = before + text + after
|
|
60
70
|
const actualValue = textarea.value
|
|
61
71
|
|
|
62
|
-
|
|
63
|
-
|
|
72
|
+
if (debugMode) {
|
|
73
|
+
console.log('Expected length:', expectedValue.length);
|
|
74
|
+
console.log('Actual length:', actualValue.length);
|
|
75
|
+
}
|
|
64
76
|
|
|
65
77
|
if (actualValue !== expectedValue) {
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
78
|
+
if (debugMode) {
|
|
79
|
+
console.log('execCommand changed the value but not as expected');
|
|
80
|
+
console.log('Expected:', JSON.stringify(expectedValue.slice(0, 100)));
|
|
81
|
+
console.log('Actual:', JSON.stringify(actualValue.slice(0, 100)));
|
|
82
|
+
}
|
|
69
83
|
// Don't set canInsertText to false here - execCommand did work
|
|
70
84
|
// We just need to not double-insert
|
|
71
85
|
}
|
|
72
86
|
}
|
|
73
87
|
|
|
74
88
|
if (!canInsertText) {
|
|
75
|
-
console.log('Using manual insertion');
|
|
89
|
+
if (debugMode) console.log('Using manual insertion');
|
|
76
90
|
// Only do manual insertion if execCommand didn't change the value
|
|
77
91
|
if (textarea.value === originalValue) {
|
|
78
|
-
console.log('Value unchanged, doing manual replacement');
|
|
92
|
+
if (debugMode) console.log('Value unchanged, doing manual replacement');
|
|
79
93
|
try {
|
|
80
94
|
document.execCommand('ms-beginUndoUnit')
|
|
81
95
|
} catch (e) {
|
|
@@ -89,19 +103,21 @@ export function insertText(textarea, { text, selectionStart, selectionEnd }) {
|
|
|
89
103
|
}
|
|
90
104
|
textarea.dispatchEvent(new CustomEvent('input', { bubbles: true, cancelable: true }))
|
|
91
105
|
} else {
|
|
92
|
-
console.log('Value was changed by execCommand, skipping manual insertion');
|
|
106
|
+
if (debugMode) console.log('Value was changed by execCommand, skipping manual insertion');
|
|
93
107
|
}
|
|
94
108
|
}
|
|
95
109
|
|
|
96
|
-
console.log('Setting selection range:', selectionStart, selectionEnd);
|
|
110
|
+
if (debugMode) console.log('Setting selection range:', selectionStart, selectionEnd);
|
|
97
111
|
if (selectionStart != null && selectionEnd != null) {
|
|
98
112
|
textarea.setSelectionRange(selectionStart, selectionEnd)
|
|
99
113
|
} else {
|
|
100
114
|
textarea.setSelectionRange(originalSelectionStart, textarea.selectionEnd)
|
|
101
115
|
}
|
|
102
116
|
|
|
103
|
-
|
|
104
|
-
|
|
117
|
+
if (debugMode) {
|
|
118
|
+
console.log('Final value length:', textarea.value.length);
|
|
119
|
+
console.groupEnd();
|
|
120
|
+
}
|
|
105
121
|
}
|
|
106
122
|
|
|
107
123
|
/**
|
package/src/core/selection.js
CHANGED
|
@@ -126,23 +126,24 @@ export function preserveSelection(textarea, callback) {
|
|
|
126
126
|
* @returns {Object} The result from the operation with adjusted cursor position
|
|
127
127
|
*/
|
|
128
128
|
export function applyLineOperation(textarea, operation, options = {}) {
|
|
129
|
-
// Save original cursor position before any expansion
|
|
129
|
+
// Save original cursor position AND selection before any expansion
|
|
130
130
|
const originalStart = textarea.selectionStart
|
|
131
131
|
const originalEnd = textarea.selectionEnd
|
|
132
132
|
const noInitialSelection = originalStart === originalEnd
|
|
133
133
|
|
|
134
|
-
//
|
|
134
|
+
// Store the line start position to calculate offset later
|
|
135
|
+
const value = textarea.value
|
|
136
|
+
let lineStart = originalStart
|
|
137
|
+
|
|
138
|
+
// Find start of the line containing the selection start
|
|
139
|
+
while (lineStart > 0 && value[lineStart - 1] !== '\n') {
|
|
140
|
+
lineStart--
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Expand selection to line boundaries for the operation
|
|
135
144
|
if (noInitialSelection) {
|
|
136
145
|
// Expand to current line when no selection
|
|
137
|
-
|
|
138
|
-
const start = originalStart
|
|
139
|
-
let lineStart = start
|
|
140
|
-
let lineEnd = start
|
|
141
|
-
|
|
142
|
-
// Find start of current line
|
|
143
|
-
while (lineStart > 0 && value[lineStart - 1] !== '\n') {
|
|
144
|
-
lineStart--
|
|
145
|
-
}
|
|
146
|
+
let lineEnd = originalStart
|
|
146
147
|
|
|
147
148
|
// Find end of current line
|
|
148
149
|
while (lineEnd < value.length && value[lineEnd] !== '\n') {
|
|
@@ -152,27 +153,41 @@ export function applyLineOperation(textarea, operation, options = {}) {
|
|
|
152
153
|
textarea.selectionStart = lineStart
|
|
153
154
|
textarea.selectionEnd = lineEnd
|
|
154
155
|
} else {
|
|
155
|
-
// For
|
|
156
|
+
// For selections, expand to full lines
|
|
156
157
|
expandSelectionToLine(textarea)
|
|
157
158
|
}
|
|
158
159
|
|
|
159
160
|
// Apply the operation
|
|
160
161
|
const result = operation(textarea)
|
|
161
162
|
|
|
162
|
-
//
|
|
163
|
-
if (
|
|
163
|
+
// Restore original selection/cursor with prefix adjustment
|
|
164
|
+
if (options.prefix) {
|
|
164
165
|
// Check if we're toggling on or off
|
|
165
166
|
const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd)
|
|
166
167
|
const isRemoving = selectedText.startsWith(options.prefix)
|
|
167
168
|
|
|
168
|
-
if (
|
|
169
|
-
//
|
|
170
|
-
|
|
171
|
-
|
|
169
|
+
if (noInitialSelection) {
|
|
170
|
+
// No selection - just restore cursor position
|
|
171
|
+
if (isRemoving) {
|
|
172
|
+
// When removing prefix, adjust cursor position
|
|
173
|
+
result.selectionStart = Math.max(originalStart - options.prefix.length, lineStart)
|
|
174
|
+
result.selectionEnd = result.selectionStart
|
|
175
|
+
} else {
|
|
176
|
+
// When adding prefix, adjust cursor position
|
|
177
|
+
result.selectionStart = originalStart + options.prefix.length
|
|
178
|
+
result.selectionEnd = result.selectionStart
|
|
179
|
+
}
|
|
172
180
|
} else {
|
|
173
|
-
//
|
|
174
|
-
|
|
175
|
-
|
|
181
|
+
// Had a selection - restore it with adjustment
|
|
182
|
+
if (isRemoving) {
|
|
183
|
+
// When removing prefix, shift selection back
|
|
184
|
+
result.selectionStart = Math.max(originalStart - options.prefix.length, lineStart)
|
|
185
|
+
result.selectionEnd = Math.max(originalEnd - options.prefix.length, lineStart)
|
|
186
|
+
} else {
|
|
187
|
+
// When adding prefix, shift selection forward
|
|
188
|
+
result.selectionStart = originalStart + options.prefix.length
|
|
189
|
+
result.selectionEnd = originalEnd + options.prefix.length
|
|
190
|
+
}
|
|
176
191
|
}
|
|
177
192
|
}
|
|
178
193
|
|
package/src/debug.js
CHANGED
|
@@ -3,7 +3,28 @@
|
|
|
3
3
|
* Add console logging to track what's happening
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
+
// Debug mode flag - disabled by default
|
|
7
|
+
let debugMode = false;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Enable or disable debug mode
|
|
11
|
+
* @param {boolean} enabled - Whether to enable debug mode
|
|
12
|
+
*/
|
|
13
|
+
export function setDebugMode(enabled) {
|
|
14
|
+
debugMode = enabled;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Get current debug mode status
|
|
19
|
+
* @returns {boolean} Whether debug mode is enabled
|
|
20
|
+
*/
|
|
21
|
+
export function getDebugMode() {
|
|
22
|
+
return debugMode;
|
|
23
|
+
}
|
|
24
|
+
|
|
6
25
|
export function debugLog(funcName, message, data) {
|
|
26
|
+
if (!debugMode) return;
|
|
27
|
+
|
|
7
28
|
console.group(`🔍 ${funcName}`);
|
|
8
29
|
console.log(message);
|
|
9
30
|
if (data) {
|
|
@@ -13,6 +34,8 @@ export function debugLog(funcName, message, data) {
|
|
|
13
34
|
}
|
|
14
35
|
|
|
15
36
|
export function debugSelection(textarea, label) {
|
|
37
|
+
if (!debugMode) return;
|
|
38
|
+
|
|
16
39
|
const selected = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
17
40
|
console.group(`📍 Selection: ${label}`);
|
|
18
41
|
console.log('Position:', `${textarea.selectionStart}-${textarea.selectionEnd}`);
|
|
@@ -27,6 +50,8 @@ export function debugSelection(textarea, label) {
|
|
|
27
50
|
}
|
|
28
51
|
|
|
29
52
|
export function debugResult(result) {
|
|
53
|
+
if (!debugMode) return;
|
|
54
|
+
|
|
30
55
|
console.group('📝 Result');
|
|
31
56
|
console.log('Text to insert:', JSON.stringify(result.text));
|
|
32
57
|
console.log('New selection:', `${result.selectionStart}-${result.selectionEnd}`);
|
package/src/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import { preserveSelection, isMultipleLines, expandSelectionToLine, applyLineOpe
|
|
|
9
9
|
import { blockStyle, multilineStyle } from './operations/block.js'
|
|
10
10
|
import { applyListStyle } from './operations/list.js'
|
|
11
11
|
import { getActiveFormats as getActive, hasFormat as has, expandSelection as expand } from './core/detection.js'
|
|
12
|
-
import { debugLog, debugSelection, debugResult } from './debug.js'
|
|
12
|
+
import { debugLog, debugSelection, debugResult, setDebugMode, getDebugMode } from './debug.js'
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* Toggle bold formatting
|
|
@@ -210,7 +210,7 @@ export function insertHeader(textarea, level = 1, toggle = false) {
|
|
|
210
210
|
let selectionStart, selectionEnd
|
|
211
211
|
|
|
212
212
|
if (noInitialSelection) {
|
|
213
|
-
//
|
|
213
|
+
// No selection - just restore cursor position
|
|
214
214
|
const cursorOffsetInLine = originalStart - lineStart
|
|
215
215
|
|
|
216
216
|
if (isRemoving) {
|
|
@@ -242,14 +242,25 @@ export function insertHeader(textarea, level = 1, toggle = false) {
|
|
|
242
242
|
selectionStart = Math.min(selectionStart, lineStart + newLine.length)
|
|
243
243
|
selectionEnd = selectionStart
|
|
244
244
|
} else {
|
|
245
|
-
//
|
|
245
|
+
// Had a selection - preserve it with adjustment
|
|
246
246
|
if (isRemoving) {
|
|
247
|
-
|
|
248
|
-
|
|
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
|
|
249
255
|
} else {
|
|
250
|
-
|
|
251
|
-
|
|
256
|
+
// We're adding a new header
|
|
257
|
+
selectionStart = originalStart + style.prefix.length
|
|
258
|
+
selectionEnd = originalEnd + style.prefix.length
|
|
252
259
|
}
|
|
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)
|
|
253
264
|
}
|
|
254
265
|
|
|
255
266
|
const result = {
|
|
@@ -336,6 +347,11 @@ export { preserveSelection }
|
|
|
336
347
|
*/
|
|
337
348
|
export { setUndoMethod }
|
|
338
349
|
|
|
350
|
+
/**
|
|
351
|
+
* Debug mode control
|
|
352
|
+
*/
|
|
353
|
+
export { setDebugMode, getDebugMode }
|
|
354
|
+
|
|
339
355
|
/**
|
|
340
356
|
* Default export with all functions
|
|
341
357
|
*/
|
|
@@ -357,5 +373,7 @@ export default {
|
|
|
357
373
|
expandSelection,
|
|
358
374
|
applyCustomFormat,
|
|
359
375
|
preserveSelection,
|
|
360
|
-
setUndoMethod
|
|
376
|
+
setUndoMethod,
|
|
377
|
+
setDebugMode,
|
|
378
|
+
getDebugMode
|
|
361
379
|
}
|