markdown-actions 1.0.3 → 1.0.4
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 +53 -65
- package/dist/markdown-actions.esm.js.map +2 -2
- package/dist/markdown-actions.js +53 -65
- package/dist/markdown-actions.js.map +2 -2
- package/dist/markdown-actions.min.js +20 -22
- package/package.json +1 -1
- package/src/core/selection.js +10 -2
- package/src/index.js +63 -99
package/src/index.js
CHANGED
|
@@ -161,113 +161,77 @@ export function insertHeader(textarea, level = 1, toggle = false) {
|
|
|
161
161
|
if (!textarea || textarea.disabled || textarea.readOnly) return
|
|
162
162
|
if (level < 1 || level > 6) level = 1
|
|
163
163
|
|
|
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
164
|
const headerKey = `header${level === 1 ? '1' : level}`
|
|
170
165
|
const style = mergeWithDefaults(FORMATS[headerKey] || FORMATS.header1)
|
|
171
166
|
|
|
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
|
|
167
|
+
// Save original positions before any operations
|
|
168
|
+
const originalStart = textarea.selectionStart
|
|
169
|
+
const originalEnd = textarea.selectionEnd
|
|
211
170
|
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
if
|
|
219
|
-
|
|
220
|
-
|
|
171
|
+
// Use applyLineOperation for consistent behavior
|
|
172
|
+
const result = applyLineOperation(
|
|
173
|
+
textarea,
|
|
174
|
+
(ta) => {
|
|
175
|
+
const currentLine = ta.value.slice(ta.selectionStart, ta.selectionEnd)
|
|
176
|
+
|
|
177
|
+
// Check if we're removing or changing existing header
|
|
178
|
+
const existingHeaderMatch = currentLine.match(/^(#{1,6})\s*/)
|
|
179
|
+
const existingLevel = existingHeaderMatch ? existingHeaderMatch[1].length : 0
|
|
180
|
+
|
|
181
|
+
// Remove any existing header formatting
|
|
182
|
+
const cleanedLine = currentLine.replace(/^#{1,6}\s*/, '')
|
|
183
|
+
|
|
184
|
+
let newLine
|
|
185
|
+
|
|
186
|
+
// If toggle mode and current line has the same header level, remove it
|
|
187
|
+
if (toggle && existingLevel === level) {
|
|
188
|
+
newLine = cleanedLine
|
|
221
189
|
} else {
|
|
222
|
-
//
|
|
223
|
-
|
|
190
|
+
// Apply new header
|
|
191
|
+
newLine = style.prefix + cleanedLine
|
|
224
192
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
text: newLine,
|
|
196
|
+
selectionStart: ta.selectionStart,
|
|
197
|
+
selectionEnd: ta.selectionEnd
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
prefix: style.prefix,
|
|
202
|
+
// Custom handler for header-specific logic
|
|
203
|
+
adjustSelection: (isRemoving, selStart, selEnd, lineStart) => {
|
|
204
|
+
const currentLine = textarea.value.slice(lineStart, textarea.selectionEnd)
|
|
205
|
+
const existingHeaderMatch = currentLine.match(/^(#{1,6})\s*/)
|
|
206
|
+
const existingPrefixLength = existingHeaderMatch ? existingHeaderMatch[0].length : 0
|
|
207
|
+
const existingLevel = existingHeaderMatch ? existingHeaderMatch[1].length : 0
|
|
208
|
+
|
|
209
|
+
// Check if we're actually removing (toggle off)
|
|
210
|
+
const actuallyRemoving = toggle && existingLevel === level
|
|
211
|
+
|
|
212
|
+
if (actuallyRemoving) {
|
|
213
|
+
// Removing the header entirely
|
|
214
|
+
return {
|
|
215
|
+
start: Math.max(selStart - existingPrefixLength, lineStart),
|
|
216
|
+
end: Math.max(selEnd - existingPrefixLength, lineStart)
|
|
217
|
+
}
|
|
218
|
+
} else if (existingPrefixLength > 0) {
|
|
219
|
+
// Replacing existing header with new one
|
|
220
|
+
const prefixDiff = style.prefix.length - existingPrefixLength
|
|
221
|
+
return {
|
|
222
|
+
start: selStart + prefixDiff,
|
|
223
|
+
end: selEnd + prefixDiff
|
|
224
|
+
}
|
|
225
|
+
} else {
|
|
226
|
+
// Adding new header
|
|
227
|
+
return {
|
|
228
|
+
start: selStart + style.prefix.length,
|
|
229
|
+
end: selEnd + style.prefix.length
|
|
230
|
+
}
|
|
231
|
+
}
|
|
234
232
|
}
|
|
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
233
|
}
|
|
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
|
-
}
|
|
234
|
+
)
|
|
271
235
|
|
|
272
236
|
insertText(textarea, result)
|
|
273
237
|
}
|