overtype 1.2.7 → 2.0.0
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 +222 -34
- package/dist/overtype-webcomponent.esm.js +4763 -0
- package/dist/overtype-webcomponent.esm.js.map +7 -0
- package/dist/overtype-webcomponent.js +4785 -0
- package/dist/overtype-webcomponent.js.map +7 -0
- package/dist/overtype-webcomponent.min.js +991 -0
- package/dist/overtype.cjs +682 -389
- package/dist/overtype.cjs.map +4 -4
- package/dist/overtype.d.ts +57 -14
- package/dist/overtype.esm.js +679 -388
- package/dist/overtype.esm.js.map +4 -4
- package/dist/overtype.js +679 -388
- package/dist/overtype.js.map +4 -4
- package/dist/overtype.min.js +157 -125
- package/package.json +18 -4
- package/src/link-tooltip.js +48 -73
- package/src/overtype-webcomponent.js +676 -0
- package/src/overtype.d.ts +57 -14
- package/src/overtype.js +186 -59
- package/src/parser.js +120 -17
- package/src/styles.js +92 -30
- package/src/toolbar-buttons.js +163 -0
- package/src/toolbar.js +194 -249
- package/diagram.png +0 -0
package/dist/overtype.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OverType
|
|
2
|
+
* OverType v2.0.0
|
|
3
3
|
* A lightweight markdown editor library with perfect WYSIWYG alignment
|
|
4
4
|
* @license MIT
|
|
5
5
|
* @author Demo User
|
|
@@ -32,7 +32,9 @@ var __publicField = (obj, key, value) => {
|
|
|
32
32
|
var overtype_exports = {};
|
|
33
33
|
__export(overtype_exports, {
|
|
34
34
|
OverType: () => OverType,
|
|
35
|
-
default: () => overtype_default
|
|
35
|
+
default: () => overtype_default,
|
|
36
|
+
defaultToolbarButtons: () => defaultToolbarButtons,
|
|
37
|
+
toolbarButtons: () => toolbarButtons
|
|
36
38
|
});
|
|
37
39
|
module.exports = __toCommonJS(overtype_exports);
|
|
38
40
|
|
|
@@ -44,6 +46,13 @@ var MarkdownParser = class {
|
|
|
44
46
|
static resetLinkIndex() {
|
|
45
47
|
this.linkIndex = 0;
|
|
46
48
|
}
|
|
49
|
+
/**
|
|
50
|
+
* Set global code highlighter function
|
|
51
|
+
* @param {Function|null} highlighter - Function that takes (code, language) and returns highlighted HTML
|
|
52
|
+
*/
|
|
53
|
+
static setCodeHighlighter(highlighter) {
|
|
54
|
+
this.codeHighlighter = highlighter;
|
|
55
|
+
}
|
|
47
56
|
/**
|
|
48
57
|
* Escape HTML special characters
|
|
49
58
|
* @param {string} text - Raw text to escape
|
|
@@ -112,6 +121,22 @@ var MarkdownParser = class {
|
|
|
112
121
|
return `${indent}<li class="bullet-list"><span class="syntax-marker">${marker} </span>${content}</li>`;
|
|
113
122
|
});
|
|
114
123
|
}
|
|
124
|
+
/**
|
|
125
|
+
* Parse task lists (GitHub Flavored Markdown checkboxes)
|
|
126
|
+
* @param {string} html - HTML line to parse
|
|
127
|
+
* @param {boolean} isPreviewMode - Whether to render actual checkboxes (preview) or keep syntax visible (normal)
|
|
128
|
+
* @returns {string} Parsed task list item
|
|
129
|
+
*/
|
|
130
|
+
static parseTaskList(html, isPreviewMode = false) {
|
|
131
|
+
return html.replace(/^((?: )*)-\s+\[([ xX])\]\s+(.+)$/, (match, indent, checked, content) => {
|
|
132
|
+
if (isPreviewMode) {
|
|
133
|
+
const isChecked = checked.toLowerCase() === "x";
|
|
134
|
+
return `${indent}<li class="task-list"><input type="checkbox" disabled ${isChecked ? "checked" : ""}> ${content}</li>`;
|
|
135
|
+
} else {
|
|
136
|
+
return `${indent}<li class="task-list"><span class="syntax-marker">- [${checked}] </span>${content}</li>`;
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
115
140
|
/**
|
|
116
141
|
* Parse numbered lists
|
|
117
142
|
* @param {string} html - HTML line to parse
|
|
@@ -301,7 +326,7 @@ var MarkdownParser = class {
|
|
|
301
326
|
processedLinkText = this.parseItalic(processedLinkText);
|
|
302
327
|
const anchorName = `--link-${this.linkIndex++}`;
|
|
303
328
|
const safeUrl = this.sanitizeUrl(sanctuary.url);
|
|
304
|
-
replacement = `<a href="${safeUrl}" style="anchor-name: ${anchorName}"><span class="syntax-marker">[</span>${processedLinkText}<span class="syntax-marker url-part">](${
|
|
329
|
+
replacement = `<a href="${safeUrl}" style="anchor-name: ${anchorName}"><span class="syntax-marker">[</span>${processedLinkText}<span class="syntax-marker url-part">](${sanctuary.url})</span></a>`;
|
|
305
330
|
}
|
|
306
331
|
html = html.replace(placeholder, replacement);
|
|
307
332
|
});
|
|
@@ -326,7 +351,7 @@ var MarkdownParser = class {
|
|
|
326
351
|
* @param {string} line - Raw markdown line
|
|
327
352
|
* @returns {string} Parsed HTML line
|
|
328
353
|
*/
|
|
329
|
-
static parseLine(line) {
|
|
354
|
+
static parseLine(line, isPreviewMode = false) {
|
|
330
355
|
let html = this.escapeHtml(line);
|
|
331
356
|
html = this.preserveIndentation(html, line);
|
|
332
357
|
const horizontalRule = this.parseHorizontalRule(html);
|
|
@@ -337,6 +362,7 @@ var MarkdownParser = class {
|
|
|
337
362
|
return codeBlock;
|
|
338
363
|
html = this.parseHeader(html);
|
|
339
364
|
html = this.parseBlockquote(html);
|
|
365
|
+
html = this.parseTaskList(html, isPreviewMode);
|
|
340
366
|
html = this.parseBulletList(html);
|
|
341
367
|
html = this.parseNumberedList(html);
|
|
342
368
|
html = this.parseInlineElements(html);
|
|
@@ -350,9 +376,10 @@ var MarkdownParser = class {
|
|
|
350
376
|
* @param {string} text - Full markdown text
|
|
351
377
|
* @param {number} activeLine - Currently active line index (optional)
|
|
352
378
|
* @param {boolean} showActiveLineRaw - Show raw markdown on active line
|
|
379
|
+
* @param {Function} instanceHighlighter - Instance-specific code highlighter (optional, overrides global if provided)
|
|
353
380
|
* @returns {string} Parsed HTML
|
|
354
381
|
*/
|
|
355
|
-
static parse(text, activeLine = -1, showActiveLineRaw = false) {
|
|
382
|
+
static parse(text, activeLine = -1, showActiveLineRaw = false, instanceHighlighter, isPreviewMode = false) {
|
|
356
383
|
this.resetLinkIndex();
|
|
357
384
|
const lines = text.split("\n");
|
|
358
385
|
let inCodeBlock = false;
|
|
@@ -364,26 +391,27 @@ var MarkdownParser = class {
|
|
|
364
391
|
const codeFenceRegex = /^```[^`]*$/;
|
|
365
392
|
if (codeFenceRegex.test(line)) {
|
|
366
393
|
inCodeBlock = !inCodeBlock;
|
|
367
|
-
return this.parseLine(line);
|
|
394
|
+
return this.parseLine(line, isPreviewMode);
|
|
368
395
|
}
|
|
369
396
|
if (inCodeBlock) {
|
|
370
397
|
const escaped = this.escapeHtml(line);
|
|
371
398
|
const indented = this.preserveIndentation(escaped, line);
|
|
372
399
|
return `<div>${indented || " "}</div>`;
|
|
373
400
|
}
|
|
374
|
-
return this.parseLine(line);
|
|
401
|
+
return this.parseLine(line, isPreviewMode);
|
|
375
402
|
});
|
|
376
403
|
const html = parsedLines.join("");
|
|
377
|
-
return this.postProcessHTML(html);
|
|
404
|
+
return this.postProcessHTML(html, instanceHighlighter);
|
|
378
405
|
}
|
|
379
406
|
/**
|
|
380
407
|
* Post-process HTML to consolidate lists and code blocks
|
|
381
408
|
* @param {string} html - HTML to post-process
|
|
409
|
+
* @param {Function} instanceHighlighter - Instance-specific code highlighter (optional, overrides global if provided)
|
|
382
410
|
* @returns {string} Post-processed HTML with consolidated lists and code blocks
|
|
383
411
|
*/
|
|
384
|
-
static postProcessHTML(html) {
|
|
412
|
+
static postProcessHTML(html, instanceHighlighter) {
|
|
385
413
|
if (typeof document === "undefined" || !document) {
|
|
386
|
-
return this.postProcessHTMLManual(html);
|
|
414
|
+
return this.postProcessHTMLManual(html, instanceHighlighter);
|
|
387
415
|
}
|
|
388
416
|
const container = document.createElement("div");
|
|
389
417
|
container.innerHTML = html;
|
|
@@ -412,8 +440,28 @@ var MarkdownParser = class {
|
|
|
412
440
|
}
|
|
413
441
|
container.insertBefore(currentCodeBlock, child.nextSibling);
|
|
414
442
|
currentCodeBlock._codeElement = codeElement;
|
|
443
|
+
currentCodeBlock._language = lang;
|
|
444
|
+
currentCodeBlock._codeContent = "";
|
|
415
445
|
continue;
|
|
416
446
|
} else {
|
|
447
|
+
const highlighter = instanceHighlighter || this.codeHighlighter;
|
|
448
|
+
if (currentCodeBlock && highlighter && currentCodeBlock._codeContent) {
|
|
449
|
+
try {
|
|
450
|
+
const result = highlighter(
|
|
451
|
+
currentCodeBlock._codeContent,
|
|
452
|
+
currentCodeBlock._language || ""
|
|
453
|
+
);
|
|
454
|
+
if (result && typeof result.then === "function") {
|
|
455
|
+
console.warn("Async highlighters are not supported in parse() because it returns an HTML string. The caller creates new DOM elements from that string, breaking references to the elements we would update. Use synchronous highlighters only.");
|
|
456
|
+
} else {
|
|
457
|
+
if (result && typeof result === "string" && result.trim()) {
|
|
458
|
+
currentCodeBlock._codeElement.innerHTML = result;
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
} catch (error) {
|
|
462
|
+
console.warn("Code highlighting failed:", error);
|
|
463
|
+
}
|
|
464
|
+
}
|
|
417
465
|
inCodeBlock = false;
|
|
418
466
|
currentCodeBlock = null;
|
|
419
467
|
continue;
|
|
@@ -422,10 +470,14 @@ var MarkdownParser = class {
|
|
|
422
470
|
}
|
|
423
471
|
if (inCodeBlock && currentCodeBlock && child.tagName === "DIV" && !child.querySelector(".code-fence")) {
|
|
424
472
|
const codeElement = currentCodeBlock._codeElement || currentCodeBlock.querySelector("code");
|
|
473
|
+
if (currentCodeBlock._codeContent.length > 0) {
|
|
474
|
+
currentCodeBlock._codeContent += "\n";
|
|
475
|
+
}
|
|
476
|
+
const lineText = child.textContent.replace(/\u00A0/g, " ");
|
|
477
|
+
currentCodeBlock._codeContent += lineText;
|
|
425
478
|
if (codeElement.textContent.length > 0) {
|
|
426
479
|
codeElement.textContent += "\n";
|
|
427
480
|
}
|
|
428
|
-
const lineText = child.textContent.replace(/\u00A0/g, " ");
|
|
429
481
|
codeElement.textContent += lineText;
|
|
430
482
|
child.remove();
|
|
431
483
|
continue;
|
|
@@ -471,9 +523,10 @@ var MarkdownParser = class {
|
|
|
471
523
|
/**
|
|
472
524
|
* Manual post-processing for Node.js environments (without DOM)
|
|
473
525
|
* @param {string} html - HTML to post-process
|
|
526
|
+
* @param {Function} instanceHighlighter - Instance-specific code highlighter (optional, overrides global if provided)
|
|
474
527
|
* @returns {string} Post-processed HTML
|
|
475
528
|
*/
|
|
476
|
-
static postProcessHTMLManual(html) {
|
|
529
|
+
static postProcessHTMLManual(html, instanceHighlighter) {
|
|
477
530
|
let processed = html;
|
|
478
531
|
processed = processed.replace(/((?:<div>(?: )*<li class="bullet-list">.*?<\/li><\/div>\s*)+)/gs, (match) => {
|
|
479
532
|
const divs = match.match(/<div>(?: )*<li class="bullet-list">.*?<\/li><\/div>/gs) || [];
|
|
@@ -518,8 +571,25 @@ var MarkdownParser = class {
|
|
|
518
571
|
}).join("\n");
|
|
519
572
|
const lang = openFence.slice(3).trim();
|
|
520
573
|
const langClass = lang ? ` class="language-${lang}"` : "";
|
|
574
|
+
let highlightedContent = codeContent;
|
|
575
|
+
const highlighter = instanceHighlighter || this.codeHighlighter;
|
|
576
|
+
if (highlighter) {
|
|
577
|
+
try {
|
|
578
|
+
const decodedCode = codeContent.replace(/"/g, '"').replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&");
|
|
579
|
+
const result2 = highlighter(decodedCode, lang);
|
|
580
|
+
if (result2 && typeof result2.then === "function") {
|
|
581
|
+
console.warn("Async highlighters are not supported in Node.js (non-DOM) context. Use synchronous highlighters for server-side rendering.");
|
|
582
|
+
} else {
|
|
583
|
+
if (result2 && typeof result2 === "string" && result2.trim()) {
|
|
584
|
+
highlightedContent = result2;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
} catch (error) {
|
|
588
|
+
console.warn("Code highlighting failed:", error);
|
|
589
|
+
}
|
|
590
|
+
}
|
|
521
591
|
let result = `<div><span class="code-fence">${openFence}</span></div>`;
|
|
522
|
-
result += `<pre class="code-block"><code${langClass}>${
|
|
592
|
+
result += `<pre class="code-block"><code${langClass}>${highlightedContent}</code></pre>`;
|
|
523
593
|
result += `<div><span class="code-fence">${closeFence}</span></div>`;
|
|
524
594
|
return result;
|
|
525
595
|
});
|
|
@@ -658,6 +728,8 @@ var MarkdownParser = class {
|
|
|
658
728
|
};
|
|
659
729
|
// Track link index for anchor naming
|
|
660
730
|
__publicField(MarkdownParser, "linkIndex", 0);
|
|
731
|
+
// Global code highlighter function
|
|
732
|
+
__publicField(MarkdownParser, "codeHighlighter", null);
|
|
661
733
|
/**
|
|
662
734
|
* List pattern definitions
|
|
663
735
|
*/
|
|
@@ -2077,12 +2149,14 @@ function generateStyles(options = {}) {
|
|
|
2077
2149
|
/* Code block styling in normal mode - yellow background */
|
|
2078
2150
|
.overtype-wrapper .overtype-preview pre.code-block {
|
|
2079
2151
|
background: var(--code-bg, rgba(244, 211, 94, 0.4)) !important;
|
|
2152
|
+
white-space: break-spaces !important; /* Prevent horizontal scrollbar that breaks alignment */
|
|
2080
2153
|
}
|
|
2081
2154
|
|
|
2082
2155
|
/* Code inside pre blocks - remove background */
|
|
2083
2156
|
.overtype-wrapper .overtype-preview pre code {
|
|
2084
2157
|
background: transparent !important;
|
|
2085
2158
|
color: var(--code, #0d3b66) !important;
|
|
2159
|
+
font-family: ${fontFamily} !important; /* Match textarea font exactly for alignment */
|
|
2086
2160
|
}
|
|
2087
2161
|
|
|
2088
2162
|
/* Blockquotes */
|
|
@@ -2309,11 +2383,11 @@ function generateStyles(options = {}) {
|
|
|
2309
2383
|
}
|
|
2310
2384
|
|
|
2311
2385
|
/* Plain mode - hide preview and show textarea text */
|
|
2312
|
-
.overtype-container
|
|
2386
|
+
.overtype-container[data-mode="plain"] .overtype-preview {
|
|
2313
2387
|
display: none !important;
|
|
2314
2388
|
}
|
|
2315
2389
|
|
|
2316
|
-
.overtype-container
|
|
2390
|
+
.overtype-container[data-mode="plain"] .overtype-input {
|
|
2317
2391
|
color: var(--text, #0d3b66) !important;
|
|
2318
2392
|
/* Use system font stack for better plain text readability */
|
|
2319
2393
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
|
@@ -2321,7 +2395,7 @@ function generateStyles(options = {}) {
|
|
|
2321
2395
|
}
|
|
2322
2396
|
|
|
2323
2397
|
/* Ensure textarea remains transparent in overlay mode */
|
|
2324
|
-
.overtype-container:not(
|
|
2398
|
+
.overtype-container:not([data-mode="plain"]) .overtype-input {
|
|
2325
2399
|
color: transparent !important;
|
|
2326
2400
|
}
|
|
2327
2401
|
|
|
@@ -2374,37 +2448,43 @@ function generateStyles(options = {}) {
|
|
|
2374
2448
|
color: var(--h1, #007bff);
|
|
2375
2449
|
}
|
|
2376
2450
|
|
|
2451
|
+
.overtype-dropdown-icon {
|
|
2452
|
+
width: 20px;
|
|
2453
|
+
margin-right: 8px;
|
|
2454
|
+
text-align: center;
|
|
2455
|
+
}
|
|
2456
|
+
|
|
2377
2457
|
/* Preview mode styles */
|
|
2378
|
-
.overtype-container
|
|
2458
|
+
.overtype-container[data-mode="preview"] .overtype-input {
|
|
2379
2459
|
display: none !important;
|
|
2380
2460
|
}
|
|
2381
2461
|
|
|
2382
|
-
.overtype-container
|
|
2462
|
+
.overtype-container[data-mode="preview"] .overtype-preview {
|
|
2383
2463
|
pointer-events: auto !important;
|
|
2384
2464
|
user-select: text !important;
|
|
2385
2465
|
cursor: text !important;
|
|
2386
2466
|
}
|
|
2387
2467
|
|
|
2388
2468
|
/* Hide syntax markers in preview mode */
|
|
2389
|
-
.overtype-container
|
|
2469
|
+
.overtype-container[data-mode="preview"] .syntax-marker {
|
|
2390
2470
|
display: none !important;
|
|
2391
2471
|
}
|
|
2392
2472
|
|
|
2393
2473
|
/* Hide URL part of links in preview mode - extra specificity */
|
|
2394
|
-
.overtype-container
|
|
2395
|
-
.overtype-container
|
|
2474
|
+
.overtype-container[data-mode="preview"] .syntax-marker.url-part,
|
|
2475
|
+
.overtype-container[data-mode="preview"] .url-part {
|
|
2396
2476
|
display: none !important;
|
|
2397
2477
|
}
|
|
2398
2478
|
|
|
2399
2479
|
/* Hide all syntax markers inside links too */
|
|
2400
|
-
.overtype-container
|
|
2480
|
+
.overtype-container[data-mode="preview"] a .syntax-marker {
|
|
2401
2481
|
display: none !important;
|
|
2402
2482
|
}
|
|
2403
2483
|
|
|
2404
2484
|
/* Headers - restore proper sizing in preview mode */
|
|
2405
|
-
.overtype-container
|
|
2406
|
-
.overtype-container
|
|
2407
|
-
.overtype-container
|
|
2485
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h1,
|
|
2486
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h2,
|
|
2487
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h3 {
|
|
2408
2488
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
|
|
2409
2489
|
font-weight: 600 !important;
|
|
2410
2490
|
margin: 0 !important;
|
|
@@ -2413,41 +2493,63 @@ function generateStyles(options = {}) {
|
|
|
2413
2493
|
line-height: 1 !important; /* Tight line height for headings */
|
|
2414
2494
|
}
|
|
2415
2495
|
|
|
2416
|
-
.overtype-container
|
|
2496
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h1 {
|
|
2417
2497
|
font-size: 2em !important;
|
|
2418
2498
|
}
|
|
2419
2499
|
|
|
2420
|
-
.overtype-container
|
|
2500
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h2 {
|
|
2421
2501
|
font-size: 1.5em !important;
|
|
2422
2502
|
}
|
|
2423
2503
|
|
|
2424
|
-
.overtype-container
|
|
2504
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h3 {
|
|
2425
2505
|
font-size: 1.17em !important;
|
|
2426
2506
|
}
|
|
2427
2507
|
|
|
2428
2508
|
/* Lists - restore list styling in preview mode */
|
|
2429
|
-
.overtype-container
|
|
2509
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview ul {
|
|
2430
2510
|
display: block !important;
|
|
2431
2511
|
list-style: disc !important;
|
|
2432
2512
|
padding-left: 2em !important;
|
|
2433
2513
|
margin: 1em 0 !important;
|
|
2434
2514
|
}
|
|
2435
2515
|
|
|
2436
|
-
.overtype-container
|
|
2516
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview ol {
|
|
2437
2517
|
display: block !important;
|
|
2438
2518
|
list-style: decimal !important;
|
|
2439
2519
|
padding-left: 2em !important;
|
|
2440
2520
|
margin: 1em 0 !important;
|
|
2441
2521
|
}
|
|
2442
2522
|
|
|
2443
|
-
.overtype-container
|
|
2523
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview li {
|
|
2444
2524
|
display: list-item !important;
|
|
2445
2525
|
margin: 0 !important;
|
|
2446
2526
|
padding: 0 !important;
|
|
2447
2527
|
}
|
|
2448
2528
|
|
|
2529
|
+
/* Task list checkboxes - only in preview mode */
|
|
2530
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview li.task-list {
|
|
2531
|
+
list-style: none !important;
|
|
2532
|
+
position: relative !important;
|
|
2533
|
+
}
|
|
2534
|
+
|
|
2535
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview li.task-list input[type="checkbox"] {
|
|
2536
|
+
margin-right: 0.5em !important;
|
|
2537
|
+
cursor: default !important;
|
|
2538
|
+
vertical-align: middle !important;
|
|
2539
|
+
}
|
|
2540
|
+
|
|
2541
|
+
/* Task list in normal mode - keep syntax visible */
|
|
2542
|
+
.overtype-container:not([data-mode="preview"]) .overtype-wrapper .overtype-preview li.task-list {
|
|
2543
|
+
list-style: none !important;
|
|
2544
|
+
}
|
|
2545
|
+
|
|
2546
|
+
.overtype-container:not([data-mode="preview"]) .overtype-wrapper .overtype-preview li.task-list .syntax-marker {
|
|
2547
|
+
color: var(--syntax, #999999) !important;
|
|
2548
|
+
font-weight: normal !important;
|
|
2549
|
+
}
|
|
2550
|
+
|
|
2449
2551
|
/* Links - make clickable in preview mode */
|
|
2450
|
-
.overtype-container
|
|
2552
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview a {
|
|
2451
2553
|
pointer-events: auto !important;
|
|
2452
2554
|
cursor: pointer !important;
|
|
2453
2555
|
color: var(--link, #0066cc) !important;
|
|
@@ -2455,7 +2557,7 @@ function generateStyles(options = {}) {
|
|
|
2455
2557
|
}
|
|
2456
2558
|
|
|
2457
2559
|
/* Code blocks - proper pre/code styling in preview mode */
|
|
2458
|
-
.overtype-container
|
|
2560
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview pre.code-block {
|
|
2459
2561
|
background: #2d2d2d !important;
|
|
2460
2562
|
color: #f8f8f2 !important;
|
|
2461
2563
|
padding: 1.2em !important;
|
|
@@ -2466,11 +2568,11 @@ function generateStyles(options = {}) {
|
|
|
2466
2568
|
}
|
|
2467
2569
|
|
|
2468
2570
|
/* Cave theme code block background in preview mode */
|
|
2469
|
-
.overtype-container[data-theme="cave"]
|
|
2571
|
+
.overtype-container[data-theme="cave"][data-mode="preview"] .overtype-wrapper .overtype-preview pre.code-block {
|
|
2470
2572
|
background: #11171F !important;
|
|
2471
2573
|
}
|
|
2472
2574
|
|
|
2473
|
-
.overtype-container
|
|
2575
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview pre.code-block code {
|
|
2474
2576
|
background: transparent !important;
|
|
2475
2577
|
color: inherit !important;
|
|
2476
2578
|
padding: 0 !important;
|
|
@@ -2480,16 +2582,16 @@ function generateStyles(options = {}) {
|
|
|
2480
2582
|
}
|
|
2481
2583
|
|
|
2482
2584
|
/* Hide old code block lines and fences in preview mode */
|
|
2483
|
-
.overtype-container
|
|
2585
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview .code-block-line {
|
|
2484
2586
|
display: none !important;
|
|
2485
2587
|
}
|
|
2486
2588
|
|
|
2487
|
-
.overtype-container
|
|
2589
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview .code-fence {
|
|
2488
2590
|
display: none !important;
|
|
2489
2591
|
}
|
|
2490
2592
|
|
|
2491
2593
|
/* Blockquotes - enhanced styling in preview mode */
|
|
2492
|
-
.overtype-container
|
|
2594
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview .blockquote {
|
|
2493
2595
|
display: block !important;
|
|
2494
2596
|
border-left: 4px solid var(--blockquote, #ddd) !important;
|
|
2495
2597
|
padding-left: 1em !important;
|
|
@@ -2498,7 +2600,7 @@ function generateStyles(options = {}) {
|
|
|
2498
2600
|
}
|
|
2499
2601
|
|
|
2500
2602
|
/* Typography improvements in preview mode */
|
|
2501
|
-
.overtype-container
|
|
2603
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview {
|
|
2502
2604
|
font-family: Georgia, 'Times New Roman', serif !important;
|
|
2503
2605
|
font-size: 16px !important;
|
|
2504
2606
|
line-height: 1.8 !important;
|
|
@@ -2506,7 +2608,7 @@ function generateStyles(options = {}) {
|
|
|
2506
2608
|
}
|
|
2507
2609
|
|
|
2508
2610
|
/* Inline code in preview mode - keep monospace */
|
|
2509
|
-
.overtype-container
|
|
2611
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview code {
|
|
2510
2612
|
font-family: ${fontFamily} !important;
|
|
2511
2613
|
font-size: 0.9em !important;
|
|
2512
2614
|
background: rgba(135, 131, 120, 0.15) !important;
|
|
@@ -2515,236 +2617,243 @@ function generateStyles(options = {}) {
|
|
|
2515
2617
|
}
|
|
2516
2618
|
|
|
2517
2619
|
/* Strong and em elements in preview mode */
|
|
2518
|
-
.overtype-container
|
|
2620
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview strong {
|
|
2519
2621
|
font-weight: 700 !important;
|
|
2520
2622
|
color: inherit !important; /* Use parent text color */
|
|
2521
2623
|
}
|
|
2522
2624
|
|
|
2523
|
-
.overtype-container
|
|
2625
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview em {
|
|
2524
2626
|
font-style: italic !important;
|
|
2525
2627
|
color: inherit !important; /* Use parent text color */
|
|
2526
2628
|
}
|
|
2527
2629
|
|
|
2528
2630
|
/* HR in preview mode */
|
|
2529
|
-
.overtype-container
|
|
2631
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview .hr-marker {
|
|
2530
2632
|
display: block !important;
|
|
2531
2633
|
border-top: 2px solid var(--hr, #ddd) !important;
|
|
2532
2634
|
text-indent: -9999px !important;
|
|
2533
2635
|
height: 2px !important;
|
|
2534
2636
|
}
|
|
2535
2637
|
|
|
2638
|
+
/* Link Tooltip - CSS Anchor Positioning */
|
|
2639
|
+
@supports (position-anchor: --x) and (position-area: center) {
|
|
2640
|
+
.overtype-link-tooltip {
|
|
2641
|
+
position: absolute;
|
|
2642
|
+
position-anchor: var(--target-anchor, --link-0);
|
|
2643
|
+
position-area: block-end center;
|
|
2644
|
+
margin-top: 8px !important;
|
|
2645
|
+
|
|
2646
|
+
background: #333 !important;
|
|
2647
|
+
color: white !important;
|
|
2648
|
+
padding: 6px 10px !important;
|
|
2649
|
+
border-radius: 16px !important;
|
|
2650
|
+
font-size: 12px !important;
|
|
2651
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
|
|
2652
|
+
display: none !important;
|
|
2653
|
+
z-index: 10000 !important;
|
|
2654
|
+
cursor: pointer !important;
|
|
2655
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.3) !important;
|
|
2656
|
+
max-width: 300px !important;
|
|
2657
|
+
white-space: nowrap !important;
|
|
2658
|
+
overflow: hidden !important;
|
|
2659
|
+
text-overflow: ellipsis !important;
|
|
2660
|
+
|
|
2661
|
+
position-try: most-width block-end inline-end, flip-inline, block-start center;
|
|
2662
|
+
position-visibility: anchors-visible;
|
|
2663
|
+
}
|
|
2664
|
+
|
|
2665
|
+
.overtype-link-tooltip.visible {
|
|
2666
|
+
display: flex !important;
|
|
2667
|
+
}
|
|
2668
|
+
}
|
|
2669
|
+
|
|
2536
2670
|
${mobileStyles}
|
|
2537
2671
|
`;
|
|
2538
2672
|
}
|
|
2539
2673
|
|
|
2540
|
-
// src/icons.js
|
|
2541
|
-
var boldIcon = `<svg viewBox="0 0 18 18">
|
|
2542
|
-
<path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5,4H9.5A2.5,2.5,0,0,1,12,6.5v0A2.5,2.5,0,0,1,9.5,9H5A0,0,0,0,1,5,9V4A0,0,0,0,1,5,4Z"></path>
|
|
2543
|
-
<path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5,9h5.5A2.5,2.5,0,0,1,13,11.5v0A2.5,2.5,0,0,1,10.5,14H5a0,0,0,0,1,0,0V9A0,0,0,0,1,5,9Z"></path>
|
|
2544
|
-
</svg>`;
|
|
2545
|
-
var italicIcon = `<svg viewBox="0 0 18 18">
|
|
2546
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="13" y1="4" y2="4"></line>
|
|
2547
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="5" x2="11" y1="14" y2="14"></line>
|
|
2548
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="10" y1="14" y2="4"></line>
|
|
2549
|
-
</svg>`;
|
|
2550
|
-
var h1Icon = `<svg viewBox="0 0 18 18">
|
|
2551
|
-
<path fill="currentColor" d="M10,4V14a1,1,0,0,1-2,0V10H3v4a1,1,0,0,1-2,0V4A1,1,0,0,1,3,4V8H8V4a1,1,0,0,1,2,0Zm6.06787,9.209H14.98975V7.59863a.54085.54085,0,0,0-.605-.60547h-.62744a1.01119,1.01119,0,0,0-.748.29688L11.645,8.56641a.5435.5435,0,0,0-.022.8584l.28613.30762a.53861.53861,0,0,0,.84717.0332l.09912-.08789a1.2137,1.2137,0,0,0,.2417-.35254h.02246s-.01123.30859-.01123.60547V13.209H12.041a.54085.54085,0,0,0-.605.60547v.43945a.54085.54085,0,0,0,.605.60547h4.02686a.54085.54085,0,0,0,.605-.60547v-.43945A.54085.54085,0,0,0,16.06787,13.209Z"></path>
|
|
2552
|
-
</svg>`;
|
|
2553
|
-
var h2Icon = `<svg viewBox="0 0 18 18">
|
|
2554
|
-
<path fill="currentColor" d="M16.73975,13.81445v.43945a.54085.54085,0,0,1-.605.60547H11.855a.58392.58392,0,0,1-.64893-.60547V14.0127c0-2.90527,3.39941-3.42187,3.39941-4.55469a.77675.77675,0,0,0-.84717-.78125,1.17684,1.17684,0,0,0-.83594.38477c-.2749.26367-.561.374-.85791.13184l-.4292-.34082c-.30811-.24219-.38525-.51758-.1543-.81445a2.97155,2.97155,0,0,1,2.45361-1.17676,2.45393,2.45393,0,0,1,2.68408,2.40918c0,2.45312-3.1792,2.92676-3.27832,3.93848h2.79443A.54085.54085,0,0,1,16.73975,13.81445ZM9,3A.99974.99974,0,0,0,8,4V8H3V4A1,1,0,0,0,1,4V14a1,1,0,0,0,2,0V10H8v4a1,1,0,0,0,2,0V4A.99974.99974,0,0,0,9,3Z"></path>
|
|
2555
|
-
</svg>`;
|
|
2556
|
-
var h3Icon = `<svg viewBox="0 0 18 18">
|
|
2557
|
-
<path fill="currentColor" d="M16.65186,12.30664a2.6742,2.6742,0,0,1-2.915,2.68457,3.96592,3.96592,0,0,1-2.25537-.6709.56007.56007,0,0,1-.13232-.83594L11.64648,13c.209-.34082.48389-.36328.82471-.1543a2.32654,2.32654,0,0,0,1.12256.33008c.71484,0,1.12207-.35156,1.12207-.78125,0-.61523-.61621-.86816-1.46338-.86816H13.2085a.65159.65159,0,0,1-.68213-.41895l-.05518-.10937a.67114.67114,0,0,1,.14307-.78125l.71533-.86914a8.55289,8.55289,0,0,1,.68213-.7373V8.58887a3.93913,3.93913,0,0,1-.748.05469H11.9873a.54085.54085,0,0,1-.605-.60547V7.59863a.54085.54085,0,0,1,.605-.60547h3.75146a.53773.53773,0,0,1,.60547.59375v.17676a1.03723,1.03723,0,0,1-.27539.748L14.74854,10.0293A2.31132,2.31132,0,0,1,16.65186,12.30664ZM9,3A.99974.99974,0,0,0,8,4V8H3V4A1,1,0,0,0,1,4V14a1,1,0,0,0,2,0V10H8v4a1,1,0,0,0,2,0V4A.99974.99974,0,0,0,9,3Z"></path>
|
|
2558
|
-
</svg>`;
|
|
2559
|
-
var linkIcon = `<svg viewBox="0 0 18 18">
|
|
2560
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="11" y1="7" y2="11"></line>
|
|
2561
|
-
<path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.9,4.577a3.476,3.476,0,0,1,.36,4.679A3.476,3.476,0,0,1,4.577,8.9C3.185,7.5,2.035,6.4,4.217,4.217S7.5,3.185,8.9,4.577Z"></path>
|
|
2562
|
-
<path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.423,9.1a3.476,3.476,0,0,0-4.679-.36,3.476,3.476,0,0,0,.36,4.679c1.392,1.392,2.5,2.542,4.679.36S14.815,10.5,13.423,9.1Z"></path>
|
|
2563
|
-
</svg>`;
|
|
2564
|
-
var codeIcon = `<svg viewBox="0 0 18 18">
|
|
2565
|
-
<polyline stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" points="5 7 3 9 5 11"></polyline>
|
|
2566
|
-
<polyline stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" points="13 7 15 9 13 11"></polyline>
|
|
2567
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="10" x2="8" y1="5" y2="13"></line>
|
|
2568
|
-
</svg>`;
|
|
2569
|
-
var bulletListIcon = `<svg viewBox="0 0 18 18">
|
|
2570
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="6" x2="15" y1="4" y2="4"></line>
|
|
2571
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="6" x2="15" y1="9" y2="9"></line>
|
|
2572
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="6" x2="15" y1="14" y2="14"></line>
|
|
2573
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="3" x2="3" y1="4" y2="4"></line>
|
|
2574
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="3" x2="3" y1="9" y2="9"></line>
|
|
2575
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="3" x2="3" y1="14" y2="14"></line>
|
|
2576
|
-
</svg>`;
|
|
2577
|
-
var orderedListIcon = `<svg viewBox="0 0 18 18">
|
|
2578
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="15" y1="4" y2="4"></line>
|
|
2579
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="15" y1="9" y2="9"></line>
|
|
2580
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="15" y1="14" y2="14"></line>
|
|
2581
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" x1="2.5" x2="4.5" y1="5.5" y2="5.5"></line>
|
|
2582
|
-
<path fill="currentColor" d="M3.5,6A0.5,0.5,0,0,1,3,5.5V3.085l-0.276.138A0.5,0.5,0,0,1,2.053,3c-0.124-.247-0.023-0.324.224-0.447l1-.5A0.5,0.5,0,0,1,4,2.5v3A0.5,0.5,0,0,1,3.5,6Z"></path>
|
|
2583
|
-
<path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M4.5,10.5h-2c0-.234,1.85-1.076,1.85-2.234A0.959,0.959,0,0,0,2.5,8.156"></path>
|
|
2584
|
-
<path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M2.5,14.846a0.959,0.959,0,0,0,1.85-.109A0.7,0.7,0,0,0,3.75,14a0.688,0.688,0,0,0,.6-0.736,0.959,0.959,0,0,0-1.85-.109"></path>
|
|
2585
|
-
</svg>`;
|
|
2586
|
-
var quoteIcon = `<svg viewBox="2 2 20 20">
|
|
2587
|
-
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 10.8182L9 10.8182C8.80222 10.8182 8.60888 10.7649 8.44443 10.665C8.27998 10.5651 8.15181 10.4231 8.07612 10.257C8.00043 10.0909 7.98063 9.90808 8.01922 9.73174C8.0578 9.55539 8.15304 9.39341 8.29289 9.26627C8.43275 9.13913 8.61093 9.05255 8.80491 9.01747C8.99889 8.98239 9.19996 9.00039 9.38268 9.0692C9.56541 9.13801 9.72159 9.25453 9.83147 9.40403C9.94135 9.55353 10 9.72929 10 9.90909L10 12.1818C10 12.664 9.78929 13.1265 9.41421 13.4675C9.03914 13.8084 8.53043 14 8 14"></path>
|
|
2588
|
-
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 10.8182L15 10.8182C14.8022 10.8182 14.6089 10.7649 14.4444 10.665C14.28 10.5651 14.1518 10.4231 14.0761 10.257C14.0004 10.0909 13.9806 9.90808 14.0192 9.73174C14.0578 9.55539 14.153 9.39341 14.2929 9.26627C14.4327 9.13913 14.6109 9.05255 14.8049 9.01747C14.9989 8.98239 15.2 9.00039 15.3827 9.0692C15.5654 9.13801 15.7216 9.25453 15.8315 9.40403C15.9414 9.55353 16 9.72929 16 9.90909L16 12.1818C16 12.664 15.7893 13.1265 15.4142 13.4675C15.0391 13.8084 14.5304 14 14 14"></path>
|
|
2589
|
-
</svg>`;
|
|
2590
|
-
var taskListIcon = `<svg viewBox="0 0 18 18">
|
|
2591
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="16" y1="4" y2="4"></line>
|
|
2592
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="16" y1="9" y2="9"></line>
|
|
2593
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="16" y1="14" y2="14"></line>
|
|
2594
|
-
<rect stroke="currentColor" fill="none" stroke-width="1.5" x="2" y="3" width="3" height="3" rx="0.5"></rect>
|
|
2595
|
-
<rect stroke="currentColor" fill="none" stroke-width="1.5" x="2" y="13" width="3" height="3" rx="0.5"></rect>
|
|
2596
|
-
<polyline stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" points="2.65 9.5 3.5 10.5 5 8.5"></polyline>
|
|
2597
|
-
</svg>`;
|
|
2598
|
-
var eyeIcon = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2599
|
-
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" fill="none"></path>
|
|
2600
|
-
<circle cx="12" cy="12" r="3" fill="none"></circle>
|
|
2601
|
-
</svg>`;
|
|
2602
|
-
|
|
2603
2674
|
// src/toolbar.js
|
|
2604
2675
|
var Toolbar = class {
|
|
2605
|
-
constructor(editor,
|
|
2676
|
+
constructor(editor, options = {}) {
|
|
2606
2677
|
this.editor = editor;
|
|
2607
2678
|
this.container = null;
|
|
2608
2679
|
this.buttons = {};
|
|
2609
|
-
this.
|
|
2680
|
+
this.toolbarButtons = options.toolbarButtons || [];
|
|
2610
2681
|
}
|
|
2611
2682
|
/**
|
|
2612
|
-
* Create and
|
|
2683
|
+
* Create and render toolbar
|
|
2613
2684
|
*/
|
|
2614
2685
|
create() {
|
|
2615
|
-
var _a;
|
|
2616
2686
|
this.container = document.createElement("div");
|
|
2617
2687
|
this.container.className = "overtype-toolbar";
|
|
2618
2688
|
this.container.setAttribute("role", "toolbar");
|
|
2619
|
-
this.container.setAttribute("aria-label", "
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
{ separator: true },
|
|
2624
|
-
{ name: "h1", icon: h1Icon, title: "Heading 1", action: "insertH1" },
|
|
2625
|
-
{ name: "h2", icon: h2Icon, title: "Heading 2", action: "insertH2" },
|
|
2626
|
-
{ name: "h3", icon: h3Icon, title: "Heading 3", action: "insertH3" },
|
|
2627
|
-
{ separator: true },
|
|
2628
|
-
{ name: "link", icon: linkIcon, title: "Insert Link (Ctrl+K)", action: "insertLink" },
|
|
2629
|
-
{ name: "code", icon: codeIcon, title: "Code (Ctrl+`)", action: "toggleCode" },
|
|
2630
|
-
{ separator: true },
|
|
2631
|
-
{ name: "quote", icon: quoteIcon, title: "Quote", action: "toggleQuote" },
|
|
2632
|
-
{ separator: true },
|
|
2633
|
-
{ name: "bulletList", icon: bulletListIcon, title: "Bullet List", action: "toggleBulletList" },
|
|
2634
|
-
{ name: "orderedList", icon: orderedListIcon, title: "Numbered List", action: "toggleNumberedList" },
|
|
2635
|
-
{ name: "taskList", icon: taskListIcon, title: "Task List", action: "toggleTaskList" },
|
|
2636
|
-
{ separator: true },
|
|
2637
|
-
{ name: "viewMode", icon: eyeIcon, title: "View mode", action: "toggle-view-menu", hasDropdown: true }
|
|
2638
|
-
];
|
|
2639
|
-
buttonConfig.forEach((config) => {
|
|
2640
|
-
if (config.separator) {
|
|
2641
|
-
const separator = document.createElement("div");
|
|
2642
|
-
separator.className = "overtype-toolbar-separator";
|
|
2643
|
-
separator.setAttribute("role", "separator");
|
|
2689
|
+
this.container.setAttribute("aria-label", "Formatting toolbar");
|
|
2690
|
+
this.toolbarButtons.forEach((buttonConfig) => {
|
|
2691
|
+
if (buttonConfig.name === "separator") {
|
|
2692
|
+
const separator = this.createSeparator();
|
|
2644
2693
|
this.container.appendChild(separator);
|
|
2645
2694
|
} else {
|
|
2646
|
-
const button = this.createButton(
|
|
2647
|
-
this.buttons[
|
|
2695
|
+
const button = this.createButton(buttonConfig);
|
|
2696
|
+
this.buttons[buttonConfig.name] = button;
|
|
2648
2697
|
this.container.appendChild(button);
|
|
2649
2698
|
}
|
|
2650
2699
|
});
|
|
2651
|
-
|
|
2652
|
-
const wrapper = this.editor.element.querySelector(".overtype-wrapper");
|
|
2653
|
-
if (container && wrapper) {
|
|
2654
|
-
container.insertBefore(this.container, wrapper);
|
|
2655
|
-
}
|
|
2656
|
-
return this.container;
|
|
2700
|
+
this.editor.wrapper.insertBefore(this.container, this.editor.wrapper.firstChild);
|
|
2657
2701
|
}
|
|
2658
2702
|
/**
|
|
2659
|
-
* Create
|
|
2703
|
+
* Create a toolbar separator
|
|
2660
2704
|
*/
|
|
2661
|
-
|
|
2705
|
+
createSeparator() {
|
|
2706
|
+
const separator = document.createElement("div");
|
|
2707
|
+
separator.className = "overtype-toolbar-separator";
|
|
2708
|
+
separator.setAttribute("role", "separator");
|
|
2709
|
+
return separator;
|
|
2710
|
+
}
|
|
2711
|
+
/**
|
|
2712
|
+
* Create a toolbar button
|
|
2713
|
+
*/
|
|
2714
|
+
createButton(buttonConfig) {
|
|
2662
2715
|
const button = document.createElement("button");
|
|
2663
2716
|
button.className = "overtype-toolbar-button";
|
|
2664
2717
|
button.type = "button";
|
|
2665
|
-
button.
|
|
2666
|
-
button.
|
|
2667
|
-
button.setAttribute("
|
|
2668
|
-
button.innerHTML =
|
|
2669
|
-
if (
|
|
2718
|
+
button.setAttribute("data-button", buttonConfig.name);
|
|
2719
|
+
button.title = buttonConfig.title || "";
|
|
2720
|
+
button.setAttribute("aria-label", buttonConfig.title || buttonConfig.name);
|
|
2721
|
+
button.innerHTML = this.sanitizeSVG(buttonConfig.icon || "");
|
|
2722
|
+
if (buttonConfig.name === "viewMode") {
|
|
2670
2723
|
button.classList.add("has-dropdown");
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2724
|
+
button.dataset.dropdown = "true";
|
|
2725
|
+
button.addEventListener("click", (e) => {
|
|
2726
|
+
e.preventDefault();
|
|
2727
|
+
this.toggleViewModeDropdown(button);
|
|
2728
|
+
});
|
|
2729
|
+
return button;
|
|
2674
2730
|
}
|
|
2675
|
-
button.
|
|
2731
|
+
button._clickHandler = async (e) => {
|
|
2676
2732
|
e.preventDefault();
|
|
2677
|
-
this.
|
|
2678
|
-
|
|
2733
|
+
this.editor.textarea.focus();
|
|
2734
|
+
try {
|
|
2735
|
+
if (buttonConfig.action) {
|
|
2736
|
+
await buttonConfig.action({
|
|
2737
|
+
editor: this.editor,
|
|
2738
|
+
getValue: () => this.editor.getValue(),
|
|
2739
|
+
setValue: (value) => this.editor.setValue(value),
|
|
2740
|
+
event: e
|
|
2741
|
+
});
|
|
2742
|
+
}
|
|
2743
|
+
} catch (error) {
|
|
2744
|
+
console.error(`Button "${buttonConfig.name}" error:`, error);
|
|
2745
|
+
this.editor.wrapper.dispatchEvent(new CustomEvent("button-error", {
|
|
2746
|
+
detail: { buttonName: buttonConfig.name, error }
|
|
2747
|
+
}));
|
|
2748
|
+
button.classList.add("button-error");
|
|
2749
|
+
button.style.animation = "buttonError 0.3s";
|
|
2750
|
+
setTimeout(() => {
|
|
2751
|
+
button.classList.remove("button-error");
|
|
2752
|
+
button.style.animation = "";
|
|
2753
|
+
}, 300);
|
|
2754
|
+
}
|
|
2755
|
+
};
|
|
2756
|
+
button.addEventListener("click", button._clickHandler);
|
|
2679
2757
|
return button;
|
|
2680
2758
|
}
|
|
2681
2759
|
/**
|
|
2682
|
-
*
|
|
2760
|
+
* Sanitize SVG to prevent XSS
|
|
2683
2761
|
*/
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2762
|
+
sanitizeSVG(svg) {
|
|
2763
|
+
if (typeof svg !== "string")
|
|
2764
|
+
return "";
|
|
2765
|
+
const cleaned = svg.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "").replace(/\son\w+\s*=\s*["'][^"']*["']/gi, "").replace(/\son\w+\s*=\s*[^\s>]*/gi, "");
|
|
2766
|
+
return cleaned;
|
|
2767
|
+
}
|
|
2768
|
+
/**
|
|
2769
|
+
* Toggle view mode dropdown (internal implementation)
|
|
2770
|
+
* Not exposed to users - viewMode button behavior is fixed
|
|
2771
|
+
*/
|
|
2772
|
+
toggleViewModeDropdown(button) {
|
|
2773
|
+
const existingDropdown = document.querySelector(".overtype-dropdown-menu");
|
|
2774
|
+
if (existingDropdown) {
|
|
2775
|
+
existingDropdown.remove();
|
|
2776
|
+
button.classList.remove("dropdown-active");
|
|
2690
2777
|
return;
|
|
2691
2778
|
}
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
case "insertH2":
|
|
2705
|
-
toggleH2(textarea);
|
|
2706
|
-
break;
|
|
2707
|
-
case "insertH3":
|
|
2708
|
-
toggleH3(textarea);
|
|
2709
|
-
break;
|
|
2710
|
-
case "insertLink":
|
|
2711
|
-
insertLink(textarea);
|
|
2712
|
-
break;
|
|
2713
|
-
case "toggleCode":
|
|
2714
|
-
toggleCode(textarea);
|
|
2715
|
-
break;
|
|
2716
|
-
case "toggleBulletList":
|
|
2717
|
-
toggleBulletList(textarea);
|
|
2718
|
-
break;
|
|
2719
|
-
case "toggleNumberedList":
|
|
2720
|
-
toggleNumberedList(textarea);
|
|
2721
|
-
break;
|
|
2722
|
-
case "toggleQuote":
|
|
2723
|
-
toggleQuote(textarea);
|
|
2724
|
-
break;
|
|
2725
|
-
case "toggleTaskList":
|
|
2726
|
-
toggleTaskList(textarea);
|
|
2727
|
-
break;
|
|
2728
|
-
case "toggle-plain":
|
|
2729
|
-
const isPlain = this.editor.container.classList.contains("plain-mode");
|
|
2730
|
-
this.editor.showPlainTextarea(!isPlain);
|
|
2731
|
-
break;
|
|
2779
|
+
button.classList.add("dropdown-active");
|
|
2780
|
+
const dropdown = this.createViewModeDropdown(button);
|
|
2781
|
+
const rect = button.getBoundingClientRect();
|
|
2782
|
+
dropdown.style.position = "absolute";
|
|
2783
|
+
dropdown.style.top = `${rect.bottom + 5}px`;
|
|
2784
|
+
dropdown.style.left = `${rect.left}px`;
|
|
2785
|
+
document.body.appendChild(dropdown);
|
|
2786
|
+
this.handleDocumentClick = (e) => {
|
|
2787
|
+
if (!dropdown.contains(e.target) && !button.contains(e.target)) {
|
|
2788
|
+
dropdown.remove();
|
|
2789
|
+
button.classList.remove("dropdown-active");
|
|
2790
|
+
document.removeEventListener("click", this.handleDocumentClick);
|
|
2732
2791
|
}
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
}
|
|
2792
|
+
};
|
|
2793
|
+
setTimeout(() => {
|
|
2794
|
+
document.addEventListener("click", this.handleDocumentClick);
|
|
2795
|
+
}, 0);
|
|
2737
2796
|
}
|
|
2738
2797
|
/**
|
|
2739
|
-
*
|
|
2798
|
+
* Create view mode dropdown menu (internal implementation)
|
|
2740
2799
|
*/
|
|
2741
|
-
|
|
2742
|
-
const
|
|
2743
|
-
|
|
2744
|
-
|
|
2800
|
+
createViewModeDropdown(button) {
|
|
2801
|
+
const dropdown = document.createElement("div");
|
|
2802
|
+
dropdown.className = "overtype-dropdown-menu";
|
|
2803
|
+
const items = [
|
|
2804
|
+
{ id: "normal", label: "Normal Edit", icon: "\u2713" },
|
|
2805
|
+
{ id: "plain", label: "Plain Textarea", icon: "\u2713" },
|
|
2806
|
+
{ id: "preview", label: "Preview Mode", icon: "\u2713" }
|
|
2807
|
+
];
|
|
2808
|
+
const currentMode = this.editor.container.dataset.mode || "normal";
|
|
2809
|
+
items.forEach((item) => {
|
|
2810
|
+
const menuItem = document.createElement("button");
|
|
2811
|
+
menuItem.className = "overtype-dropdown-item";
|
|
2812
|
+
menuItem.type = "button";
|
|
2813
|
+
menuItem.textContent = item.label;
|
|
2814
|
+
if (item.id === currentMode) {
|
|
2815
|
+
menuItem.classList.add("active");
|
|
2816
|
+
menuItem.setAttribute("aria-current", "true");
|
|
2817
|
+
const checkmark = document.createElement("span");
|
|
2818
|
+
checkmark.className = "overtype-dropdown-icon";
|
|
2819
|
+
checkmark.textContent = item.icon;
|
|
2820
|
+
menuItem.prepend(checkmark);
|
|
2821
|
+
}
|
|
2822
|
+
menuItem.addEventListener("click", (e) => {
|
|
2823
|
+
e.preventDefault();
|
|
2824
|
+
switch (item.id) {
|
|
2825
|
+
case "plain":
|
|
2826
|
+
this.editor.showPlainTextarea();
|
|
2827
|
+
break;
|
|
2828
|
+
case "preview":
|
|
2829
|
+
this.editor.showPreviewMode();
|
|
2830
|
+
break;
|
|
2831
|
+
case "normal":
|
|
2832
|
+
default:
|
|
2833
|
+
this.editor.showNormalEditMode();
|
|
2834
|
+
break;
|
|
2835
|
+
}
|
|
2836
|
+
dropdown.remove();
|
|
2837
|
+
button.classList.remove("dropdown-active");
|
|
2838
|
+
document.removeEventListener("click", this.handleDocumentClick);
|
|
2839
|
+
});
|
|
2840
|
+
dropdown.appendChild(menuItem);
|
|
2841
|
+
});
|
|
2842
|
+
return dropdown;
|
|
2843
|
+
}
|
|
2844
|
+
/**
|
|
2845
|
+
* Update active states of toolbar buttons
|
|
2846
|
+
*/
|
|
2847
|
+
updateButtonStates() {
|
|
2848
|
+
var _a;
|
|
2745
2849
|
try {
|
|
2746
|
-
const activeFormats = getActiveFormats2(
|
|
2850
|
+
const activeFormats = ((_a = getActiveFormats2) == null ? void 0 : _a(
|
|
2851
|
+
this.editor.textarea,
|
|
2852
|
+
this.editor.textarea.selectionStart
|
|
2853
|
+
)) || [];
|
|
2747
2854
|
Object.entries(this.buttons).forEach(([name, button]) => {
|
|
2855
|
+
if (name === "viewMode")
|
|
2856
|
+
return;
|
|
2748
2857
|
let isActive = false;
|
|
2749
2858
|
switch (name) {
|
|
2750
2859
|
case "bold":
|
|
@@ -2762,12 +2871,12 @@ var Toolbar = class {
|
|
|
2762
2871
|
case "orderedList":
|
|
2763
2872
|
isActive = activeFormats.includes("numbered-list");
|
|
2764
2873
|
break;
|
|
2765
|
-
case "quote":
|
|
2766
|
-
isActive = activeFormats.includes("quote");
|
|
2767
|
-
break;
|
|
2768
2874
|
case "taskList":
|
|
2769
2875
|
isActive = activeFormats.includes("task-list");
|
|
2770
2876
|
break;
|
|
2877
|
+
case "quote":
|
|
2878
|
+
isActive = activeFormats.includes("quote");
|
|
2879
|
+
break;
|
|
2771
2880
|
case "h1":
|
|
2772
2881
|
isActive = activeFormats.includes("header");
|
|
2773
2882
|
break;
|
|
@@ -2777,9 +2886,6 @@ var Toolbar = class {
|
|
|
2777
2886
|
case "h3":
|
|
2778
2887
|
isActive = activeFormats.includes("header-3");
|
|
2779
2888
|
break;
|
|
2780
|
-
case "togglePlain":
|
|
2781
|
-
isActive = !this.editor.container.classList.contains("plain-mode");
|
|
2782
|
-
break;
|
|
2783
2889
|
}
|
|
2784
2890
|
button.classList.toggle("active", isActive);
|
|
2785
2891
|
button.setAttribute("aria-pressed", isActive.toString());
|
|
@@ -2788,101 +2894,19 @@ var Toolbar = class {
|
|
|
2788
2894
|
}
|
|
2789
2895
|
}
|
|
2790
2896
|
/**
|
|
2791
|
-
*
|
|
2792
|
-
*/
|
|
2793
|
-
toggleViewDropdown(button) {
|
|
2794
|
-
const existingDropdown = document.querySelector(".overtype-dropdown-menu");
|
|
2795
|
-
if (existingDropdown) {
|
|
2796
|
-
existingDropdown.remove();
|
|
2797
|
-
button.classList.remove("dropdown-active");
|
|
2798
|
-
document.removeEventListener("click", this.handleDocumentClick);
|
|
2799
|
-
return;
|
|
2800
|
-
}
|
|
2801
|
-
const dropdown = this.createViewDropdown();
|
|
2802
|
-
const rect = button.getBoundingClientRect();
|
|
2803
|
-
dropdown.style.top = `${rect.bottom + 4}px`;
|
|
2804
|
-
dropdown.style.left = `${rect.left}px`;
|
|
2805
|
-
document.body.appendChild(dropdown);
|
|
2806
|
-
button.classList.add("dropdown-active");
|
|
2807
|
-
this.handleDocumentClick = (e) => {
|
|
2808
|
-
if (!button.contains(e.target) && !dropdown.contains(e.target)) {
|
|
2809
|
-
dropdown.remove();
|
|
2810
|
-
button.classList.remove("dropdown-active");
|
|
2811
|
-
document.removeEventListener("click", this.handleDocumentClick);
|
|
2812
|
-
}
|
|
2813
|
-
};
|
|
2814
|
-
setTimeout(() => {
|
|
2815
|
-
document.addEventListener("click", this.handleDocumentClick);
|
|
2816
|
-
}, 0);
|
|
2817
|
-
}
|
|
2818
|
-
/**
|
|
2819
|
-
* Create view mode dropdown menu
|
|
2820
|
-
*/
|
|
2821
|
-
createViewDropdown() {
|
|
2822
|
-
const dropdown = document.createElement("div");
|
|
2823
|
-
dropdown.className = "overtype-dropdown-menu";
|
|
2824
|
-
const isPlain = this.editor.container.classList.contains("plain-mode");
|
|
2825
|
-
const isPreview = this.editor.container.classList.contains("preview-mode");
|
|
2826
|
-
const currentMode = isPreview ? "preview" : isPlain ? "plain" : "normal";
|
|
2827
|
-
const modes = [
|
|
2828
|
-
{ id: "normal", label: "Normal Edit", icon: "\u2713" },
|
|
2829
|
-
{ id: "plain", label: "Plain Textarea", icon: "\u2713" },
|
|
2830
|
-
{ id: "preview", label: "Preview Mode", icon: "\u2713" }
|
|
2831
|
-
];
|
|
2832
|
-
modes.forEach((mode) => {
|
|
2833
|
-
const item = document.createElement("button");
|
|
2834
|
-
item.className = "overtype-dropdown-item";
|
|
2835
|
-
item.type = "button";
|
|
2836
|
-
const check = document.createElement("span");
|
|
2837
|
-
check.className = "overtype-dropdown-check";
|
|
2838
|
-
check.textContent = currentMode === mode.id ? mode.icon : "";
|
|
2839
|
-
const label = document.createElement("span");
|
|
2840
|
-
label.textContent = mode.label;
|
|
2841
|
-
item.appendChild(check);
|
|
2842
|
-
item.appendChild(label);
|
|
2843
|
-
if (currentMode === mode.id) {
|
|
2844
|
-
item.classList.add("active");
|
|
2845
|
-
}
|
|
2846
|
-
item.addEventListener("click", (e) => {
|
|
2847
|
-
e.stopPropagation();
|
|
2848
|
-
this.setViewMode(mode.id);
|
|
2849
|
-
dropdown.remove();
|
|
2850
|
-
this.viewModeButton.classList.remove("dropdown-active");
|
|
2851
|
-
document.removeEventListener("click", this.handleDocumentClick);
|
|
2852
|
-
});
|
|
2853
|
-
dropdown.appendChild(item);
|
|
2854
|
-
});
|
|
2855
|
-
return dropdown;
|
|
2856
|
-
}
|
|
2857
|
-
/**
|
|
2858
|
-
* Set view mode
|
|
2859
|
-
*/
|
|
2860
|
-
setViewMode(mode) {
|
|
2861
|
-
this.editor.container.classList.remove("plain-mode", "preview-mode");
|
|
2862
|
-
switch (mode) {
|
|
2863
|
-
case "plain":
|
|
2864
|
-
this.editor.showPlainTextarea(true);
|
|
2865
|
-
break;
|
|
2866
|
-
case "preview":
|
|
2867
|
-
this.editor.showPreviewMode(true);
|
|
2868
|
-
break;
|
|
2869
|
-
case "normal":
|
|
2870
|
-
default:
|
|
2871
|
-
this.editor.showPlainTextarea(false);
|
|
2872
|
-
if (typeof this.editor.showPreviewMode === "function") {
|
|
2873
|
-
this.editor.showPreviewMode(false);
|
|
2874
|
-
}
|
|
2875
|
-
break;
|
|
2876
|
-
}
|
|
2877
|
-
}
|
|
2878
|
-
/**
|
|
2879
|
-
* Destroy toolbar
|
|
2897
|
+
* Destroy toolbar and cleanup
|
|
2880
2898
|
*/
|
|
2881
2899
|
destroy() {
|
|
2882
2900
|
if (this.container) {
|
|
2883
2901
|
if (this.handleDocumentClick) {
|
|
2884
2902
|
document.removeEventListener("click", this.handleDocumentClick);
|
|
2885
2903
|
}
|
|
2904
|
+
Object.values(this.buttons).forEach((button) => {
|
|
2905
|
+
if (button._clickHandler) {
|
|
2906
|
+
button.removeEventListener("click", button._clickHandler);
|
|
2907
|
+
delete button._clickHandler;
|
|
2908
|
+
}
|
|
2909
|
+
});
|
|
2886
2910
|
this.container.remove();
|
|
2887
2911
|
this.container = null;
|
|
2888
2912
|
this.buttons = {};
|
|
@@ -2897,13 +2921,10 @@ var LinkTooltip = class {
|
|
|
2897
2921
|
this.tooltip = null;
|
|
2898
2922
|
this.currentLink = null;
|
|
2899
2923
|
this.hideTimeout = null;
|
|
2924
|
+
this.visibilityChangeHandler = null;
|
|
2900
2925
|
this.init();
|
|
2901
2926
|
}
|
|
2902
2927
|
init() {
|
|
2903
|
-
const supportsAnchor = CSS.supports("position-anchor: --x") && CSS.supports("position-area: center");
|
|
2904
|
-
if (!supportsAnchor) {
|
|
2905
|
-
return;
|
|
2906
|
-
}
|
|
2907
2928
|
this.createTooltip();
|
|
2908
2929
|
this.editor.textarea.addEventListener("selectionchange", () => this.checkCursorPosition());
|
|
2909
2930
|
this.editor.textarea.addEventListener("keyup", (e) => {
|
|
@@ -2913,46 +2934,19 @@ var LinkTooltip = class {
|
|
|
2913
2934
|
});
|
|
2914
2935
|
this.editor.textarea.addEventListener("input", () => this.hide());
|
|
2915
2936
|
this.editor.textarea.addEventListener("scroll", () => this.hide());
|
|
2937
|
+
this.editor.textarea.addEventListener("blur", () => this.hide());
|
|
2938
|
+
this.visibilityChangeHandler = () => {
|
|
2939
|
+
if (document.hidden) {
|
|
2940
|
+
this.hide();
|
|
2941
|
+
}
|
|
2942
|
+
};
|
|
2943
|
+
document.addEventListener("visibilitychange", this.visibilityChangeHandler);
|
|
2916
2944
|
this.tooltip.addEventListener("mouseenter", () => this.cancelHide());
|
|
2917
2945
|
this.tooltip.addEventListener("mouseleave", () => this.scheduleHide());
|
|
2918
2946
|
}
|
|
2919
2947
|
createTooltip() {
|
|
2920
2948
|
this.tooltip = document.createElement("div");
|
|
2921
2949
|
this.tooltip.className = "overtype-link-tooltip";
|
|
2922
|
-
const tooltipStyles = document.createElement("style");
|
|
2923
|
-
tooltipStyles.textContent = `
|
|
2924
|
-
@supports (position-anchor: --x) and (position-area: center) {
|
|
2925
|
-
.overtype-link-tooltip {
|
|
2926
|
-
position: absolute;
|
|
2927
|
-
position-anchor: var(--target-anchor, --link-0);
|
|
2928
|
-
position-area: block-end center;
|
|
2929
|
-
margin-top: 8px !important;
|
|
2930
|
-
|
|
2931
|
-
background: #333 !important;
|
|
2932
|
-
color: white !important;
|
|
2933
|
-
padding: 6px 10px !important;
|
|
2934
|
-
border-radius: 16px !important;
|
|
2935
|
-
font-size: 12px !important;
|
|
2936
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
|
|
2937
|
-
display: none !important;
|
|
2938
|
-
z-index: 10000 !important;
|
|
2939
|
-
cursor: pointer !important;
|
|
2940
|
-
box-shadow: 0 2px 8px rgba(0,0,0,0.3) !important;
|
|
2941
|
-
max-width: 300px !important;
|
|
2942
|
-
white-space: nowrap !important;
|
|
2943
|
-
overflow: hidden !important;
|
|
2944
|
-
text-overflow: ellipsis !important;
|
|
2945
|
-
|
|
2946
|
-
position-try: most-width block-end inline-end, flip-inline, block-start center;
|
|
2947
|
-
position-visibility: anchors-visible;
|
|
2948
|
-
}
|
|
2949
|
-
|
|
2950
|
-
.overtype-link-tooltip.visible {
|
|
2951
|
-
display: flex !important;
|
|
2952
|
-
}
|
|
2953
|
-
}
|
|
2954
|
-
`;
|
|
2955
|
-
document.head.appendChild(tooltipStyles);
|
|
2956
2950
|
this.tooltip.innerHTML = `
|
|
2957
2951
|
<span style="display: flex; align-items: center; gap: 6px;">
|
|
2958
2952
|
<svg width="12" height="12" viewBox="0 0 20 20" fill="currentColor" style="flex-shrink: 0;">
|
|
@@ -3028,6 +3022,10 @@ var LinkTooltip = class {
|
|
|
3028
3022
|
}
|
|
3029
3023
|
destroy() {
|
|
3030
3024
|
this.cancelHide();
|
|
3025
|
+
if (this.visibilityChangeHandler) {
|
|
3026
|
+
document.removeEventListener("visibilitychange", this.visibilityChangeHandler);
|
|
3027
|
+
this.visibilityChangeHandler = null;
|
|
3028
|
+
}
|
|
3031
3029
|
if (this.tooltip && this.tooltip.parentNode) {
|
|
3032
3030
|
this.tooltip.parentNode.removeChild(this.tooltip);
|
|
3033
3031
|
}
|
|
@@ -3036,6 +3034,204 @@ var LinkTooltip = class {
|
|
|
3036
3034
|
}
|
|
3037
3035
|
};
|
|
3038
3036
|
|
|
3037
|
+
// src/icons.js
|
|
3038
|
+
var boldIcon = `<svg viewBox="0 0 18 18">
|
|
3039
|
+
<path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5,4H9.5A2.5,2.5,0,0,1,12,6.5v0A2.5,2.5,0,0,1,9.5,9H5A0,0,0,0,1,5,9V4A0,0,0,0,1,5,4Z"></path>
|
|
3040
|
+
<path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5,9h5.5A2.5,2.5,0,0,1,13,11.5v0A2.5,2.5,0,0,1,10.5,14H5a0,0,0,0,1,0,0V9A0,0,0,0,1,5,9Z"></path>
|
|
3041
|
+
</svg>`;
|
|
3042
|
+
var italicIcon = `<svg viewBox="0 0 18 18">
|
|
3043
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="13" y1="4" y2="4"></line>
|
|
3044
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="5" x2="11" y1="14" y2="14"></line>
|
|
3045
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="10" y1="14" y2="4"></line>
|
|
3046
|
+
</svg>`;
|
|
3047
|
+
var h1Icon = `<svg viewBox="0 0 18 18">
|
|
3048
|
+
<path fill="currentColor" d="M10,4V14a1,1,0,0,1-2,0V10H3v4a1,1,0,0,1-2,0V4A1,1,0,0,1,3,4V8H8V4a1,1,0,0,1,2,0Zm6.06787,9.209H14.98975V7.59863a.54085.54085,0,0,0-.605-.60547h-.62744a1.01119,1.01119,0,0,0-.748.29688L11.645,8.56641a.5435.5435,0,0,0-.022.8584l.28613.30762a.53861.53861,0,0,0,.84717.0332l.09912-.08789a1.2137,1.2137,0,0,0,.2417-.35254h.02246s-.01123.30859-.01123.60547V13.209H12.041a.54085.54085,0,0,0-.605.60547v.43945a.54085.54085,0,0,0,.605.60547h4.02686a.54085.54085,0,0,0,.605-.60547v-.43945A.54085.54085,0,0,0,16.06787,13.209Z"></path>
|
|
3049
|
+
</svg>`;
|
|
3050
|
+
var h2Icon = `<svg viewBox="0 0 18 18">
|
|
3051
|
+
<path fill="currentColor" d="M16.73975,13.81445v.43945a.54085.54085,0,0,1-.605.60547H11.855a.58392.58392,0,0,1-.64893-.60547V14.0127c0-2.90527,3.39941-3.42187,3.39941-4.55469a.77675.77675,0,0,0-.84717-.78125,1.17684,1.17684,0,0,0-.83594.38477c-.2749.26367-.561.374-.85791.13184l-.4292-.34082c-.30811-.24219-.38525-.51758-.1543-.81445a2.97155,2.97155,0,0,1,2.45361-1.17676,2.45393,2.45393,0,0,1,2.68408,2.40918c0,2.45312-3.1792,2.92676-3.27832,3.93848h2.79443A.54085.54085,0,0,1,16.73975,13.81445ZM9,3A.99974.99974,0,0,0,8,4V8H3V4A1,1,0,0,0,1,4V14a1,1,0,0,0,2,0V10H8v4a1,1,0,0,0,2,0V4A.99974.99974,0,0,0,9,3Z"></path>
|
|
3052
|
+
</svg>`;
|
|
3053
|
+
var h3Icon = `<svg viewBox="0 0 18 18">
|
|
3054
|
+
<path fill="currentColor" d="M16.65186,12.30664a2.6742,2.6742,0,0,1-2.915,2.68457,3.96592,3.96592,0,0,1-2.25537-.6709.56007.56007,0,0,1-.13232-.83594L11.64648,13c.209-.34082.48389-.36328.82471-.1543a2.32654,2.32654,0,0,0,1.12256.33008c.71484,0,1.12207-.35156,1.12207-.78125,0-.61523-.61621-.86816-1.46338-.86816H13.2085a.65159.65159,0,0,1-.68213-.41895l-.05518-.10937a.67114.67114,0,0,1,.14307-.78125l.71533-.86914a8.55289,8.55289,0,0,1,.68213-.7373V8.58887a3.93913,3.93913,0,0,1-.748.05469H11.9873a.54085.54085,0,0,1-.605-.60547V7.59863a.54085.54085,0,0,1,.605-.60547h3.75146a.53773.53773,0,0,1,.60547.59375v.17676a1.03723,1.03723,0,0,1-.27539.748L14.74854,10.0293A2.31132,2.31132,0,0,1,16.65186,12.30664ZM9,3A.99974.99974,0,0,0,8,4V8H3V4A1,1,0,0,0,1,4V14a1,1,0,0,0,2,0V10H8v4a1,1,0,0,0,2,0V4A.99974.99974,0,0,0,9,3Z"></path>
|
|
3055
|
+
</svg>`;
|
|
3056
|
+
var linkIcon = `<svg viewBox="0 0 18 18">
|
|
3057
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="11" y1="7" y2="11"></line>
|
|
3058
|
+
<path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8.9,4.577a3.476,3.476,0,0,1,.36,4.679A3.476,3.476,0,0,1,4.577,8.9C3.185,7.5,2.035,6.4,4.217,4.217S7.5,3.185,8.9,4.577Z"></path>
|
|
3059
|
+
<path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13.423,9.1a3.476,3.476,0,0,0-4.679-.36,3.476,3.476,0,0,0,.36,4.679c1.392,1.392,2.5,2.542,4.679.36S14.815,10.5,13.423,9.1Z"></path>
|
|
3060
|
+
</svg>`;
|
|
3061
|
+
var codeIcon = `<svg viewBox="0 0 18 18">
|
|
3062
|
+
<polyline stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" points="5 7 3 9 5 11"></polyline>
|
|
3063
|
+
<polyline stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" points="13 7 15 9 13 11"></polyline>
|
|
3064
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="10" x2="8" y1="5" y2="13"></line>
|
|
3065
|
+
</svg>`;
|
|
3066
|
+
var bulletListIcon = `<svg viewBox="0 0 18 18">
|
|
3067
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="6" x2="15" y1="4" y2="4"></line>
|
|
3068
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="6" x2="15" y1="9" y2="9"></line>
|
|
3069
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="6" x2="15" y1="14" y2="14"></line>
|
|
3070
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="3" x2="3" y1="4" y2="4"></line>
|
|
3071
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="3" x2="3" y1="9" y2="9"></line>
|
|
3072
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="3" x2="3" y1="14" y2="14"></line>
|
|
3073
|
+
</svg>`;
|
|
3074
|
+
var orderedListIcon = `<svg viewBox="0 0 18 18">
|
|
3075
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="15" y1="4" y2="4"></line>
|
|
3076
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="15" y1="9" y2="9"></line>
|
|
3077
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="15" y1="14" y2="14"></line>
|
|
3078
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" x1="2.5" x2="4.5" y1="5.5" y2="5.5"></line>
|
|
3079
|
+
<path fill="currentColor" d="M3.5,6A0.5,0.5,0,0,1,3,5.5V3.085l-0.276.138A0.5,0.5,0,0,1,2.053,3c-0.124-.247-0.023-0.324.224-0.447l1-.5A0.5,0.5,0,0,1,4,2.5v3A0.5,0.5,0,0,1,3.5,6Z"></path>
|
|
3080
|
+
<path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M4.5,10.5h-2c0-.234,1.85-1.076,1.85-2.234A0.959,0.959,0,0,0,2.5,8.156"></path>
|
|
3081
|
+
<path stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M2.5,14.846a0.959,0.959,0,0,0,1.85-.109A0.7,0.7,0,0,0,3.75,14a0.688,0.688,0,0,0,.6-0.736,0.959,0.959,0,0,0-1.85-.109"></path>
|
|
3082
|
+
</svg>`;
|
|
3083
|
+
var quoteIcon = `<svg viewBox="2 2 20 20">
|
|
3084
|
+
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 10.8182L9 10.8182C8.80222 10.8182 8.60888 10.7649 8.44443 10.665C8.27998 10.5651 8.15181 10.4231 8.07612 10.257C8.00043 10.0909 7.98063 9.90808 8.01922 9.73174C8.0578 9.55539 8.15304 9.39341 8.29289 9.26627C8.43275 9.13913 8.61093 9.05255 8.80491 9.01747C8.99889 8.98239 9.19996 9.00039 9.38268 9.0692C9.56541 9.13801 9.72159 9.25453 9.83147 9.40403C9.94135 9.55353 10 9.72929 10 9.90909L10 12.1818C10 12.664 9.78929 13.1265 9.41421 13.4675C9.03914 13.8084 8.53043 14 8 14"></path>
|
|
3085
|
+
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 10.8182L15 10.8182C14.8022 10.8182 14.6089 10.7649 14.4444 10.665C14.28 10.5651 14.1518 10.4231 14.0761 10.257C14.0004 10.0909 13.9806 9.90808 14.0192 9.73174C14.0578 9.55539 14.153 9.39341 14.2929 9.26627C14.4327 9.13913 14.6109 9.05255 14.8049 9.01747C14.9989 8.98239 15.2 9.00039 15.3827 9.0692C15.5654 9.13801 15.7216 9.25453 15.8315 9.40403C15.9414 9.55353 16 9.72929 16 9.90909L16 12.1818C16 12.664 15.7893 13.1265 15.4142 13.4675C15.0391 13.8084 14.5304 14 14 14"></path>
|
|
3086
|
+
</svg>`;
|
|
3087
|
+
var taskListIcon = `<svg viewBox="0 0 18 18">
|
|
3088
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="16" y1="4" y2="4"></line>
|
|
3089
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="16" y1="9" y2="9"></line>
|
|
3090
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="16" y1="14" y2="14"></line>
|
|
3091
|
+
<rect stroke="currentColor" fill="none" stroke-width="1.5" x="2" y="3" width="3" height="3" rx="0.5"></rect>
|
|
3092
|
+
<rect stroke="currentColor" fill="none" stroke-width="1.5" x="2" y="13" width="3" height="3" rx="0.5"></rect>
|
|
3093
|
+
<polyline stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="1.5" points="2.65 9.5 3.5 10.5 5 8.5"></polyline>
|
|
3094
|
+
</svg>`;
|
|
3095
|
+
var eyeIcon = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
3096
|
+
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" fill="none"></path>
|
|
3097
|
+
<circle cx="12" cy="12" r="3" fill="none"></circle>
|
|
3098
|
+
</svg>`;
|
|
3099
|
+
|
|
3100
|
+
// src/toolbar-buttons.js
|
|
3101
|
+
var toolbarButtons = {
|
|
3102
|
+
bold: {
|
|
3103
|
+
name: "bold",
|
|
3104
|
+
icon: boldIcon,
|
|
3105
|
+
title: "Bold (Ctrl+B)",
|
|
3106
|
+
action: ({ editor, event }) => {
|
|
3107
|
+
toggleBold(editor.textarea);
|
|
3108
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3109
|
+
}
|
|
3110
|
+
},
|
|
3111
|
+
italic: {
|
|
3112
|
+
name: "italic",
|
|
3113
|
+
icon: italicIcon,
|
|
3114
|
+
title: "Italic (Ctrl+I)",
|
|
3115
|
+
action: ({ editor, event }) => {
|
|
3116
|
+
toggleItalic(editor.textarea);
|
|
3117
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3118
|
+
}
|
|
3119
|
+
},
|
|
3120
|
+
code: {
|
|
3121
|
+
name: "code",
|
|
3122
|
+
icon: codeIcon,
|
|
3123
|
+
title: "Inline Code",
|
|
3124
|
+
action: ({ editor, event }) => {
|
|
3125
|
+
toggleCode(editor.textarea);
|
|
3126
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3127
|
+
}
|
|
3128
|
+
},
|
|
3129
|
+
separator: {
|
|
3130
|
+
name: "separator"
|
|
3131
|
+
// No icon, title, or action - special separator element
|
|
3132
|
+
},
|
|
3133
|
+
link: {
|
|
3134
|
+
name: "link",
|
|
3135
|
+
icon: linkIcon,
|
|
3136
|
+
title: "Insert Link",
|
|
3137
|
+
action: ({ editor, event }) => {
|
|
3138
|
+
insertLink(editor.textarea);
|
|
3139
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3140
|
+
}
|
|
3141
|
+
},
|
|
3142
|
+
h1: {
|
|
3143
|
+
name: "h1",
|
|
3144
|
+
icon: h1Icon,
|
|
3145
|
+
title: "Heading 1",
|
|
3146
|
+
action: ({ editor, event }) => {
|
|
3147
|
+
toggleH1(editor.textarea);
|
|
3148
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3149
|
+
}
|
|
3150
|
+
},
|
|
3151
|
+
h2: {
|
|
3152
|
+
name: "h2",
|
|
3153
|
+
icon: h2Icon,
|
|
3154
|
+
title: "Heading 2",
|
|
3155
|
+
action: ({ editor, event }) => {
|
|
3156
|
+
toggleH2(editor.textarea);
|
|
3157
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3158
|
+
}
|
|
3159
|
+
},
|
|
3160
|
+
h3: {
|
|
3161
|
+
name: "h3",
|
|
3162
|
+
icon: h3Icon,
|
|
3163
|
+
title: "Heading 3",
|
|
3164
|
+
action: ({ editor, event }) => {
|
|
3165
|
+
toggleH3(editor.textarea);
|
|
3166
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3167
|
+
}
|
|
3168
|
+
},
|
|
3169
|
+
bulletList: {
|
|
3170
|
+
name: "bulletList",
|
|
3171
|
+
icon: bulletListIcon,
|
|
3172
|
+
title: "Bullet List",
|
|
3173
|
+
action: ({ editor, event }) => {
|
|
3174
|
+
toggleBulletList(editor.textarea);
|
|
3175
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3176
|
+
}
|
|
3177
|
+
},
|
|
3178
|
+
orderedList: {
|
|
3179
|
+
name: "orderedList",
|
|
3180
|
+
icon: orderedListIcon,
|
|
3181
|
+
title: "Numbered List",
|
|
3182
|
+
action: ({ editor, event }) => {
|
|
3183
|
+
toggleNumberedList(editor.textarea);
|
|
3184
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3185
|
+
}
|
|
3186
|
+
},
|
|
3187
|
+
taskList: {
|
|
3188
|
+
name: "taskList",
|
|
3189
|
+
icon: taskListIcon,
|
|
3190
|
+
title: "Task List",
|
|
3191
|
+
action: ({ editor, event }) => {
|
|
3192
|
+
if (toggleTaskList) {
|
|
3193
|
+
toggleTaskList(editor.textarea);
|
|
3194
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3195
|
+
}
|
|
3196
|
+
}
|
|
3197
|
+
},
|
|
3198
|
+
quote: {
|
|
3199
|
+
name: "quote",
|
|
3200
|
+
icon: quoteIcon,
|
|
3201
|
+
title: "Quote",
|
|
3202
|
+
action: ({ editor, event }) => {
|
|
3203
|
+
toggleQuote(editor.textarea);
|
|
3204
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3205
|
+
}
|
|
3206
|
+
},
|
|
3207
|
+
viewMode: {
|
|
3208
|
+
name: "viewMode",
|
|
3209
|
+
icon: eyeIcon,
|
|
3210
|
+
title: "View mode"
|
|
3211
|
+
// Special: handled internally by Toolbar class as dropdown
|
|
3212
|
+
// No action property - dropdown behavior is internal
|
|
3213
|
+
}
|
|
3214
|
+
};
|
|
3215
|
+
var defaultToolbarButtons = [
|
|
3216
|
+
toolbarButtons.bold,
|
|
3217
|
+
toolbarButtons.italic,
|
|
3218
|
+
toolbarButtons.code,
|
|
3219
|
+
toolbarButtons.separator,
|
|
3220
|
+
toolbarButtons.link,
|
|
3221
|
+
toolbarButtons.separator,
|
|
3222
|
+
toolbarButtons.h1,
|
|
3223
|
+
toolbarButtons.h2,
|
|
3224
|
+
toolbarButtons.h3,
|
|
3225
|
+
toolbarButtons.separator,
|
|
3226
|
+
toolbarButtons.bulletList,
|
|
3227
|
+
toolbarButtons.orderedList,
|
|
3228
|
+
toolbarButtons.taskList,
|
|
3229
|
+
toolbarButtons.separator,
|
|
3230
|
+
toolbarButtons.quote,
|
|
3231
|
+
toolbarButtons.separator,
|
|
3232
|
+
toolbarButtons.viewMode
|
|
3233
|
+
];
|
|
3234
|
+
|
|
3039
3235
|
// src/overtype.js
|
|
3040
3236
|
var _OverType = class _OverType {
|
|
3041
3237
|
/**
|
|
@@ -3095,17 +3291,6 @@ var _OverType = class _OverType {
|
|
|
3095
3291
|
}
|
|
3096
3292
|
this.shortcuts = new ShortcutsManager(this);
|
|
3097
3293
|
this.linkTooltip = new LinkTooltip(this);
|
|
3098
|
-
if (this.options.toolbar) {
|
|
3099
|
-
const toolbarButtons = typeof this.options.toolbar === "object" ? this.options.toolbar.buttons : null;
|
|
3100
|
-
this.toolbar = new Toolbar(this, toolbarButtons);
|
|
3101
|
-
this.toolbar.create();
|
|
3102
|
-
this.textarea.addEventListener("selectionchange", () => {
|
|
3103
|
-
this.toolbar.updateButtonStates();
|
|
3104
|
-
});
|
|
3105
|
-
this.textarea.addEventListener("input", () => {
|
|
3106
|
-
this.toolbar.updateButtonStates();
|
|
3107
|
-
});
|
|
3108
|
-
}
|
|
3109
3294
|
this.initialized = true;
|
|
3110
3295
|
if (this.options.onChange) {
|
|
3111
3296
|
this.options.onChange(this.getValue(), this);
|
|
@@ -3149,9 +3334,13 @@ var _OverType = class _OverType {
|
|
|
3149
3334
|
showActiveLineRaw: false,
|
|
3150
3335
|
showStats: false,
|
|
3151
3336
|
toolbar: false,
|
|
3337
|
+
toolbarButtons: null,
|
|
3338
|
+
// Defaults to defaultToolbarButtons if toolbar: true
|
|
3152
3339
|
statsFormatter: null,
|
|
3153
|
-
smartLists: true
|
|
3340
|
+
smartLists: true,
|
|
3154
3341
|
// Enable smart list continuation
|
|
3342
|
+
codeHighlighter: null
|
|
3343
|
+
// Per-instance code highlighter
|
|
3155
3344
|
};
|
|
3156
3345
|
const { theme, colors, ...cleanOptions } = options;
|
|
3157
3346
|
return {
|
|
@@ -3327,6 +3516,41 @@ var _OverType = class _OverType {
|
|
|
3327
3516
|
this.textarea.setAttribute("data-gramm_editor", "false");
|
|
3328
3517
|
this.textarea.setAttribute("data-enable-grammarly", "false");
|
|
3329
3518
|
}
|
|
3519
|
+
/**
|
|
3520
|
+
* Create and setup toolbar
|
|
3521
|
+
* @private
|
|
3522
|
+
*/
|
|
3523
|
+
_createToolbar() {
|
|
3524
|
+
const toolbarButtons2 = this.options.toolbarButtons || defaultToolbarButtons;
|
|
3525
|
+
this.toolbar = new Toolbar(this, { toolbarButtons: toolbarButtons2 });
|
|
3526
|
+
this.toolbar.create();
|
|
3527
|
+
this._toolbarSelectionListener = () => {
|
|
3528
|
+
if (this.toolbar) {
|
|
3529
|
+
this.toolbar.updateButtonStates();
|
|
3530
|
+
}
|
|
3531
|
+
};
|
|
3532
|
+
this._toolbarInputListener = () => {
|
|
3533
|
+
if (this.toolbar) {
|
|
3534
|
+
this.toolbar.updateButtonStates();
|
|
3535
|
+
}
|
|
3536
|
+
};
|
|
3537
|
+
this.textarea.addEventListener("selectionchange", this._toolbarSelectionListener);
|
|
3538
|
+
this.textarea.addEventListener("input", this._toolbarInputListener);
|
|
3539
|
+
}
|
|
3540
|
+
/**
|
|
3541
|
+
* Cleanup toolbar event listeners
|
|
3542
|
+
* @private
|
|
3543
|
+
*/
|
|
3544
|
+
_cleanupToolbarListeners() {
|
|
3545
|
+
if (this._toolbarSelectionListener) {
|
|
3546
|
+
this.textarea.removeEventListener("selectionchange", this._toolbarSelectionListener);
|
|
3547
|
+
this._toolbarSelectionListener = null;
|
|
3548
|
+
}
|
|
3549
|
+
if (this._toolbarInputListener) {
|
|
3550
|
+
this.textarea.removeEventListener("input", this._toolbarInputListener);
|
|
3551
|
+
this._toolbarInputListener = null;
|
|
3552
|
+
}
|
|
3553
|
+
}
|
|
3330
3554
|
/**
|
|
3331
3555
|
* Apply options to the editor
|
|
3332
3556
|
* @private
|
|
@@ -3342,6 +3566,13 @@ var _OverType = class _OverType {
|
|
|
3342
3566
|
} else {
|
|
3343
3567
|
this.container.classList.remove("overtype-auto-resize");
|
|
3344
3568
|
}
|
|
3569
|
+
if (this.options.toolbar && !this.toolbar) {
|
|
3570
|
+
this._createToolbar();
|
|
3571
|
+
} else if (!this.options.toolbar && this.toolbar) {
|
|
3572
|
+
this._cleanupToolbarListeners();
|
|
3573
|
+
this.toolbar.destroy();
|
|
3574
|
+
this.toolbar = null;
|
|
3575
|
+
}
|
|
3345
3576
|
this.updatePreview();
|
|
3346
3577
|
}
|
|
3347
3578
|
/**
|
|
@@ -3351,7 +3582,8 @@ var _OverType = class _OverType {
|
|
|
3351
3582
|
const text = this.textarea.value;
|
|
3352
3583
|
const cursorPos = this.textarea.selectionStart;
|
|
3353
3584
|
const activeLine = this._getCurrentLine(text, cursorPos);
|
|
3354
|
-
const
|
|
3585
|
+
const isPreviewMode = this.container.dataset.mode === "preview";
|
|
3586
|
+
const html = MarkdownParser.parse(text, activeLine, this.options.showActiveLineRaw, this.options.codeHighlighter, isPreviewMode);
|
|
3355
3587
|
this.preview.innerHTML = html || '<span style="color: #808080;">Start typing...</span>';
|
|
3356
3588
|
this._applyCodeBlockBackgrounds();
|
|
3357
3589
|
if (this.options.showStats && this.statsBar) {
|
|
@@ -3585,7 +3817,7 @@ var _OverType = class _OverType {
|
|
|
3585
3817
|
*/
|
|
3586
3818
|
getRenderedHTML(options = {}) {
|
|
3587
3819
|
const markdown = this.getValue();
|
|
3588
|
-
let html = MarkdownParser.parse(markdown);
|
|
3820
|
+
let html = MarkdownParser.parse(markdown, -1, false, this.options.codeHighlighter);
|
|
3589
3821
|
if (options.cleanHTML) {
|
|
3590
3822
|
html = html.replace(/<span class="syntax-marker[^"]*">.*?<\/span>/g, "");
|
|
3591
3823
|
html = html.replace(/\sclass="(bullet-list|ordered-list|code-fence|hr-marker|blockquote|url-part)"/g, "");
|
|
@@ -3637,6 +3869,33 @@ var _OverType = class _OverType {
|
|
|
3637
3869
|
this._applyOptions();
|
|
3638
3870
|
this.updatePreview();
|
|
3639
3871
|
}
|
|
3872
|
+
/**
|
|
3873
|
+
* Set theme for this instance
|
|
3874
|
+
* @param {string|Object} theme - Theme name or custom theme object
|
|
3875
|
+
* @returns {this} Returns this for chaining
|
|
3876
|
+
*/
|
|
3877
|
+
setTheme(theme) {
|
|
3878
|
+
this.instanceTheme = theme;
|
|
3879
|
+
const themeObj = typeof theme === "string" ? getTheme(theme) : theme;
|
|
3880
|
+
const themeName = typeof themeObj === "string" ? themeObj : themeObj.name;
|
|
3881
|
+
if (themeName) {
|
|
3882
|
+
this.container.setAttribute("data-theme", themeName);
|
|
3883
|
+
}
|
|
3884
|
+
if (themeObj && themeObj.colors) {
|
|
3885
|
+
const cssVars = themeToCSSVars(themeObj.colors);
|
|
3886
|
+
this.container.style.cssText += cssVars;
|
|
3887
|
+
}
|
|
3888
|
+
this.updatePreview();
|
|
3889
|
+
return this;
|
|
3890
|
+
}
|
|
3891
|
+
/**
|
|
3892
|
+
* Set instance-specific code highlighter
|
|
3893
|
+
* @param {Function|null} highlighter - Function that takes (code, language) and returns highlighted HTML
|
|
3894
|
+
*/
|
|
3895
|
+
setCodeHighlighter(highlighter) {
|
|
3896
|
+
this.options.codeHighlighter = highlighter;
|
|
3897
|
+
this.updatePreview();
|
|
3898
|
+
}
|
|
3640
3899
|
/**
|
|
3641
3900
|
* Update stats bar
|
|
3642
3901
|
* @private
|
|
@@ -3739,37 +3998,39 @@ var _OverType = class _OverType {
|
|
|
3739
3998
|
}
|
|
3740
3999
|
}
|
|
3741
4000
|
/**
|
|
3742
|
-
* Show
|
|
3743
|
-
* @
|
|
3744
|
-
* @returns {boolean} Current plain textarea state
|
|
4001
|
+
* Show normal edit mode (overlay with markdown preview)
|
|
4002
|
+
* @returns {this} Returns this for chaining
|
|
3745
4003
|
*/
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
this.
|
|
3751
|
-
}
|
|
4004
|
+
showNormalEditMode() {
|
|
4005
|
+
this.container.dataset.mode = "normal";
|
|
4006
|
+
requestAnimationFrame(() => {
|
|
4007
|
+
this.textarea.scrollTop = this.preview.scrollTop;
|
|
4008
|
+
this.textarea.scrollLeft = this.preview.scrollLeft;
|
|
4009
|
+
});
|
|
4010
|
+
return this;
|
|
4011
|
+
}
|
|
4012
|
+
/**
|
|
4013
|
+
* Show plain textarea mode (no overlay)
|
|
4014
|
+
* @returns {this} Returns this for chaining
|
|
4015
|
+
*/
|
|
4016
|
+
showPlainTextarea() {
|
|
4017
|
+
this.container.dataset.mode = "plain";
|
|
3752
4018
|
if (this.toolbar) {
|
|
3753
4019
|
const toggleBtn = this.container.querySelector('[data-action="toggle-plain"]');
|
|
3754
4020
|
if (toggleBtn) {
|
|
3755
|
-
toggleBtn.classList.
|
|
3756
|
-
toggleBtn.title =
|
|
4021
|
+
toggleBtn.classList.remove("active");
|
|
4022
|
+
toggleBtn.title = "Show markdown preview";
|
|
3757
4023
|
}
|
|
3758
4024
|
}
|
|
3759
|
-
return
|
|
4025
|
+
return this;
|
|
3760
4026
|
}
|
|
3761
4027
|
/**
|
|
3762
|
-
* Show
|
|
3763
|
-
* @
|
|
3764
|
-
* @returns {boolean} Current preview mode state
|
|
4028
|
+
* Show preview mode (read-only view)
|
|
4029
|
+
* @returns {this} Returns this for chaining
|
|
3765
4030
|
*/
|
|
3766
|
-
showPreviewMode(
|
|
3767
|
-
|
|
3768
|
-
|
|
3769
|
-
} else {
|
|
3770
|
-
this.container.classList.remove("preview-mode");
|
|
3771
|
-
}
|
|
3772
|
-
return show;
|
|
4031
|
+
showPreviewMode() {
|
|
4032
|
+
this.container.dataset.mode = "preview";
|
|
4033
|
+
return this;
|
|
3773
4034
|
}
|
|
3774
4035
|
/**
|
|
3775
4036
|
* Destroy the editor instance
|
|
@@ -3849,16 +4110,16 @@ var _OverType = class _OverType {
|
|
|
3849
4110
|
_OverType.currentTheme = themeObj;
|
|
3850
4111
|
_OverType.injectStyles(true);
|
|
3851
4112
|
document.querySelectorAll(".overtype-container").forEach((container) => {
|
|
3852
|
-
const
|
|
3853
|
-
if (
|
|
3854
|
-
container.setAttribute("data-theme",
|
|
4113
|
+
const themeName2 = typeof themeObj === "string" ? themeObj : themeObj.name;
|
|
4114
|
+
if (themeName2) {
|
|
4115
|
+
container.setAttribute("data-theme", themeName2);
|
|
3855
4116
|
}
|
|
3856
4117
|
});
|
|
3857
4118
|
document.querySelectorAll(".overtype-wrapper").forEach((wrapper) => {
|
|
3858
4119
|
if (!wrapper.closest(".overtype-container")) {
|
|
3859
|
-
const
|
|
3860
|
-
if (
|
|
3861
|
-
wrapper.setAttribute("data-theme",
|
|
4120
|
+
const themeName2 = typeof themeObj === "string" ? themeObj : themeObj.name;
|
|
4121
|
+
if (themeName2) {
|
|
4122
|
+
wrapper.setAttribute("data-theme", themeName2);
|
|
3862
4123
|
}
|
|
3863
4124
|
}
|
|
3864
4125
|
const instance = wrapper._instance;
|
|
@@ -3866,6 +4127,36 @@ var _OverType = class _OverType {
|
|
|
3866
4127
|
instance.updatePreview();
|
|
3867
4128
|
}
|
|
3868
4129
|
});
|
|
4130
|
+
const themeName = typeof themeObj === "string" ? themeObj : themeObj.name;
|
|
4131
|
+
document.querySelectorAll("overtype-editor").forEach((webComponent) => {
|
|
4132
|
+
if (themeName && typeof webComponent.setAttribute === "function") {
|
|
4133
|
+
webComponent.setAttribute("theme", themeName);
|
|
4134
|
+
}
|
|
4135
|
+
if (typeof webComponent.refreshTheme === "function") {
|
|
4136
|
+
webComponent.refreshTheme();
|
|
4137
|
+
}
|
|
4138
|
+
});
|
|
4139
|
+
}
|
|
4140
|
+
/**
|
|
4141
|
+
* Set global code highlighter for all OverType instances
|
|
4142
|
+
* @param {Function|null} highlighter - Function that takes (code, language) and returns highlighted HTML
|
|
4143
|
+
*/
|
|
4144
|
+
static setCodeHighlighter(highlighter) {
|
|
4145
|
+
MarkdownParser.setCodeHighlighter(highlighter);
|
|
4146
|
+
document.querySelectorAll(".overtype-wrapper").forEach((wrapper) => {
|
|
4147
|
+
const instance = wrapper._instance;
|
|
4148
|
+
if (instance && instance.updatePreview) {
|
|
4149
|
+
instance.updatePreview();
|
|
4150
|
+
}
|
|
4151
|
+
});
|
|
4152
|
+
document.querySelectorAll("overtype-editor").forEach((webComponent) => {
|
|
4153
|
+
if (typeof webComponent.getEditor === "function") {
|
|
4154
|
+
const instance = webComponent.getEditor();
|
|
4155
|
+
if (instance && instance.updatePreview) {
|
|
4156
|
+
instance.updatePreview();
|
|
4157
|
+
}
|
|
4158
|
+
}
|
|
4159
|
+
});
|
|
3869
4160
|
}
|
|
3870
4161
|
/**
|
|
3871
4162
|
* Initialize global event listeners
|
|
@@ -3930,7 +4221,9 @@ OverType.currentTheme = solar;
|
|
|
3930
4221
|
var overtype_default = OverType;
|
|
3931
4222
|
// Annotate the CommonJS export names for ESM import in node:
|
|
3932
4223
|
0 && (module.exports = {
|
|
3933
|
-
OverType
|
|
4224
|
+
OverType,
|
|
4225
|
+
defaultToolbarButtons,
|
|
4226
|
+
toolbarButtons
|
|
3934
4227
|
});
|
|
3935
4228
|
/**
|
|
3936
4229
|
* OverType - A lightweight markdown editor library with perfect WYSIWYG alignment
|