overtype 1.2.0 → 1.2.2
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/README.md +23 -3
- package/dist/overtype.cjs +851 -977
- package/dist/overtype.cjs.map +4 -4
- package/dist/overtype.esm.js +53 -30
- package/dist/overtype.esm.js.map +2 -2
- package/dist/overtype.js +53 -30
- package/dist/overtype.js.map +2 -2
- package/dist/overtype.min.js +45 -39
- package/package.json +5 -2
- package/src/overtype.js +33 -28
- package/src/parser.js +48 -19
- package/src/styles.js +6 -0
package/dist/overtype.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OverType v1.2.
|
|
2
|
+
* OverType v1.2.2
|
|
3
3
|
* A lightweight markdown editor library with perfect WYSIWYG alignment
|
|
4
4
|
* @license MIT
|
|
5
5
|
* @author Demo User
|
|
@@ -258,11 +258,22 @@ var MarkdownParser = class {
|
|
|
258
258
|
static parse(text, activeLine = -1, showActiveLineRaw = false) {
|
|
259
259
|
this.resetLinkIndex();
|
|
260
260
|
const lines = text.split("\n");
|
|
261
|
+
let inCodeBlock = false;
|
|
261
262
|
const parsedLines = lines.map((line, index) => {
|
|
262
263
|
if (showActiveLineRaw && index === activeLine) {
|
|
263
264
|
const content = this.escapeHtml(line) || " ";
|
|
264
265
|
return `<div class="raw-line">${content}</div>`;
|
|
265
266
|
}
|
|
267
|
+
const codeFenceRegex = /^```[^`]*$/;
|
|
268
|
+
if (codeFenceRegex.test(line)) {
|
|
269
|
+
inCodeBlock = !inCodeBlock;
|
|
270
|
+
return this.parseLine(line);
|
|
271
|
+
}
|
|
272
|
+
if (inCodeBlock) {
|
|
273
|
+
const escaped = this.escapeHtml(line);
|
|
274
|
+
const indented = this.preserveIndentation(escaped, line);
|
|
275
|
+
return `<div>${indented || " "}</div>`;
|
|
276
|
+
}
|
|
266
277
|
return this.parseLine(line);
|
|
267
278
|
});
|
|
268
279
|
const html = parsedLines.join("");
|
|
@@ -302,23 +313,22 @@ var MarkdownParser = class {
|
|
|
302
313
|
if (lang) {
|
|
303
314
|
codeElement.className = `language-${lang}`;
|
|
304
315
|
}
|
|
305
|
-
container.insertBefore(currentCodeBlock, child);
|
|
306
|
-
|
|
316
|
+
container.insertBefore(currentCodeBlock, child.nextSibling);
|
|
317
|
+
currentCodeBlock._codeElement = codeElement;
|
|
307
318
|
continue;
|
|
308
319
|
} else {
|
|
309
320
|
inCodeBlock = false;
|
|
310
321
|
currentCodeBlock = null;
|
|
311
|
-
child.remove();
|
|
312
322
|
continue;
|
|
313
323
|
}
|
|
314
324
|
}
|
|
315
325
|
}
|
|
316
326
|
if (inCodeBlock && currentCodeBlock && child.tagName === "DIV" && !child.querySelector(".code-fence")) {
|
|
317
|
-
const codeElement = currentCodeBlock.querySelector("code");
|
|
327
|
+
const codeElement = currentCodeBlock._codeElement || currentCodeBlock.querySelector("code");
|
|
318
328
|
if (codeElement.textContent.length > 0) {
|
|
319
329
|
codeElement.textContent += "\n";
|
|
320
330
|
}
|
|
321
|
-
const lineText = child.
|
|
331
|
+
const lineText = child.textContent.replace(/\u00A0/g, " ");
|
|
322
332
|
codeElement.textContent += lineText;
|
|
323
333
|
child.remove();
|
|
324
334
|
continue;
|
|
@@ -371,15 +381,19 @@ var MarkdownParser = class {
|
|
|
371
381
|
}
|
|
372
382
|
return match;
|
|
373
383
|
});
|
|
374
|
-
const codeBlockRegex = /<div><span class="code-fence"
|
|
375
|
-
processed = processed.replace(codeBlockRegex, (match,
|
|
384
|
+
const codeBlockRegex = /<div><span class="code-fence">(```[^<]*)<\/span><\/div>(.*?)<div><span class="code-fence">(```)<\/span><\/div>/gs;
|
|
385
|
+
processed = processed.replace(codeBlockRegex, (match, openFence, content, closeFence) => {
|
|
376
386
|
const lines = content.match(/<div>(.*?)<\/div>/gs) || [];
|
|
377
387
|
const codeContent = lines.map((line) => {
|
|
378
|
-
const text = line.replace(/<div>(.*?)<\/div>/s, "$1").replace(/ /g, " ")
|
|
388
|
+
const text = line.replace(/<div>(.*?)<\/div>/s, "$1").replace(/ /g, " ");
|
|
379
389
|
return text;
|
|
380
390
|
}).join("\n");
|
|
381
|
-
const
|
|
382
|
-
|
|
391
|
+
const lang = openFence.slice(3).trim();
|
|
392
|
+
const langClass = lang ? ` class="language-${lang}"` : "";
|
|
393
|
+
let result = `<div><span class="code-fence">${openFence}</span></div>`;
|
|
394
|
+
result += `<pre class="code-block"><code${langClass}>${codeContent}</code></pre>`;
|
|
395
|
+
result += `<div><span class="code-fence">${closeFence}</span></div>`;
|
|
396
|
+
return result;
|
|
383
397
|
});
|
|
384
398
|
return processed;
|
|
385
399
|
}
|
|
@@ -387,997 +401,848 @@ var MarkdownParser = class {
|
|
|
387
401
|
// Track link index for anchor naming
|
|
388
402
|
__publicField(MarkdownParser, "linkIndex", 0);
|
|
389
403
|
|
|
390
|
-
// node_modules/markdown-actions/dist/markdown-actions.js
|
|
391
|
-
var
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
var
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
404
|
+
// node_modules/markdown-actions/dist/markdown-actions.esm.js
|
|
405
|
+
var __defProp2 = Object.defineProperty;
|
|
406
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
407
|
+
var __hasOwnProp2 = Object.prototype.hasOwnProperty;
|
|
408
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
409
|
+
var __defNormalProp2 = (obj, key, value) => key in obj ? __defProp2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
410
|
+
var __spreadValues = (a, b) => {
|
|
411
|
+
for (var prop in b || (b = {}))
|
|
412
|
+
if (__hasOwnProp2.call(b, prop))
|
|
413
|
+
__defNormalProp2(a, prop, b[prop]);
|
|
414
|
+
if (__getOwnPropSymbols)
|
|
415
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
416
|
+
if (__propIsEnum.call(b, prop))
|
|
402
417
|
__defNormalProp2(a, prop, b[prop]);
|
|
403
|
-
if (__getOwnPropSymbols)
|
|
404
|
-
for (var prop of __getOwnPropSymbols(b)) {
|
|
405
|
-
if (__propIsEnum.call(b, prop))
|
|
406
|
-
__defNormalProp2(a, prop, b[prop]);
|
|
407
|
-
}
|
|
408
|
-
return a;
|
|
409
|
-
};
|
|
410
|
-
var __export2 = (target, all) => {
|
|
411
|
-
for (var name in all)
|
|
412
|
-
__defProp2(target, name, { get: all[name], enumerable: true });
|
|
413
|
-
};
|
|
414
|
-
var __copyProps2 = (to, from, except, desc) => {
|
|
415
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
416
|
-
for (let key of __getOwnPropNames2(from))
|
|
417
|
-
if (!__hasOwnProp2.call(to, key) && key !== except)
|
|
418
|
-
__defProp2(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc2(from, key)) || desc.enumerable });
|
|
419
418
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
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
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
prefix: "- [ ] ",
|
|
487
|
-
multiline: true,
|
|
488
|
-
surroundWithNewlines: true
|
|
489
|
-
},
|
|
490
|
-
header1: { prefix: "# " },
|
|
491
|
-
header2: { prefix: "## " },
|
|
492
|
-
header3: { prefix: "### " },
|
|
493
|
-
header4: { prefix: "#### " },
|
|
494
|
-
header5: { prefix: "##### " },
|
|
495
|
-
header6: { prefix: "###### " }
|
|
419
|
+
return a;
|
|
420
|
+
};
|
|
421
|
+
var FORMATS = {
|
|
422
|
+
bold: {
|
|
423
|
+
prefix: "**",
|
|
424
|
+
suffix: "**",
|
|
425
|
+
trimFirst: true
|
|
426
|
+
},
|
|
427
|
+
italic: {
|
|
428
|
+
prefix: "_",
|
|
429
|
+
suffix: "_",
|
|
430
|
+
trimFirst: true
|
|
431
|
+
},
|
|
432
|
+
code: {
|
|
433
|
+
prefix: "`",
|
|
434
|
+
suffix: "`",
|
|
435
|
+
blockPrefix: "```",
|
|
436
|
+
blockSuffix: "```"
|
|
437
|
+
},
|
|
438
|
+
link: {
|
|
439
|
+
prefix: "[",
|
|
440
|
+
suffix: "](url)",
|
|
441
|
+
replaceNext: "url",
|
|
442
|
+
scanFor: "https?://"
|
|
443
|
+
},
|
|
444
|
+
bulletList: {
|
|
445
|
+
prefix: "- ",
|
|
446
|
+
multiline: true,
|
|
447
|
+
unorderedList: true
|
|
448
|
+
},
|
|
449
|
+
numberedList: {
|
|
450
|
+
prefix: "1. ",
|
|
451
|
+
multiline: true,
|
|
452
|
+
orderedList: true
|
|
453
|
+
},
|
|
454
|
+
quote: {
|
|
455
|
+
prefix: "> ",
|
|
456
|
+
multiline: true,
|
|
457
|
+
surroundWithNewlines: true
|
|
458
|
+
},
|
|
459
|
+
taskList: {
|
|
460
|
+
prefix: "- [ ] ",
|
|
461
|
+
multiline: true,
|
|
462
|
+
surroundWithNewlines: true
|
|
463
|
+
},
|
|
464
|
+
header1: { prefix: "# " },
|
|
465
|
+
header2: { prefix: "## " },
|
|
466
|
+
header3: { prefix: "### " },
|
|
467
|
+
header4: { prefix: "#### " },
|
|
468
|
+
header5: { prefix: "##### " },
|
|
469
|
+
header6: { prefix: "###### " }
|
|
470
|
+
};
|
|
471
|
+
function getDefaultStyle() {
|
|
472
|
+
return {
|
|
473
|
+
prefix: "",
|
|
474
|
+
suffix: "",
|
|
475
|
+
blockPrefix: "",
|
|
476
|
+
blockSuffix: "",
|
|
477
|
+
multiline: false,
|
|
478
|
+
replaceNext: "",
|
|
479
|
+
prefixSpace: false,
|
|
480
|
+
scanFor: "",
|
|
481
|
+
surroundWithNewlines: false,
|
|
482
|
+
orderedList: false,
|
|
483
|
+
unorderedList: false,
|
|
484
|
+
trimFirst: false
|
|
496
485
|
};
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
}
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
}
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
486
|
+
}
|
|
487
|
+
function mergeWithDefaults(format) {
|
|
488
|
+
return __spreadValues(__spreadValues({}, getDefaultStyle()), format);
|
|
489
|
+
}
|
|
490
|
+
var debugMode = false;
|
|
491
|
+
function getDebugMode() {
|
|
492
|
+
return debugMode;
|
|
493
|
+
}
|
|
494
|
+
function debugLog(funcName, message, data) {
|
|
495
|
+
if (!debugMode)
|
|
496
|
+
return;
|
|
497
|
+
console.group(`\u{1F50D} ${funcName}`);
|
|
498
|
+
console.log(message);
|
|
499
|
+
if (data) {
|
|
500
|
+
console.log("Data:", data);
|
|
501
|
+
}
|
|
502
|
+
console.groupEnd();
|
|
503
|
+
}
|
|
504
|
+
function debugSelection(textarea, label) {
|
|
505
|
+
if (!debugMode)
|
|
506
|
+
return;
|
|
507
|
+
const selected = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
508
|
+
console.group(`\u{1F4CD} Selection: ${label}`);
|
|
509
|
+
console.log("Position:", `${textarea.selectionStart}-${textarea.selectionEnd}`);
|
|
510
|
+
console.log("Selected text:", JSON.stringify(selected));
|
|
511
|
+
console.log("Length:", selected.length);
|
|
512
|
+
const before = textarea.value.slice(Math.max(0, textarea.selectionStart - 10), textarea.selectionStart);
|
|
513
|
+
const after = textarea.value.slice(textarea.selectionEnd, Math.min(textarea.value.length, textarea.selectionEnd + 10));
|
|
514
|
+
console.log("Context:", JSON.stringify(before) + "[SELECTION]" + JSON.stringify(after));
|
|
515
|
+
console.groupEnd();
|
|
516
|
+
}
|
|
517
|
+
function debugResult(result) {
|
|
518
|
+
if (!debugMode)
|
|
519
|
+
return;
|
|
520
|
+
console.group("\u{1F4DD} Result");
|
|
521
|
+
console.log("Text to insert:", JSON.stringify(result.text));
|
|
522
|
+
console.log("New selection:", `${result.selectionStart}-${result.selectionEnd}`);
|
|
523
|
+
console.groupEnd();
|
|
524
|
+
}
|
|
525
|
+
var canInsertText = null;
|
|
526
|
+
function insertText(textarea, { text, selectionStart, selectionEnd }) {
|
|
527
|
+
const debugMode2 = getDebugMode();
|
|
528
|
+
if (debugMode2) {
|
|
529
|
+
console.group("\u{1F527} insertText");
|
|
530
|
+
console.log("Current selection:", `${textarea.selectionStart}-${textarea.selectionEnd}`);
|
|
531
|
+
console.log("Text to insert:", JSON.stringify(text));
|
|
532
|
+
console.log("New selection to set:", selectionStart, "-", selectionEnd);
|
|
533
|
+
}
|
|
534
|
+
textarea.focus();
|
|
535
|
+
const originalSelectionStart = textarea.selectionStart;
|
|
536
|
+
const originalSelectionEnd = textarea.selectionEnd;
|
|
537
|
+
const before = textarea.value.slice(0, originalSelectionStart);
|
|
538
|
+
const after = textarea.value.slice(originalSelectionEnd);
|
|
539
|
+
if (debugMode2) {
|
|
540
|
+
console.log("Before text (last 20):", JSON.stringify(before.slice(-20)));
|
|
541
|
+
console.log("After text (first 20):", JSON.stringify(after.slice(0, 20)));
|
|
542
|
+
console.log("Selected text being replaced:", JSON.stringify(textarea.value.slice(originalSelectionStart, originalSelectionEnd)));
|
|
543
|
+
}
|
|
544
|
+
const originalValue = textarea.value;
|
|
545
|
+
const hasSelection = originalSelectionStart !== originalSelectionEnd;
|
|
546
|
+
if (canInsertText === null || canInsertText === true) {
|
|
547
|
+
textarea.contentEditable = "true";
|
|
548
|
+
try {
|
|
549
|
+
canInsertText = document.execCommand("insertText", false, text);
|
|
550
|
+
if (debugMode2)
|
|
551
|
+
console.log("execCommand returned:", canInsertText, "for text with", text.split("\n").length, "lines");
|
|
552
|
+
} catch (error) {
|
|
553
|
+
canInsertText = false;
|
|
554
|
+
if (debugMode2)
|
|
555
|
+
console.log("execCommand threw error:", error);
|
|
530
556
|
}
|
|
531
|
-
|
|
557
|
+
textarea.contentEditable = "false";
|
|
532
558
|
}
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
const selected = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
537
|
-
console.group(`\u{1F4CD} Selection: ${label}`);
|
|
538
|
-
console.log("Position:", `${textarea.selectionStart}-${textarea.selectionEnd}`);
|
|
539
|
-
console.log("Selected text:", JSON.stringify(selected));
|
|
540
|
-
console.log("Length:", selected.length);
|
|
541
|
-
const before = textarea.value.slice(Math.max(0, textarea.selectionStart - 10), textarea.selectionStart);
|
|
542
|
-
const after = textarea.value.slice(textarea.selectionEnd, Math.min(textarea.value.length, textarea.selectionEnd + 10));
|
|
543
|
-
console.log("Context:", JSON.stringify(before) + "[SELECTION]" + JSON.stringify(after));
|
|
544
|
-
console.groupEnd();
|
|
545
|
-
}
|
|
546
|
-
function debugResult(result) {
|
|
547
|
-
if (!debugMode)
|
|
548
|
-
return;
|
|
549
|
-
console.group("\u{1F4DD} Result");
|
|
550
|
-
console.log("Text to insert:", JSON.stringify(result.text));
|
|
551
|
-
console.log("New selection:", `${result.selectionStart}-${result.selectionEnd}`);
|
|
552
|
-
console.groupEnd();
|
|
559
|
+
if (debugMode2) {
|
|
560
|
+
console.log("canInsertText before:", canInsertText);
|
|
561
|
+
console.log("execCommand result:", canInsertText);
|
|
553
562
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
const
|
|
557
|
-
if (debugMode2) {
|
|
558
|
-
console.group("\u{1F527} insertText");
|
|
559
|
-
console.log("Current selection:", `${textarea.selectionStart}-${textarea.selectionEnd}`);
|
|
560
|
-
console.log("Text to insert:", JSON.stringify(text));
|
|
561
|
-
console.log("New selection to set:", selectionStart, "-", selectionEnd);
|
|
562
|
-
}
|
|
563
|
-
textarea.focus();
|
|
564
|
-
const originalSelectionStart = textarea.selectionStart;
|
|
565
|
-
const originalSelectionEnd = textarea.selectionEnd;
|
|
566
|
-
const before = textarea.value.slice(0, originalSelectionStart);
|
|
567
|
-
const after = textarea.value.slice(originalSelectionEnd);
|
|
568
|
-
if (debugMode2) {
|
|
569
|
-
console.log("Before text (last 20):", JSON.stringify(before.slice(-20)));
|
|
570
|
-
console.log("After text (first 20):", JSON.stringify(after.slice(0, 20)));
|
|
571
|
-
console.log("Selected text being replaced:", JSON.stringify(textarea.value.slice(originalSelectionStart, originalSelectionEnd)));
|
|
572
|
-
}
|
|
573
|
-
const originalValue = textarea.value;
|
|
574
|
-
const hasSelection = originalSelectionStart !== originalSelectionEnd;
|
|
575
|
-
if (canInsertText === null || canInsertText === true) {
|
|
576
|
-
textarea.contentEditable = "true";
|
|
577
|
-
try {
|
|
578
|
-
canInsertText = document.execCommand("insertText", false, text);
|
|
579
|
-
if (debugMode2)
|
|
580
|
-
console.log("execCommand returned:", canInsertText, "for text with", text.split("\n").length, "lines");
|
|
581
|
-
} catch (error) {
|
|
582
|
-
canInsertText = false;
|
|
583
|
-
if (debugMode2)
|
|
584
|
-
console.log("execCommand threw error:", error);
|
|
585
|
-
}
|
|
586
|
-
textarea.contentEditable = "false";
|
|
587
|
-
}
|
|
563
|
+
if (canInsertText) {
|
|
564
|
+
const expectedValue = before + text + after;
|
|
565
|
+
const actualValue = textarea.value;
|
|
588
566
|
if (debugMode2) {
|
|
589
|
-
console.log("
|
|
590
|
-
console.log("
|
|
567
|
+
console.log("Expected length:", expectedValue.length);
|
|
568
|
+
console.log("Actual length:", actualValue.length);
|
|
591
569
|
}
|
|
592
|
-
if (
|
|
593
|
-
const expectedValue = before + text + after;
|
|
594
|
-
const actualValue = textarea.value;
|
|
570
|
+
if (actualValue !== expectedValue) {
|
|
595
571
|
if (debugMode2) {
|
|
596
|
-
console.log("
|
|
597
|
-
console.log("
|
|
598
|
-
|
|
599
|
-
if (actualValue !== expectedValue) {
|
|
600
|
-
if (debugMode2) {
|
|
601
|
-
console.log("execCommand changed the value but not as expected");
|
|
602
|
-
console.log("Expected:", JSON.stringify(expectedValue.slice(0, 100)));
|
|
603
|
-
console.log("Actual:", JSON.stringify(actualValue.slice(0, 100)));
|
|
604
|
-
}
|
|
572
|
+
console.log("execCommand changed the value but not as expected");
|
|
573
|
+
console.log("Expected:", JSON.stringify(expectedValue.slice(0, 100)));
|
|
574
|
+
console.log("Actual:", JSON.stringify(actualValue.slice(0, 100)));
|
|
605
575
|
}
|
|
606
576
|
}
|
|
607
|
-
|
|
577
|
+
}
|
|
578
|
+
if (!canInsertText) {
|
|
579
|
+
if (debugMode2)
|
|
580
|
+
console.log("Using manual insertion");
|
|
581
|
+
if (textarea.value === originalValue) {
|
|
608
582
|
if (debugMode2)
|
|
609
|
-
console.log("
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
try {
|
|
614
|
-
document.execCommand("ms-beginUndoUnit");
|
|
615
|
-
} catch (e) {
|
|
616
|
-
}
|
|
617
|
-
textarea.value = before + text + after;
|
|
618
|
-
try {
|
|
619
|
-
document.execCommand("ms-endUndoUnit");
|
|
620
|
-
} catch (e) {
|
|
621
|
-
}
|
|
622
|
-
textarea.dispatchEvent(new CustomEvent("input", { bubbles: true, cancelable: true }));
|
|
623
|
-
} else {
|
|
624
|
-
if (debugMode2)
|
|
625
|
-
console.log("Value was changed by execCommand, skipping manual insertion");
|
|
583
|
+
console.log("Value unchanged, doing manual replacement");
|
|
584
|
+
try {
|
|
585
|
+
document.execCommand("ms-beginUndoUnit");
|
|
586
|
+
} catch (e) {
|
|
626
587
|
}
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
588
|
+
textarea.value = before + text + after;
|
|
589
|
+
try {
|
|
590
|
+
document.execCommand("ms-endUndoUnit");
|
|
591
|
+
} catch (e) {
|
|
592
|
+
}
|
|
593
|
+
textarea.dispatchEvent(new CustomEvent("input", { bubbles: true, cancelable: true }));
|
|
632
594
|
} else {
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
if (debugMode2) {
|
|
636
|
-
console.log("Final value length:", textarea.value.length);
|
|
637
|
-
console.groupEnd();
|
|
638
|
-
}
|
|
639
|
-
}
|
|
640
|
-
function setUndoMethod(method) {
|
|
641
|
-
switch (method) {
|
|
642
|
-
case "native":
|
|
643
|
-
canInsertText = true;
|
|
644
|
-
break;
|
|
645
|
-
case "manual":
|
|
646
|
-
canInsertText = false;
|
|
647
|
-
break;
|
|
648
|
-
case "auto":
|
|
649
|
-
canInsertText = null;
|
|
650
|
-
break;
|
|
595
|
+
if (debugMode2)
|
|
596
|
+
console.log("Value was changed by execCommand, skipping manual insertion");
|
|
651
597
|
}
|
|
652
598
|
}
|
|
653
|
-
|
|
654
|
-
|
|
599
|
+
if (debugMode2)
|
|
600
|
+
console.log("Setting selection range:", selectionStart, selectionEnd);
|
|
601
|
+
if (selectionStart != null && selectionEnd != null) {
|
|
602
|
+
textarea.setSelectionRange(selectionStart, selectionEnd);
|
|
603
|
+
} else {
|
|
604
|
+
textarea.setSelectionRange(originalSelectionStart, textarea.selectionEnd);
|
|
655
605
|
}
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
index--;
|
|
660
|
-
}
|
|
661
|
-
return index;
|
|
606
|
+
if (debugMode2) {
|
|
607
|
+
console.log("Final value length:", textarea.value.length);
|
|
608
|
+
console.groupEnd();
|
|
662
609
|
}
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
610
|
+
}
|
|
611
|
+
function isMultipleLines(string) {
|
|
612
|
+
return string.trim().split("\n").length > 1;
|
|
613
|
+
}
|
|
614
|
+
function wordSelectionStart(text, i) {
|
|
615
|
+
let index = i;
|
|
616
|
+
while (text[index] && text[index - 1] != null && !text[index - 1].match(/\s/)) {
|
|
617
|
+
index--;
|
|
670
618
|
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
}
|
|
679
|
-
if (textarea.selectionEnd >= counter && textarea.selectionEnd < counter + lineLength) {
|
|
680
|
-
if (index === lines.length - 1) {
|
|
681
|
-
textarea.selectionEnd = Math.min(counter + lines[index].length, textarea.value.length);
|
|
682
|
-
} else {
|
|
683
|
-
textarea.selectionEnd = counter + lineLength - 1;
|
|
684
|
-
}
|
|
685
|
-
}
|
|
686
|
-
counter += lineLength;
|
|
687
|
-
}
|
|
619
|
+
return index;
|
|
620
|
+
}
|
|
621
|
+
function wordSelectionEnd(text, i, multiline) {
|
|
622
|
+
let index = i;
|
|
623
|
+
const breakpoint = multiline ? /\n/ : /\s/;
|
|
624
|
+
while (text[index] && !text[index].match(breakpoint)) {
|
|
625
|
+
index++;
|
|
688
626
|
}
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
627
|
+
return index;
|
|
628
|
+
}
|
|
629
|
+
function expandSelectionToLine(textarea) {
|
|
630
|
+
const lines = textarea.value.split("\n");
|
|
631
|
+
let counter = 0;
|
|
632
|
+
for (let index = 0; index < lines.length; index++) {
|
|
633
|
+
const lineLength = lines[index].length + 1;
|
|
634
|
+
if (textarea.selectionStart >= counter && textarea.selectionStart < counter + lineLength) {
|
|
635
|
+
textarea.selectionStart = counter;
|
|
636
|
+
}
|
|
637
|
+
if (textarea.selectionEnd >= counter && textarea.selectionEnd < counter + lineLength) {
|
|
638
|
+
if (index === lines.length - 1) {
|
|
639
|
+
textarea.selectionEnd = Math.min(counter + lines[index].length, textarea.value.length);
|
|
640
|
+
} else {
|
|
641
|
+
textarea.selectionEnd = counter + lineLength - 1;
|
|
701
642
|
}
|
|
702
643
|
}
|
|
703
|
-
|
|
644
|
+
counter += lineLength;
|
|
704
645
|
}
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
const
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
646
|
+
}
|
|
647
|
+
function expandSelectedText(textarea, prefixToUse, suffixToUse, multiline = false) {
|
|
648
|
+
if (textarea.selectionStart === textarea.selectionEnd) {
|
|
649
|
+
textarea.selectionStart = wordSelectionStart(textarea.value, textarea.selectionStart);
|
|
650
|
+
textarea.selectionEnd = wordSelectionEnd(textarea.value, textarea.selectionEnd, multiline);
|
|
651
|
+
} else {
|
|
652
|
+
const expandedSelectionStart = textarea.selectionStart - prefixToUse.length;
|
|
653
|
+
const expandedSelectionEnd = textarea.selectionEnd + suffixToUse.length;
|
|
654
|
+
const beginsWithPrefix = textarea.value.slice(expandedSelectionStart, textarea.selectionStart) === prefixToUse;
|
|
655
|
+
const endsWithSuffix = textarea.value.slice(textarea.selectionEnd, expandedSelectionEnd) === suffixToUse;
|
|
656
|
+
if (beginsWithPrefix && endsWithSuffix) {
|
|
657
|
+
textarea.selectionStart = expandedSelectionStart;
|
|
658
|
+
textarea.selectionEnd = expandedSelectionEnd;
|
|
659
|
+
}
|
|
660
|
+
}
|
|
661
|
+
return textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
662
|
+
}
|
|
663
|
+
function newlinesToSurroundSelectedText(textarea) {
|
|
664
|
+
const beforeSelection = textarea.value.slice(0, textarea.selectionStart);
|
|
665
|
+
const afterSelection = textarea.value.slice(textarea.selectionEnd);
|
|
666
|
+
const breaksBefore = beforeSelection.match(/\n*$/);
|
|
667
|
+
const breaksAfter = afterSelection.match(/^\n*/);
|
|
668
|
+
const newlinesBeforeSelection = breaksBefore ? breaksBefore[0].length : 0;
|
|
669
|
+
const newlinesAfterSelection = breaksAfter ? breaksAfter[0].length : 0;
|
|
670
|
+
let newlinesToAppend = "";
|
|
671
|
+
let newlinesToPrepend = "";
|
|
672
|
+
if (beforeSelection.match(/\S/) && newlinesBeforeSelection < 2) {
|
|
673
|
+
newlinesToAppend = "\n".repeat(2 - newlinesBeforeSelection);
|
|
674
|
+
}
|
|
675
|
+
if (afterSelection.match(/\S/) && newlinesAfterSelection < 2) {
|
|
676
|
+
newlinesToPrepend = "\n".repeat(2 - newlinesAfterSelection);
|
|
677
|
+
}
|
|
678
|
+
return { newlinesToAppend, newlinesToPrepend };
|
|
679
|
+
}
|
|
680
|
+
function applyLineOperation(textarea, operation, options = {}) {
|
|
681
|
+
const originalStart = textarea.selectionStart;
|
|
682
|
+
const originalEnd = textarea.selectionEnd;
|
|
683
|
+
const noInitialSelection = originalStart === originalEnd;
|
|
684
|
+
const value = textarea.value;
|
|
685
|
+
let lineStart = originalStart;
|
|
686
|
+
while (lineStart > 0 && value[lineStart - 1] !== "\n") {
|
|
687
|
+
lineStart--;
|
|
688
|
+
}
|
|
689
|
+
if (noInitialSelection) {
|
|
690
|
+
let lineEnd = originalStart;
|
|
691
|
+
while (lineEnd < value.length && value[lineEnd] !== "\n") {
|
|
692
|
+
lineEnd++;
|
|
719
693
|
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
const end = textarea.selectionEnd;
|
|
725
|
-
const scrollTop = textarea.scrollTop;
|
|
726
|
-
callback();
|
|
727
|
-
textarea.selectionStart = start;
|
|
728
|
-
textarea.selectionEnd = end;
|
|
729
|
-
textarea.scrollTop = scrollTop;
|
|
694
|
+
textarea.selectionStart = lineStart;
|
|
695
|
+
textarea.selectionEnd = lineEnd;
|
|
696
|
+
} else {
|
|
697
|
+
expandSelectionToLine(textarea);
|
|
730
698
|
}
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
const
|
|
734
|
-
const
|
|
735
|
-
const
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
699
|
+
const result = operation(textarea);
|
|
700
|
+
if (options.adjustSelection) {
|
|
701
|
+
const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
702
|
+
const isRemoving = selectedText.startsWith(options.prefix);
|
|
703
|
+
const adjusted = options.adjustSelection(isRemoving, originalStart, originalEnd, lineStart);
|
|
704
|
+
result.selectionStart = adjusted.start;
|
|
705
|
+
result.selectionEnd = adjusted.end;
|
|
706
|
+
} else if (options.prefix) {
|
|
707
|
+
const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
708
|
+
const isRemoving = selectedText.startsWith(options.prefix);
|
|
740
709
|
if (noInitialSelection) {
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
710
|
+
if (isRemoving) {
|
|
711
|
+
result.selectionStart = Math.max(originalStart - options.prefix.length, lineStart);
|
|
712
|
+
result.selectionEnd = result.selectionStart;
|
|
713
|
+
} else {
|
|
714
|
+
result.selectionStart = originalStart + options.prefix.length;
|
|
715
|
+
result.selectionEnd = result.selectionStart;
|
|
744
716
|
}
|
|
745
|
-
textarea.selectionStart = lineStart;
|
|
746
|
-
textarea.selectionEnd = lineEnd;
|
|
747
717
|
} else {
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
if (options.adjustSelection) {
|
|
752
|
-
const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
753
|
-
const isRemoving = selectedText.startsWith(options.prefix);
|
|
754
|
-
const adjusted = options.adjustSelection(isRemoving, originalStart, originalEnd, lineStart);
|
|
755
|
-
result.selectionStart = adjusted.start;
|
|
756
|
-
result.selectionEnd = adjusted.end;
|
|
757
|
-
} else if (options.prefix) {
|
|
758
|
-
const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
759
|
-
const isRemoving = selectedText.startsWith(options.prefix);
|
|
760
|
-
if (noInitialSelection) {
|
|
761
|
-
if (isRemoving) {
|
|
762
|
-
result.selectionStart = Math.max(originalStart - options.prefix.length, lineStart);
|
|
763
|
-
result.selectionEnd = result.selectionStart;
|
|
764
|
-
} else {
|
|
765
|
-
result.selectionStart = originalStart + options.prefix.length;
|
|
766
|
-
result.selectionEnd = result.selectionStart;
|
|
767
|
-
}
|
|
718
|
+
if (isRemoving) {
|
|
719
|
+
result.selectionStart = Math.max(originalStart - options.prefix.length, lineStart);
|
|
720
|
+
result.selectionEnd = Math.max(originalEnd - options.prefix.length, lineStart);
|
|
768
721
|
} else {
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
result.selectionEnd = Math.max(originalEnd - options.prefix.length, lineStart);
|
|
772
|
-
} else {
|
|
773
|
-
result.selectionStart = originalStart + options.prefix.length;
|
|
774
|
-
result.selectionEnd = originalEnd + options.prefix.length;
|
|
775
|
-
}
|
|
722
|
+
result.selectionStart = originalStart + options.prefix.length;
|
|
723
|
+
result.selectionEnd = originalEnd + options.prefix.length;
|
|
776
724
|
}
|
|
777
725
|
}
|
|
778
|
-
return result;
|
|
779
726
|
}
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
727
|
+
return result;
|
|
728
|
+
}
|
|
729
|
+
function blockStyle(textarea, style) {
|
|
730
|
+
let newlinesToAppend;
|
|
731
|
+
let newlinesToPrepend;
|
|
732
|
+
const { prefix, suffix, blockPrefix, blockSuffix, replaceNext, prefixSpace, scanFor, surroundWithNewlines, trimFirst } = style;
|
|
733
|
+
const originalSelectionStart = textarea.selectionStart;
|
|
734
|
+
const originalSelectionEnd = textarea.selectionEnd;
|
|
735
|
+
let selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
736
|
+
let prefixToUse = isMultipleLines(selectedText) && blockPrefix && blockPrefix.length > 0 ? `${blockPrefix}
|
|
788
737
|
` : prefix;
|
|
789
|
-
|
|
738
|
+
let suffixToUse = isMultipleLines(selectedText) && blockSuffix && blockSuffix.length > 0 ? `
|
|
790
739
|
${blockSuffix}` : suffix;
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
} else {
|
|
816
|
-
selectionEnd = selectionStart + replacementText.length;
|
|
817
|
-
}
|
|
818
|
-
return { text: replacementText, selectionStart, selectionEnd };
|
|
819
|
-
} else if (!hasReplaceNext) {
|
|
820
|
-
let replacementText = prefixToUse + selectedText + suffixToUse;
|
|
821
|
-
selectionStart = originalSelectionStart + prefixToUse.length;
|
|
822
|
-
selectionEnd = originalSelectionEnd + prefixToUse.length;
|
|
823
|
-
const whitespaceEdges = selectedText.match(/^\s*|\s*$/g);
|
|
824
|
-
if (trimFirst && whitespaceEdges) {
|
|
825
|
-
const leadingWhitespace = whitespaceEdges[0] || "";
|
|
826
|
-
const trailingWhitespace = whitespaceEdges[1] || "";
|
|
827
|
-
replacementText = leadingWhitespace + prefixToUse + selectedText.trim() + suffixToUse + trailingWhitespace;
|
|
828
|
-
selectionStart += leadingWhitespace.length;
|
|
829
|
-
selectionEnd -= trailingWhitespace.length;
|
|
830
|
-
}
|
|
831
|
-
return { text: replacementText, selectionStart, selectionEnd };
|
|
832
|
-
} else if (scanFor && scanFor.length > 0 && selectedText.match(scanFor)) {
|
|
833
|
-
suffixToUse = suffixToUse.replace(replaceNext, selectedText);
|
|
834
|
-
const replacementText = prefixToUse + suffixToUse;
|
|
835
|
-
selectionStart = selectionEnd = selectionStart + prefixToUse.length;
|
|
836
|
-
return { text: replacementText, selectionStart, selectionEnd };
|
|
740
|
+
if (prefixSpace) {
|
|
741
|
+
const beforeSelection = textarea.value[textarea.selectionStart - 1];
|
|
742
|
+
if (textarea.selectionStart !== 0 && beforeSelection != null && !beforeSelection.match(/\s/)) {
|
|
743
|
+
prefixToUse = ` ${prefixToUse}`;
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
selectedText = expandSelectedText(textarea, prefixToUse, suffixToUse, style.multiline);
|
|
747
|
+
let selectionStart = textarea.selectionStart;
|
|
748
|
+
let selectionEnd = textarea.selectionEnd;
|
|
749
|
+
const hasReplaceNext = replaceNext && replaceNext.length > 0 && suffixToUse.indexOf(replaceNext) > -1 && selectedText.length > 0;
|
|
750
|
+
if (surroundWithNewlines) {
|
|
751
|
+
const ref = newlinesToSurroundSelectedText(textarea);
|
|
752
|
+
newlinesToAppend = ref.newlinesToAppend;
|
|
753
|
+
newlinesToPrepend = ref.newlinesToPrepend;
|
|
754
|
+
prefixToUse = newlinesToAppend + prefix;
|
|
755
|
+
suffixToUse += newlinesToPrepend;
|
|
756
|
+
}
|
|
757
|
+
if (selectedText.startsWith(prefixToUse) && selectedText.endsWith(suffixToUse)) {
|
|
758
|
+
const replacementText = selectedText.slice(prefixToUse.length, selectedText.length - suffixToUse.length);
|
|
759
|
+
if (originalSelectionStart === originalSelectionEnd) {
|
|
760
|
+
let position = originalSelectionStart - prefixToUse.length;
|
|
761
|
+
position = Math.max(position, selectionStart);
|
|
762
|
+
position = Math.min(position, selectionStart + replacementText.length);
|
|
763
|
+
selectionStart = selectionEnd = position;
|
|
837
764
|
} else {
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
765
|
+
selectionEnd = selectionStart + replacementText.length;
|
|
766
|
+
}
|
|
767
|
+
return { text: replacementText, selectionStart, selectionEnd };
|
|
768
|
+
} else if (!hasReplaceNext) {
|
|
769
|
+
let replacementText = prefixToUse + selectedText + suffixToUse;
|
|
770
|
+
selectionStart = originalSelectionStart + prefixToUse.length;
|
|
771
|
+
selectionEnd = originalSelectionEnd + prefixToUse.length;
|
|
772
|
+
const whitespaceEdges = selectedText.match(/^\s*|\s*$/g);
|
|
773
|
+
if (trimFirst && whitespaceEdges) {
|
|
774
|
+
const leadingWhitespace = whitespaceEdges[0] || "";
|
|
775
|
+
const trailingWhitespace = whitespaceEdges[1] || "";
|
|
776
|
+
replacementText = leadingWhitespace + prefixToUse + selectedText.trim() + suffixToUse + trailingWhitespace;
|
|
777
|
+
selectionStart += leadingWhitespace.length;
|
|
778
|
+
selectionEnd -= trailingWhitespace.length;
|
|
779
|
+
}
|
|
780
|
+
return { text: replacementText, selectionStart, selectionEnd };
|
|
781
|
+
} else if (scanFor && scanFor.length > 0 && selectedText.match(scanFor)) {
|
|
782
|
+
suffixToUse = suffixToUse.replace(replaceNext, selectedText);
|
|
783
|
+
const replacementText = prefixToUse + suffixToUse;
|
|
784
|
+
selectionStart = selectionEnd = selectionStart + prefixToUse.length;
|
|
785
|
+
return { text: replacementText, selectionStart, selectionEnd };
|
|
786
|
+
} else {
|
|
787
|
+
const replacementText = prefixToUse + selectedText + suffixToUse;
|
|
788
|
+
selectionStart = selectionStart + prefixToUse.length + selectedText.length + suffixToUse.indexOf(replaceNext);
|
|
789
|
+
selectionEnd = selectionStart + replaceNext.length;
|
|
790
|
+
return { text: replacementText, selectionStart, selectionEnd };
|
|
843
791
|
}
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
792
|
+
}
|
|
793
|
+
function multilineStyle(textarea, style) {
|
|
794
|
+
const { prefix, suffix, surroundWithNewlines } = style;
|
|
795
|
+
let text = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
796
|
+
let selectionStart = textarea.selectionStart;
|
|
797
|
+
let selectionEnd = textarea.selectionEnd;
|
|
798
|
+
const lines = text.split("\n");
|
|
799
|
+
const undoStyle = lines.every((line) => line.startsWith(prefix) && (!suffix || line.endsWith(suffix)));
|
|
800
|
+
if (undoStyle) {
|
|
801
|
+
text = lines.map((line) => {
|
|
802
|
+
let result = line.slice(prefix.length);
|
|
803
|
+
if (suffix) {
|
|
804
|
+
result = result.slice(0, result.length - suffix.length);
|
|
805
|
+
}
|
|
806
|
+
return result;
|
|
807
|
+
}).join("\n");
|
|
808
|
+
selectionEnd = selectionStart + text.length;
|
|
809
|
+
} else {
|
|
810
|
+
text = lines.map((line) => prefix + line + (suffix || "")).join("\n");
|
|
811
|
+
if (surroundWithNewlines) {
|
|
812
|
+
const { newlinesToAppend, newlinesToPrepend } = newlinesToSurroundSelectedText(textarea);
|
|
813
|
+
selectionStart += newlinesToAppend.length;
|
|
859
814
|
selectionEnd = selectionStart + text.length;
|
|
860
|
-
|
|
861
|
-
text = lines.map((line) => prefix + line + (suffix || "")).join("\n");
|
|
862
|
-
if (surroundWithNewlines) {
|
|
863
|
-
const { newlinesToAppend, newlinesToPrepend } = newlinesToSurroundSelectedText(textarea);
|
|
864
|
-
selectionStart += newlinesToAppend.length;
|
|
865
|
-
selectionEnd = selectionStart + text.length;
|
|
866
|
-
text = newlinesToAppend + text + newlinesToPrepend;
|
|
867
|
-
}
|
|
868
|
-
}
|
|
869
|
-
return { text, selectionStart, selectionEnd };
|
|
870
|
-
}
|
|
871
|
-
function undoOrderedListStyle(text) {
|
|
872
|
-
const lines = text.split("\n");
|
|
873
|
-
const orderedListRegex = /^\d+\.\s+/;
|
|
874
|
-
const shouldUndoOrderedList = lines.every((line) => orderedListRegex.test(line));
|
|
875
|
-
let result = lines;
|
|
876
|
-
if (shouldUndoOrderedList) {
|
|
877
|
-
result = lines.map((line) => line.replace(orderedListRegex, ""));
|
|
815
|
+
text = newlinesToAppend + text + newlinesToPrepend;
|
|
878
816
|
}
|
|
879
|
-
return {
|
|
880
|
-
text: result.join("\n"),
|
|
881
|
-
processed: shouldUndoOrderedList
|
|
882
|
-
};
|
|
883
817
|
}
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
text: result.join("\n"),
|
|
894
|
-
processed: shouldUndoUnorderedList
|
|
895
|
-
};
|
|
818
|
+
return { text, selectionStart, selectionEnd };
|
|
819
|
+
}
|
|
820
|
+
function undoOrderedListStyle(text) {
|
|
821
|
+
const lines = text.split("\n");
|
|
822
|
+
const orderedListRegex = /^\d+\.\s+/;
|
|
823
|
+
const shouldUndoOrderedList = lines.every((line) => orderedListRegex.test(line));
|
|
824
|
+
let result = lines;
|
|
825
|
+
if (shouldUndoOrderedList) {
|
|
826
|
+
result = lines.map((line) => line.replace(orderedListRegex, ""));
|
|
896
827
|
}
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
828
|
+
return {
|
|
829
|
+
text: result.join("\n"),
|
|
830
|
+
processed: shouldUndoOrderedList
|
|
831
|
+
};
|
|
832
|
+
}
|
|
833
|
+
function undoUnorderedListStyle(text) {
|
|
834
|
+
const lines = text.split("\n");
|
|
835
|
+
const unorderedListPrefix = "- ";
|
|
836
|
+
const shouldUndoUnorderedList = lines.every((line) => line.startsWith(unorderedListPrefix));
|
|
837
|
+
let result = lines;
|
|
838
|
+
if (shouldUndoUnorderedList) {
|
|
839
|
+
result = lines.map((line) => line.slice(unorderedListPrefix.length));
|
|
903
840
|
}
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
undoResultOppositeList = undoOrderedListStyle(undoResult.text);
|
|
915
|
-
pristineText = undoResultOppositeList.text;
|
|
916
|
-
}
|
|
917
|
-
return [undoResult, undoResultOppositeList, pristineText];
|
|
841
|
+
return {
|
|
842
|
+
text: result.join("\n"),
|
|
843
|
+
processed: shouldUndoUnorderedList
|
|
844
|
+
};
|
|
845
|
+
}
|
|
846
|
+
function makePrefix(index, unorderedList) {
|
|
847
|
+
if (unorderedList) {
|
|
848
|
+
return "- ";
|
|
849
|
+
} else {
|
|
850
|
+
return `${index + 1}. `;
|
|
918
851
|
}
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
852
|
+
}
|
|
853
|
+
function clearExistingListStyle(style, selectedText) {
|
|
854
|
+
let undoResult;
|
|
855
|
+
let undoResultOppositeList;
|
|
856
|
+
let pristineText;
|
|
857
|
+
if (style.orderedList) {
|
|
858
|
+
undoResult = undoOrderedListStyle(selectedText);
|
|
859
|
+
undoResultOppositeList = undoUnorderedListStyle(undoResult.text);
|
|
860
|
+
pristineText = undoResultOppositeList.text;
|
|
861
|
+
} else {
|
|
862
|
+
undoResult = undoUnorderedListStyle(selectedText);
|
|
863
|
+
undoResultOppositeList = undoOrderedListStyle(undoResult.text);
|
|
864
|
+
pristineText = undoResultOppositeList.text;
|
|
865
|
+
}
|
|
866
|
+
return [undoResult, undoResultOppositeList, pristineText];
|
|
867
|
+
}
|
|
868
|
+
function listStyle(textarea, style) {
|
|
869
|
+
const noInitialSelection = textarea.selectionStart === textarea.selectionEnd;
|
|
870
|
+
let selectionStart = textarea.selectionStart;
|
|
871
|
+
let selectionEnd = textarea.selectionEnd;
|
|
872
|
+
expandSelectionToLine(textarea);
|
|
873
|
+
const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
874
|
+
const [undoResult, undoResultOppositeList, pristineText] = clearExistingListStyle(style, selectedText);
|
|
875
|
+
const prefixedLines = pristineText.split("\n").map((value, index) => {
|
|
876
|
+
return `${makePrefix(index, style.unorderedList)}${value}`;
|
|
877
|
+
});
|
|
878
|
+
const totalPrefixLength = prefixedLines.reduce((previousValue, _currentValue, currentIndex) => {
|
|
879
|
+
return previousValue + makePrefix(currentIndex, style.unorderedList).length;
|
|
880
|
+
}, 0);
|
|
881
|
+
const totalPrefixLengthOppositeList = prefixedLines.reduce((previousValue, _currentValue, currentIndex) => {
|
|
882
|
+
return previousValue + makePrefix(currentIndex, !style.unorderedList).length;
|
|
883
|
+
}, 0);
|
|
884
|
+
if (undoResult.processed) {
|
|
947
885
|
if (noInitialSelection) {
|
|
948
|
-
selectionStart = Math.max(selectionStart
|
|
886
|
+
selectionStart = Math.max(selectionStart - makePrefix(0, style.unorderedList).length, 0);
|
|
949
887
|
selectionEnd = selectionStart;
|
|
950
888
|
} else {
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
889
|
+
selectionStart = textarea.selectionStart;
|
|
890
|
+
selectionEnd = textarea.selectionEnd - totalPrefixLength;
|
|
891
|
+
}
|
|
892
|
+
return { text: pristineText, selectionStart, selectionEnd };
|
|
893
|
+
}
|
|
894
|
+
const { newlinesToAppend, newlinesToPrepend } = newlinesToSurroundSelectedText(textarea);
|
|
895
|
+
const text = newlinesToAppend + prefixedLines.join("\n") + newlinesToPrepend;
|
|
896
|
+
if (noInitialSelection) {
|
|
897
|
+
selectionStart = Math.max(selectionStart + makePrefix(0, style.unorderedList).length + newlinesToAppend.length, 0);
|
|
898
|
+
selectionEnd = selectionStart;
|
|
899
|
+
} else {
|
|
900
|
+
if (undoResultOppositeList.processed) {
|
|
901
|
+
selectionStart = Math.max(textarea.selectionStart + newlinesToAppend.length, 0);
|
|
902
|
+
selectionEnd = textarea.selectionEnd + newlinesToAppend.length + totalPrefixLength - totalPrefixLengthOppositeList;
|
|
903
|
+
} else {
|
|
904
|
+
selectionStart = Math.max(textarea.selectionStart + newlinesToAppend.length, 0);
|
|
905
|
+
selectionEnd = textarea.selectionEnd + newlinesToAppend.length + totalPrefixLength;
|
|
958
906
|
}
|
|
959
|
-
|
|
960
|
-
}
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
}
|
|
992
|
-
const prefixLength = style.unorderedList ? 2 : 3;
|
|
993
|
-
return {
|
|
994
|
-
start: selStart + prefixLength,
|
|
995
|
-
end: selStart + prefixLength
|
|
996
|
-
};
|
|
997
|
-
}
|
|
907
|
+
}
|
|
908
|
+
return { text, selectionStart, selectionEnd };
|
|
909
|
+
}
|
|
910
|
+
function applyListStyle(textarea, style) {
|
|
911
|
+
const result = applyLineOperation(
|
|
912
|
+
textarea,
|
|
913
|
+
(ta) => listStyle(ta, style),
|
|
914
|
+
{
|
|
915
|
+
// Custom selection adjustment for lists
|
|
916
|
+
adjustSelection: (isRemoving, selStart, selEnd, lineStart) => {
|
|
917
|
+
const currentLine = textarea.value.slice(lineStart, textarea.selectionEnd);
|
|
918
|
+
const orderedListRegex = /^\d+\.\s+/;
|
|
919
|
+
const unorderedListRegex = /^- /;
|
|
920
|
+
const hasOrderedList = orderedListRegex.test(currentLine);
|
|
921
|
+
const hasUnorderedList = unorderedListRegex.test(currentLine);
|
|
922
|
+
const isRemovingCurrent = style.orderedList && hasOrderedList || style.unorderedList && hasUnorderedList;
|
|
923
|
+
if (selStart === selEnd) {
|
|
924
|
+
if (isRemovingCurrent) {
|
|
925
|
+
const prefixMatch = currentLine.match(style.orderedList ? orderedListRegex : unorderedListRegex);
|
|
926
|
+
const prefixLength = prefixMatch ? prefixMatch[0].length : 0;
|
|
927
|
+
return {
|
|
928
|
+
start: Math.max(selStart - prefixLength, lineStart),
|
|
929
|
+
end: Math.max(selStart - prefixLength, lineStart)
|
|
930
|
+
};
|
|
931
|
+
} else if (hasOrderedList || hasUnorderedList) {
|
|
932
|
+
const oldPrefixMatch = currentLine.match(hasOrderedList ? orderedListRegex : unorderedListRegex);
|
|
933
|
+
const oldPrefixLength = oldPrefixMatch ? oldPrefixMatch[0].length : 0;
|
|
934
|
+
const newPrefixLength = style.unorderedList ? 2 : 3;
|
|
935
|
+
const adjustment = newPrefixLength - oldPrefixLength;
|
|
936
|
+
return {
|
|
937
|
+
start: selStart + adjustment,
|
|
938
|
+
end: selStart + adjustment
|
|
939
|
+
};
|
|
998
940
|
} else {
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
end: Math.max(selEnd - prefixLength, lineStart)
|
|
1005
|
-
};
|
|
1006
|
-
} else if (hasOrderedList || hasUnorderedList) {
|
|
1007
|
-
const oldPrefixMatch = currentLine.match(hasOrderedList ? orderedListRegex : unorderedListRegex);
|
|
1008
|
-
const oldPrefixLength = oldPrefixMatch ? oldPrefixMatch[0].length : 0;
|
|
1009
|
-
const newPrefixLength = style.unorderedList ? 2 : 3;
|
|
1010
|
-
const adjustment = newPrefixLength - oldPrefixLength;
|
|
1011
|
-
return {
|
|
1012
|
-
start: selStart + adjustment,
|
|
1013
|
-
end: selEnd + adjustment
|
|
1014
|
-
};
|
|
1015
|
-
} else {
|
|
1016
|
-
const prefixLength = style.unorderedList ? 2 : 3;
|
|
1017
|
-
return {
|
|
1018
|
-
start: selStart + prefixLength,
|
|
1019
|
-
end: selEnd + prefixLength
|
|
1020
|
-
};
|
|
1021
|
-
}
|
|
941
|
+
const prefixLength = style.unorderedList ? 2 : 3;
|
|
942
|
+
return {
|
|
943
|
+
start: selStart + prefixLength,
|
|
944
|
+
end: selStart + prefixLength
|
|
945
|
+
};
|
|
1022
946
|
}
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
);
|
|
1026
|
-
insertText(textarea, result);
|
|
1027
|
-
}
|
|
1028
|
-
function getActiveFormats2(textarea) {
|
|
1029
|
-
if (!textarea)
|
|
1030
|
-
return [];
|
|
1031
|
-
const formats = [];
|
|
1032
|
-
const { selectionStart, selectionEnd, value } = textarea;
|
|
1033
|
-
const lines = value.split("\n");
|
|
1034
|
-
let lineStart = 0;
|
|
1035
|
-
let currentLine = "";
|
|
1036
|
-
for (const line of lines) {
|
|
1037
|
-
if (selectionStart >= lineStart && selectionStart <= lineStart + line.length) {
|
|
1038
|
-
currentLine = line;
|
|
1039
|
-
break;
|
|
1040
|
-
}
|
|
1041
|
-
lineStart += line.length + 1;
|
|
1042
|
-
}
|
|
1043
|
-
if (currentLine.startsWith("- ")) {
|
|
1044
|
-
if (currentLine.startsWith("- [ ] ") || currentLine.startsWith("- [x] ")) {
|
|
1045
|
-
formats.push("task-list");
|
|
1046
|
-
} else {
|
|
1047
|
-
formats.push("bullet-list");
|
|
1048
|
-
}
|
|
1049
|
-
}
|
|
1050
|
-
if (/^\d+\.\s/.test(currentLine)) {
|
|
1051
|
-
formats.push("numbered-list");
|
|
1052
|
-
}
|
|
1053
|
-
if (currentLine.startsWith("> ")) {
|
|
1054
|
-
formats.push("quote");
|
|
1055
|
-
}
|
|
1056
|
-
if (currentLine.startsWith("# "))
|
|
1057
|
-
formats.push("header");
|
|
1058
|
-
if (currentLine.startsWith("## "))
|
|
1059
|
-
formats.push("header-2");
|
|
1060
|
-
if (currentLine.startsWith("### "))
|
|
1061
|
-
formats.push("header-3");
|
|
1062
|
-
const lookBehind = Math.max(0, selectionStart - 10);
|
|
1063
|
-
const lookAhead = Math.min(value.length, selectionEnd + 10);
|
|
1064
|
-
const surrounding = value.slice(lookBehind, lookAhead);
|
|
1065
|
-
if (surrounding.includes("**")) {
|
|
1066
|
-
const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
|
|
1067
|
-
const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
|
|
1068
|
-
const lastOpenBold = beforeCursor.lastIndexOf("**");
|
|
1069
|
-
const nextCloseBold = afterCursor.indexOf("**");
|
|
1070
|
-
if (lastOpenBold !== -1 && nextCloseBold !== -1) {
|
|
1071
|
-
formats.push("bold");
|
|
1072
|
-
}
|
|
1073
|
-
}
|
|
1074
|
-
if (surrounding.includes("_")) {
|
|
1075
|
-
const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
|
|
1076
|
-
const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
|
|
1077
|
-
const lastOpenItalic = beforeCursor.lastIndexOf("_");
|
|
1078
|
-
const nextCloseItalic = afterCursor.indexOf("_");
|
|
1079
|
-
if (lastOpenItalic !== -1 && nextCloseItalic !== -1) {
|
|
1080
|
-
formats.push("italic");
|
|
1081
|
-
}
|
|
1082
|
-
}
|
|
1083
|
-
if (surrounding.includes("`")) {
|
|
1084
|
-
const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
|
|
1085
|
-
const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
|
|
1086
|
-
if (beforeCursor.includes("`") && afterCursor.includes("`")) {
|
|
1087
|
-
formats.push("code");
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
if (surrounding.includes("[") && surrounding.includes("]")) {
|
|
1091
|
-
const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
|
|
1092
|
-
const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
|
|
1093
|
-
const lastOpenBracket = beforeCursor.lastIndexOf("[");
|
|
1094
|
-
const nextCloseBracket = afterCursor.indexOf("]");
|
|
1095
|
-
if (lastOpenBracket !== -1 && nextCloseBracket !== -1) {
|
|
1096
|
-
const afterBracket = value.slice(selectionEnd + nextCloseBracket + 1, selectionEnd + nextCloseBracket + 10);
|
|
1097
|
-
if (afterBracket.startsWith("(")) {
|
|
1098
|
-
formats.push("link");
|
|
1099
|
-
}
|
|
1100
|
-
}
|
|
1101
|
-
}
|
|
1102
|
-
return formats;
|
|
1103
|
-
}
|
|
1104
|
-
function hasFormat(textarea, format) {
|
|
1105
|
-
const activeFormats = getActiveFormats2(textarea);
|
|
1106
|
-
return activeFormats.includes(format);
|
|
1107
|
-
}
|
|
1108
|
-
function expandSelection(textarea, options = {}) {
|
|
1109
|
-
if (!textarea)
|
|
1110
|
-
return;
|
|
1111
|
-
const { toWord, toLine, toFormat } = options;
|
|
1112
|
-
const { selectionStart, selectionEnd, value } = textarea;
|
|
1113
|
-
if (toLine) {
|
|
1114
|
-
const lines = value.split("\n");
|
|
1115
|
-
let lineStart = 0;
|
|
1116
|
-
let lineEnd = 0;
|
|
1117
|
-
let currentPos = 0;
|
|
1118
|
-
for (const line of lines) {
|
|
1119
|
-
if (selectionStart >= currentPos && selectionStart <= currentPos + line.length) {
|
|
1120
|
-
lineStart = currentPos;
|
|
1121
|
-
lineEnd = currentPos + line.length;
|
|
1122
|
-
break;
|
|
1123
|
-
}
|
|
1124
|
-
currentPos += line.length + 1;
|
|
1125
|
-
}
|
|
1126
|
-
textarea.selectionStart = lineStart;
|
|
1127
|
-
textarea.selectionEnd = lineEnd;
|
|
1128
|
-
} else if (toWord && selectionStart === selectionEnd) {
|
|
1129
|
-
let start = selectionStart;
|
|
1130
|
-
let end = selectionEnd;
|
|
1131
|
-
while (start > 0 && !/\s/.test(value[start - 1])) {
|
|
1132
|
-
start--;
|
|
1133
|
-
}
|
|
1134
|
-
while (end < value.length && !/\s/.test(value[end])) {
|
|
1135
|
-
end++;
|
|
1136
|
-
}
|
|
1137
|
-
textarea.selectionStart = start;
|
|
1138
|
-
textarea.selectionEnd = end;
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
function toggleBold3(textarea) {
|
|
1142
|
-
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
1143
|
-
return;
|
|
1144
|
-
debugLog("toggleBold", "Starting");
|
|
1145
|
-
debugSelection(textarea, "Before");
|
|
1146
|
-
const style = mergeWithDefaults(FORMATS.bold);
|
|
1147
|
-
const result = blockStyle(textarea, style);
|
|
1148
|
-
debugResult(result);
|
|
1149
|
-
insertText(textarea, result);
|
|
1150
|
-
debugSelection(textarea, "After");
|
|
1151
|
-
}
|
|
1152
|
-
function toggleItalic3(textarea) {
|
|
1153
|
-
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
1154
|
-
return;
|
|
1155
|
-
const style = mergeWithDefaults(FORMATS.italic);
|
|
1156
|
-
const result = blockStyle(textarea, style);
|
|
1157
|
-
insertText(textarea, result);
|
|
1158
|
-
}
|
|
1159
|
-
function toggleCode2(textarea) {
|
|
1160
|
-
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
1161
|
-
return;
|
|
1162
|
-
const style = mergeWithDefaults(FORMATS.code);
|
|
1163
|
-
const result = blockStyle(textarea, style);
|
|
1164
|
-
insertText(textarea, result);
|
|
1165
|
-
}
|
|
1166
|
-
function insertLink3(textarea, options = {}) {
|
|
1167
|
-
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
1168
|
-
return;
|
|
1169
|
-
const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
1170
|
-
let style = mergeWithDefaults(FORMATS.link);
|
|
1171
|
-
const isURL = selectedText && selectedText.match(/^https?:\/\//);
|
|
1172
|
-
if (isURL && !options.url) {
|
|
1173
|
-
style.suffix = `](${selectedText})`;
|
|
1174
|
-
style.replaceNext = "";
|
|
1175
|
-
} else if (options.url) {
|
|
1176
|
-
style.suffix = `](${options.url})`;
|
|
1177
|
-
style.replaceNext = "";
|
|
1178
|
-
}
|
|
1179
|
-
if (options.text && !selectedText) {
|
|
1180
|
-
const pos = textarea.selectionStart;
|
|
1181
|
-
textarea.value = textarea.value.slice(0, pos) + options.text + textarea.value.slice(pos);
|
|
1182
|
-
textarea.selectionStart = pos;
|
|
1183
|
-
textarea.selectionEnd = pos + options.text.length;
|
|
1184
|
-
}
|
|
1185
|
-
const result = blockStyle(textarea, style);
|
|
1186
|
-
insertText(textarea, result);
|
|
1187
|
-
}
|
|
1188
|
-
function toggleBulletList3(textarea) {
|
|
1189
|
-
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
1190
|
-
return;
|
|
1191
|
-
const style = mergeWithDefaults(FORMATS.bulletList);
|
|
1192
|
-
applyListStyle(textarea, style);
|
|
1193
|
-
}
|
|
1194
|
-
function toggleNumberedList3(textarea) {
|
|
1195
|
-
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
1196
|
-
return;
|
|
1197
|
-
const style = mergeWithDefaults(FORMATS.numberedList);
|
|
1198
|
-
applyListStyle(textarea, style);
|
|
1199
|
-
}
|
|
1200
|
-
function toggleQuote2(textarea) {
|
|
1201
|
-
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
1202
|
-
return;
|
|
1203
|
-
debugLog("toggleQuote", "Starting");
|
|
1204
|
-
debugSelection(textarea, "Initial");
|
|
1205
|
-
const style = mergeWithDefaults(FORMATS.quote);
|
|
1206
|
-
const result = applyLineOperation(
|
|
1207
|
-
textarea,
|
|
1208
|
-
(ta) => multilineStyle(ta, style),
|
|
1209
|
-
{ prefix: style.prefix }
|
|
1210
|
-
);
|
|
1211
|
-
debugResult(result);
|
|
1212
|
-
insertText(textarea, result);
|
|
1213
|
-
debugSelection(textarea, "Final");
|
|
1214
|
-
}
|
|
1215
|
-
function toggleTaskList2(textarea) {
|
|
1216
|
-
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
1217
|
-
return;
|
|
1218
|
-
const style = mergeWithDefaults(FORMATS.taskList);
|
|
1219
|
-
const result = applyLineOperation(
|
|
1220
|
-
textarea,
|
|
1221
|
-
(ta) => multilineStyle(ta, style),
|
|
1222
|
-
{ prefix: style.prefix }
|
|
1223
|
-
);
|
|
1224
|
-
insertText(textarea, result);
|
|
1225
|
-
}
|
|
1226
|
-
function insertHeader(textarea, level = 1, toggle = false) {
|
|
1227
|
-
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
1228
|
-
return;
|
|
1229
|
-
if (level < 1 || level > 6)
|
|
1230
|
-
level = 1;
|
|
1231
|
-
debugLog("insertHeader", `============ START ============`);
|
|
1232
|
-
debugLog("insertHeader", `Level: ${level}, Toggle: ${toggle}`);
|
|
1233
|
-
debugLog("insertHeader", `Initial cursor: ${textarea.selectionStart}-${textarea.selectionEnd}`);
|
|
1234
|
-
const headerKey = `header${level === 1 ? "1" : level}`;
|
|
1235
|
-
const style = mergeWithDefaults(FORMATS[headerKey] || FORMATS.header1);
|
|
1236
|
-
debugLog("insertHeader", `Style prefix: "${style.prefix}"`);
|
|
1237
|
-
const value = textarea.value;
|
|
1238
|
-
const originalStart = textarea.selectionStart;
|
|
1239
|
-
const originalEnd = textarea.selectionEnd;
|
|
1240
|
-
let lineStart = originalStart;
|
|
1241
|
-
while (lineStart > 0 && value[lineStart - 1] !== "\n") {
|
|
1242
|
-
lineStart--;
|
|
1243
|
-
}
|
|
1244
|
-
let lineEnd = originalEnd;
|
|
1245
|
-
while (lineEnd < value.length && value[lineEnd] !== "\n") {
|
|
1246
|
-
lineEnd++;
|
|
1247
|
-
}
|
|
1248
|
-
const currentLineContent = value.slice(lineStart, lineEnd);
|
|
1249
|
-
debugLog("insertHeader", `Current line (before): "${currentLineContent}"`);
|
|
1250
|
-
const existingHeaderMatch = currentLineContent.match(/^(#{1,6})\s*/);
|
|
1251
|
-
const existingLevel = existingHeaderMatch ? existingHeaderMatch[1].length : 0;
|
|
1252
|
-
const existingPrefixLength = existingHeaderMatch ? existingHeaderMatch[0].length : 0;
|
|
1253
|
-
debugLog("insertHeader", `Existing header check:`);
|
|
1254
|
-
debugLog("insertHeader", ` - Match: ${existingHeaderMatch ? `"${existingHeaderMatch[0]}"` : "none"}`);
|
|
1255
|
-
debugLog("insertHeader", ` - Existing level: ${existingLevel}`);
|
|
1256
|
-
debugLog("insertHeader", ` - Existing prefix length: ${existingPrefixLength}`);
|
|
1257
|
-
debugLog("insertHeader", ` - Target level: ${level}`);
|
|
1258
|
-
const shouldToggleOff = toggle && existingLevel === level;
|
|
1259
|
-
debugLog("insertHeader", `Should toggle OFF: ${shouldToggleOff} (toggle=${toggle}, existingLevel=${existingLevel}, level=${level})`);
|
|
1260
|
-
const result = applyLineOperation(
|
|
1261
|
-
textarea,
|
|
1262
|
-
(ta) => {
|
|
1263
|
-
const currentLine = ta.value.slice(ta.selectionStart, ta.selectionEnd);
|
|
1264
|
-
debugLog("insertHeader", `Line in operation: "${currentLine}"`);
|
|
1265
|
-
const cleanedLine = currentLine.replace(/^#{1,6}\s*/, "");
|
|
1266
|
-
debugLog("insertHeader", `Cleaned line: "${cleanedLine}"`);
|
|
1267
|
-
let newLine;
|
|
1268
|
-
if (shouldToggleOff) {
|
|
1269
|
-
debugLog("insertHeader", "ACTION: Toggling OFF - removing header");
|
|
1270
|
-
newLine = cleanedLine;
|
|
1271
|
-
} else if (existingLevel > 0) {
|
|
1272
|
-
debugLog("insertHeader", `ACTION: Replacing H${existingLevel} with H${level}`);
|
|
1273
|
-
newLine = style.prefix + cleanedLine;
|
|
1274
947
|
} else {
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
debugLog("insertHeader", `New line: "${newLine}"`);
|
|
1279
|
-
return {
|
|
1280
|
-
text: newLine,
|
|
1281
|
-
selectionStart: ta.selectionStart,
|
|
1282
|
-
selectionEnd: ta.selectionEnd
|
|
1283
|
-
};
|
|
1284
|
-
},
|
|
1285
|
-
{
|
|
1286
|
-
prefix: style.prefix,
|
|
1287
|
-
// Custom selection adjustment for headers
|
|
1288
|
-
adjustSelection: (isRemoving, selStart, selEnd, lineStartPos) => {
|
|
1289
|
-
debugLog("insertHeader", `Adjusting selection:`);
|
|
1290
|
-
debugLog("insertHeader", ` - isRemoving param: ${isRemoving}`);
|
|
1291
|
-
debugLog("insertHeader", ` - shouldToggleOff: ${shouldToggleOff}`);
|
|
1292
|
-
debugLog("insertHeader", ` - selStart: ${selStart}, selEnd: ${selEnd}`);
|
|
1293
|
-
debugLog("insertHeader", ` - lineStartPos: ${lineStartPos}`);
|
|
1294
|
-
if (shouldToggleOff) {
|
|
1295
|
-
const adjustment = Math.max(selStart - existingPrefixLength, lineStartPos);
|
|
1296
|
-
debugLog("insertHeader", ` - Removing header, adjusting by -${existingPrefixLength}`);
|
|
948
|
+
if (isRemovingCurrent) {
|
|
949
|
+
const prefixMatch = currentLine.match(style.orderedList ? orderedListRegex : unorderedListRegex);
|
|
950
|
+
const prefixLength = prefixMatch ? prefixMatch[0].length : 0;
|
|
1297
951
|
return {
|
|
1298
|
-
start:
|
|
1299
|
-
end:
|
|
952
|
+
start: Math.max(selStart - prefixLength, lineStart),
|
|
953
|
+
end: Math.max(selEnd - prefixLength, lineStart)
|
|
1300
954
|
};
|
|
1301
|
-
} else if (
|
|
1302
|
-
const
|
|
1303
|
-
|
|
955
|
+
} else if (hasOrderedList || hasUnorderedList) {
|
|
956
|
+
const oldPrefixMatch = currentLine.match(hasOrderedList ? orderedListRegex : unorderedListRegex);
|
|
957
|
+
const oldPrefixLength = oldPrefixMatch ? oldPrefixMatch[0].length : 0;
|
|
958
|
+
const newPrefixLength = style.unorderedList ? 2 : 3;
|
|
959
|
+
const adjustment = newPrefixLength - oldPrefixLength;
|
|
1304
960
|
return {
|
|
1305
|
-
start: selStart +
|
|
1306
|
-
end: selEnd +
|
|
961
|
+
start: selStart + adjustment,
|
|
962
|
+
end: selEnd + adjustment
|
|
1307
963
|
};
|
|
1308
964
|
} else {
|
|
1309
|
-
|
|
965
|
+
const prefixLength = style.unorderedList ? 2 : 3;
|
|
1310
966
|
return {
|
|
1311
|
-
start: selStart +
|
|
1312
|
-
end: selEnd +
|
|
967
|
+
start: selStart + prefixLength,
|
|
968
|
+
end: selEnd + prefixLength
|
|
1313
969
|
};
|
|
1314
970
|
}
|
|
1315
971
|
}
|
|
1316
972
|
}
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
973
|
+
}
|
|
974
|
+
);
|
|
975
|
+
insertText(textarea, result);
|
|
976
|
+
}
|
|
977
|
+
function getActiveFormats(textarea) {
|
|
978
|
+
if (!textarea)
|
|
979
|
+
return [];
|
|
980
|
+
const formats = [];
|
|
981
|
+
const { selectionStart, selectionEnd, value } = textarea;
|
|
982
|
+
const lines = value.split("\n");
|
|
983
|
+
let lineStart = 0;
|
|
984
|
+
let currentLine = "";
|
|
985
|
+
for (const line of lines) {
|
|
986
|
+
if (selectionStart >= lineStart && selectionStart <= lineStart + line.length) {
|
|
987
|
+
currentLine = line;
|
|
988
|
+
break;
|
|
989
|
+
}
|
|
990
|
+
lineStart += line.length + 1;
|
|
991
|
+
}
|
|
992
|
+
if (currentLine.startsWith("- ")) {
|
|
993
|
+
if (currentLine.startsWith("- [ ] ") || currentLine.startsWith("- [x] ")) {
|
|
994
|
+
formats.push("task-list");
|
|
995
|
+
} else {
|
|
996
|
+
formats.push("bullet-list");
|
|
997
|
+
}
|
|
998
|
+
}
|
|
999
|
+
if (/^\d+\.\s/.test(currentLine)) {
|
|
1000
|
+
formats.push("numbered-list");
|
|
1001
|
+
}
|
|
1002
|
+
if (currentLine.startsWith("> ")) {
|
|
1003
|
+
formats.push("quote");
|
|
1004
|
+
}
|
|
1005
|
+
if (currentLine.startsWith("# "))
|
|
1006
|
+
formats.push("header");
|
|
1007
|
+
if (currentLine.startsWith("## "))
|
|
1008
|
+
formats.push("header-2");
|
|
1009
|
+
if (currentLine.startsWith("### "))
|
|
1010
|
+
formats.push("header-3");
|
|
1011
|
+
const lookBehind = Math.max(0, selectionStart - 10);
|
|
1012
|
+
const lookAhead = Math.min(value.length, selectionEnd + 10);
|
|
1013
|
+
const surrounding = value.slice(lookBehind, lookAhead);
|
|
1014
|
+
if (surrounding.includes("**")) {
|
|
1015
|
+
const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
|
|
1016
|
+
const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
|
|
1017
|
+
const lastOpenBold = beforeCursor.lastIndexOf("**");
|
|
1018
|
+
const nextCloseBold = afterCursor.indexOf("**");
|
|
1019
|
+
if (lastOpenBold !== -1 && nextCloseBold !== -1) {
|
|
1020
|
+
formats.push("bold");
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
if (surrounding.includes("_")) {
|
|
1024
|
+
const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
|
|
1025
|
+
const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
|
|
1026
|
+
const lastOpenItalic = beforeCursor.lastIndexOf("_");
|
|
1027
|
+
const nextCloseItalic = afterCursor.indexOf("_");
|
|
1028
|
+
if (lastOpenItalic !== -1 && nextCloseItalic !== -1) {
|
|
1029
|
+
formats.push("italic");
|
|
1030
|
+
}
|
|
1031
|
+
}
|
|
1032
|
+
if (surrounding.includes("`")) {
|
|
1033
|
+
const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
|
|
1034
|
+
const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
|
|
1035
|
+
if (beforeCursor.includes("`") && afterCursor.includes("`")) {
|
|
1036
|
+
formats.push("code");
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
if (surrounding.includes("[") && surrounding.includes("]")) {
|
|
1040
|
+
const beforeCursor = value.slice(Math.max(0, selectionStart - 100), selectionStart);
|
|
1041
|
+
const afterCursor = value.slice(selectionEnd, Math.min(value.length, selectionEnd + 100));
|
|
1042
|
+
const lastOpenBracket = beforeCursor.lastIndexOf("[");
|
|
1043
|
+
const nextCloseBracket = afterCursor.indexOf("]");
|
|
1044
|
+
if (lastOpenBracket !== -1 && nextCloseBracket !== -1) {
|
|
1045
|
+
const afterBracket = value.slice(selectionEnd + nextCloseBracket + 1, selectionEnd + nextCloseBracket + 10);
|
|
1046
|
+
if (afterBracket.startsWith("(")) {
|
|
1047
|
+
formats.push("link");
|
|
1048
|
+
}
|
|
1049
|
+
}
|
|
1050
|
+
}
|
|
1051
|
+
return formats;
|
|
1052
|
+
}
|
|
1053
|
+
function toggleBold(textarea) {
|
|
1054
|
+
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
1055
|
+
return;
|
|
1056
|
+
debugLog("toggleBold", "Starting");
|
|
1057
|
+
debugSelection(textarea, "Before");
|
|
1058
|
+
const style = mergeWithDefaults(FORMATS.bold);
|
|
1059
|
+
const result = blockStyle(textarea, style);
|
|
1060
|
+
debugResult(result);
|
|
1061
|
+
insertText(textarea, result);
|
|
1062
|
+
debugSelection(textarea, "After");
|
|
1063
|
+
}
|
|
1064
|
+
function toggleItalic(textarea) {
|
|
1065
|
+
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
1066
|
+
return;
|
|
1067
|
+
const style = mergeWithDefaults(FORMATS.italic);
|
|
1068
|
+
const result = blockStyle(textarea, style);
|
|
1069
|
+
insertText(textarea, result);
|
|
1070
|
+
}
|
|
1071
|
+
function toggleCode(textarea) {
|
|
1072
|
+
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
1073
|
+
return;
|
|
1074
|
+
const style = mergeWithDefaults(FORMATS.code);
|
|
1075
|
+
const result = blockStyle(textarea, style);
|
|
1076
|
+
insertText(textarea, result);
|
|
1077
|
+
}
|
|
1078
|
+
function insertLink(textarea, options = {}) {
|
|
1079
|
+
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
1080
|
+
return;
|
|
1081
|
+
const selectedText = textarea.value.slice(textarea.selectionStart, textarea.selectionEnd);
|
|
1082
|
+
let style = mergeWithDefaults(FORMATS.link);
|
|
1083
|
+
const isURL = selectedText && selectedText.match(/^https?:\/\//);
|
|
1084
|
+
if (isURL && !options.url) {
|
|
1085
|
+
style.suffix = `](${selectedText})`;
|
|
1086
|
+
style.replaceNext = "";
|
|
1087
|
+
} else if (options.url) {
|
|
1088
|
+
style.suffix = `](${options.url})`;
|
|
1089
|
+
style.replaceNext = "";
|
|
1090
|
+
}
|
|
1091
|
+
if (options.text && !selectedText) {
|
|
1092
|
+
const pos = textarea.selectionStart;
|
|
1093
|
+
textarea.value = textarea.value.slice(0, pos) + options.text + textarea.value.slice(pos);
|
|
1094
|
+
textarea.selectionStart = pos;
|
|
1095
|
+
textarea.selectionEnd = pos + options.text.length;
|
|
1096
|
+
}
|
|
1097
|
+
const result = blockStyle(textarea, style);
|
|
1098
|
+
insertText(textarea, result);
|
|
1099
|
+
}
|
|
1100
|
+
function toggleBulletList(textarea) {
|
|
1101
|
+
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
1102
|
+
return;
|
|
1103
|
+
const style = mergeWithDefaults(FORMATS.bulletList);
|
|
1104
|
+
applyListStyle(textarea, style);
|
|
1105
|
+
}
|
|
1106
|
+
function toggleNumberedList(textarea) {
|
|
1107
|
+
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
1108
|
+
return;
|
|
1109
|
+
const style = mergeWithDefaults(FORMATS.numberedList);
|
|
1110
|
+
applyListStyle(textarea, style);
|
|
1111
|
+
}
|
|
1112
|
+
function toggleQuote(textarea) {
|
|
1113
|
+
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
1114
|
+
return;
|
|
1115
|
+
debugLog("toggleQuote", "Starting");
|
|
1116
|
+
debugSelection(textarea, "Initial");
|
|
1117
|
+
const style = mergeWithDefaults(FORMATS.quote);
|
|
1118
|
+
const result = applyLineOperation(
|
|
1119
|
+
textarea,
|
|
1120
|
+
(ta) => multilineStyle(ta, style),
|
|
1121
|
+
{ prefix: style.prefix }
|
|
1122
|
+
);
|
|
1123
|
+
debugResult(result);
|
|
1124
|
+
insertText(textarea, result);
|
|
1125
|
+
debugSelection(textarea, "Final");
|
|
1126
|
+
}
|
|
1127
|
+
function toggleTaskList(textarea) {
|
|
1128
|
+
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
1129
|
+
return;
|
|
1130
|
+
const style = mergeWithDefaults(FORMATS.taskList);
|
|
1131
|
+
const result = applyLineOperation(
|
|
1132
|
+
textarea,
|
|
1133
|
+
(ta) => multilineStyle(ta, style),
|
|
1134
|
+
{ prefix: style.prefix }
|
|
1135
|
+
);
|
|
1136
|
+
insertText(textarea, result);
|
|
1137
|
+
}
|
|
1138
|
+
function insertHeader(textarea, level = 1, toggle = false) {
|
|
1139
|
+
if (!textarea || textarea.disabled || textarea.readOnly)
|
|
1140
|
+
return;
|
|
1141
|
+
if (level < 1 || level > 6)
|
|
1142
|
+
level = 1;
|
|
1143
|
+
debugLog("insertHeader", `============ START ============`);
|
|
1144
|
+
debugLog("insertHeader", `Level: ${level}, Toggle: ${toggle}`);
|
|
1145
|
+
debugLog("insertHeader", `Initial cursor: ${textarea.selectionStart}-${textarea.selectionEnd}`);
|
|
1146
|
+
const headerKey = `header${level === 1 ? "1" : level}`;
|
|
1147
|
+
const style = mergeWithDefaults(FORMATS[headerKey] || FORMATS.header1);
|
|
1148
|
+
debugLog("insertHeader", `Style prefix: "${style.prefix}"`);
|
|
1149
|
+
const value = textarea.value;
|
|
1150
|
+
const originalStart = textarea.selectionStart;
|
|
1151
|
+
const originalEnd = textarea.selectionEnd;
|
|
1152
|
+
let lineStart = originalStart;
|
|
1153
|
+
while (lineStart > 0 && value[lineStart - 1] !== "\n") {
|
|
1154
|
+
lineStart--;
|
|
1155
|
+
}
|
|
1156
|
+
let lineEnd = originalEnd;
|
|
1157
|
+
while (lineEnd < value.length && value[lineEnd] !== "\n") {
|
|
1158
|
+
lineEnd++;
|
|
1159
|
+
}
|
|
1160
|
+
const currentLineContent = value.slice(lineStart, lineEnd);
|
|
1161
|
+
debugLog("insertHeader", `Current line (before): "${currentLineContent}"`);
|
|
1162
|
+
const existingHeaderMatch = currentLineContent.match(/^(#{1,6})\s*/);
|
|
1163
|
+
const existingLevel = existingHeaderMatch ? existingHeaderMatch[1].length : 0;
|
|
1164
|
+
const existingPrefixLength = existingHeaderMatch ? existingHeaderMatch[0].length : 0;
|
|
1165
|
+
debugLog("insertHeader", `Existing header check:`);
|
|
1166
|
+
debugLog("insertHeader", ` - Match: ${existingHeaderMatch ? `"${existingHeaderMatch[0]}"` : "none"}`);
|
|
1167
|
+
debugLog("insertHeader", ` - Existing level: ${existingLevel}`);
|
|
1168
|
+
debugLog("insertHeader", ` - Existing prefix length: ${existingPrefixLength}`);
|
|
1169
|
+
debugLog("insertHeader", ` - Target level: ${level}`);
|
|
1170
|
+
const shouldToggleOff = toggle && existingLevel === level;
|
|
1171
|
+
debugLog("insertHeader", `Should toggle OFF: ${shouldToggleOff} (toggle=${toggle}, existingLevel=${existingLevel}, level=${level})`);
|
|
1172
|
+
const result = applyLineOperation(
|
|
1173
|
+
textarea,
|
|
1174
|
+
(ta) => {
|
|
1175
|
+
const currentLine = ta.value.slice(ta.selectionStart, ta.selectionEnd);
|
|
1176
|
+
debugLog("insertHeader", `Line in operation: "${currentLine}"`);
|
|
1177
|
+
const cleanedLine = currentLine.replace(/^#{1,6}\s*/, "");
|
|
1178
|
+
debugLog("insertHeader", `Cleaned line: "${cleanedLine}"`);
|
|
1179
|
+
let newLine;
|
|
1180
|
+
if (shouldToggleOff) {
|
|
1181
|
+
debugLog("insertHeader", "ACTION: Toggling OFF - removing header");
|
|
1182
|
+
newLine = cleanedLine;
|
|
1183
|
+
} else if (existingLevel > 0) {
|
|
1184
|
+
debugLog("insertHeader", `ACTION: Replacing H${existingLevel} with H${level}`);
|
|
1185
|
+
newLine = style.prefix + cleanedLine;
|
|
1349
1186
|
} else {
|
|
1350
|
-
|
|
1187
|
+
debugLog("insertHeader", "ACTION: Adding new header");
|
|
1188
|
+
newLine = style.prefix + cleanedLine;
|
|
1189
|
+
}
|
|
1190
|
+
debugLog("insertHeader", `New line: "${newLine}"`);
|
|
1191
|
+
return {
|
|
1192
|
+
text: newLine,
|
|
1193
|
+
selectionStart: ta.selectionStart,
|
|
1194
|
+
selectionEnd: ta.selectionEnd
|
|
1195
|
+
};
|
|
1196
|
+
},
|
|
1197
|
+
{
|
|
1198
|
+
prefix: style.prefix,
|
|
1199
|
+
// Custom selection adjustment for headers
|
|
1200
|
+
adjustSelection: (isRemoving, selStart, selEnd, lineStartPos) => {
|
|
1201
|
+
debugLog("insertHeader", `Adjusting selection:`);
|
|
1202
|
+
debugLog("insertHeader", ` - isRemoving param: ${isRemoving}`);
|
|
1203
|
+
debugLog("insertHeader", ` - shouldToggleOff: ${shouldToggleOff}`);
|
|
1204
|
+
debugLog("insertHeader", ` - selStart: ${selStart}, selEnd: ${selEnd}`);
|
|
1205
|
+
debugLog("insertHeader", ` - lineStartPos: ${lineStartPos}`);
|
|
1206
|
+
if (shouldToggleOff) {
|
|
1207
|
+
const adjustment = Math.max(selStart - existingPrefixLength, lineStartPos);
|
|
1208
|
+
debugLog("insertHeader", ` - Removing header, adjusting by -${existingPrefixLength}`);
|
|
1209
|
+
return {
|
|
1210
|
+
start: adjustment,
|
|
1211
|
+
end: selStart === selEnd ? adjustment : Math.max(selEnd - existingPrefixLength, lineStartPos)
|
|
1212
|
+
};
|
|
1213
|
+
} else if (existingPrefixLength > 0) {
|
|
1214
|
+
const prefixDiff = style.prefix.length - existingPrefixLength;
|
|
1215
|
+
debugLog("insertHeader", ` - Replacing header, adjusting by ${prefixDiff}`);
|
|
1216
|
+
return {
|
|
1217
|
+
start: selStart + prefixDiff,
|
|
1218
|
+
end: selEnd + prefixDiff
|
|
1219
|
+
};
|
|
1220
|
+
} else {
|
|
1221
|
+
debugLog("insertHeader", ` - Adding header, adjusting by +${style.prefix.length}`);
|
|
1222
|
+
return {
|
|
1223
|
+
start: selStart + style.prefix.length,
|
|
1224
|
+
end: selEnd + style.prefix.length
|
|
1225
|
+
};
|
|
1226
|
+
}
|
|
1351
1227
|
}
|
|
1352
|
-
}
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
getActiveFormats: getActiveFormats22,
|
|
1371
|
-
hasFormat: hasFormat2,
|
|
1372
|
-
expandSelection: expandSelection2,
|
|
1373
|
-
applyCustomFormat,
|
|
1374
|
-
preserveSelection,
|
|
1375
|
-
setUndoMethod,
|
|
1376
|
-
setDebugMode,
|
|
1377
|
-
getDebugMode
|
|
1378
|
-
};
|
|
1379
|
-
return __toCommonJS2(src_exports);
|
|
1380
|
-
})();
|
|
1228
|
+
}
|
|
1229
|
+
);
|
|
1230
|
+
debugLog("insertHeader", `Final result: text="${result.text}", cursor=${result.selectionStart}-${result.selectionEnd}`);
|
|
1231
|
+
debugLog("insertHeader", `============ END ============`);
|
|
1232
|
+
insertText(textarea, result);
|
|
1233
|
+
}
|
|
1234
|
+
function toggleH1(textarea) {
|
|
1235
|
+
insertHeader(textarea, 1, true);
|
|
1236
|
+
}
|
|
1237
|
+
function toggleH2(textarea) {
|
|
1238
|
+
insertHeader(textarea, 2, true);
|
|
1239
|
+
}
|
|
1240
|
+
function toggleH3(textarea) {
|
|
1241
|
+
insertHeader(textarea, 3, true);
|
|
1242
|
+
}
|
|
1243
|
+
function getActiveFormats2(textarea) {
|
|
1244
|
+
return getActiveFormats(textarea);
|
|
1245
|
+
}
|
|
1381
1246
|
|
|
1382
1247
|
// src/shortcuts.js
|
|
1383
1248
|
var ShortcutsManager = class {
|
|
@@ -1446,19 +1311,19 @@ var ShortcutsManager = class {
|
|
|
1446
1311
|
try {
|
|
1447
1312
|
switch (action) {
|
|
1448
1313
|
case "toggleBold":
|
|
1449
|
-
(
|
|
1314
|
+
toggleBold(textarea);
|
|
1450
1315
|
break;
|
|
1451
1316
|
case "toggleItalic":
|
|
1452
|
-
(
|
|
1317
|
+
toggleItalic(textarea);
|
|
1453
1318
|
break;
|
|
1454
1319
|
case "insertLink":
|
|
1455
|
-
(
|
|
1320
|
+
insertLink(textarea);
|
|
1456
1321
|
break;
|
|
1457
1322
|
case "toggleBulletList":
|
|
1458
|
-
(
|
|
1323
|
+
toggleBulletList(textarea);
|
|
1459
1324
|
break;
|
|
1460
1325
|
case "toggleNumberedList":
|
|
1461
|
-
(
|
|
1326
|
+
toggleNumberedList(textarea);
|
|
1462
1327
|
break;
|
|
1463
1328
|
}
|
|
1464
1329
|
textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -1669,11 +1534,17 @@ function generateStyles(options = {}) {
|
|
|
1669
1534
|
position: relative !important; /* Override reset - needed for absolute children */
|
|
1670
1535
|
overflow: visible !important; /* Allow dropdown to overflow container */
|
|
1671
1536
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
|
|
1537
|
+
text-align: left !important;
|
|
1672
1538
|
${themeVars ? `
|
|
1673
1539
|
/* Theme Variables */
|
|
1674
1540
|
${themeVars}` : ""}
|
|
1675
1541
|
}
|
|
1676
1542
|
|
|
1543
|
+
/* Force left alignment for all elements in the editor */
|
|
1544
|
+
.overtype-container .overtype-wrapper * {
|
|
1545
|
+
text-align: left !important;
|
|
1546
|
+
}
|
|
1547
|
+
|
|
1677
1548
|
/* Auto-resize mode styles */
|
|
1678
1549
|
.overtype-container.overtype-auto-resize {
|
|
1679
1550
|
height: auto !important;
|
|
@@ -2546,37 +2417,37 @@ var Toolbar = class {
|
|
|
2546
2417
|
try {
|
|
2547
2418
|
switch (action) {
|
|
2548
2419
|
case "toggleBold":
|
|
2549
|
-
(
|
|
2420
|
+
toggleBold(textarea);
|
|
2550
2421
|
break;
|
|
2551
2422
|
case "toggleItalic":
|
|
2552
|
-
(
|
|
2423
|
+
toggleItalic(textarea);
|
|
2553
2424
|
break;
|
|
2554
2425
|
case "insertH1":
|
|
2555
|
-
(
|
|
2426
|
+
toggleH1(textarea);
|
|
2556
2427
|
break;
|
|
2557
2428
|
case "insertH2":
|
|
2558
|
-
(
|
|
2429
|
+
toggleH2(textarea);
|
|
2559
2430
|
break;
|
|
2560
2431
|
case "insertH3":
|
|
2561
|
-
(
|
|
2432
|
+
toggleH3(textarea);
|
|
2562
2433
|
break;
|
|
2563
2434
|
case "insertLink":
|
|
2564
|
-
(
|
|
2435
|
+
insertLink(textarea);
|
|
2565
2436
|
break;
|
|
2566
2437
|
case "toggleCode":
|
|
2567
|
-
(
|
|
2438
|
+
toggleCode(textarea);
|
|
2568
2439
|
break;
|
|
2569
2440
|
case "toggleBulletList":
|
|
2570
|
-
(
|
|
2441
|
+
toggleBulletList(textarea);
|
|
2571
2442
|
break;
|
|
2572
2443
|
case "toggleNumberedList":
|
|
2573
|
-
(
|
|
2444
|
+
toggleNumberedList(textarea);
|
|
2574
2445
|
break;
|
|
2575
2446
|
case "toggleQuote":
|
|
2576
|
-
(
|
|
2447
|
+
toggleQuote(textarea);
|
|
2577
2448
|
break;
|
|
2578
2449
|
case "toggleTaskList":
|
|
2579
|
-
(
|
|
2450
|
+
toggleTaskList(textarea);
|
|
2580
2451
|
break;
|
|
2581
2452
|
case "toggle-plain":
|
|
2582
2453
|
const isPlain = this.editor.container.classList.contains("plain-mode");
|
|
@@ -2596,7 +2467,7 @@ var Toolbar = class {
|
|
|
2596
2467
|
if (!textarea)
|
|
2597
2468
|
return;
|
|
2598
2469
|
try {
|
|
2599
|
-
const activeFormats = (
|
|
2470
|
+
const activeFormats = getActiveFormats2(textarea);
|
|
2600
2471
|
Object.entries(this.buttons).forEach(([name, button]) => {
|
|
2601
2472
|
let isActive = false;
|
|
2602
2473
|
switch (name) {
|
|
@@ -3228,17 +3099,6 @@ var _OverType = class _OverType {
|
|
|
3228
3099
|
closeFence.style.display = "block";
|
|
3229
3100
|
openParent.classList.add("code-block-line");
|
|
3230
3101
|
closeParent.classList.add("code-block-line");
|
|
3231
|
-
let currentDiv = openParent.nextElementSibling;
|
|
3232
|
-
while (currentDiv && currentDiv !== closeParent) {
|
|
3233
|
-
if (currentDiv.tagName === "DIV") {
|
|
3234
|
-
currentDiv.classList.add("code-block-line");
|
|
3235
|
-
const plainText = currentDiv.textContent;
|
|
3236
|
-
currentDiv.textContent = plainText;
|
|
3237
|
-
}
|
|
3238
|
-
currentDiv = currentDiv.nextElementSibling;
|
|
3239
|
-
if (!currentDiv)
|
|
3240
|
-
break;
|
|
3241
|
-
}
|
|
3242
3102
|
}
|
|
3243
3103
|
}
|
|
3244
3104
|
/**
|
|
@@ -3272,21 +3132,35 @@ var _OverType = class _OverType {
|
|
|
3272
3132
|
const after = value.substring(end);
|
|
3273
3133
|
const lines = selection.split("\n");
|
|
3274
3134
|
const outdented = lines.map((line) => line.replace(/^ /, "")).join("\n");
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3135
|
+
if (document.execCommand) {
|
|
3136
|
+
this.textarea.setSelectionRange(start, end);
|
|
3137
|
+
document.execCommand("insertText", false, outdented);
|
|
3138
|
+
} else {
|
|
3139
|
+
this.textarea.value = before + outdented + after;
|
|
3140
|
+
this.textarea.selectionStart = start;
|
|
3141
|
+
this.textarea.selectionEnd = start + outdented.length;
|
|
3142
|
+
}
|
|
3278
3143
|
} else if (start !== end) {
|
|
3279
3144
|
const before = value.substring(0, start);
|
|
3280
3145
|
const selection = value.substring(start, end);
|
|
3281
3146
|
const after = value.substring(end);
|
|
3282
3147
|
const lines = selection.split("\n");
|
|
3283
3148
|
const indented = lines.map((line) => " " + line).join("\n");
|
|
3284
|
-
|
|
3285
|
-
|
|
3286
|
-
|
|
3149
|
+
if (document.execCommand) {
|
|
3150
|
+
this.textarea.setSelectionRange(start, end);
|
|
3151
|
+
document.execCommand("insertText", false, indented);
|
|
3152
|
+
} else {
|
|
3153
|
+
this.textarea.value = before + indented + after;
|
|
3154
|
+
this.textarea.selectionStart = start;
|
|
3155
|
+
this.textarea.selectionEnd = start + indented.length;
|
|
3156
|
+
}
|
|
3287
3157
|
} else {
|
|
3288
|
-
|
|
3289
|
-
|
|
3158
|
+
if (document.execCommand) {
|
|
3159
|
+
document.execCommand("insertText", false, " ");
|
|
3160
|
+
} else {
|
|
3161
|
+
this.textarea.value = value.substring(0, start) + " " + value.substring(end);
|
|
3162
|
+
this.textarea.selectionStart = this.textarea.selectionEnd = start + 2;
|
|
3163
|
+
}
|
|
3290
3164
|
}
|
|
3291
3165
|
this.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3292
3166
|
return;
|