markdown-actions 1.0.0 → 1.0.1
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 +421 -187
- package/dist/markdown-actions.esm.js.map +4 -4
- package/dist/markdown-actions.js +425 -191
- package/dist/markdown-actions.js.map +4 -4
- package/dist/markdown-actions.min.js +22 -19
- package/package.json +1 -1
- package/src/core/formats.js +5 -0
- package/src/core/insertion.js +48 -4
- package/src/core/selection.js +63 -0
- package/src/debug.js +34 -0
- package/src/index.js +143 -11
- package/src/operations/block.js +2 -1
|
@@ -15,8 +15,58 @@ var __spreadValues = (a, b) => {
|
|
|
15
15
|
return a;
|
|
16
16
|
};
|
|
17
17
|
|
|
18
|
-
// src/core/
|
|
19
|
-
|
|
18
|
+
// src/core/formats.js
|
|
19
|
+
var FORMATS = {
|
|
20
|
+
bold: {
|
|
21
|
+
prefix: "**",
|
|
22
|
+
suffix: "**",
|
|
23
|
+
trimFirst: true
|
|
24
|
+
},
|
|
25
|
+
italic: {
|
|
26
|
+
prefix: "_",
|
|
27
|
+
suffix: "_",
|
|
28
|
+
trimFirst: true
|
|
29
|
+
},
|
|
30
|
+
code: {
|
|
31
|
+
prefix: "`",
|
|
32
|
+
suffix: "`",
|
|
33
|
+
blockPrefix: "```",
|
|
34
|
+
blockSuffix: "```"
|
|
35
|
+
},
|
|
36
|
+
link: {
|
|
37
|
+
prefix: "[",
|
|
38
|
+
suffix: "](url)",
|
|
39
|
+
replaceNext: "url",
|
|
40
|
+
scanFor: "https?://"
|
|
41
|
+
},
|
|
42
|
+
bulletList: {
|
|
43
|
+
prefix: "- ",
|
|
44
|
+
multiline: true,
|
|
45
|
+
unorderedList: true
|
|
46
|
+
},
|
|
47
|
+
numberedList: {
|
|
48
|
+
prefix: "1. ",
|
|
49
|
+
multiline: true,
|
|
50
|
+
orderedList: true
|
|
51
|
+
},
|
|
52
|
+
quote: {
|
|
53
|
+
prefix: "> ",
|
|
54
|
+
multiline: true,
|
|
55
|
+
surroundWithNewlines: true
|
|
56
|
+
},
|
|
57
|
+
taskList: {
|
|
58
|
+
prefix: "- [ ] ",
|
|
59
|
+
multiline: true,
|
|
60
|
+
surroundWithNewlines: true
|
|
61
|
+
},
|
|
62
|
+
header1: { prefix: "# " },
|
|
63
|
+
header2: { prefix: "## " },
|
|
64
|
+
header3: { prefix: "### " },
|
|
65
|
+
header4: { prefix: "#### " },
|
|
66
|
+
header5: { prefix: "##### " },
|
|
67
|
+
header6: { prefix: "###### " }
|
|
68
|
+
};
|
|
69
|
+
function getDefaultStyle() {
|
|
20
70
|
return {
|
|
21
71
|
prefix: "",
|
|
22
72
|
suffix: "",
|
|
@@ -32,17 +82,97 @@ function getDefaultStyleArgs() {
|
|
|
32
82
|
trimFirst: false
|
|
33
83
|
};
|
|
34
84
|
}
|
|
35
|
-
function
|
|
36
|
-
return __spreadValues(__spreadValues({},
|
|
85
|
+
function mergeWithDefaults(format) {
|
|
86
|
+
return __spreadValues(__spreadValues({}, getDefaultStyle()), format);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// src/core/insertion.js
|
|
90
|
+
var canInsertText = null;
|
|
91
|
+
function insertText(textarea, { text, selectionStart, selectionEnd }) {
|
|
92
|
+
console.group("\u{1F527} insertText");
|
|
93
|
+
console.log("Current selection:", `${textarea.selectionStart}-${textarea.selectionEnd}`);
|
|
94
|
+
console.log("Text to insert:", JSON.stringify(text));
|
|
95
|
+
console.log("New selection to set:", selectionStart, "-", selectionEnd);
|
|
96
|
+
textarea.focus();
|
|
97
|
+
const originalSelectionStart = textarea.selectionStart;
|
|
98
|
+
const originalSelectionEnd = textarea.selectionEnd;
|
|
99
|
+
const before = textarea.value.slice(0, originalSelectionStart);
|
|
100
|
+
const after = textarea.value.slice(originalSelectionEnd);
|
|
101
|
+
console.log("Before text (last 20):", JSON.stringify(before.slice(-20)));
|
|
102
|
+
console.log("After text (first 20):", JSON.stringify(after.slice(0, 20)));
|
|
103
|
+
console.log("Selected text being replaced:", JSON.stringify(textarea.value.slice(originalSelectionStart, originalSelectionEnd)));
|
|
104
|
+
const originalValue = textarea.value;
|
|
105
|
+
const hasSelection = originalSelectionStart !== originalSelectionEnd;
|
|
106
|
+
if (!hasSelection && (canInsertText === null || canInsertText === true)) {
|
|
107
|
+
textarea.contentEditable = "true";
|
|
108
|
+
try {
|
|
109
|
+
canInsertText = document.execCommand("insertText", false, text);
|
|
110
|
+
} catch (error) {
|
|
111
|
+
canInsertText = false;
|
|
112
|
+
}
|
|
113
|
+
textarea.contentEditable = "false";
|
|
114
|
+
} else if (hasSelection) {
|
|
115
|
+
console.log("Has selection, skipping execCommand and using manual mode");
|
|
116
|
+
canInsertText = false;
|
|
117
|
+
}
|
|
118
|
+
console.log("canInsertText before:", canInsertText);
|
|
119
|
+
console.log("execCommand result:", canInsertText);
|
|
120
|
+
if (canInsertText) {
|
|
121
|
+
const expectedValue = before + text + after;
|
|
122
|
+
const actualValue = textarea.value;
|
|
123
|
+
console.log("Expected length:", expectedValue.length);
|
|
124
|
+
console.log("Actual length:", actualValue.length);
|
|
125
|
+
if (actualValue !== expectedValue) {
|
|
126
|
+
console.log("execCommand changed the value but not as expected");
|
|
127
|
+
console.log("Expected:", JSON.stringify(expectedValue.slice(0, 100)));
|
|
128
|
+
console.log("Actual:", JSON.stringify(actualValue.slice(0, 100)));
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (!canInsertText) {
|
|
132
|
+
console.log("Using manual insertion");
|
|
133
|
+
if (textarea.value === originalValue) {
|
|
134
|
+
console.log("Value unchanged, doing manual replacement");
|
|
135
|
+
try {
|
|
136
|
+
document.execCommand("ms-beginUndoUnit");
|
|
137
|
+
} catch (e) {
|
|
138
|
+
}
|
|
139
|
+
textarea.value = before + text + after;
|
|
140
|
+
try {
|
|
141
|
+
document.execCommand("ms-endUndoUnit");
|
|
142
|
+
} catch (e) {
|
|
143
|
+
}
|
|
144
|
+
textarea.dispatchEvent(new CustomEvent("input", { bubbles: true, cancelable: true }));
|
|
145
|
+
} else {
|
|
146
|
+
console.log("Value was changed by execCommand, skipping manual insertion");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
console.log("Setting selection range:", selectionStart, selectionEnd);
|
|
150
|
+
if (selectionStart != null && selectionEnd != null) {
|
|
151
|
+
textarea.setSelectionRange(selectionStart, selectionEnd);
|
|
152
|
+
} else {
|
|
153
|
+
textarea.setSelectionRange(originalSelectionStart, textarea.selectionEnd);
|
|
154
|
+
}
|
|
155
|
+
console.log("Final value length:", textarea.value.length);
|
|
156
|
+
console.groupEnd();
|
|
157
|
+
}
|
|
158
|
+
function setUndoMethod(method) {
|
|
159
|
+
switch (method) {
|
|
160
|
+
case "native":
|
|
161
|
+
canInsertText = true;
|
|
162
|
+
break;
|
|
163
|
+
case "manual":
|
|
164
|
+
canInsertText = false;
|
|
165
|
+
break;
|
|
166
|
+
case "auto":
|
|
167
|
+
canInsertText = null;
|
|
168
|
+
break;
|
|
169
|
+
}
|
|
37
170
|
}
|
|
38
171
|
|
|
39
|
-
// src/core/selection
|
|
172
|
+
// src/core/selection.js
|
|
40
173
|
function isMultipleLines(string) {
|
|
41
174
|
return string.trim().split("\n").length > 1;
|
|
42
175
|
}
|
|
43
|
-
function repeat(string, n) {
|
|
44
|
-
return Array(n + 1).join(string);
|
|
45
|
-
}
|
|
46
176
|
function wordSelectionStart(text, i) {
|
|
47
177
|
let index = i;
|
|
48
178
|
while (text[index] && text[index - 1] != null && !text[index - 1].match(/\s/)) {
|
|
@@ -67,7 +197,11 @@ function expandSelectionToLine(textarea) {
|
|
|
67
197
|
textarea.selectionStart = counter;
|
|
68
198
|
}
|
|
69
199
|
if (textarea.selectionEnd >= counter && textarea.selectionEnd < counter + lineLength) {
|
|
70
|
-
|
|
200
|
+
if (index === lines.length - 1) {
|
|
201
|
+
textarea.selectionEnd = Math.min(counter + lines[index].length, textarea.value.length);
|
|
202
|
+
} else {
|
|
203
|
+
textarea.selectionEnd = counter + lineLength - 1;
|
|
204
|
+
}
|
|
71
205
|
}
|
|
72
206
|
counter += lineLength;
|
|
73
207
|
}
|
|
@@ -95,19 +229,13 @@ function newlinesToSurroundSelectedText(textarea) {
|
|
|
95
229
|
const breaksAfter = afterSelection.match(/^\n*/);
|
|
96
230
|
const newlinesBeforeSelection = breaksBefore ? breaksBefore[0].length : 0;
|
|
97
231
|
const newlinesAfterSelection = breaksAfter ? breaksAfter[0].length : 0;
|
|
98
|
-
let newlinesToAppend;
|
|
99
|
-
let newlinesToPrepend;
|
|
232
|
+
let newlinesToAppend = "";
|
|
233
|
+
let newlinesToPrepend = "";
|
|
100
234
|
if (beforeSelection.match(/\S/) && newlinesBeforeSelection < 2) {
|
|
101
|
-
newlinesToAppend =
|
|
235
|
+
newlinesToAppend = "\n".repeat(2 - newlinesBeforeSelection);
|
|
102
236
|
}
|
|
103
237
|
if (afterSelection.match(/\S/) && newlinesAfterSelection < 2) {
|
|
104
|
-
newlinesToPrepend =
|
|
105
|
-
}
|
|
106
|
-
if (newlinesToAppend == null) {
|
|
107
|
-
newlinesToAppend = "";
|
|
108
|
-
}
|
|
109
|
-
if (newlinesToPrepend == null) {
|
|
110
|
-
newlinesToPrepend = "";
|
|
238
|
+
newlinesToPrepend = "\n".repeat(2 - newlinesAfterSelection);
|
|
111
239
|
}
|
|
112
240
|
return { newlinesToAppend, newlinesToPrepend };
|
|
113
241
|
}
|
|
@@ -120,64 +248,52 @@ function preserveSelection(textarea, callback) {
|
|
|
120
248
|
textarea.selectionEnd = end;
|
|
121
249
|
textarea.scrollTop = scrollTop;
|
|
122
250
|
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
} catch (error) {
|
|
135
|
-
canInsertText = false;
|
|
136
|
-
}
|
|
137
|
-
textarea.contentEditable = "false";
|
|
138
|
-
}
|
|
139
|
-
if (canInsertText && !textarea.value.slice(0, textarea.selectionStart).endsWith(text)) {
|
|
140
|
-
canInsertText = false;
|
|
141
|
-
}
|
|
142
|
-
if (!canInsertText) {
|
|
143
|
-
try {
|
|
144
|
-
document.execCommand("ms-beginUndoUnit");
|
|
145
|
-
} catch (e) {
|
|
251
|
+
function applyLineOperation(textarea, operation, options = {}) {
|
|
252
|
+
const originalStart = textarea.selectionStart;
|
|
253
|
+
const originalEnd = textarea.selectionEnd;
|
|
254
|
+
const noInitialSelection = originalStart === originalEnd;
|
|
255
|
+
if (noInitialSelection) {
|
|
256
|
+
const value = textarea.value;
|
|
257
|
+
const start = originalStart;
|
|
258
|
+
let lineStart = start;
|
|
259
|
+
let lineEnd = start;
|
|
260
|
+
while (lineStart > 0 && value[lineStart - 1] !== "\n") {
|
|
261
|
+
lineStart--;
|
|
146
262
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
document.execCommand("ms-endUndoUnit");
|
|
150
|
-
} catch (e) {
|
|
263
|
+
while (lineEnd < value.length && value[lineEnd] !== "\n") {
|
|
264
|
+
lineEnd++;
|
|
151
265
|
}
|
|
152
|
-
textarea.
|
|
153
|
-
|
|
154
|
-
if (selectionStart != null && selectionEnd != null) {
|
|
155
|
-
textarea.setSelectionRange(selectionStart, selectionEnd);
|
|
266
|
+
textarea.selectionStart = lineStart;
|
|
267
|
+
textarea.selectionEnd = lineEnd;
|
|
156
268
|
} else {
|
|
157
|
-
|
|
269
|
+
expandSelectionToLine(textarea);
|
|
158
270
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
271
|
+
const result = operation(textarea);
|
|
272
|
+
if (noInitialSelection && options.prefix) {
|
|
273
|
+
const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
274
|
+
const isRemoving = selectedText.startsWith(options.prefix);
|
|
275
|
+
if (isRemoving) {
|
|
276
|
+
result.selectionStart = Math.max(originalStart - options.prefix.length, textarea.selectionStart);
|
|
277
|
+
result.selectionEnd = result.selectionStart;
|
|
278
|
+
} else {
|
|
279
|
+
result.selectionStart = originalStart + options.prefix.length;
|
|
280
|
+
result.selectionEnd = result.selectionStart;
|
|
281
|
+
}
|
|
167
282
|
}
|
|
283
|
+
return result;
|
|
168
284
|
}
|
|
169
285
|
|
|
170
|
-
// src/operations/block
|
|
171
|
-
function blockStyle(textarea,
|
|
286
|
+
// src/operations/block.js
|
|
287
|
+
function blockStyle(textarea, style) {
|
|
172
288
|
let newlinesToAppend;
|
|
173
289
|
let newlinesToPrepend;
|
|
174
|
-
const { prefix, suffix, blockPrefix, blockSuffix, replaceNext, prefixSpace, scanFor, surroundWithNewlines } =
|
|
290
|
+
const { prefix, suffix, blockPrefix, blockSuffix, replaceNext, prefixSpace, scanFor, surroundWithNewlines, trimFirst } = style;
|
|
175
291
|
const originalSelectionStart = textarea.selectionStart;
|
|
176
292
|
const originalSelectionEnd = textarea.selectionEnd;
|
|
177
293
|
let selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
178
|
-
let prefixToUse = isMultipleLines(selectedText) && blockPrefix.length > 0 ? `${blockPrefix}
|
|
294
|
+
let prefixToUse = isMultipleLines(selectedText) && blockPrefix && blockPrefix.length > 0 ? `${blockPrefix}
|
|
179
295
|
` : prefix;
|
|
180
|
-
let suffixToUse = isMultipleLines(selectedText) && blockSuffix.length > 0 ? `
|
|
296
|
+
let suffixToUse = isMultipleLines(selectedText) && blockSuffix && blockSuffix.length > 0 ? `
|
|
181
297
|
${blockSuffix}` : suffix;
|
|
182
298
|
if (prefixSpace) {
|
|
183
299
|
const beforeSelection = textarea.value[textarea.selectionStart - 1];
|
|
@@ -185,10 +301,10 @@ ${blockSuffix}` : suffix;
|
|
|
185
301
|
prefixToUse = ` ${prefixToUse}`;
|
|
186
302
|
}
|
|
187
303
|
}
|
|
188
|
-
selectedText = expandSelectedText(textarea, prefixToUse, suffixToUse,
|
|
304
|
+
selectedText = expandSelectedText(textarea, prefixToUse, suffixToUse, style.multiline);
|
|
189
305
|
let selectionStart = textarea.selectionStart;
|
|
190
306
|
let selectionEnd = textarea.selectionEnd;
|
|
191
|
-
const hasReplaceNext = replaceNext.length > 0 && suffixToUse.indexOf(replaceNext) > -1 && selectedText.length > 0;
|
|
307
|
+
const hasReplaceNext = replaceNext && replaceNext.length > 0 && suffixToUse.indexOf(replaceNext) > -1 && selectedText.length > 0;
|
|
192
308
|
if (surroundWithNewlines) {
|
|
193
309
|
const ref = newlinesToSurroundSelectedText(textarea);
|
|
194
310
|
newlinesToAppend = ref.newlinesToAppend;
|
|
@@ -212,7 +328,7 @@ ${blockSuffix}` : suffix;
|
|
|
212
328
|
selectionStart = originalSelectionStart + prefixToUse.length;
|
|
213
329
|
selectionEnd = originalSelectionEnd + prefixToUse.length;
|
|
214
330
|
const whitespaceEdges = selectedText.match(/^\s*|\s*$/g);
|
|
215
|
-
if (
|
|
331
|
+
if (trimFirst && whitespaceEdges) {
|
|
216
332
|
const leadingWhitespace = whitespaceEdges[0] || "";
|
|
217
333
|
const trailingWhitespace = whitespaceEdges[1] || "";
|
|
218
334
|
replacementText = leadingWhitespace + prefixToUse + selectedText.trim() + suffixToUse + trailingWhitespace;
|
|
@@ -220,9 +336,9 @@ ${blockSuffix}` : suffix;
|
|
|
220
336
|
selectionEnd -= trailingWhitespace.length;
|
|
221
337
|
}
|
|
222
338
|
return { text: replacementText, selectionStart, selectionEnd };
|
|
223
|
-
} else if (scanFor.length > 0 && selectedText.match(scanFor)) {
|
|
339
|
+
} else if (scanFor && scanFor.length > 0 && selectedText.match(scanFor)) {
|
|
224
340
|
suffixToUse = suffixToUse.replace(replaceNext, selectedText);
|
|
225
|
-
const replacementText = prefixToUse +
|
|
341
|
+
const replacementText = prefixToUse + suffixToUse;
|
|
226
342
|
selectionStart = selectionEnd = selectionStart + prefixToUse.length;
|
|
227
343
|
return { text: replacementText, selectionStart, selectionEnd };
|
|
228
344
|
} else {
|
|
@@ -232,18 +348,24 @@ ${blockSuffix}` : suffix;
|
|
|
232
348
|
return { text: replacementText, selectionStart, selectionEnd };
|
|
233
349
|
}
|
|
234
350
|
}
|
|
235
|
-
function multilineStyle(textarea,
|
|
236
|
-
const { prefix, suffix, surroundWithNewlines } =
|
|
351
|
+
function multilineStyle(textarea, style) {
|
|
352
|
+
const { prefix, suffix, surroundWithNewlines } = style;
|
|
237
353
|
let text = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
238
354
|
let selectionStart = textarea.selectionStart;
|
|
239
355
|
let selectionEnd = textarea.selectionEnd;
|
|
240
356
|
const lines = text.split("\n");
|
|
241
|
-
const undoStyle = lines.every((line) => line.startsWith(prefix) && line.endsWith(suffix));
|
|
357
|
+
const undoStyle = lines.every((line) => line.startsWith(prefix) && (!suffix || line.endsWith(suffix)));
|
|
242
358
|
if (undoStyle) {
|
|
243
|
-
text = lines.map((line) =>
|
|
359
|
+
text = lines.map((line) => {
|
|
360
|
+
let result = line.slice(prefix.length);
|
|
361
|
+
if (suffix) {
|
|
362
|
+
result = result.slice(0, result.length - suffix.length);
|
|
363
|
+
}
|
|
364
|
+
return result;
|
|
365
|
+
}).join("\n");
|
|
244
366
|
selectionEnd = selectionStart + text.length;
|
|
245
367
|
} else {
|
|
246
|
-
text = lines.map((line) => prefix + line + suffix).join("\n");
|
|
368
|
+
text = lines.map((line) => prefix + line + (suffix || "")).join("\n");
|
|
247
369
|
if (surroundWithNewlines) {
|
|
248
370
|
const { newlinesToAppend, newlinesToPrepend } = newlinesToSurroundSelectedText(textarea);
|
|
249
371
|
selectionStart += newlinesToAppend.length;
|
|
@@ -254,7 +376,7 @@ function multilineStyle(textarea, arg) {
|
|
|
254
376
|
return { text, selectionStart, selectionEnd };
|
|
255
377
|
}
|
|
256
378
|
|
|
257
|
-
// src/operations/list
|
|
379
|
+
// src/operations/list.js
|
|
258
380
|
function undoOrderedListStyle(text) {
|
|
259
381
|
const lines = text.split("\n");
|
|
260
382
|
const orderedListRegex = /^\d+\.\s+/;
|
|
@@ -274,7 +396,7 @@ function undoUnorderedListStyle(text) {
|
|
|
274
396
|
const shouldUndoUnorderedList = lines.every((line) => line.startsWith(unorderedListPrefix));
|
|
275
397
|
let result = lines;
|
|
276
398
|
if (shouldUndoUnorderedList) {
|
|
277
|
-
result = lines.map((line) => line.slice(unorderedListPrefix.length
|
|
399
|
+
result = lines.map((line) => line.slice(unorderedListPrefix.length));
|
|
278
400
|
}
|
|
279
401
|
return {
|
|
280
402
|
text: result.join("\n"),
|
|
@@ -289,19 +411,19 @@ function makePrefix(index, unorderedList) {
|
|
|
289
411
|
}
|
|
290
412
|
}
|
|
291
413
|
function clearExistingListStyle(style, selectedText) {
|
|
292
|
-
let undoResultOpositeList;
|
|
293
414
|
let undoResult;
|
|
415
|
+
let undoResultOppositeList;
|
|
294
416
|
let pristineText;
|
|
295
417
|
if (style.orderedList) {
|
|
296
418
|
undoResult = undoOrderedListStyle(selectedText);
|
|
297
|
-
|
|
298
|
-
pristineText =
|
|
419
|
+
undoResultOppositeList = undoUnorderedListStyle(undoResult.text);
|
|
420
|
+
pristineText = undoResultOppositeList.text;
|
|
299
421
|
} else {
|
|
300
422
|
undoResult = undoUnorderedListStyle(selectedText);
|
|
301
|
-
|
|
302
|
-
pristineText =
|
|
423
|
+
undoResultOppositeList = undoOrderedListStyle(undoResult.text);
|
|
424
|
+
pristineText = undoResultOppositeList.text;
|
|
303
425
|
}
|
|
304
|
-
return [undoResult,
|
|
426
|
+
return [undoResult, undoResultOppositeList, pristineText];
|
|
305
427
|
}
|
|
306
428
|
function listStyle(textarea, style) {
|
|
307
429
|
const noInitialSelection = textarea.selectionStart === textarea.selectionEnd;
|
|
@@ -309,14 +431,14 @@ function listStyle(textarea, style) {
|
|
|
309
431
|
let selectionEnd = textarea.selectionEnd;
|
|
310
432
|
expandSelectionToLine(textarea);
|
|
311
433
|
const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
312
|
-
const [undoResult,
|
|
434
|
+
const [undoResult, undoResultOppositeList, pristineText] = clearExistingListStyle(style, selectedText);
|
|
313
435
|
const prefixedLines = pristineText.split("\n").map((value, index) => {
|
|
314
436
|
return `${makePrefix(index, style.unorderedList)}${value}`;
|
|
315
437
|
});
|
|
316
438
|
const totalPrefixLength = prefixedLines.reduce((previousValue, _currentValue, currentIndex) => {
|
|
317
439
|
return previousValue + makePrefix(currentIndex, style.unorderedList).length;
|
|
318
440
|
}, 0);
|
|
319
|
-
const
|
|
441
|
+
const totalPrefixLengthOppositeList = prefixedLines.reduce((previousValue, _currentValue, currentIndex) => {
|
|
320
442
|
return previousValue + makePrefix(currentIndex, !style.unorderedList).length;
|
|
321
443
|
}, 0);
|
|
322
444
|
if (undoResult.processed) {
|
|
@@ -335,9 +457,9 @@ function listStyle(textarea, style) {
|
|
|
335
457
|
selectionStart = Math.max(selectionStart + makePrefix(0, style.unorderedList).length + newlinesToAppend.length, 0);
|
|
336
458
|
selectionEnd = selectionStart;
|
|
337
459
|
} else {
|
|
338
|
-
if (
|
|
460
|
+
if (undoResultOppositeList.processed) {
|
|
339
461
|
selectionStart = Math.max(textarea.selectionStart + newlinesToAppend.length, 0);
|
|
340
|
-
selectionEnd = textarea.selectionEnd + newlinesToAppend.length + totalPrefixLength -
|
|
462
|
+
selectionEnd = textarea.selectionEnd + newlinesToAppend.length + totalPrefixLength - totalPrefixLengthOppositeList;
|
|
341
463
|
} else {
|
|
342
464
|
selectionStart = Math.max(textarea.selectionStart + newlinesToAppend.length, 0);
|
|
343
465
|
selectionEnd = textarea.selectionEnd + newlinesToAppend.length + totalPrefixLength;
|
|
@@ -345,18 +467,10 @@ function listStyle(textarea, style) {
|
|
|
345
467
|
}
|
|
346
468
|
return { text, selectionStart, selectionEnd };
|
|
347
469
|
}
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
const
|
|
352
|
-
let result;
|
|
353
|
-
if (styleArgs.orderedList || styleArgs.unorderedList) {
|
|
354
|
-
result = listStyle(textarea, styleArgs);
|
|
355
|
-
} else if (styleArgs.multiline && isMultipleLines(text)) {
|
|
356
|
-
result = multilineStyle(textarea, styleArgs);
|
|
357
|
-
} else {
|
|
358
|
-
result = blockStyle(textarea, styleArgs);
|
|
359
|
-
}
|
|
470
|
+
function applyListStyle(textarea, style) {
|
|
471
|
+
const originalStart = textarea.selectionStart;
|
|
472
|
+
const originalEnd = textarea.selectionEnd;
|
|
473
|
+
const result = listStyle(textarea, style);
|
|
360
474
|
insertText(textarea, result);
|
|
361
475
|
}
|
|
362
476
|
|
|
@@ -441,107 +555,173 @@ function hasFormat(textarea, format) {
|
|
|
441
555
|
const activeFormats = getActiveFormats(textarea);
|
|
442
556
|
return activeFormats.includes(format);
|
|
443
557
|
}
|
|
558
|
+
function expandSelection(textarea, options = {}) {
|
|
559
|
+
if (!textarea)
|
|
560
|
+
return;
|
|
561
|
+
const { toWord, toLine, toFormat } = options;
|
|
562
|
+
const { selectionStart, selectionEnd, value } = textarea;
|
|
563
|
+
if (toLine) {
|
|
564
|
+
const lines = value.split("\n");
|
|
565
|
+
let lineStart = 0;
|
|
566
|
+
let lineEnd = 0;
|
|
567
|
+
let currentPos = 0;
|
|
568
|
+
for (const line of lines) {
|
|
569
|
+
if (selectionStart >= currentPos && selectionStart <= currentPos + line.length) {
|
|
570
|
+
lineStart = currentPos;
|
|
571
|
+
lineEnd = currentPos + line.length;
|
|
572
|
+
break;
|
|
573
|
+
}
|
|
574
|
+
currentPos += line.length + 1;
|
|
575
|
+
}
|
|
576
|
+
textarea.selectionStart = lineStart;
|
|
577
|
+
textarea.selectionEnd = lineEnd;
|
|
578
|
+
} else if (toWord && selectionStart === selectionEnd) {
|
|
579
|
+
let start = selectionStart;
|
|
580
|
+
let end = selectionEnd;
|
|
581
|
+
while (start > 0 && !/\s/.test(value[start - 1])) {
|
|
582
|
+
start--;
|
|
583
|
+
}
|
|
584
|
+
while (end < value.length && !/\s/.test(value[end])) {
|
|
585
|
+
end++;
|
|
586
|
+
}
|
|
587
|
+
textarea.selectionStart = start;
|
|
588
|
+
textarea.selectionEnd = end;
|
|
589
|
+
}
|
|
590
|
+
}
|
|
444
591
|
|
|
445
|
-
// src/
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
},
|
|
471
|
-
numberedList: {
|
|
472
|
-
prefix: "1. ",
|
|
473
|
-
multiline: true,
|
|
474
|
-
orderedList: true
|
|
475
|
-
},
|
|
476
|
-
header1: { prefix: "# " },
|
|
477
|
-
header2: { prefix: "## " },
|
|
478
|
-
header3: { prefix: "### " },
|
|
479
|
-
header4: { prefix: "#### " },
|
|
480
|
-
header5: { prefix: "##### " },
|
|
481
|
-
header6: { prefix: "###### " }
|
|
482
|
-
};
|
|
483
|
-
function applyStyle(textarea, format) {
|
|
484
|
-
const style = mergeStyleWithDefaults(format);
|
|
485
|
-
textarea.focus();
|
|
486
|
-
styleSelectedText(textarea, style);
|
|
592
|
+
// src/debug.js
|
|
593
|
+
function debugLog(funcName, message, data) {
|
|
594
|
+
console.group(`\u{1F50D} ${funcName}`);
|
|
595
|
+
console.log(message);
|
|
596
|
+
if (data) {
|
|
597
|
+
console.log("Data:", data);
|
|
598
|
+
}
|
|
599
|
+
console.groupEnd();
|
|
600
|
+
}
|
|
601
|
+
function debugSelection(textarea, label) {
|
|
602
|
+
const selected = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
603
|
+
console.group(`\u{1F4CD} Selection: ${label}`);
|
|
604
|
+
console.log("Position:", `${textarea.selectionStart}-${textarea.selectionEnd}`);
|
|
605
|
+
console.log("Selected text:", JSON.stringify(selected));
|
|
606
|
+
console.log("Length:", selected.length);
|
|
607
|
+
const before = textarea.value.slice(Math.max(0, textarea.selectionStart - 10), textarea.selectionStart);
|
|
608
|
+
const after = textarea.value.slice(textarea.selectionEnd, Math.min(textarea.value.length, textarea.selectionEnd + 10));
|
|
609
|
+
console.log("Context:", JSON.stringify(before) + "[SELECTION]" + JSON.stringify(after));
|
|
610
|
+
console.groupEnd();
|
|
611
|
+
}
|
|
612
|
+
function debugResult(result) {
|
|
613
|
+
console.group("\u{1F4DD} Result");
|
|
614
|
+
console.log("Text to insert:", JSON.stringify(result.text));
|
|
615
|
+
console.log("New selection:", `${result.selectionStart}-${result.selectionEnd}`);
|
|
616
|
+
console.groupEnd();
|
|
487
617
|
}
|
|
618
|
+
|
|
619
|
+
// src/index.js
|
|
488
620
|
function toggleBold(textarea) {
|
|
489
621
|
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
490
622
|
return;
|
|
491
|
-
|
|
623
|
+
debugLog("toggleBold", "Starting");
|
|
624
|
+
debugSelection(textarea, "Before");
|
|
625
|
+
const style = mergeWithDefaults(FORMATS.bold);
|
|
626
|
+
const result = blockStyle(textarea, style);
|
|
627
|
+
debugResult(result);
|
|
628
|
+
insertText(textarea, result);
|
|
629
|
+
debugSelection(textarea, "After");
|
|
492
630
|
}
|
|
493
631
|
function toggleItalic(textarea) {
|
|
494
632
|
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
495
633
|
return;
|
|
496
|
-
|
|
634
|
+
const style = mergeWithDefaults(FORMATS.italic);
|
|
635
|
+
const result = blockStyle(textarea, style);
|
|
636
|
+
insertText(textarea, result);
|
|
497
637
|
}
|
|
498
638
|
function toggleCode(textarea) {
|
|
499
639
|
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
500
640
|
return;
|
|
501
|
-
|
|
641
|
+
const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
642
|
+
const style = mergeWithDefaults(FORMATS.code);
|
|
643
|
+
let result;
|
|
644
|
+
if (isMultipleLines(selectedText)) {
|
|
645
|
+
const blockStyle2 = {
|
|
646
|
+
prefix: "```\n",
|
|
647
|
+
suffix: "\n```",
|
|
648
|
+
surroundWithNewlines: true
|
|
649
|
+
};
|
|
650
|
+
result = multilineStyle(textarea, mergeWithDefaults(blockStyle2));
|
|
651
|
+
} else {
|
|
652
|
+
result = blockStyle(textarea, style);
|
|
653
|
+
}
|
|
654
|
+
insertText(textarea, result);
|
|
502
655
|
}
|
|
503
656
|
function insertLink(textarea, options = {}) {
|
|
504
657
|
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
505
658
|
return;
|
|
506
|
-
|
|
659
|
+
const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
660
|
+
let style = mergeWithDefaults(FORMATS.link);
|
|
507
661
|
if (options.url) {
|
|
508
|
-
|
|
509
|
-
|
|
662
|
+
style.suffix = `](${options.url})`;
|
|
663
|
+
style.replaceNext = "";
|
|
510
664
|
}
|
|
511
|
-
if (options.text && !
|
|
665
|
+
if (options.text && !selectedText) {
|
|
512
666
|
const pos = textarea.selectionStart;
|
|
513
667
|
textarea.value = textarea.value.slice(0, pos) + options.text + textarea.value.slice(pos);
|
|
514
668
|
textarea.selectionStart = pos;
|
|
515
669
|
textarea.selectionEnd = pos + options.text.length;
|
|
516
670
|
}
|
|
517
|
-
|
|
671
|
+
const result = blockStyle(textarea, style);
|
|
672
|
+
insertText(textarea, result);
|
|
518
673
|
}
|
|
519
674
|
function toggleBulletList(textarea) {
|
|
520
675
|
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
521
676
|
return;
|
|
522
|
-
|
|
677
|
+
const style = mergeWithDefaults(FORMATS.bulletList);
|
|
678
|
+
applyListStyle(textarea, style);
|
|
523
679
|
}
|
|
524
680
|
function toggleNumberedList(textarea) {
|
|
525
681
|
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
526
682
|
return;
|
|
527
|
-
|
|
683
|
+
const style = mergeWithDefaults(FORMATS.numberedList);
|
|
684
|
+
applyListStyle(textarea, style);
|
|
528
685
|
}
|
|
529
686
|
function toggleQuote(textarea) {
|
|
530
687
|
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
531
688
|
return;
|
|
532
|
-
|
|
689
|
+
debugLog("toggleQuote", "Starting");
|
|
690
|
+
debugSelection(textarea, "Initial");
|
|
691
|
+
const style = mergeWithDefaults(FORMATS.quote);
|
|
692
|
+
const result = applyLineOperation(
|
|
693
|
+
textarea,
|
|
694
|
+
(ta) => multilineStyle(ta, style),
|
|
695
|
+
{ prefix: style.prefix }
|
|
696
|
+
);
|
|
697
|
+
debugResult(result);
|
|
698
|
+
insertText(textarea, result);
|
|
699
|
+
debugSelection(textarea, "Final");
|
|
533
700
|
}
|
|
534
|
-
function
|
|
701
|
+
function toggleTaskList(textarea) {
|
|
702
|
+
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
703
|
+
return;
|
|
704
|
+
const style = mergeWithDefaults(FORMATS.taskList);
|
|
705
|
+
const result = applyLineOperation(
|
|
706
|
+
textarea,
|
|
707
|
+
(ta) => multilineStyle(ta, style),
|
|
708
|
+
{ prefix: style.prefix }
|
|
709
|
+
);
|
|
710
|
+
insertText(textarea, result);
|
|
711
|
+
}
|
|
712
|
+
function insertHeader(textarea, level = 1, toggle = false) {
|
|
535
713
|
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
536
714
|
return;
|
|
537
715
|
if (level < 1 || level > 6)
|
|
538
716
|
level = 1;
|
|
539
|
-
const
|
|
540
|
-
const
|
|
717
|
+
const originalStart = textarea.selectionStart;
|
|
718
|
+
const originalEnd = textarea.selectionEnd;
|
|
719
|
+
const noInitialSelection = originalStart === originalEnd;
|
|
720
|
+
const headerKey = `header${level === 1 ? "1" : level}`;
|
|
721
|
+
const style = mergeWithDefaults(FORMATS[headerKey] || FORMATS.header1);
|
|
541
722
|
const value = textarea.value;
|
|
542
|
-
|
|
543
|
-
let
|
|
544
|
-
let lineEnd = start;
|
|
723
|
+
let lineStart = originalStart;
|
|
724
|
+
let lineEnd = originalStart;
|
|
545
725
|
while (lineStart > 0 && value[lineStart - 1] !== "\n") {
|
|
546
726
|
lineStart--;
|
|
547
727
|
}
|
|
@@ -551,12 +731,63 @@ function insertHeader(textarea, level = 1) {
|
|
|
551
731
|
textarea.selectionStart = lineStart;
|
|
552
732
|
textarea.selectionEnd = lineEnd;
|
|
553
733
|
const currentLine = value.slice(lineStart, lineEnd);
|
|
734
|
+
const existingHeaderMatch = currentLine.match(/^(#{1,6})\s*/);
|
|
735
|
+
const existingPrefixLength = existingHeaderMatch ? existingHeaderMatch[0].length : 0;
|
|
736
|
+
const existingLevel = existingHeaderMatch ? existingHeaderMatch[1].length : 0;
|
|
554
737
|
const cleanedLine = currentLine.replace(/^#{1,6}\s*/, "");
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
738
|
+
let newLine;
|
|
739
|
+
let isRemoving = false;
|
|
740
|
+
if (toggle && existingLevel === level) {
|
|
741
|
+
newLine = cleanedLine;
|
|
742
|
+
isRemoving = true;
|
|
743
|
+
} else {
|
|
744
|
+
newLine = style.prefix + cleanedLine;
|
|
745
|
+
}
|
|
746
|
+
let selectionStart, selectionEnd;
|
|
747
|
+
if (noInitialSelection) {
|
|
748
|
+
const cursorOffsetInLine = originalStart - lineStart;
|
|
749
|
+
if (isRemoving) {
|
|
750
|
+
if (cursorOffsetInLine < existingPrefixLength) {
|
|
751
|
+
selectionStart = lineStart;
|
|
752
|
+
} else {
|
|
753
|
+
selectionStart = originalStart - existingPrefixLength;
|
|
754
|
+
}
|
|
755
|
+
} else if (existingPrefixLength > 0) {
|
|
756
|
+
if (cursorOffsetInLine < existingPrefixLength) {
|
|
757
|
+
selectionStart = lineStart + Math.min(cursorOffsetInLine, style.prefix.length);
|
|
758
|
+
} else {
|
|
759
|
+
const prefixDiff = style.prefix.length - existingPrefixLength;
|
|
760
|
+
selectionStart = originalStart + prefixDiff;
|
|
761
|
+
}
|
|
762
|
+
} else {
|
|
763
|
+
selectionStart = originalStart + style.prefix.length;
|
|
764
|
+
}
|
|
765
|
+
selectionStart = Math.min(selectionStart, lineStart + newLine.length);
|
|
766
|
+
selectionEnd = selectionStart;
|
|
767
|
+
} else {
|
|
768
|
+
if (isRemoving) {
|
|
769
|
+
selectionStart = lineStart;
|
|
770
|
+
selectionEnd = lineStart + newLine.length;
|
|
771
|
+
} else {
|
|
772
|
+
selectionStart = lineStart + style.prefix.length;
|
|
773
|
+
selectionEnd = lineStart + newLine.length;
|
|
774
|
+
}
|
|
775
|
+
}
|
|
776
|
+
const result = {
|
|
777
|
+
text: newLine,
|
|
778
|
+
selectionStart,
|
|
779
|
+
selectionEnd
|
|
780
|
+
};
|
|
781
|
+
insertText(textarea, result);
|
|
782
|
+
}
|
|
783
|
+
function toggleH1(textarea) {
|
|
784
|
+
insertHeader(textarea, 1, true);
|
|
785
|
+
}
|
|
786
|
+
function toggleH2(textarea) {
|
|
787
|
+
insertHeader(textarea, 2, true);
|
|
788
|
+
}
|
|
789
|
+
function toggleH3(textarea) {
|
|
790
|
+
insertHeader(textarea, 3, true);
|
|
560
791
|
}
|
|
561
792
|
function getActiveFormats2(textarea) {
|
|
562
793
|
return getActiveFormats(textarea);
|
|
@@ -564,32 +795,27 @@ function getActiveFormats2(textarea) {
|
|
|
564
795
|
function hasFormat2(textarea, format) {
|
|
565
796
|
return hasFormat(textarea, format);
|
|
566
797
|
}
|
|
567
|
-
function
|
|
568
|
-
|
|
569
|
-
return;
|
|
570
|
-
const { toWord, toLine } = options;
|
|
571
|
-
const { selectionStart, selectionEnd, value } = textarea;
|
|
572
|
-
if (toLine) {
|
|
573
|
-
expandSelectionToLine(textarea);
|
|
574
|
-
} else if (toWord && selectionStart === selectionEnd) {
|
|
575
|
-
let start = selectionStart;
|
|
576
|
-
let end = selectionEnd;
|
|
577
|
-
while (start > 0 && !/\s/.test(value[start - 1])) {
|
|
578
|
-
start--;
|
|
579
|
-
}
|
|
580
|
-
while (end < value.length && !/\s/.test(value[end])) {
|
|
581
|
-
end++;
|
|
582
|
-
}
|
|
583
|
-
textarea.selectionStart = start;
|
|
584
|
-
textarea.selectionEnd = end;
|
|
585
|
-
}
|
|
798
|
+
function expandSelection2(textarea, options = {}) {
|
|
799
|
+
expandSelection(textarea, options);
|
|
586
800
|
}
|
|
587
801
|
function applyCustomFormat(textarea, format) {
|
|
588
802
|
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
589
803
|
return;
|
|
590
|
-
|
|
804
|
+
const style = mergeWithDefaults(format);
|
|
805
|
+
let result;
|
|
806
|
+
if (style.multiline) {
|
|
807
|
+
const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
808
|
+
if (isMultipleLines(selectedText)) {
|
|
809
|
+
result = multilineStyle(textarea, style);
|
|
810
|
+
} else {
|
|
811
|
+
result = blockStyle(textarea, style);
|
|
812
|
+
}
|
|
813
|
+
} else {
|
|
814
|
+
result = blockStyle(textarea, style);
|
|
815
|
+
}
|
|
816
|
+
insertText(textarea, result);
|
|
591
817
|
}
|
|
592
|
-
var
|
|
818
|
+
var src_default = {
|
|
593
819
|
toggleBold,
|
|
594
820
|
toggleItalic,
|
|
595
821
|
toggleCode,
|
|
@@ -597,18 +823,22 @@ var index_new_default = {
|
|
|
597
823
|
toggleBulletList,
|
|
598
824
|
toggleNumberedList,
|
|
599
825
|
toggleQuote,
|
|
826
|
+
toggleTaskList,
|
|
600
827
|
insertHeader,
|
|
828
|
+
toggleH1,
|
|
829
|
+
toggleH2,
|
|
830
|
+
toggleH3,
|
|
601
831
|
getActiveFormats: getActiveFormats2,
|
|
602
832
|
hasFormat: hasFormat2,
|
|
603
|
-
expandSelection,
|
|
833
|
+
expandSelection: expandSelection2,
|
|
604
834
|
applyCustomFormat,
|
|
605
835
|
preserveSelection,
|
|
606
836
|
setUndoMethod
|
|
607
837
|
};
|
|
608
838
|
export {
|
|
609
839
|
applyCustomFormat,
|
|
610
|
-
|
|
611
|
-
expandSelection,
|
|
840
|
+
src_default as default,
|
|
841
|
+
expandSelection2 as expandSelection,
|
|
612
842
|
getActiveFormats2 as getActiveFormats,
|
|
613
843
|
hasFormat2 as hasFormat,
|
|
614
844
|
insertHeader,
|
|
@@ -618,8 +848,12 @@ export {
|
|
|
618
848
|
toggleBold,
|
|
619
849
|
toggleBulletList,
|
|
620
850
|
toggleCode,
|
|
851
|
+
toggleH1,
|
|
852
|
+
toggleH2,
|
|
853
|
+
toggleH3,
|
|
621
854
|
toggleItalic,
|
|
622
855
|
toggleNumberedList,
|
|
623
|
-
toggleQuote
|
|
856
|
+
toggleQuote,
|
|
857
|
+
toggleTaskList
|
|
624
858
|
};
|
|
625
859
|
//# sourceMappingURL=markdown-actions.esm.js.map
|