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.esm.js
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
|
|
@@ -20,6 +20,13 @@ var MarkdownParser = class {
|
|
|
20
20
|
static resetLinkIndex() {
|
|
21
21
|
this.linkIndex = 0;
|
|
22
22
|
}
|
|
23
|
+
/**
|
|
24
|
+
* Set global code highlighter function
|
|
25
|
+
* @param {Function|null} highlighter - Function that takes (code, language) and returns highlighted HTML
|
|
26
|
+
*/
|
|
27
|
+
static setCodeHighlighter(highlighter) {
|
|
28
|
+
this.codeHighlighter = highlighter;
|
|
29
|
+
}
|
|
23
30
|
/**
|
|
24
31
|
* Escape HTML special characters
|
|
25
32
|
* @param {string} text - Raw text to escape
|
|
@@ -88,6 +95,22 @@ var MarkdownParser = class {
|
|
|
88
95
|
return `${indent}<li class="bullet-list"><span class="syntax-marker">${marker} </span>${content}</li>`;
|
|
89
96
|
});
|
|
90
97
|
}
|
|
98
|
+
/**
|
|
99
|
+
* Parse task lists (GitHub Flavored Markdown checkboxes)
|
|
100
|
+
* @param {string} html - HTML line to parse
|
|
101
|
+
* @param {boolean} isPreviewMode - Whether to render actual checkboxes (preview) or keep syntax visible (normal)
|
|
102
|
+
* @returns {string} Parsed task list item
|
|
103
|
+
*/
|
|
104
|
+
static parseTaskList(html, isPreviewMode = false) {
|
|
105
|
+
return html.replace(/^((?: )*)-\s+\[([ xX])\]\s+(.+)$/, (match, indent, checked, content) => {
|
|
106
|
+
if (isPreviewMode) {
|
|
107
|
+
const isChecked = checked.toLowerCase() === "x";
|
|
108
|
+
return `${indent}<li class="task-list"><input type="checkbox" disabled ${isChecked ? "checked" : ""}> ${content}</li>`;
|
|
109
|
+
} else {
|
|
110
|
+
return `${indent}<li class="task-list"><span class="syntax-marker">- [${checked}] </span>${content}</li>`;
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
}
|
|
91
114
|
/**
|
|
92
115
|
* Parse numbered lists
|
|
93
116
|
* @param {string} html - HTML line to parse
|
|
@@ -277,7 +300,7 @@ var MarkdownParser = class {
|
|
|
277
300
|
processedLinkText = this.parseItalic(processedLinkText);
|
|
278
301
|
const anchorName = `--link-${this.linkIndex++}`;
|
|
279
302
|
const safeUrl = this.sanitizeUrl(sanctuary.url);
|
|
280
|
-
replacement = `<a href="${safeUrl}" style="anchor-name: ${anchorName}"><span class="syntax-marker">[</span>${processedLinkText}<span class="syntax-marker url-part">](${
|
|
303
|
+
replacement = `<a href="${safeUrl}" style="anchor-name: ${anchorName}"><span class="syntax-marker">[</span>${processedLinkText}<span class="syntax-marker url-part">](${sanctuary.url})</span></a>`;
|
|
281
304
|
}
|
|
282
305
|
html = html.replace(placeholder, replacement);
|
|
283
306
|
});
|
|
@@ -302,7 +325,7 @@ var MarkdownParser = class {
|
|
|
302
325
|
* @param {string} line - Raw markdown line
|
|
303
326
|
* @returns {string} Parsed HTML line
|
|
304
327
|
*/
|
|
305
|
-
static parseLine(line) {
|
|
328
|
+
static parseLine(line, isPreviewMode = false) {
|
|
306
329
|
let html = this.escapeHtml(line);
|
|
307
330
|
html = this.preserveIndentation(html, line);
|
|
308
331
|
const horizontalRule = this.parseHorizontalRule(html);
|
|
@@ -313,6 +336,7 @@ var MarkdownParser = class {
|
|
|
313
336
|
return codeBlock;
|
|
314
337
|
html = this.parseHeader(html);
|
|
315
338
|
html = this.parseBlockquote(html);
|
|
339
|
+
html = this.parseTaskList(html, isPreviewMode);
|
|
316
340
|
html = this.parseBulletList(html);
|
|
317
341
|
html = this.parseNumberedList(html);
|
|
318
342
|
html = this.parseInlineElements(html);
|
|
@@ -326,9 +350,10 @@ var MarkdownParser = class {
|
|
|
326
350
|
* @param {string} text - Full markdown text
|
|
327
351
|
* @param {number} activeLine - Currently active line index (optional)
|
|
328
352
|
* @param {boolean} showActiveLineRaw - Show raw markdown on active line
|
|
353
|
+
* @param {Function} instanceHighlighter - Instance-specific code highlighter (optional, overrides global if provided)
|
|
329
354
|
* @returns {string} Parsed HTML
|
|
330
355
|
*/
|
|
331
|
-
static parse(text, activeLine = -1, showActiveLineRaw = false) {
|
|
356
|
+
static parse(text, activeLine = -1, showActiveLineRaw = false, instanceHighlighter, isPreviewMode = false) {
|
|
332
357
|
this.resetLinkIndex();
|
|
333
358
|
const lines = text.split("\n");
|
|
334
359
|
let inCodeBlock = false;
|
|
@@ -340,26 +365,27 @@ var MarkdownParser = class {
|
|
|
340
365
|
const codeFenceRegex = /^```[^`]*$/;
|
|
341
366
|
if (codeFenceRegex.test(line)) {
|
|
342
367
|
inCodeBlock = !inCodeBlock;
|
|
343
|
-
return this.parseLine(line);
|
|
368
|
+
return this.parseLine(line, isPreviewMode);
|
|
344
369
|
}
|
|
345
370
|
if (inCodeBlock) {
|
|
346
371
|
const escaped = this.escapeHtml(line);
|
|
347
372
|
const indented = this.preserveIndentation(escaped, line);
|
|
348
373
|
return `<div>${indented || " "}</div>`;
|
|
349
374
|
}
|
|
350
|
-
return this.parseLine(line);
|
|
375
|
+
return this.parseLine(line, isPreviewMode);
|
|
351
376
|
});
|
|
352
377
|
const html = parsedLines.join("");
|
|
353
|
-
return this.postProcessHTML(html);
|
|
378
|
+
return this.postProcessHTML(html, instanceHighlighter);
|
|
354
379
|
}
|
|
355
380
|
/**
|
|
356
381
|
* Post-process HTML to consolidate lists and code blocks
|
|
357
382
|
* @param {string} html - HTML to post-process
|
|
383
|
+
* @param {Function} instanceHighlighter - Instance-specific code highlighter (optional, overrides global if provided)
|
|
358
384
|
* @returns {string} Post-processed HTML with consolidated lists and code blocks
|
|
359
385
|
*/
|
|
360
|
-
static postProcessHTML(html) {
|
|
386
|
+
static postProcessHTML(html, instanceHighlighter) {
|
|
361
387
|
if (typeof document === "undefined" || !document) {
|
|
362
|
-
return this.postProcessHTMLManual(html);
|
|
388
|
+
return this.postProcessHTMLManual(html, instanceHighlighter);
|
|
363
389
|
}
|
|
364
390
|
const container = document.createElement("div");
|
|
365
391
|
container.innerHTML = html;
|
|
@@ -388,8 +414,28 @@ var MarkdownParser = class {
|
|
|
388
414
|
}
|
|
389
415
|
container.insertBefore(currentCodeBlock, child.nextSibling);
|
|
390
416
|
currentCodeBlock._codeElement = codeElement;
|
|
417
|
+
currentCodeBlock._language = lang;
|
|
418
|
+
currentCodeBlock._codeContent = "";
|
|
391
419
|
continue;
|
|
392
420
|
} else {
|
|
421
|
+
const highlighter = instanceHighlighter || this.codeHighlighter;
|
|
422
|
+
if (currentCodeBlock && highlighter && currentCodeBlock._codeContent) {
|
|
423
|
+
try {
|
|
424
|
+
const result = highlighter(
|
|
425
|
+
currentCodeBlock._codeContent,
|
|
426
|
+
currentCodeBlock._language || ""
|
|
427
|
+
);
|
|
428
|
+
if (result && typeof result.then === "function") {
|
|
429
|
+
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.");
|
|
430
|
+
} else {
|
|
431
|
+
if (result && typeof result === "string" && result.trim()) {
|
|
432
|
+
currentCodeBlock._codeElement.innerHTML = result;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
} catch (error) {
|
|
436
|
+
console.warn("Code highlighting failed:", error);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
393
439
|
inCodeBlock = false;
|
|
394
440
|
currentCodeBlock = null;
|
|
395
441
|
continue;
|
|
@@ -398,10 +444,14 @@ var MarkdownParser = class {
|
|
|
398
444
|
}
|
|
399
445
|
if (inCodeBlock && currentCodeBlock && child.tagName === "DIV" && !child.querySelector(".code-fence")) {
|
|
400
446
|
const codeElement = currentCodeBlock._codeElement || currentCodeBlock.querySelector("code");
|
|
447
|
+
if (currentCodeBlock._codeContent.length > 0) {
|
|
448
|
+
currentCodeBlock._codeContent += "\n";
|
|
449
|
+
}
|
|
450
|
+
const lineText = child.textContent.replace(/\u00A0/g, " ");
|
|
451
|
+
currentCodeBlock._codeContent += lineText;
|
|
401
452
|
if (codeElement.textContent.length > 0) {
|
|
402
453
|
codeElement.textContent += "\n";
|
|
403
454
|
}
|
|
404
|
-
const lineText = child.textContent.replace(/\u00A0/g, " ");
|
|
405
455
|
codeElement.textContent += lineText;
|
|
406
456
|
child.remove();
|
|
407
457
|
continue;
|
|
@@ -447,9 +497,10 @@ var MarkdownParser = class {
|
|
|
447
497
|
/**
|
|
448
498
|
* Manual post-processing for Node.js environments (without DOM)
|
|
449
499
|
* @param {string} html - HTML to post-process
|
|
500
|
+
* @param {Function} instanceHighlighter - Instance-specific code highlighter (optional, overrides global if provided)
|
|
450
501
|
* @returns {string} Post-processed HTML
|
|
451
502
|
*/
|
|
452
|
-
static postProcessHTMLManual(html) {
|
|
503
|
+
static postProcessHTMLManual(html, instanceHighlighter) {
|
|
453
504
|
let processed = html;
|
|
454
505
|
processed = processed.replace(/((?:<div>(?: )*<li class="bullet-list">.*?<\/li><\/div>\s*)+)/gs, (match) => {
|
|
455
506
|
const divs = match.match(/<div>(?: )*<li class="bullet-list">.*?<\/li><\/div>/gs) || [];
|
|
@@ -494,8 +545,25 @@ var MarkdownParser = class {
|
|
|
494
545
|
}).join("\n");
|
|
495
546
|
const lang = openFence.slice(3).trim();
|
|
496
547
|
const langClass = lang ? ` class="language-${lang}"` : "";
|
|
548
|
+
let highlightedContent = codeContent;
|
|
549
|
+
const highlighter = instanceHighlighter || this.codeHighlighter;
|
|
550
|
+
if (highlighter) {
|
|
551
|
+
try {
|
|
552
|
+
const decodedCode = codeContent.replace(/"/g, '"').replace(/'/g, "'").replace(/</g, "<").replace(/>/g, ">").replace(/&/g, "&");
|
|
553
|
+
const result2 = highlighter(decodedCode, lang);
|
|
554
|
+
if (result2 && typeof result2.then === "function") {
|
|
555
|
+
console.warn("Async highlighters are not supported in Node.js (non-DOM) context. Use synchronous highlighters for server-side rendering.");
|
|
556
|
+
} else {
|
|
557
|
+
if (result2 && typeof result2 === "string" && result2.trim()) {
|
|
558
|
+
highlightedContent = result2;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
} catch (error) {
|
|
562
|
+
console.warn("Code highlighting failed:", error);
|
|
563
|
+
}
|
|
564
|
+
}
|
|
497
565
|
let result = `<div><span class="code-fence">${openFence}</span></div>`;
|
|
498
|
-
result += `<pre class="code-block"><code${langClass}>${
|
|
566
|
+
result += `<pre class="code-block"><code${langClass}>${highlightedContent}</code></pre>`;
|
|
499
567
|
result += `<div><span class="code-fence">${closeFence}</span></div>`;
|
|
500
568
|
return result;
|
|
501
569
|
});
|
|
@@ -634,6 +702,8 @@ var MarkdownParser = class {
|
|
|
634
702
|
};
|
|
635
703
|
// Track link index for anchor naming
|
|
636
704
|
__publicField(MarkdownParser, "linkIndex", 0);
|
|
705
|
+
// Global code highlighter function
|
|
706
|
+
__publicField(MarkdownParser, "codeHighlighter", null);
|
|
637
707
|
/**
|
|
638
708
|
* List pattern definitions
|
|
639
709
|
*/
|
|
@@ -2053,12 +2123,14 @@ function generateStyles(options = {}) {
|
|
|
2053
2123
|
/* Code block styling in normal mode - yellow background */
|
|
2054
2124
|
.overtype-wrapper .overtype-preview pre.code-block {
|
|
2055
2125
|
background: var(--code-bg, rgba(244, 211, 94, 0.4)) !important;
|
|
2126
|
+
white-space: break-spaces !important; /* Prevent horizontal scrollbar that breaks alignment */
|
|
2056
2127
|
}
|
|
2057
2128
|
|
|
2058
2129
|
/* Code inside pre blocks - remove background */
|
|
2059
2130
|
.overtype-wrapper .overtype-preview pre code {
|
|
2060
2131
|
background: transparent !important;
|
|
2061
2132
|
color: var(--code, #0d3b66) !important;
|
|
2133
|
+
font-family: ${fontFamily} !important; /* Match textarea font exactly for alignment */
|
|
2062
2134
|
}
|
|
2063
2135
|
|
|
2064
2136
|
/* Blockquotes */
|
|
@@ -2285,11 +2357,11 @@ function generateStyles(options = {}) {
|
|
|
2285
2357
|
}
|
|
2286
2358
|
|
|
2287
2359
|
/* Plain mode - hide preview and show textarea text */
|
|
2288
|
-
.overtype-container
|
|
2360
|
+
.overtype-container[data-mode="plain"] .overtype-preview {
|
|
2289
2361
|
display: none !important;
|
|
2290
2362
|
}
|
|
2291
2363
|
|
|
2292
|
-
.overtype-container
|
|
2364
|
+
.overtype-container[data-mode="plain"] .overtype-input {
|
|
2293
2365
|
color: var(--text, #0d3b66) !important;
|
|
2294
2366
|
/* Use system font stack for better plain text readability */
|
|
2295
2367
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
|
@@ -2297,7 +2369,7 @@ function generateStyles(options = {}) {
|
|
|
2297
2369
|
}
|
|
2298
2370
|
|
|
2299
2371
|
/* Ensure textarea remains transparent in overlay mode */
|
|
2300
|
-
.overtype-container:not(
|
|
2372
|
+
.overtype-container:not([data-mode="plain"]) .overtype-input {
|
|
2301
2373
|
color: transparent !important;
|
|
2302
2374
|
}
|
|
2303
2375
|
|
|
@@ -2350,37 +2422,43 @@ function generateStyles(options = {}) {
|
|
|
2350
2422
|
color: var(--h1, #007bff);
|
|
2351
2423
|
}
|
|
2352
2424
|
|
|
2425
|
+
.overtype-dropdown-icon {
|
|
2426
|
+
width: 20px;
|
|
2427
|
+
margin-right: 8px;
|
|
2428
|
+
text-align: center;
|
|
2429
|
+
}
|
|
2430
|
+
|
|
2353
2431
|
/* Preview mode styles */
|
|
2354
|
-
.overtype-container
|
|
2432
|
+
.overtype-container[data-mode="preview"] .overtype-input {
|
|
2355
2433
|
display: none !important;
|
|
2356
2434
|
}
|
|
2357
2435
|
|
|
2358
|
-
.overtype-container
|
|
2436
|
+
.overtype-container[data-mode="preview"] .overtype-preview {
|
|
2359
2437
|
pointer-events: auto !important;
|
|
2360
2438
|
user-select: text !important;
|
|
2361
2439
|
cursor: text !important;
|
|
2362
2440
|
}
|
|
2363
2441
|
|
|
2364
2442
|
/* Hide syntax markers in preview mode */
|
|
2365
|
-
.overtype-container
|
|
2443
|
+
.overtype-container[data-mode="preview"] .syntax-marker {
|
|
2366
2444
|
display: none !important;
|
|
2367
2445
|
}
|
|
2368
2446
|
|
|
2369
2447
|
/* Hide URL part of links in preview mode - extra specificity */
|
|
2370
|
-
.overtype-container
|
|
2371
|
-
.overtype-container
|
|
2448
|
+
.overtype-container[data-mode="preview"] .syntax-marker.url-part,
|
|
2449
|
+
.overtype-container[data-mode="preview"] .url-part {
|
|
2372
2450
|
display: none !important;
|
|
2373
2451
|
}
|
|
2374
2452
|
|
|
2375
2453
|
/* Hide all syntax markers inside links too */
|
|
2376
|
-
.overtype-container
|
|
2454
|
+
.overtype-container[data-mode="preview"] a .syntax-marker {
|
|
2377
2455
|
display: none !important;
|
|
2378
2456
|
}
|
|
2379
2457
|
|
|
2380
2458
|
/* Headers - restore proper sizing in preview mode */
|
|
2381
|
-
.overtype-container
|
|
2382
|
-
.overtype-container
|
|
2383
|
-
.overtype-container
|
|
2459
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h1,
|
|
2460
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h2,
|
|
2461
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h3 {
|
|
2384
2462
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
|
|
2385
2463
|
font-weight: 600 !important;
|
|
2386
2464
|
margin: 0 !important;
|
|
@@ -2389,41 +2467,63 @@ function generateStyles(options = {}) {
|
|
|
2389
2467
|
line-height: 1 !important; /* Tight line height for headings */
|
|
2390
2468
|
}
|
|
2391
2469
|
|
|
2392
|
-
.overtype-container
|
|
2470
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h1 {
|
|
2393
2471
|
font-size: 2em !important;
|
|
2394
2472
|
}
|
|
2395
2473
|
|
|
2396
|
-
.overtype-container
|
|
2474
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h2 {
|
|
2397
2475
|
font-size: 1.5em !important;
|
|
2398
2476
|
}
|
|
2399
2477
|
|
|
2400
|
-
.overtype-container
|
|
2478
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview h3 {
|
|
2401
2479
|
font-size: 1.17em !important;
|
|
2402
2480
|
}
|
|
2403
2481
|
|
|
2404
2482
|
/* Lists - restore list styling in preview mode */
|
|
2405
|
-
.overtype-container
|
|
2483
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview ul {
|
|
2406
2484
|
display: block !important;
|
|
2407
2485
|
list-style: disc !important;
|
|
2408
2486
|
padding-left: 2em !important;
|
|
2409
2487
|
margin: 1em 0 !important;
|
|
2410
2488
|
}
|
|
2411
2489
|
|
|
2412
|
-
.overtype-container
|
|
2490
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview ol {
|
|
2413
2491
|
display: block !important;
|
|
2414
2492
|
list-style: decimal !important;
|
|
2415
2493
|
padding-left: 2em !important;
|
|
2416
2494
|
margin: 1em 0 !important;
|
|
2417
2495
|
}
|
|
2418
2496
|
|
|
2419
|
-
.overtype-container
|
|
2497
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview li {
|
|
2420
2498
|
display: list-item !important;
|
|
2421
2499
|
margin: 0 !important;
|
|
2422
2500
|
padding: 0 !important;
|
|
2423
2501
|
}
|
|
2424
2502
|
|
|
2503
|
+
/* Task list checkboxes - only in preview mode */
|
|
2504
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview li.task-list {
|
|
2505
|
+
list-style: none !important;
|
|
2506
|
+
position: relative !important;
|
|
2507
|
+
}
|
|
2508
|
+
|
|
2509
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview li.task-list input[type="checkbox"] {
|
|
2510
|
+
margin-right: 0.5em !important;
|
|
2511
|
+
cursor: default !important;
|
|
2512
|
+
vertical-align: middle !important;
|
|
2513
|
+
}
|
|
2514
|
+
|
|
2515
|
+
/* Task list in normal mode - keep syntax visible */
|
|
2516
|
+
.overtype-container:not([data-mode="preview"]) .overtype-wrapper .overtype-preview li.task-list {
|
|
2517
|
+
list-style: none !important;
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
.overtype-container:not([data-mode="preview"]) .overtype-wrapper .overtype-preview li.task-list .syntax-marker {
|
|
2521
|
+
color: var(--syntax, #999999) !important;
|
|
2522
|
+
font-weight: normal !important;
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2425
2525
|
/* Links - make clickable in preview mode */
|
|
2426
|
-
.overtype-container
|
|
2526
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview a {
|
|
2427
2527
|
pointer-events: auto !important;
|
|
2428
2528
|
cursor: pointer !important;
|
|
2429
2529
|
color: var(--link, #0066cc) !important;
|
|
@@ -2431,7 +2531,7 @@ function generateStyles(options = {}) {
|
|
|
2431
2531
|
}
|
|
2432
2532
|
|
|
2433
2533
|
/* Code blocks - proper pre/code styling in preview mode */
|
|
2434
|
-
.overtype-container
|
|
2534
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview pre.code-block {
|
|
2435
2535
|
background: #2d2d2d !important;
|
|
2436
2536
|
color: #f8f8f2 !important;
|
|
2437
2537
|
padding: 1.2em !important;
|
|
@@ -2442,11 +2542,11 @@ function generateStyles(options = {}) {
|
|
|
2442
2542
|
}
|
|
2443
2543
|
|
|
2444
2544
|
/* Cave theme code block background in preview mode */
|
|
2445
|
-
.overtype-container[data-theme="cave"]
|
|
2545
|
+
.overtype-container[data-theme="cave"][data-mode="preview"] .overtype-wrapper .overtype-preview pre.code-block {
|
|
2446
2546
|
background: #11171F !important;
|
|
2447
2547
|
}
|
|
2448
2548
|
|
|
2449
|
-
.overtype-container
|
|
2549
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview pre.code-block code {
|
|
2450
2550
|
background: transparent !important;
|
|
2451
2551
|
color: inherit !important;
|
|
2452
2552
|
padding: 0 !important;
|
|
@@ -2456,16 +2556,16 @@ function generateStyles(options = {}) {
|
|
|
2456
2556
|
}
|
|
2457
2557
|
|
|
2458
2558
|
/* Hide old code block lines and fences in preview mode */
|
|
2459
|
-
.overtype-container
|
|
2559
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview .code-block-line {
|
|
2460
2560
|
display: none !important;
|
|
2461
2561
|
}
|
|
2462
2562
|
|
|
2463
|
-
.overtype-container
|
|
2563
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview .code-fence {
|
|
2464
2564
|
display: none !important;
|
|
2465
2565
|
}
|
|
2466
2566
|
|
|
2467
2567
|
/* Blockquotes - enhanced styling in preview mode */
|
|
2468
|
-
.overtype-container
|
|
2568
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview .blockquote {
|
|
2469
2569
|
display: block !important;
|
|
2470
2570
|
border-left: 4px solid var(--blockquote, #ddd) !important;
|
|
2471
2571
|
padding-left: 1em !important;
|
|
@@ -2474,7 +2574,7 @@ function generateStyles(options = {}) {
|
|
|
2474
2574
|
}
|
|
2475
2575
|
|
|
2476
2576
|
/* Typography improvements in preview mode */
|
|
2477
|
-
.overtype-container
|
|
2577
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview {
|
|
2478
2578
|
font-family: Georgia, 'Times New Roman', serif !important;
|
|
2479
2579
|
font-size: 16px !important;
|
|
2480
2580
|
line-height: 1.8 !important;
|
|
@@ -2482,7 +2582,7 @@ function generateStyles(options = {}) {
|
|
|
2482
2582
|
}
|
|
2483
2583
|
|
|
2484
2584
|
/* Inline code in preview mode - keep monospace */
|
|
2485
|
-
.overtype-container
|
|
2585
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview code {
|
|
2486
2586
|
font-family: ${fontFamily} !important;
|
|
2487
2587
|
font-size: 0.9em !important;
|
|
2488
2588
|
background: rgba(135, 131, 120, 0.15) !important;
|
|
@@ -2491,236 +2591,243 @@ function generateStyles(options = {}) {
|
|
|
2491
2591
|
}
|
|
2492
2592
|
|
|
2493
2593
|
/* Strong and em elements in preview mode */
|
|
2494
|
-
.overtype-container
|
|
2594
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview strong {
|
|
2495
2595
|
font-weight: 700 !important;
|
|
2496
2596
|
color: inherit !important; /* Use parent text color */
|
|
2497
2597
|
}
|
|
2498
2598
|
|
|
2499
|
-
.overtype-container
|
|
2599
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview em {
|
|
2500
2600
|
font-style: italic !important;
|
|
2501
2601
|
color: inherit !important; /* Use parent text color */
|
|
2502
2602
|
}
|
|
2503
2603
|
|
|
2504
2604
|
/* HR in preview mode */
|
|
2505
|
-
.overtype-container
|
|
2605
|
+
.overtype-container[data-mode="preview"] .overtype-wrapper .overtype-preview .hr-marker {
|
|
2506
2606
|
display: block !important;
|
|
2507
2607
|
border-top: 2px solid var(--hr, #ddd) !important;
|
|
2508
2608
|
text-indent: -9999px !important;
|
|
2509
2609
|
height: 2px !important;
|
|
2510
2610
|
}
|
|
2511
2611
|
|
|
2612
|
+
/* Link Tooltip - CSS Anchor Positioning */
|
|
2613
|
+
@supports (position-anchor: --x) and (position-area: center) {
|
|
2614
|
+
.overtype-link-tooltip {
|
|
2615
|
+
position: absolute;
|
|
2616
|
+
position-anchor: var(--target-anchor, --link-0);
|
|
2617
|
+
position-area: block-end center;
|
|
2618
|
+
margin-top: 8px !important;
|
|
2619
|
+
|
|
2620
|
+
background: #333 !important;
|
|
2621
|
+
color: white !important;
|
|
2622
|
+
padding: 6px 10px !important;
|
|
2623
|
+
border-radius: 16px !important;
|
|
2624
|
+
font-size: 12px !important;
|
|
2625
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
|
|
2626
|
+
display: none !important;
|
|
2627
|
+
z-index: 10000 !important;
|
|
2628
|
+
cursor: pointer !important;
|
|
2629
|
+
box-shadow: 0 2px 8px rgba(0,0,0,0.3) !important;
|
|
2630
|
+
max-width: 300px !important;
|
|
2631
|
+
white-space: nowrap !important;
|
|
2632
|
+
overflow: hidden !important;
|
|
2633
|
+
text-overflow: ellipsis !important;
|
|
2634
|
+
|
|
2635
|
+
position-try: most-width block-end inline-end, flip-inline, block-start center;
|
|
2636
|
+
position-visibility: anchors-visible;
|
|
2637
|
+
}
|
|
2638
|
+
|
|
2639
|
+
.overtype-link-tooltip.visible {
|
|
2640
|
+
display: flex !important;
|
|
2641
|
+
}
|
|
2642
|
+
}
|
|
2643
|
+
|
|
2512
2644
|
${mobileStyles}
|
|
2513
2645
|
`;
|
|
2514
2646
|
}
|
|
2515
2647
|
|
|
2516
|
-
// src/icons.js
|
|
2517
|
-
var boldIcon = `<svg viewBox="0 0 18 18">
|
|
2518
|
-
<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>
|
|
2519
|
-
<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>
|
|
2520
|
-
</svg>`;
|
|
2521
|
-
var italicIcon = `<svg viewBox="0 0 18 18">
|
|
2522
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="13" y1="4" y2="4"></line>
|
|
2523
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="5" x2="11" y1="14" y2="14"></line>
|
|
2524
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="10" y1="14" y2="4"></line>
|
|
2525
|
-
</svg>`;
|
|
2526
|
-
var h1Icon = `<svg viewBox="0 0 18 18">
|
|
2527
|
-
<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>
|
|
2528
|
-
</svg>`;
|
|
2529
|
-
var h2Icon = `<svg viewBox="0 0 18 18">
|
|
2530
|
-
<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>
|
|
2531
|
-
</svg>`;
|
|
2532
|
-
var h3Icon = `<svg viewBox="0 0 18 18">
|
|
2533
|
-
<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>
|
|
2534
|
-
</svg>`;
|
|
2535
|
-
var linkIcon = `<svg viewBox="0 0 18 18">
|
|
2536
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="11" y1="7" y2="11"></line>
|
|
2537
|
-
<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>
|
|
2538
|
-
<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>
|
|
2539
|
-
</svg>`;
|
|
2540
|
-
var codeIcon = `<svg viewBox="0 0 18 18">
|
|
2541
|
-
<polyline stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" points="5 7 3 9 5 11"></polyline>
|
|
2542
|
-
<polyline stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" points="13 7 15 9 13 11"></polyline>
|
|
2543
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="10" x2="8" y1="5" y2="13"></line>
|
|
2544
|
-
</svg>`;
|
|
2545
|
-
var bulletListIcon = `<svg viewBox="0 0 18 18">
|
|
2546
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="6" x2="15" y1="4" y2="4"></line>
|
|
2547
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="6" x2="15" y1="9" y2="9"></line>
|
|
2548
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="6" x2="15" y1="14" y2="14"></line>
|
|
2549
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="3" x2="3" y1="4" y2="4"></line>
|
|
2550
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="3" x2="3" y1="9" y2="9"></line>
|
|
2551
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="3" x2="3" y1="14" y2="14"></line>
|
|
2552
|
-
</svg>`;
|
|
2553
|
-
var orderedListIcon = `<svg viewBox="0 0 18 18">
|
|
2554
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="15" y1="4" y2="4"></line>
|
|
2555
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="15" y1="9" y2="9"></line>
|
|
2556
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="15" y1="14" y2="14"></line>
|
|
2557
|
-
<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>
|
|
2558
|
-
<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>
|
|
2559
|
-
<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>
|
|
2560
|
-
<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>
|
|
2561
|
-
</svg>`;
|
|
2562
|
-
var quoteIcon = `<svg viewBox="2 2 20 20">
|
|
2563
|
-
<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>
|
|
2564
|
-
<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>
|
|
2565
|
-
</svg>`;
|
|
2566
|
-
var taskListIcon = `<svg viewBox="0 0 18 18">
|
|
2567
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="16" y1="4" y2="4"></line>
|
|
2568
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="16" y1="9" y2="9"></line>
|
|
2569
|
-
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="16" y1="14" y2="14"></line>
|
|
2570
|
-
<rect stroke="currentColor" fill="none" stroke-width="1.5" x="2" y="3" width="3" height="3" rx="0.5"></rect>
|
|
2571
|
-
<rect stroke="currentColor" fill="none" stroke-width="1.5" x="2" y="13" width="3" height="3" rx="0.5"></rect>
|
|
2572
|
-
<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>
|
|
2573
|
-
</svg>`;
|
|
2574
|
-
var eyeIcon = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
2575
|
-
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" fill="none"></path>
|
|
2576
|
-
<circle cx="12" cy="12" r="3" fill="none"></circle>
|
|
2577
|
-
</svg>`;
|
|
2578
|
-
|
|
2579
2648
|
// src/toolbar.js
|
|
2580
2649
|
var Toolbar = class {
|
|
2581
|
-
constructor(editor,
|
|
2650
|
+
constructor(editor, options = {}) {
|
|
2582
2651
|
this.editor = editor;
|
|
2583
2652
|
this.container = null;
|
|
2584
2653
|
this.buttons = {};
|
|
2585
|
-
this.
|
|
2654
|
+
this.toolbarButtons = options.toolbarButtons || [];
|
|
2586
2655
|
}
|
|
2587
2656
|
/**
|
|
2588
|
-
* Create and
|
|
2657
|
+
* Create and render toolbar
|
|
2589
2658
|
*/
|
|
2590
2659
|
create() {
|
|
2591
|
-
var _a;
|
|
2592
2660
|
this.container = document.createElement("div");
|
|
2593
2661
|
this.container.className = "overtype-toolbar";
|
|
2594
2662
|
this.container.setAttribute("role", "toolbar");
|
|
2595
|
-
this.container.setAttribute("aria-label", "
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
{ separator: true },
|
|
2600
|
-
{ name: "h1", icon: h1Icon, title: "Heading 1", action: "insertH1" },
|
|
2601
|
-
{ name: "h2", icon: h2Icon, title: "Heading 2", action: "insertH2" },
|
|
2602
|
-
{ name: "h3", icon: h3Icon, title: "Heading 3", action: "insertH3" },
|
|
2603
|
-
{ separator: true },
|
|
2604
|
-
{ name: "link", icon: linkIcon, title: "Insert Link (Ctrl+K)", action: "insertLink" },
|
|
2605
|
-
{ name: "code", icon: codeIcon, title: "Code (Ctrl+`)", action: "toggleCode" },
|
|
2606
|
-
{ separator: true },
|
|
2607
|
-
{ name: "quote", icon: quoteIcon, title: "Quote", action: "toggleQuote" },
|
|
2608
|
-
{ separator: true },
|
|
2609
|
-
{ name: "bulletList", icon: bulletListIcon, title: "Bullet List", action: "toggleBulletList" },
|
|
2610
|
-
{ name: "orderedList", icon: orderedListIcon, title: "Numbered List", action: "toggleNumberedList" },
|
|
2611
|
-
{ name: "taskList", icon: taskListIcon, title: "Task List", action: "toggleTaskList" },
|
|
2612
|
-
{ separator: true },
|
|
2613
|
-
{ name: "viewMode", icon: eyeIcon, title: "View mode", action: "toggle-view-menu", hasDropdown: true }
|
|
2614
|
-
];
|
|
2615
|
-
buttonConfig.forEach((config) => {
|
|
2616
|
-
if (config.separator) {
|
|
2617
|
-
const separator = document.createElement("div");
|
|
2618
|
-
separator.className = "overtype-toolbar-separator";
|
|
2619
|
-
separator.setAttribute("role", "separator");
|
|
2663
|
+
this.container.setAttribute("aria-label", "Formatting toolbar");
|
|
2664
|
+
this.toolbarButtons.forEach((buttonConfig) => {
|
|
2665
|
+
if (buttonConfig.name === "separator") {
|
|
2666
|
+
const separator = this.createSeparator();
|
|
2620
2667
|
this.container.appendChild(separator);
|
|
2621
2668
|
} else {
|
|
2622
|
-
const button = this.createButton(
|
|
2623
|
-
this.buttons[
|
|
2669
|
+
const button = this.createButton(buttonConfig);
|
|
2670
|
+
this.buttons[buttonConfig.name] = button;
|
|
2624
2671
|
this.container.appendChild(button);
|
|
2625
2672
|
}
|
|
2626
2673
|
});
|
|
2627
|
-
|
|
2628
|
-
const wrapper = this.editor.element.querySelector(".overtype-wrapper");
|
|
2629
|
-
if (container && wrapper) {
|
|
2630
|
-
container.insertBefore(this.container, wrapper);
|
|
2631
|
-
}
|
|
2632
|
-
return this.container;
|
|
2674
|
+
this.editor.wrapper.insertBefore(this.container, this.editor.wrapper.firstChild);
|
|
2633
2675
|
}
|
|
2634
2676
|
/**
|
|
2635
|
-
* Create
|
|
2677
|
+
* Create a toolbar separator
|
|
2636
2678
|
*/
|
|
2637
|
-
|
|
2679
|
+
createSeparator() {
|
|
2680
|
+
const separator = document.createElement("div");
|
|
2681
|
+
separator.className = "overtype-toolbar-separator";
|
|
2682
|
+
separator.setAttribute("role", "separator");
|
|
2683
|
+
return separator;
|
|
2684
|
+
}
|
|
2685
|
+
/**
|
|
2686
|
+
* Create a toolbar button
|
|
2687
|
+
*/
|
|
2688
|
+
createButton(buttonConfig) {
|
|
2638
2689
|
const button = document.createElement("button");
|
|
2639
2690
|
button.className = "overtype-toolbar-button";
|
|
2640
2691
|
button.type = "button";
|
|
2641
|
-
button.
|
|
2642
|
-
button.
|
|
2643
|
-
button.setAttribute("
|
|
2644
|
-
button.innerHTML =
|
|
2645
|
-
if (
|
|
2692
|
+
button.setAttribute("data-button", buttonConfig.name);
|
|
2693
|
+
button.title = buttonConfig.title || "";
|
|
2694
|
+
button.setAttribute("aria-label", buttonConfig.title || buttonConfig.name);
|
|
2695
|
+
button.innerHTML = this.sanitizeSVG(buttonConfig.icon || "");
|
|
2696
|
+
if (buttonConfig.name === "viewMode") {
|
|
2646
2697
|
button.classList.add("has-dropdown");
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2698
|
+
button.dataset.dropdown = "true";
|
|
2699
|
+
button.addEventListener("click", (e) => {
|
|
2700
|
+
e.preventDefault();
|
|
2701
|
+
this.toggleViewModeDropdown(button);
|
|
2702
|
+
});
|
|
2703
|
+
return button;
|
|
2650
2704
|
}
|
|
2651
|
-
button.
|
|
2705
|
+
button._clickHandler = async (e) => {
|
|
2652
2706
|
e.preventDefault();
|
|
2653
|
-
this.
|
|
2654
|
-
|
|
2707
|
+
this.editor.textarea.focus();
|
|
2708
|
+
try {
|
|
2709
|
+
if (buttonConfig.action) {
|
|
2710
|
+
await buttonConfig.action({
|
|
2711
|
+
editor: this.editor,
|
|
2712
|
+
getValue: () => this.editor.getValue(),
|
|
2713
|
+
setValue: (value) => this.editor.setValue(value),
|
|
2714
|
+
event: e
|
|
2715
|
+
});
|
|
2716
|
+
}
|
|
2717
|
+
} catch (error) {
|
|
2718
|
+
console.error(`Button "${buttonConfig.name}" error:`, error);
|
|
2719
|
+
this.editor.wrapper.dispatchEvent(new CustomEvent("button-error", {
|
|
2720
|
+
detail: { buttonName: buttonConfig.name, error }
|
|
2721
|
+
}));
|
|
2722
|
+
button.classList.add("button-error");
|
|
2723
|
+
button.style.animation = "buttonError 0.3s";
|
|
2724
|
+
setTimeout(() => {
|
|
2725
|
+
button.classList.remove("button-error");
|
|
2726
|
+
button.style.animation = "";
|
|
2727
|
+
}, 300);
|
|
2728
|
+
}
|
|
2729
|
+
};
|
|
2730
|
+
button.addEventListener("click", button._clickHandler);
|
|
2655
2731
|
return button;
|
|
2656
2732
|
}
|
|
2657
2733
|
/**
|
|
2658
|
-
*
|
|
2734
|
+
* Sanitize SVG to prevent XSS
|
|
2659
2735
|
*/
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2736
|
+
sanitizeSVG(svg) {
|
|
2737
|
+
if (typeof svg !== "string")
|
|
2738
|
+
return "";
|
|
2739
|
+
const cleaned = svg.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, "").replace(/\son\w+\s*=\s*["'][^"']*["']/gi, "").replace(/\son\w+\s*=\s*[^\s>]*/gi, "");
|
|
2740
|
+
return cleaned;
|
|
2741
|
+
}
|
|
2742
|
+
/**
|
|
2743
|
+
* Toggle view mode dropdown (internal implementation)
|
|
2744
|
+
* Not exposed to users - viewMode button behavior is fixed
|
|
2745
|
+
*/
|
|
2746
|
+
toggleViewModeDropdown(button) {
|
|
2747
|
+
const existingDropdown = document.querySelector(".overtype-dropdown-menu");
|
|
2748
|
+
if (existingDropdown) {
|
|
2749
|
+
existingDropdown.remove();
|
|
2750
|
+
button.classList.remove("dropdown-active");
|
|
2666
2751
|
return;
|
|
2667
2752
|
}
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
case "insertH2":
|
|
2681
|
-
toggleH2(textarea);
|
|
2682
|
-
break;
|
|
2683
|
-
case "insertH3":
|
|
2684
|
-
toggleH3(textarea);
|
|
2685
|
-
break;
|
|
2686
|
-
case "insertLink":
|
|
2687
|
-
insertLink(textarea);
|
|
2688
|
-
break;
|
|
2689
|
-
case "toggleCode":
|
|
2690
|
-
toggleCode(textarea);
|
|
2691
|
-
break;
|
|
2692
|
-
case "toggleBulletList":
|
|
2693
|
-
toggleBulletList(textarea);
|
|
2694
|
-
break;
|
|
2695
|
-
case "toggleNumberedList":
|
|
2696
|
-
toggleNumberedList(textarea);
|
|
2697
|
-
break;
|
|
2698
|
-
case "toggleQuote":
|
|
2699
|
-
toggleQuote(textarea);
|
|
2700
|
-
break;
|
|
2701
|
-
case "toggleTaskList":
|
|
2702
|
-
toggleTaskList(textarea);
|
|
2703
|
-
break;
|
|
2704
|
-
case "toggle-plain":
|
|
2705
|
-
const isPlain = this.editor.container.classList.contains("plain-mode");
|
|
2706
|
-
this.editor.showPlainTextarea(!isPlain);
|
|
2707
|
-
break;
|
|
2753
|
+
button.classList.add("dropdown-active");
|
|
2754
|
+
const dropdown = this.createViewModeDropdown(button);
|
|
2755
|
+
const rect = button.getBoundingClientRect();
|
|
2756
|
+
dropdown.style.position = "absolute";
|
|
2757
|
+
dropdown.style.top = `${rect.bottom + 5}px`;
|
|
2758
|
+
dropdown.style.left = `${rect.left}px`;
|
|
2759
|
+
document.body.appendChild(dropdown);
|
|
2760
|
+
this.handleDocumentClick = (e) => {
|
|
2761
|
+
if (!dropdown.contains(e.target) && !button.contains(e.target)) {
|
|
2762
|
+
dropdown.remove();
|
|
2763
|
+
button.classList.remove("dropdown-active");
|
|
2764
|
+
document.removeEventListener("click", this.handleDocumentClick);
|
|
2708
2765
|
}
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
}
|
|
2766
|
+
};
|
|
2767
|
+
setTimeout(() => {
|
|
2768
|
+
document.addEventListener("click", this.handleDocumentClick);
|
|
2769
|
+
}, 0);
|
|
2713
2770
|
}
|
|
2714
2771
|
/**
|
|
2715
|
-
*
|
|
2772
|
+
* Create view mode dropdown menu (internal implementation)
|
|
2716
2773
|
*/
|
|
2717
|
-
|
|
2718
|
-
const
|
|
2719
|
-
|
|
2720
|
-
|
|
2774
|
+
createViewModeDropdown(button) {
|
|
2775
|
+
const dropdown = document.createElement("div");
|
|
2776
|
+
dropdown.className = "overtype-dropdown-menu";
|
|
2777
|
+
const items = [
|
|
2778
|
+
{ id: "normal", label: "Normal Edit", icon: "\u2713" },
|
|
2779
|
+
{ id: "plain", label: "Plain Textarea", icon: "\u2713" },
|
|
2780
|
+
{ id: "preview", label: "Preview Mode", icon: "\u2713" }
|
|
2781
|
+
];
|
|
2782
|
+
const currentMode = this.editor.container.dataset.mode || "normal";
|
|
2783
|
+
items.forEach((item) => {
|
|
2784
|
+
const menuItem = document.createElement("button");
|
|
2785
|
+
menuItem.className = "overtype-dropdown-item";
|
|
2786
|
+
menuItem.type = "button";
|
|
2787
|
+
menuItem.textContent = item.label;
|
|
2788
|
+
if (item.id === currentMode) {
|
|
2789
|
+
menuItem.classList.add("active");
|
|
2790
|
+
menuItem.setAttribute("aria-current", "true");
|
|
2791
|
+
const checkmark = document.createElement("span");
|
|
2792
|
+
checkmark.className = "overtype-dropdown-icon";
|
|
2793
|
+
checkmark.textContent = item.icon;
|
|
2794
|
+
menuItem.prepend(checkmark);
|
|
2795
|
+
}
|
|
2796
|
+
menuItem.addEventListener("click", (e) => {
|
|
2797
|
+
e.preventDefault();
|
|
2798
|
+
switch (item.id) {
|
|
2799
|
+
case "plain":
|
|
2800
|
+
this.editor.showPlainTextarea();
|
|
2801
|
+
break;
|
|
2802
|
+
case "preview":
|
|
2803
|
+
this.editor.showPreviewMode();
|
|
2804
|
+
break;
|
|
2805
|
+
case "normal":
|
|
2806
|
+
default:
|
|
2807
|
+
this.editor.showNormalEditMode();
|
|
2808
|
+
break;
|
|
2809
|
+
}
|
|
2810
|
+
dropdown.remove();
|
|
2811
|
+
button.classList.remove("dropdown-active");
|
|
2812
|
+
document.removeEventListener("click", this.handleDocumentClick);
|
|
2813
|
+
});
|
|
2814
|
+
dropdown.appendChild(menuItem);
|
|
2815
|
+
});
|
|
2816
|
+
return dropdown;
|
|
2817
|
+
}
|
|
2818
|
+
/**
|
|
2819
|
+
* Update active states of toolbar buttons
|
|
2820
|
+
*/
|
|
2821
|
+
updateButtonStates() {
|
|
2822
|
+
var _a;
|
|
2721
2823
|
try {
|
|
2722
|
-
const activeFormats = getActiveFormats2(
|
|
2824
|
+
const activeFormats = ((_a = getActiveFormats2) == null ? void 0 : _a(
|
|
2825
|
+
this.editor.textarea,
|
|
2826
|
+
this.editor.textarea.selectionStart
|
|
2827
|
+
)) || [];
|
|
2723
2828
|
Object.entries(this.buttons).forEach(([name, button]) => {
|
|
2829
|
+
if (name === "viewMode")
|
|
2830
|
+
return;
|
|
2724
2831
|
let isActive = false;
|
|
2725
2832
|
switch (name) {
|
|
2726
2833
|
case "bold":
|
|
@@ -2738,12 +2845,12 @@ var Toolbar = class {
|
|
|
2738
2845
|
case "orderedList":
|
|
2739
2846
|
isActive = activeFormats.includes("numbered-list");
|
|
2740
2847
|
break;
|
|
2741
|
-
case "quote":
|
|
2742
|
-
isActive = activeFormats.includes("quote");
|
|
2743
|
-
break;
|
|
2744
2848
|
case "taskList":
|
|
2745
2849
|
isActive = activeFormats.includes("task-list");
|
|
2746
2850
|
break;
|
|
2851
|
+
case "quote":
|
|
2852
|
+
isActive = activeFormats.includes("quote");
|
|
2853
|
+
break;
|
|
2747
2854
|
case "h1":
|
|
2748
2855
|
isActive = activeFormats.includes("header");
|
|
2749
2856
|
break;
|
|
@@ -2753,9 +2860,6 @@ var Toolbar = class {
|
|
|
2753
2860
|
case "h3":
|
|
2754
2861
|
isActive = activeFormats.includes("header-3");
|
|
2755
2862
|
break;
|
|
2756
|
-
case "togglePlain":
|
|
2757
|
-
isActive = !this.editor.container.classList.contains("plain-mode");
|
|
2758
|
-
break;
|
|
2759
2863
|
}
|
|
2760
2864
|
button.classList.toggle("active", isActive);
|
|
2761
2865
|
button.setAttribute("aria-pressed", isActive.toString());
|
|
@@ -2764,101 +2868,19 @@ var Toolbar = class {
|
|
|
2764
2868
|
}
|
|
2765
2869
|
}
|
|
2766
2870
|
/**
|
|
2767
|
-
*
|
|
2768
|
-
*/
|
|
2769
|
-
toggleViewDropdown(button) {
|
|
2770
|
-
const existingDropdown = document.querySelector(".overtype-dropdown-menu");
|
|
2771
|
-
if (existingDropdown) {
|
|
2772
|
-
existingDropdown.remove();
|
|
2773
|
-
button.classList.remove("dropdown-active");
|
|
2774
|
-
document.removeEventListener("click", this.handleDocumentClick);
|
|
2775
|
-
return;
|
|
2776
|
-
}
|
|
2777
|
-
const dropdown = this.createViewDropdown();
|
|
2778
|
-
const rect = button.getBoundingClientRect();
|
|
2779
|
-
dropdown.style.top = `${rect.bottom + 4}px`;
|
|
2780
|
-
dropdown.style.left = `${rect.left}px`;
|
|
2781
|
-
document.body.appendChild(dropdown);
|
|
2782
|
-
button.classList.add("dropdown-active");
|
|
2783
|
-
this.handleDocumentClick = (e) => {
|
|
2784
|
-
if (!button.contains(e.target) && !dropdown.contains(e.target)) {
|
|
2785
|
-
dropdown.remove();
|
|
2786
|
-
button.classList.remove("dropdown-active");
|
|
2787
|
-
document.removeEventListener("click", this.handleDocumentClick);
|
|
2788
|
-
}
|
|
2789
|
-
};
|
|
2790
|
-
setTimeout(() => {
|
|
2791
|
-
document.addEventListener("click", this.handleDocumentClick);
|
|
2792
|
-
}, 0);
|
|
2793
|
-
}
|
|
2794
|
-
/**
|
|
2795
|
-
* Create view mode dropdown menu
|
|
2796
|
-
*/
|
|
2797
|
-
createViewDropdown() {
|
|
2798
|
-
const dropdown = document.createElement("div");
|
|
2799
|
-
dropdown.className = "overtype-dropdown-menu";
|
|
2800
|
-
const isPlain = this.editor.container.classList.contains("plain-mode");
|
|
2801
|
-
const isPreview = this.editor.container.classList.contains("preview-mode");
|
|
2802
|
-
const currentMode = isPreview ? "preview" : isPlain ? "plain" : "normal";
|
|
2803
|
-
const modes = [
|
|
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
|
-
modes.forEach((mode) => {
|
|
2809
|
-
const item = document.createElement("button");
|
|
2810
|
-
item.className = "overtype-dropdown-item";
|
|
2811
|
-
item.type = "button";
|
|
2812
|
-
const check = document.createElement("span");
|
|
2813
|
-
check.className = "overtype-dropdown-check";
|
|
2814
|
-
check.textContent = currentMode === mode.id ? mode.icon : "";
|
|
2815
|
-
const label = document.createElement("span");
|
|
2816
|
-
label.textContent = mode.label;
|
|
2817
|
-
item.appendChild(check);
|
|
2818
|
-
item.appendChild(label);
|
|
2819
|
-
if (currentMode === mode.id) {
|
|
2820
|
-
item.classList.add("active");
|
|
2821
|
-
}
|
|
2822
|
-
item.addEventListener("click", (e) => {
|
|
2823
|
-
e.stopPropagation();
|
|
2824
|
-
this.setViewMode(mode.id);
|
|
2825
|
-
dropdown.remove();
|
|
2826
|
-
this.viewModeButton.classList.remove("dropdown-active");
|
|
2827
|
-
document.removeEventListener("click", this.handleDocumentClick);
|
|
2828
|
-
});
|
|
2829
|
-
dropdown.appendChild(item);
|
|
2830
|
-
});
|
|
2831
|
-
return dropdown;
|
|
2832
|
-
}
|
|
2833
|
-
/**
|
|
2834
|
-
* Set view mode
|
|
2835
|
-
*/
|
|
2836
|
-
setViewMode(mode) {
|
|
2837
|
-
this.editor.container.classList.remove("plain-mode", "preview-mode");
|
|
2838
|
-
switch (mode) {
|
|
2839
|
-
case "plain":
|
|
2840
|
-
this.editor.showPlainTextarea(true);
|
|
2841
|
-
break;
|
|
2842
|
-
case "preview":
|
|
2843
|
-
this.editor.showPreviewMode(true);
|
|
2844
|
-
break;
|
|
2845
|
-
case "normal":
|
|
2846
|
-
default:
|
|
2847
|
-
this.editor.showPlainTextarea(false);
|
|
2848
|
-
if (typeof this.editor.showPreviewMode === "function") {
|
|
2849
|
-
this.editor.showPreviewMode(false);
|
|
2850
|
-
}
|
|
2851
|
-
break;
|
|
2852
|
-
}
|
|
2853
|
-
}
|
|
2854
|
-
/**
|
|
2855
|
-
* Destroy toolbar
|
|
2871
|
+
* Destroy toolbar and cleanup
|
|
2856
2872
|
*/
|
|
2857
2873
|
destroy() {
|
|
2858
2874
|
if (this.container) {
|
|
2859
2875
|
if (this.handleDocumentClick) {
|
|
2860
2876
|
document.removeEventListener("click", this.handleDocumentClick);
|
|
2861
2877
|
}
|
|
2878
|
+
Object.values(this.buttons).forEach((button) => {
|
|
2879
|
+
if (button._clickHandler) {
|
|
2880
|
+
button.removeEventListener("click", button._clickHandler);
|
|
2881
|
+
delete button._clickHandler;
|
|
2882
|
+
}
|
|
2883
|
+
});
|
|
2862
2884
|
this.container.remove();
|
|
2863
2885
|
this.container = null;
|
|
2864
2886
|
this.buttons = {};
|
|
@@ -2873,13 +2895,10 @@ var LinkTooltip = class {
|
|
|
2873
2895
|
this.tooltip = null;
|
|
2874
2896
|
this.currentLink = null;
|
|
2875
2897
|
this.hideTimeout = null;
|
|
2898
|
+
this.visibilityChangeHandler = null;
|
|
2876
2899
|
this.init();
|
|
2877
2900
|
}
|
|
2878
2901
|
init() {
|
|
2879
|
-
const supportsAnchor = CSS.supports("position-anchor: --x") && CSS.supports("position-area: center");
|
|
2880
|
-
if (!supportsAnchor) {
|
|
2881
|
-
return;
|
|
2882
|
-
}
|
|
2883
2902
|
this.createTooltip();
|
|
2884
2903
|
this.editor.textarea.addEventListener("selectionchange", () => this.checkCursorPosition());
|
|
2885
2904
|
this.editor.textarea.addEventListener("keyup", (e) => {
|
|
@@ -2889,46 +2908,19 @@ var LinkTooltip = class {
|
|
|
2889
2908
|
});
|
|
2890
2909
|
this.editor.textarea.addEventListener("input", () => this.hide());
|
|
2891
2910
|
this.editor.textarea.addEventListener("scroll", () => this.hide());
|
|
2911
|
+
this.editor.textarea.addEventListener("blur", () => this.hide());
|
|
2912
|
+
this.visibilityChangeHandler = () => {
|
|
2913
|
+
if (document.hidden) {
|
|
2914
|
+
this.hide();
|
|
2915
|
+
}
|
|
2916
|
+
};
|
|
2917
|
+
document.addEventListener("visibilitychange", this.visibilityChangeHandler);
|
|
2892
2918
|
this.tooltip.addEventListener("mouseenter", () => this.cancelHide());
|
|
2893
2919
|
this.tooltip.addEventListener("mouseleave", () => this.scheduleHide());
|
|
2894
2920
|
}
|
|
2895
2921
|
createTooltip() {
|
|
2896
2922
|
this.tooltip = document.createElement("div");
|
|
2897
2923
|
this.tooltip.className = "overtype-link-tooltip";
|
|
2898
|
-
const tooltipStyles = document.createElement("style");
|
|
2899
|
-
tooltipStyles.textContent = `
|
|
2900
|
-
@supports (position-anchor: --x) and (position-area: center) {
|
|
2901
|
-
.overtype-link-tooltip {
|
|
2902
|
-
position: absolute;
|
|
2903
|
-
position-anchor: var(--target-anchor, --link-0);
|
|
2904
|
-
position-area: block-end center;
|
|
2905
|
-
margin-top: 8px !important;
|
|
2906
|
-
|
|
2907
|
-
background: #333 !important;
|
|
2908
|
-
color: white !important;
|
|
2909
|
-
padding: 6px 10px !important;
|
|
2910
|
-
border-radius: 16px !important;
|
|
2911
|
-
font-size: 12px !important;
|
|
2912
|
-
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif !important;
|
|
2913
|
-
display: none !important;
|
|
2914
|
-
z-index: 10000 !important;
|
|
2915
|
-
cursor: pointer !important;
|
|
2916
|
-
box-shadow: 0 2px 8px rgba(0,0,0,0.3) !important;
|
|
2917
|
-
max-width: 300px !important;
|
|
2918
|
-
white-space: nowrap !important;
|
|
2919
|
-
overflow: hidden !important;
|
|
2920
|
-
text-overflow: ellipsis !important;
|
|
2921
|
-
|
|
2922
|
-
position-try: most-width block-end inline-end, flip-inline, block-start center;
|
|
2923
|
-
position-visibility: anchors-visible;
|
|
2924
|
-
}
|
|
2925
|
-
|
|
2926
|
-
.overtype-link-tooltip.visible {
|
|
2927
|
-
display: flex !important;
|
|
2928
|
-
}
|
|
2929
|
-
}
|
|
2930
|
-
`;
|
|
2931
|
-
document.head.appendChild(tooltipStyles);
|
|
2932
2924
|
this.tooltip.innerHTML = `
|
|
2933
2925
|
<span style="display: flex; align-items: center; gap: 6px;">
|
|
2934
2926
|
<svg width="12" height="12" viewBox="0 0 20 20" fill="currentColor" style="flex-shrink: 0;">
|
|
@@ -3004,6 +2996,10 @@ var LinkTooltip = class {
|
|
|
3004
2996
|
}
|
|
3005
2997
|
destroy() {
|
|
3006
2998
|
this.cancelHide();
|
|
2999
|
+
if (this.visibilityChangeHandler) {
|
|
3000
|
+
document.removeEventListener("visibilitychange", this.visibilityChangeHandler);
|
|
3001
|
+
this.visibilityChangeHandler = null;
|
|
3002
|
+
}
|
|
3007
3003
|
if (this.tooltip && this.tooltip.parentNode) {
|
|
3008
3004
|
this.tooltip.parentNode.removeChild(this.tooltip);
|
|
3009
3005
|
}
|
|
@@ -3012,6 +3008,204 @@ var LinkTooltip = class {
|
|
|
3012
3008
|
}
|
|
3013
3009
|
};
|
|
3014
3010
|
|
|
3011
|
+
// src/icons.js
|
|
3012
|
+
var boldIcon = `<svg viewBox="0 0 18 18">
|
|
3013
|
+
<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>
|
|
3014
|
+
<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>
|
|
3015
|
+
</svg>`;
|
|
3016
|
+
var italicIcon = `<svg viewBox="0 0 18 18">
|
|
3017
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="13" y1="4" y2="4"></line>
|
|
3018
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="5" x2="11" y1="14" y2="14"></line>
|
|
3019
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="10" y1="14" y2="4"></line>
|
|
3020
|
+
</svg>`;
|
|
3021
|
+
var h1Icon = `<svg viewBox="0 0 18 18">
|
|
3022
|
+
<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>
|
|
3023
|
+
</svg>`;
|
|
3024
|
+
var h2Icon = `<svg viewBox="0 0 18 18">
|
|
3025
|
+
<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>
|
|
3026
|
+
</svg>`;
|
|
3027
|
+
var h3Icon = `<svg viewBox="0 0 18 18">
|
|
3028
|
+
<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>
|
|
3029
|
+
</svg>`;
|
|
3030
|
+
var linkIcon = `<svg viewBox="0 0 18 18">
|
|
3031
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="11" y1="7" y2="11"></line>
|
|
3032
|
+
<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>
|
|
3033
|
+
<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>
|
|
3034
|
+
</svg>`;
|
|
3035
|
+
var codeIcon = `<svg viewBox="0 0 18 18">
|
|
3036
|
+
<polyline stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" points="5 7 3 9 5 11"></polyline>
|
|
3037
|
+
<polyline stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" points="13 7 15 9 13 11"></polyline>
|
|
3038
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="10" x2="8" y1="5" y2="13"></line>
|
|
3039
|
+
</svg>`;
|
|
3040
|
+
var bulletListIcon = `<svg viewBox="0 0 18 18">
|
|
3041
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="6" x2="15" y1="4" y2="4"></line>
|
|
3042
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="6" x2="15" y1="9" y2="9"></line>
|
|
3043
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="6" x2="15" y1="14" y2="14"></line>
|
|
3044
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="3" x2="3" y1="4" y2="4"></line>
|
|
3045
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="3" x2="3" y1="9" y2="9"></line>
|
|
3046
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="3" x2="3" y1="14" y2="14"></line>
|
|
3047
|
+
</svg>`;
|
|
3048
|
+
var orderedListIcon = `<svg viewBox="0 0 18 18">
|
|
3049
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="15" y1="4" y2="4"></line>
|
|
3050
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="15" y1="9" y2="9"></line>
|
|
3051
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="7" x2="15" y1="14" y2="14"></line>
|
|
3052
|
+
<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>
|
|
3053
|
+
<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>
|
|
3054
|
+
<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>
|
|
3055
|
+
<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>
|
|
3056
|
+
</svg>`;
|
|
3057
|
+
var quoteIcon = `<svg viewBox="2 2 20 20">
|
|
3058
|
+
<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>
|
|
3059
|
+
<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>
|
|
3060
|
+
</svg>`;
|
|
3061
|
+
var taskListIcon = `<svg viewBox="0 0 18 18">
|
|
3062
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="16" y1="4" y2="4"></line>
|
|
3063
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="16" y1="9" y2="9"></line>
|
|
3064
|
+
<line stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" x1="8" x2="16" y1="14" y2="14"></line>
|
|
3065
|
+
<rect stroke="currentColor" fill="none" stroke-width="1.5" x="2" y="3" width="3" height="3" rx="0.5"></rect>
|
|
3066
|
+
<rect stroke="currentColor" fill="none" stroke-width="1.5" x="2" y="13" width="3" height="3" rx="0.5"></rect>
|
|
3067
|
+
<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>
|
|
3068
|
+
</svg>`;
|
|
3069
|
+
var eyeIcon = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
3070
|
+
<path d="M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" fill="none"></path>
|
|
3071
|
+
<circle cx="12" cy="12" r="3" fill="none"></circle>
|
|
3072
|
+
</svg>`;
|
|
3073
|
+
|
|
3074
|
+
// src/toolbar-buttons.js
|
|
3075
|
+
var toolbarButtons = {
|
|
3076
|
+
bold: {
|
|
3077
|
+
name: "bold",
|
|
3078
|
+
icon: boldIcon,
|
|
3079
|
+
title: "Bold (Ctrl+B)",
|
|
3080
|
+
action: ({ editor, event }) => {
|
|
3081
|
+
toggleBold(editor.textarea);
|
|
3082
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3083
|
+
}
|
|
3084
|
+
},
|
|
3085
|
+
italic: {
|
|
3086
|
+
name: "italic",
|
|
3087
|
+
icon: italicIcon,
|
|
3088
|
+
title: "Italic (Ctrl+I)",
|
|
3089
|
+
action: ({ editor, event }) => {
|
|
3090
|
+
toggleItalic(editor.textarea);
|
|
3091
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3092
|
+
}
|
|
3093
|
+
},
|
|
3094
|
+
code: {
|
|
3095
|
+
name: "code",
|
|
3096
|
+
icon: codeIcon,
|
|
3097
|
+
title: "Inline Code",
|
|
3098
|
+
action: ({ editor, event }) => {
|
|
3099
|
+
toggleCode(editor.textarea);
|
|
3100
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3101
|
+
}
|
|
3102
|
+
},
|
|
3103
|
+
separator: {
|
|
3104
|
+
name: "separator"
|
|
3105
|
+
// No icon, title, or action - special separator element
|
|
3106
|
+
},
|
|
3107
|
+
link: {
|
|
3108
|
+
name: "link",
|
|
3109
|
+
icon: linkIcon,
|
|
3110
|
+
title: "Insert Link",
|
|
3111
|
+
action: ({ editor, event }) => {
|
|
3112
|
+
insertLink(editor.textarea);
|
|
3113
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3114
|
+
}
|
|
3115
|
+
},
|
|
3116
|
+
h1: {
|
|
3117
|
+
name: "h1",
|
|
3118
|
+
icon: h1Icon,
|
|
3119
|
+
title: "Heading 1",
|
|
3120
|
+
action: ({ editor, event }) => {
|
|
3121
|
+
toggleH1(editor.textarea);
|
|
3122
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3123
|
+
}
|
|
3124
|
+
},
|
|
3125
|
+
h2: {
|
|
3126
|
+
name: "h2",
|
|
3127
|
+
icon: h2Icon,
|
|
3128
|
+
title: "Heading 2",
|
|
3129
|
+
action: ({ editor, event }) => {
|
|
3130
|
+
toggleH2(editor.textarea);
|
|
3131
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3132
|
+
}
|
|
3133
|
+
},
|
|
3134
|
+
h3: {
|
|
3135
|
+
name: "h3",
|
|
3136
|
+
icon: h3Icon,
|
|
3137
|
+
title: "Heading 3",
|
|
3138
|
+
action: ({ editor, event }) => {
|
|
3139
|
+
toggleH3(editor.textarea);
|
|
3140
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3141
|
+
}
|
|
3142
|
+
},
|
|
3143
|
+
bulletList: {
|
|
3144
|
+
name: "bulletList",
|
|
3145
|
+
icon: bulletListIcon,
|
|
3146
|
+
title: "Bullet List",
|
|
3147
|
+
action: ({ editor, event }) => {
|
|
3148
|
+
toggleBulletList(editor.textarea);
|
|
3149
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3150
|
+
}
|
|
3151
|
+
},
|
|
3152
|
+
orderedList: {
|
|
3153
|
+
name: "orderedList",
|
|
3154
|
+
icon: orderedListIcon,
|
|
3155
|
+
title: "Numbered List",
|
|
3156
|
+
action: ({ editor, event }) => {
|
|
3157
|
+
toggleNumberedList(editor.textarea);
|
|
3158
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3159
|
+
}
|
|
3160
|
+
},
|
|
3161
|
+
taskList: {
|
|
3162
|
+
name: "taskList",
|
|
3163
|
+
icon: taskListIcon,
|
|
3164
|
+
title: "Task List",
|
|
3165
|
+
action: ({ editor, event }) => {
|
|
3166
|
+
if (toggleTaskList) {
|
|
3167
|
+
toggleTaskList(editor.textarea);
|
|
3168
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3169
|
+
}
|
|
3170
|
+
}
|
|
3171
|
+
},
|
|
3172
|
+
quote: {
|
|
3173
|
+
name: "quote",
|
|
3174
|
+
icon: quoteIcon,
|
|
3175
|
+
title: "Quote",
|
|
3176
|
+
action: ({ editor, event }) => {
|
|
3177
|
+
toggleQuote(editor.textarea);
|
|
3178
|
+
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
3179
|
+
}
|
|
3180
|
+
},
|
|
3181
|
+
viewMode: {
|
|
3182
|
+
name: "viewMode",
|
|
3183
|
+
icon: eyeIcon,
|
|
3184
|
+
title: "View mode"
|
|
3185
|
+
// Special: handled internally by Toolbar class as dropdown
|
|
3186
|
+
// No action property - dropdown behavior is internal
|
|
3187
|
+
}
|
|
3188
|
+
};
|
|
3189
|
+
var defaultToolbarButtons = [
|
|
3190
|
+
toolbarButtons.bold,
|
|
3191
|
+
toolbarButtons.italic,
|
|
3192
|
+
toolbarButtons.code,
|
|
3193
|
+
toolbarButtons.separator,
|
|
3194
|
+
toolbarButtons.link,
|
|
3195
|
+
toolbarButtons.separator,
|
|
3196
|
+
toolbarButtons.h1,
|
|
3197
|
+
toolbarButtons.h2,
|
|
3198
|
+
toolbarButtons.h3,
|
|
3199
|
+
toolbarButtons.separator,
|
|
3200
|
+
toolbarButtons.bulletList,
|
|
3201
|
+
toolbarButtons.orderedList,
|
|
3202
|
+
toolbarButtons.taskList,
|
|
3203
|
+
toolbarButtons.separator,
|
|
3204
|
+
toolbarButtons.quote,
|
|
3205
|
+
toolbarButtons.separator,
|
|
3206
|
+
toolbarButtons.viewMode
|
|
3207
|
+
];
|
|
3208
|
+
|
|
3015
3209
|
// src/overtype.js
|
|
3016
3210
|
var _OverType = class _OverType {
|
|
3017
3211
|
/**
|
|
@@ -3071,17 +3265,6 @@ var _OverType = class _OverType {
|
|
|
3071
3265
|
}
|
|
3072
3266
|
this.shortcuts = new ShortcutsManager(this);
|
|
3073
3267
|
this.linkTooltip = new LinkTooltip(this);
|
|
3074
|
-
if (this.options.toolbar) {
|
|
3075
|
-
const toolbarButtons = typeof this.options.toolbar === "object" ? this.options.toolbar.buttons : null;
|
|
3076
|
-
this.toolbar = new Toolbar(this, toolbarButtons);
|
|
3077
|
-
this.toolbar.create();
|
|
3078
|
-
this.textarea.addEventListener("selectionchange", () => {
|
|
3079
|
-
this.toolbar.updateButtonStates();
|
|
3080
|
-
});
|
|
3081
|
-
this.textarea.addEventListener("input", () => {
|
|
3082
|
-
this.toolbar.updateButtonStates();
|
|
3083
|
-
});
|
|
3084
|
-
}
|
|
3085
3268
|
this.initialized = true;
|
|
3086
3269
|
if (this.options.onChange) {
|
|
3087
3270
|
this.options.onChange(this.getValue(), this);
|
|
@@ -3125,9 +3308,13 @@ var _OverType = class _OverType {
|
|
|
3125
3308
|
showActiveLineRaw: false,
|
|
3126
3309
|
showStats: false,
|
|
3127
3310
|
toolbar: false,
|
|
3311
|
+
toolbarButtons: null,
|
|
3312
|
+
// Defaults to defaultToolbarButtons if toolbar: true
|
|
3128
3313
|
statsFormatter: null,
|
|
3129
|
-
smartLists: true
|
|
3314
|
+
smartLists: true,
|
|
3130
3315
|
// Enable smart list continuation
|
|
3316
|
+
codeHighlighter: null
|
|
3317
|
+
// Per-instance code highlighter
|
|
3131
3318
|
};
|
|
3132
3319
|
const { theme, colors, ...cleanOptions } = options;
|
|
3133
3320
|
return {
|
|
@@ -3303,6 +3490,41 @@ var _OverType = class _OverType {
|
|
|
3303
3490
|
this.textarea.setAttribute("data-gramm_editor", "false");
|
|
3304
3491
|
this.textarea.setAttribute("data-enable-grammarly", "false");
|
|
3305
3492
|
}
|
|
3493
|
+
/**
|
|
3494
|
+
* Create and setup toolbar
|
|
3495
|
+
* @private
|
|
3496
|
+
*/
|
|
3497
|
+
_createToolbar() {
|
|
3498
|
+
const toolbarButtons2 = this.options.toolbarButtons || defaultToolbarButtons;
|
|
3499
|
+
this.toolbar = new Toolbar(this, { toolbarButtons: toolbarButtons2 });
|
|
3500
|
+
this.toolbar.create();
|
|
3501
|
+
this._toolbarSelectionListener = () => {
|
|
3502
|
+
if (this.toolbar) {
|
|
3503
|
+
this.toolbar.updateButtonStates();
|
|
3504
|
+
}
|
|
3505
|
+
};
|
|
3506
|
+
this._toolbarInputListener = () => {
|
|
3507
|
+
if (this.toolbar) {
|
|
3508
|
+
this.toolbar.updateButtonStates();
|
|
3509
|
+
}
|
|
3510
|
+
};
|
|
3511
|
+
this.textarea.addEventListener("selectionchange", this._toolbarSelectionListener);
|
|
3512
|
+
this.textarea.addEventListener("input", this._toolbarInputListener);
|
|
3513
|
+
}
|
|
3514
|
+
/**
|
|
3515
|
+
* Cleanup toolbar event listeners
|
|
3516
|
+
* @private
|
|
3517
|
+
*/
|
|
3518
|
+
_cleanupToolbarListeners() {
|
|
3519
|
+
if (this._toolbarSelectionListener) {
|
|
3520
|
+
this.textarea.removeEventListener("selectionchange", this._toolbarSelectionListener);
|
|
3521
|
+
this._toolbarSelectionListener = null;
|
|
3522
|
+
}
|
|
3523
|
+
if (this._toolbarInputListener) {
|
|
3524
|
+
this.textarea.removeEventListener("input", this._toolbarInputListener);
|
|
3525
|
+
this._toolbarInputListener = null;
|
|
3526
|
+
}
|
|
3527
|
+
}
|
|
3306
3528
|
/**
|
|
3307
3529
|
* Apply options to the editor
|
|
3308
3530
|
* @private
|
|
@@ -3318,6 +3540,13 @@ var _OverType = class _OverType {
|
|
|
3318
3540
|
} else {
|
|
3319
3541
|
this.container.classList.remove("overtype-auto-resize");
|
|
3320
3542
|
}
|
|
3543
|
+
if (this.options.toolbar && !this.toolbar) {
|
|
3544
|
+
this._createToolbar();
|
|
3545
|
+
} else if (!this.options.toolbar && this.toolbar) {
|
|
3546
|
+
this._cleanupToolbarListeners();
|
|
3547
|
+
this.toolbar.destroy();
|
|
3548
|
+
this.toolbar = null;
|
|
3549
|
+
}
|
|
3321
3550
|
this.updatePreview();
|
|
3322
3551
|
}
|
|
3323
3552
|
/**
|
|
@@ -3327,7 +3556,8 @@ var _OverType = class _OverType {
|
|
|
3327
3556
|
const text = this.textarea.value;
|
|
3328
3557
|
const cursorPos = this.textarea.selectionStart;
|
|
3329
3558
|
const activeLine = this._getCurrentLine(text, cursorPos);
|
|
3330
|
-
const
|
|
3559
|
+
const isPreviewMode = this.container.dataset.mode === "preview";
|
|
3560
|
+
const html = MarkdownParser.parse(text, activeLine, this.options.showActiveLineRaw, this.options.codeHighlighter, isPreviewMode);
|
|
3331
3561
|
this.preview.innerHTML = html || '<span style="color: #808080;">Start typing...</span>';
|
|
3332
3562
|
this._applyCodeBlockBackgrounds();
|
|
3333
3563
|
if (this.options.showStats && this.statsBar) {
|
|
@@ -3561,7 +3791,7 @@ var _OverType = class _OverType {
|
|
|
3561
3791
|
*/
|
|
3562
3792
|
getRenderedHTML(options = {}) {
|
|
3563
3793
|
const markdown = this.getValue();
|
|
3564
|
-
let html = MarkdownParser.parse(markdown);
|
|
3794
|
+
let html = MarkdownParser.parse(markdown, -1, false, this.options.codeHighlighter);
|
|
3565
3795
|
if (options.cleanHTML) {
|
|
3566
3796
|
html = html.replace(/<span class="syntax-marker[^"]*">.*?<\/span>/g, "");
|
|
3567
3797
|
html = html.replace(/\sclass="(bullet-list|ordered-list|code-fence|hr-marker|blockquote|url-part)"/g, "");
|
|
@@ -3613,6 +3843,33 @@ var _OverType = class _OverType {
|
|
|
3613
3843
|
this._applyOptions();
|
|
3614
3844
|
this.updatePreview();
|
|
3615
3845
|
}
|
|
3846
|
+
/**
|
|
3847
|
+
* Set theme for this instance
|
|
3848
|
+
* @param {string|Object} theme - Theme name or custom theme object
|
|
3849
|
+
* @returns {this} Returns this for chaining
|
|
3850
|
+
*/
|
|
3851
|
+
setTheme(theme) {
|
|
3852
|
+
this.instanceTheme = theme;
|
|
3853
|
+
const themeObj = typeof theme === "string" ? getTheme(theme) : theme;
|
|
3854
|
+
const themeName = typeof themeObj === "string" ? themeObj : themeObj.name;
|
|
3855
|
+
if (themeName) {
|
|
3856
|
+
this.container.setAttribute("data-theme", themeName);
|
|
3857
|
+
}
|
|
3858
|
+
if (themeObj && themeObj.colors) {
|
|
3859
|
+
const cssVars = themeToCSSVars(themeObj.colors);
|
|
3860
|
+
this.container.style.cssText += cssVars;
|
|
3861
|
+
}
|
|
3862
|
+
this.updatePreview();
|
|
3863
|
+
return this;
|
|
3864
|
+
}
|
|
3865
|
+
/**
|
|
3866
|
+
* Set instance-specific code highlighter
|
|
3867
|
+
* @param {Function|null} highlighter - Function that takes (code, language) and returns highlighted HTML
|
|
3868
|
+
*/
|
|
3869
|
+
setCodeHighlighter(highlighter) {
|
|
3870
|
+
this.options.codeHighlighter = highlighter;
|
|
3871
|
+
this.updatePreview();
|
|
3872
|
+
}
|
|
3616
3873
|
/**
|
|
3617
3874
|
* Update stats bar
|
|
3618
3875
|
* @private
|
|
@@ -3715,37 +3972,39 @@ var _OverType = class _OverType {
|
|
|
3715
3972
|
}
|
|
3716
3973
|
}
|
|
3717
3974
|
/**
|
|
3718
|
-
* Show
|
|
3719
|
-
* @
|
|
3720
|
-
* @returns {boolean} Current plain textarea state
|
|
3975
|
+
* Show normal edit mode (overlay with markdown preview)
|
|
3976
|
+
* @returns {this} Returns this for chaining
|
|
3721
3977
|
*/
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
3725
|
-
|
|
3726
|
-
this.
|
|
3727
|
-
}
|
|
3978
|
+
showNormalEditMode() {
|
|
3979
|
+
this.container.dataset.mode = "normal";
|
|
3980
|
+
requestAnimationFrame(() => {
|
|
3981
|
+
this.textarea.scrollTop = this.preview.scrollTop;
|
|
3982
|
+
this.textarea.scrollLeft = this.preview.scrollLeft;
|
|
3983
|
+
});
|
|
3984
|
+
return this;
|
|
3985
|
+
}
|
|
3986
|
+
/**
|
|
3987
|
+
* Show plain textarea mode (no overlay)
|
|
3988
|
+
* @returns {this} Returns this for chaining
|
|
3989
|
+
*/
|
|
3990
|
+
showPlainTextarea() {
|
|
3991
|
+
this.container.dataset.mode = "plain";
|
|
3728
3992
|
if (this.toolbar) {
|
|
3729
3993
|
const toggleBtn = this.container.querySelector('[data-action="toggle-plain"]');
|
|
3730
3994
|
if (toggleBtn) {
|
|
3731
|
-
toggleBtn.classList.
|
|
3732
|
-
toggleBtn.title =
|
|
3995
|
+
toggleBtn.classList.remove("active");
|
|
3996
|
+
toggleBtn.title = "Show markdown preview";
|
|
3733
3997
|
}
|
|
3734
3998
|
}
|
|
3735
|
-
return
|
|
3999
|
+
return this;
|
|
3736
4000
|
}
|
|
3737
4001
|
/**
|
|
3738
|
-
* Show
|
|
3739
|
-
* @
|
|
3740
|
-
* @returns {boolean} Current preview mode state
|
|
4002
|
+
* Show preview mode (read-only view)
|
|
4003
|
+
* @returns {this} Returns this for chaining
|
|
3741
4004
|
*/
|
|
3742
|
-
showPreviewMode(
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
} else {
|
|
3746
|
-
this.container.classList.remove("preview-mode");
|
|
3747
|
-
}
|
|
3748
|
-
return show;
|
|
4005
|
+
showPreviewMode() {
|
|
4006
|
+
this.container.dataset.mode = "preview";
|
|
4007
|
+
return this;
|
|
3749
4008
|
}
|
|
3750
4009
|
/**
|
|
3751
4010
|
* Destroy the editor instance
|
|
@@ -3825,16 +4084,16 @@ var _OverType = class _OverType {
|
|
|
3825
4084
|
_OverType.currentTheme = themeObj;
|
|
3826
4085
|
_OverType.injectStyles(true);
|
|
3827
4086
|
document.querySelectorAll(".overtype-container").forEach((container) => {
|
|
3828
|
-
const
|
|
3829
|
-
if (
|
|
3830
|
-
container.setAttribute("data-theme",
|
|
4087
|
+
const themeName2 = typeof themeObj === "string" ? themeObj : themeObj.name;
|
|
4088
|
+
if (themeName2) {
|
|
4089
|
+
container.setAttribute("data-theme", themeName2);
|
|
3831
4090
|
}
|
|
3832
4091
|
});
|
|
3833
4092
|
document.querySelectorAll(".overtype-wrapper").forEach((wrapper) => {
|
|
3834
4093
|
if (!wrapper.closest(".overtype-container")) {
|
|
3835
|
-
const
|
|
3836
|
-
if (
|
|
3837
|
-
wrapper.setAttribute("data-theme",
|
|
4094
|
+
const themeName2 = typeof themeObj === "string" ? themeObj : themeObj.name;
|
|
4095
|
+
if (themeName2) {
|
|
4096
|
+
wrapper.setAttribute("data-theme", themeName2);
|
|
3838
4097
|
}
|
|
3839
4098
|
}
|
|
3840
4099
|
const instance = wrapper._instance;
|
|
@@ -3842,6 +4101,36 @@ var _OverType = class _OverType {
|
|
|
3842
4101
|
instance.updatePreview();
|
|
3843
4102
|
}
|
|
3844
4103
|
});
|
|
4104
|
+
const themeName = typeof themeObj === "string" ? themeObj : themeObj.name;
|
|
4105
|
+
document.querySelectorAll("overtype-editor").forEach((webComponent) => {
|
|
4106
|
+
if (themeName && typeof webComponent.setAttribute === "function") {
|
|
4107
|
+
webComponent.setAttribute("theme", themeName);
|
|
4108
|
+
}
|
|
4109
|
+
if (typeof webComponent.refreshTheme === "function") {
|
|
4110
|
+
webComponent.refreshTheme();
|
|
4111
|
+
}
|
|
4112
|
+
});
|
|
4113
|
+
}
|
|
4114
|
+
/**
|
|
4115
|
+
* Set global code highlighter for all OverType instances
|
|
4116
|
+
* @param {Function|null} highlighter - Function that takes (code, language) and returns highlighted HTML
|
|
4117
|
+
*/
|
|
4118
|
+
static setCodeHighlighter(highlighter) {
|
|
4119
|
+
MarkdownParser.setCodeHighlighter(highlighter);
|
|
4120
|
+
document.querySelectorAll(".overtype-wrapper").forEach((wrapper) => {
|
|
4121
|
+
const instance = wrapper._instance;
|
|
4122
|
+
if (instance && instance.updatePreview) {
|
|
4123
|
+
instance.updatePreview();
|
|
4124
|
+
}
|
|
4125
|
+
});
|
|
4126
|
+
document.querySelectorAll("overtype-editor").forEach((webComponent) => {
|
|
4127
|
+
if (typeof webComponent.getEditor === "function") {
|
|
4128
|
+
const instance = webComponent.getEditor();
|
|
4129
|
+
if (instance && instance.updatePreview) {
|
|
4130
|
+
instance.updatePreview();
|
|
4131
|
+
}
|
|
4132
|
+
}
|
|
4133
|
+
});
|
|
3845
4134
|
}
|
|
3846
4135
|
/**
|
|
3847
4136
|
* Initialize global event listeners
|
|
@@ -3906,7 +4195,9 @@ OverType.currentTheme = solar;
|
|
|
3906
4195
|
var overtype_default = OverType;
|
|
3907
4196
|
export {
|
|
3908
4197
|
OverType,
|
|
3909
|
-
overtype_default as default
|
|
4198
|
+
overtype_default as default,
|
|
4199
|
+
defaultToolbarButtons,
|
|
4200
|
+
toolbarButtons
|
|
3910
4201
|
};
|
|
3911
4202
|
/**
|
|
3912
4203
|
* OverType - A lightweight markdown editor library with perfect WYSIWYG alignment
|