@mdzip/editor 1.3.13 → 1.3.16
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/AGENTS.md +4 -0
- package/dist/library-info.d.ts +2 -2
- package/dist/library-info.js +2 -2
- package/dist/mermaid.d.ts.map +1 -1
- package/dist/mermaid.js +26 -2
- package/dist/mermaid.js.map +1 -1
- package/dist/view-css.d.ts.map +1 -1
- package/dist/view-css.js +130 -3
- package/dist/view-css.js.map +1 -1
- package/dist/view.d.ts +41 -0
- package/dist/view.d.ts.map +1 -1
- package/dist/view.js +624 -293
- package/dist/view.js.map +1 -1
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +19 -6
- package/dist/workspace.js.map +1 -1
- package/package.json +3 -2
package/dist/view.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { defaultKeymap, history, historyKeymap, indentWithTab } from '@codemirror/commands';
|
|
2
2
|
import { markdown } from '@codemirror/lang-markdown';
|
|
3
3
|
import { HighlightStyle, syntaxHighlighting } from '@codemirror/language';
|
|
4
|
+
import { closeSearchPanel, openSearchPanel, search, searchKeymap } from '@codemirror/search';
|
|
4
5
|
import { Compartment, EditorState } from '@codemirror/state';
|
|
5
6
|
import { Decoration, EditorView, MatchDecorator, ViewPlugin, dropCursor, keymap, lineNumbers } from '@codemirror/view';
|
|
6
7
|
import { tags } from '@lezer/highlight';
|
|
7
|
-
import { Bold, ChevronDown, ChevronRight, ClipboardPaste, ClipboardType, Code, Columns2, Copy, Eraser, Eye, File, FileBraces, FileImage, Folder, FolderOpen, Hash, Heading1, Heading2, Heading3, Heading4, Heading5, Heading6, Highlighter, ImagePlus, Info, Italic, Link2Off, Link, List, ListOrdered, CornerDownLeft, Moon, PackagePlus, PanelLeft, Pilcrow, Quote, Save, Scissors, SquareCode, SquarePen, Strikethrough, Sun, TextSelect, ZoomIn } from 'lucide';
|
|
8
|
+
import { Bold, Check, ChevronDown, ChevronRight, ClipboardPaste, ClipboardType, Code, Columns2, Copy, Eraser, Eye, File, FileBraces, FileImage, Folder, FolderOpen, Hash, Heading1, Heading2, Heading3, Heading4, Heading5, Heading6, Highlighter, ImagePlus, Info, Italic, Link2Off, Link, List, ListOrdered, CornerDownLeft, Moon, PackagePlus, PanelLeft, Pilcrow, Quote, Save, Scissors, Search, SquareCode, SquarePen, Strikethrough, Sun, TextSelect, ZoomIn } from 'lucide';
|
|
8
9
|
import { browserClipboardHasImage, readBrowserClipboardImage } from './browser.js';
|
|
9
10
|
import { MdzipAssetSession, mdzipArchiveSourceId, sniffImageSize } from './asset-cache.js';
|
|
10
11
|
import { MD_MARKDOWN_ICON } from './icons/md-markdown.js';
|
|
@@ -35,6 +36,7 @@ const CONVERT_TO_MDZ_ICON_HTML = lucideIcon(PackagePlus, `${TOOLBAR_ICON_CLASS}
|
|
|
35
36
|
const PREVIEW_ICON_HTML = lucideIcon(Eye, TOOLBAR_ICON_CLASS);
|
|
36
37
|
const SPLIT_ICON_HTML = lucideIcon(Columns2, TOOLBAR_ICON_CLASS);
|
|
37
38
|
const SAVE_ICON_HTML = lucideIcon(Save, TOOLBAR_ICON_CLASS);
|
|
39
|
+
const SEARCH_ICON_HTML = lucideIcon(Search, TOOLBAR_ICON_CLASS);
|
|
38
40
|
const ZOOM_ICON_HTML = lucideIcon(ZoomIn, TOOLBAR_ICON_CLASS);
|
|
39
41
|
const DARK_THEME_ICON_HTML = lucideIcon(Moon, TOOLBAR_ICON_CLASS);
|
|
40
42
|
const LIGHT_THEME_ICON_HTML = lucideIcon(Sun, TOOLBAR_ICON_CLASS);
|
|
@@ -52,6 +54,16 @@ const LINK_ICON_HTML = lucideIcon(Link, FORMAT_ICON_CLASS);
|
|
|
52
54
|
const IMAGE_FORMAT_ICON_HTML = lucideIcon(ImagePlus, FORMAT_ICON_CLASS);
|
|
53
55
|
const CHEVRON_ICON_HTML = lucideIcon(ChevronDown, 'format-chevron');
|
|
54
56
|
const INFO_ICON_HTML = lucideIcon(Info, 'document-info-icon');
|
|
57
|
+
const CODE_BLOCK_ICON_CLASS = 'mdzip-code-block-icon';
|
|
58
|
+
const CODE_BLOCK_COPY_ICON_HTML = lucideIcon(Copy, CODE_BLOCK_ICON_CLASS);
|
|
59
|
+
const CODE_BLOCK_COPIED_ICON_HTML = lucideIcon(Check, CODE_BLOCK_ICON_CLASS);
|
|
60
|
+
const CODE_BLOCK_COLLAPSE_ICON_HTML = lucideIcon(ChevronDown, CODE_BLOCK_ICON_CLASS);
|
|
61
|
+
// Below this, collapsing (240px / ~12 visible lines) would have no visible
|
|
62
|
+
// effect, so the collapse button isn't shown at all rather than appearing to
|
|
63
|
+
// do nothing when clicked.
|
|
64
|
+
const CODE_BLOCK_COLLAPSIBLE_MIN_LINES = 15;
|
|
65
|
+
// Blocks taller than this start collapsed; still manually expandable either way.
|
|
66
|
+
const CODE_BLOCK_AUTO_COLLAPSE_LINES = 25;
|
|
55
67
|
// Leading icons for context-menu items (Obsidian-style icon column).
|
|
56
68
|
const MENU_ICON_CLASS = 'nav-menu-icon';
|
|
57
69
|
const MENU_CUT_ICON_HTML = lucideIcon(Scissors, MENU_ICON_CLASS);
|
|
@@ -179,7 +191,9 @@ const CONTROL_PRESETS = {
|
|
|
179
191
|
zoom: false,
|
|
180
192
|
colorScheme: false,
|
|
181
193
|
orphanActions: false,
|
|
182
|
-
fileActions: false
|
|
194
|
+
fileActions: false,
|
|
195
|
+
search: false,
|
|
196
|
+
codeBlockTools: true
|
|
183
197
|
},
|
|
184
198
|
viewer: {
|
|
185
199
|
preset: 'viewer',
|
|
@@ -193,7 +207,9 @@ const CONTROL_PRESETS = {
|
|
|
193
207
|
zoom: true,
|
|
194
208
|
colorScheme: true,
|
|
195
209
|
orphanActions: false,
|
|
196
|
-
fileActions: false
|
|
210
|
+
fileActions: false,
|
|
211
|
+
search: true,
|
|
212
|
+
codeBlockTools: true
|
|
197
213
|
},
|
|
198
214
|
'standalone-editor': {
|
|
199
215
|
preset: 'standalone-editor',
|
|
@@ -207,7 +223,9 @@ const CONTROL_PRESETS = {
|
|
|
207
223
|
zoom: true,
|
|
208
224
|
colorScheme: true,
|
|
209
225
|
orphanActions: true,
|
|
210
|
-
fileActions: true
|
|
226
|
+
fileActions: true,
|
|
227
|
+
search: true,
|
|
228
|
+
codeBlockTools: true
|
|
211
229
|
},
|
|
212
230
|
'hosted-editor': {
|
|
213
231
|
preset: 'hosted-editor',
|
|
@@ -221,7 +239,9 @@ const CONTROL_PRESETS = {
|
|
|
221
239
|
zoom: true,
|
|
222
240
|
colorScheme: true,
|
|
223
241
|
orphanActions: true,
|
|
224
|
-
fileActions: true
|
|
242
|
+
fileActions: true,
|
|
243
|
+
search: true,
|
|
244
|
+
codeBlockTools: true
|
|
225
245
|
}
|
|
226
246
|
};
|
|
227
247
|
export function resolveMdzipControlPolicy(controls) {
|
|
@@ -367,6 +387,73 @@ const mdzipEditorTheme = EditorView.theme({
|
|
|
367
387
|
color: 'var(--mdzip-muted-foreground-color)',
|
|
368
388
|
opacity: '0.65',
|
|
369
389
|
},
|
|
390
|
+
'.cm-panels': {
|
|
391
|
+
background: 'var(--mdzip-widget-background-color)',
|
|
392
|
+
color: 'var(--mdzip-editor-foreground-color)',
|
|
393
|
+
zIndex: '2',
|
|
394
|
+
},
|
|
395
|
+
'.cm-panels.cm-panels-top': {
|
|
396
|
+
borderBottom: '1px solid var(--mdzip-border-color)',
|
|
397
|
+
},
|
|
398
|
+
'.cm-search': {
|
|
399
|
+
display: 'flex',
|
|
400
|
+
flexWrap: 'wrap',
|
|
401
|
+
alignItems: 'center',
|
|
402
|
+
gap: '8px',
|
|
403
|
+
padding: '10px 14px',
|
|
404
|
+
fontSize: '13px',
|
|
405
|
+
},
|
|
406
|
+
// CodeMirror separates the find and replace rows with a bare <br>; in a
|
|
407
|
+
// flex container that collapses to zero width instead of breaking the
|
|
408
|
+
// line, so force it to take the full row.
|
|
409
|
+
'.cm-search br': {
|
|
410
|
+
flexBasis: '100%',
|
|
411
|
+
height: '0',
|
|
412
|
+
},
|
|
413
|
+
'.cm-search label': {
|
|
414
|
+
display: 'inline-flex',
|
|
415
|
+
alignItems: 'center',
|
|
416
|
+
gap: '5px',
|
|
417
|
+
color: 'var(--mdzip-muted-foreground-color)',
|
|
418
|
+
},
|
|
419
|
+
'.cm-search input[type="checkbox"]': {
|
|
420
|
+
width: '14px',
|
|
421
|
+
height: '14px',
|
|
422
|
+
accentColor: 'var(--mdzip-accent-color)',
|
|
423
|
+
},
|
|
424
|
+
'.cm-textfield': {
|
|
425
|
+
background: 'var(--mdzip-editor-background-color)',
|
|
426
|
+
color: 'var(--mdzip-editor-foreground-color)',
|
|
427
|
+
border: '1px solid var(--mdzip-border-color)',
|
|
428
|
+
borderRadius: '5px',
|
|
429
|
+
padding: '5px 9px',
|
|
430
|
+
fontSize: 'inherit',
|
|
431
|
+
width: '220px',
|
|
432
|
+
},
|
|
433
|
+
'.cm-textfield:focus-visible': {
|
|
434
|
+
outline: '1px solid var(--mdzip-focus-outline-color)',
|
|
435
|
+
outlineOffset: '-1px',
|
|
436
|
+
},
|
|
437
|
+
'.cm-button': {
|
|
438
|
+
background: 'var(--mdzip-widget-background-color)',
|
|
439
|
+
backgroundImage: 'none',
|
|
440
|
+
color: 'var(--mdzip-control-foreground-color)',
|
|
441
|
+
border: '1px solid var(--mdzip-border-color)',
|
|
442
|
+
borderRadius: '5px',
|
|
443
|
+
padding: '5px 12px',
|
|
444
|
+
fontSize: 'inherit',
|
|
445
|
+
cursor: 'pointer',
|
|
446
|
+
},
|
|
447
|
+
'.cm-button:hover': {
|
|
448
|
+
background: 'var(--mdzip-control-hover-background-color)',
|
|
449
|
+
},
|
|
450
|
+
'.cm-searchMatch': {
|
|
451
|
+
backgroundColor: 'rgba(255, 214, 0, 0.35)',
|
|
452
|
+
},
|
|
453
|
+
'.cm-searchMatch-selected': {
|
|
454
|
+
backgroundColor: 'var(--mdzip-accent-color)',
|
|
455
|
+
color: 'var(--mdzip-accent-foreground-color)',
|
|
456
|
+
},
|
|
370
457
|
});
|
|
371
458
|
const mdzipMarkdownHighlight = HighlightStyle.define([
|
|
372
459
|
{ tag: [tags.heading1, tags.heading2, tags.heading3, tags.heading4, tags.heading5, tags.heading6],
|
|
@@ -376,7 +463,7 @@ const mdzipMarkdownHighlight = HighlightStyle.define([
|
|
|
376
463
|
{ tag: tags.emphasis, color: '#008b8b', fontStyle: 'italic' },
|
|
377
464
|
{ tag: tags.strikethrough, color: '#57606a', textDecoration: 'line-through' },
|
|
378
465
|
{ tag: tags.link, color: '#0969da' },
|
|
379
|
-
{ tag: tags.url, color: '#
|
|
466
|
+
{ tag: tags.url, color: '#6e7781' },
|
|
380
467
|
{ tag: tags.monospace, color: '#8a8f00' },
|
|
381
468
|
{ tag: tags.quote, color: '#7a5c00' },
|
|
382
469
|
{ tag: tags.contentSeparator, color: '#6a9955' },
|
|
@@ -398,6 +485,27 @@ const hardBreakMarkerHighlight = ViewPlugin.fromClass(class {
|
|
|
398
485
|
}, {
|
|
399
486
|
decorations: value => value.decorations
|
|
400
487
|
});
|
|
488
|
+
// Matches raw HTML tags other than <br> (which hardBreakMarkerMatcher already
|
|
489
|
+
// covers) so authors can visually distinguish raw HTML from Markdown prose.
|
|
490
|
+
// Excludes autolinks like <https://example.com> — those have no space before
|
|
491
|
+
// '>' and no closing '/', so the tag-name-only branch requires the char after
|
|
492
|
+
// the name to be '>' directly, which a URL's ':' never satisfies.
|
|
493
|
+
const htmlTagMarkerMatcher = new MatchDecorator({
|
|
494
|
+
regexp: /<\/?(?!br\b)[a-zA-Z][a-zA-Z0-9-]*(?:\s[^<>]*)?\/?>/gi,
|
|
495
|
+
decoration: Decoration.mark({ class: 'mdzip-hard-break-marker' })
|
|
496
|
+
});
|
|
497
|
+
const htmlTagMarkerHighlight = ViewPlugin.fromClass(class {
|
|
498
|
+
constructor(view) {
|
|
499
|
+
this.decorations = htmlTagMarkerMatcher.createDeco(view);
|
|
500
|
+
}
|
|
501
|
+
update(update) {
|
|
502
|
+
if (update.docChanged || update.viewportChanged) {
|
|
503
|
+
this.decorations = htmlTagMarkerMatcher.updateDeco(update, this.decorations);
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
}, {
|
|
507
|
+
decorations: value => value.decorations
|
|
508
|
+
});
|
|
401
509
|
function injectStyles(doc) {
|
|
402
510
|
const existing = doc.querySelector(`style[${STYLE_ATTR}]`);
|
|
403
511
|
if (existing) {
|
|
@@ -469,19 +577,19 @@ depth = 0) {
|
|
|
469
577
|
: isImageFile(node.entry.path)
|
|
470
578
|
? IMAGE_ICON_HTML
|
|
471
579
|
: FILE_ICON_HTML;
|
|
472
|
-
const orphanBtnHtml = isOrphaned && options.allowOrphanActions ? `
|
|
473
|
-
<span class="nav-orphan-button" role="button" tabindex="0"
|
|
474
|
-
title="Orphaned asset" aria-label="Orphaned asset actions"
|
|
475
|
-
data-orphan-path="${safePath}">
|
|
476
|
-
${ORPHAN_ICON_HTML}
|
|
580
|
+
const orphanBtnHtml = isOrphaned && options.allowOrphanActions ? `
|
|
581
|
+
<span class="nav-orphan-button" role="button" tabindex="0"
|
|
582
|
+
title="Orphaned asset" aria-label="Orphaned asset actions"
|
|
583
|
+
data-orphan-path="${safePath}">
|
|
584
|
+
${ORPHAN_ICON_HTML}
|
|
477
585
|
</span>` : '';
|
|
478
586
|
const draggable = options.allowDrag && !isManifest;
|
|
479
|
-
return `<button type="button" class="${classes}" title="${title}"
|
|
480
|
-
data-nav-path="${safePath}" data-orphan="${isOrphaned ? 'true' : ''}"${draggable ? ' draggable="true"' : ''}>
|
|
481
|
-
${guides}<span class="nav-caret"></span>
|
|
482
|
-
<span class="nav-file-icon ${iconKind}">${iconHtml}</span>
|
|
483
|
-
${orphanBtnHtml}
|
|
484
|
-
<span class="nav-label">${safeName}</span>
|
|
587
|
+
return `<button type="button" class="${classes}" title="${title}"
|
|
588
|
+
data-nav-path="${safePath}" data-orphan="${isOrphaned ? 'true' : ''}"${draggable ? ' draggable="true"' : ''}>
|
|
589
|
+
${guides}<span class="nav-caret"></span>
|
|
590
|
+
<span class="nav-file-icon ${iconKind}">${iconHtml}</span>
|
|
591
|
+
${orphanBtnHtml}
|
|
592
|
+
<span class="nav-label">${safeName}</span>
|
|
485
593
|
</button>`;
|
|
486
594
|
}
|
|
487
595
|
const childTrail = depth === 0 ? [] : [...trail, !isLast];
|
|
@@ -489,14 +597,14 @@ depth = 0) {
|
|
|
489
597
|
.map((child, index) => renderNavNode(child, state, options, childTrail, index === node.children.length - 1, depth + 1))
|
|
490
598
|
.join('');
|
|
491
599
|
const pending = options.pendingFolders.has(node.path.toLowerCase());
|
|
492
|
-
return `<details class="nav-directory${pending ? ' pending-folder' : ''}" open data-nav-dir="${escapeHtml(node.path)}">
|
|
493
|
-
<summary${pending ? ` title="${escapeHtml(node.path)} — not saved until it contains a file"` : ''}>
|
|
494
|
-
${guides}<span class="nav-caret" aria-hidden="true"></span>
|
|
495
|
-
<span class="nav-folder-icon closed">${FOLDER_CLOSED_ICON_HTML}</span>
|
|
496
|
-
<span class="nav-folder-icon open">${FOLDER_OPEN_ICON_HTML}</span>
|
|
497
|
-
<span class="nav-label">${escapeHtml(node.name)}</span>
|
|
498
|
-
</summary>
|
|
499
|
-
<div class="nav-directory-children">${children}</div>
|
|
600
|
+
return `<details class="nav-directory${pending ? ' pending-folder' : ''}" open data-nav-dir="${escapeHtml(node.path)}">
|
|
601
|
+
<summary${pending ? ` title="${escapeHtml(node.path)} — not saved until it contains a file"` : ''}>
|
|
602
|
+
${guides}<span class="nav-caret" aria-hidden="true"></span>
|
|
603
|
+
<span class="nav-folder-icon closed">${FOLDER_CLOSED_ICON_HTML}</span>
|
|
604
|
+
<span class="nav-folder-icon open">${FOLDER_OPEN_ICON_HTML}</span>
|
|
605
|
+
<span class="nav-label">${escapeHtml(node.name)}</span>
|
|
606
|
+
</summary>
|
|
607
|
+
<div class="nav-directory-children">${children}</div>
|
|
500
608
|
</details>`;
|
|
501
609
|
}
|
|
502
610
|
// Inserts view-local pending (not yet saved) folders into the nav tree so they
|
|
@@ -532,6 +640,35 @@ function navNodeOrder(a, b) {
|
|
|
532
640
|
return 1;
|
|
533
641
|
return a.name.localeCompare(b.name);
|
|
534
642
|
}
|
|
643
|
+
// Browsers apply raw HTML width/height attributes as presentational sizing
|
|
644
|
+
// hints, but the preview's `img { height: auto }` rule (for responsive
|
|
645
|
+
// scaling) overrides that hint via the normal CSS cascade — so an author's
|
|
646
|
+
// `<img height="300">` was silently ignored. Re-applying numeric, unitless
|
|
647
|
+
// width/height attributes as inline pixel styles restores that sizing
|
|
648
|
+
// without touching an author-supplied inline style.
|
|
649
|
+
function applyRawHtmlImageSizeAttributes(image) {
|
|
650
|
+
const width = image.getAttribute('width');
|
|
651
|
+
if (width && /^\d+$/.test(width) && !image.style.width) {
|
|
652
|
+
image.style.width = `${width}px`;
|
|
653
|
+
}
|
|
654
|
+
const height = image.getAttribute('height');
|
|
655
|
+
if (height && /^\d+$/.test(height) && !image.style.height) {
|
|
656
|
+
image.style.height = `${height}px`;
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
// Maps the legacy raw HTML `align="left"|"right"` attribute (or the editor's
|
|
660
|
+
// own wrap classes) to a layout direction, for images that skip archive
|
|
661
|
+
// hydration — external, data, and fragment sources — and so never get a slot.
|
|
662
|
+
function rawHtmlImageAlignClass(image) {
|
|
663
|
+
const align = image.getAttribute('align')?.toLowerCase();
|
|
664
|
+
if (align === 'left' || image.classList.contains('mdzip-image-wrap-left')) {
|
|
665
|
+
return 'mdzip-image-left';
|
|
666
|
+
}
|
|
667
|
+
if (align === 'right' || image.classList.contains('mdzip-image-wrap-right')) {
|
|
668
|
+
return 'mdzip-image-right';
|
|
669
|
+
}
|
|
670
|
+
return null;
|
|
671
|
+
}
|
|
535
672
|
export class MdzipWorkspaceView {
|
|
536
673
|
constructor(container, options = {}) {
|
|
537
674
|
this.workspace = null;
|
|
@@ -574,6 +711,7 @@ export class MdzipWorkspaceView {
|
|
|
574
711
|
this.cmEditor = null;
|
|
575
712
|
this.readOnlyCompartment = new Compartment();
|
|
576
713
|
this.lineNumbersCompartment = new Compartment();
|
|
714
|
+
this.searchCompartment = new Compartment();
|
|
577
715
|
this.updatingCm = false;
|
|
578
716
|
this.syncing = false;
|
|
579
717
|
this.markdownExtensions = [];
|
|
@@ -630,6 +768,7 @@ export class MdzipWorkspaceView {
|
|
|
630
768
|
this.elSourceBtn = q('[data-ref="source-btn"]');
|
|
631
769
|
this.elSourceIcon = q('[data-ref="source-icon"]');
|
|
632
770
|
this.elSaveBtn = q('[data-ref="save-btn"]');
|
|
771
|
+
this.elSearchBtn = q('[data-ref="search-btn"]');
|
|
633
772
|
this.elZoomBtn = q('[data-ref="zoom-btn"]');
|
|
634
773
|
this.elThemeControls = q('[data-ref="theme-controls"]');
|
|
635
774
|
this.elDarkThemeBtn = q('[data-ref="dark-theme-btn"]');
|
|
@@ -907,6 +1046,40 @@ export class MdzipWorkspaceView {
|
|
|
907
1046
|
this.applyMarkdownFormat(command);
|
|
908
1047
|
return true;
|
|
909
1048
|
}
|
|
1049
|
+
/**
|
|
1050
|
+
* Opens CodeMirror's find/replace panel for the current document. Unlike
|
|
1051
|
+
* {@link executeCommand}, this works in read-only (Viewer) hosts too —
|
|
1052
|
+
* searching doesn't require edit access, only a visible source pane. If
|
|
1053
|
+
* the current layout is preview-only, switches to split/source first so
|
|
1054
|
+
* the panel has somewhere to render.
|
|
1055
|
+
*/
|
|
1056
|
+
async openSearch() {
|
|
1057
|
+
if (!this.controlPolicy.search) {
|
|
1058
|
+
return false;
|
|
1059
|
+
}
|
|
1060
|
+
const snapshot = this.workspace?.snapshot();
|
|
1061
|
+
if (!snapshot || snapshot.currentPathType !== 'markdown') {
|
|
1062
|
+
return false;
|
|
1063
|
+
}
|
|
1064
|
+
if (this.layout === 'preview') {
|
|
1065
|
+
const nextLayout = this.controlPolicy.layout.split
|
|
1066
|
+
? 'split'
|
|
1067
|
+
: this.controlPolicy.layout.source ? 'source' : null;
|
|
1068
|
+
if (!nextLayout) {
|
|
1069
|
+
return false;
|
|
1070
|
+
}
|
|
1071
|
+
await this.setLayout(nextLayout);
|
|
1072
|
+
}
|
|
1073
|
+
const editor = await this.ensureCmEditor(true);
|
|
1074
|
+
if (!editor) {
|
|
1075
|
+
return false;
|
|
1076
|
+
}
|
|
1077
|
+
editor.focus();
|
|
1078
|
+
return openSearchPanel(editor);
|
|
1079
|
+
}
|
|
1080
|
+
closeSearch() {
|
|
1081
|
+
return this.cmEditor ? closeSearchPanel(this.cmEditor) : false;
|
|
1082
|
+
}
|
|
910
1083
|
async convertToMdz() {
|
|
911
1084
|
if (!this.workspace || this.workspace.mode === 'read-only') {
|
|
912
1085
|
return false;
|
|
@@ -982,12 +1155,21 @@ export class MdzipWorkspaceView {
|
|
|
982
1155
|
setControls(controls) {
|
|
983
1156
|
const next = resolveMdzipControlPolicy(controls);
|
|
984
1157
|
const lineNumbersChanged = next.lineNumbers !== this.controlPolicy.lineNumbers;
|
|
1158
|
+
const searchChanged = next.search !== this.controlPolicy.search;
|
|
985
1159
|
this.controlPolicy = next;
|
|
986
1160
|
if (lineNumbersChanged && this.cmEditor) {
|
|
987
1161
|
this.cmEditor.dispatch({
|
|
988
1162
|
effects: this.lineNumbersCompartment.reconfigure(next.lineNumbers ? lineNumbers() : [])
|
|
989
1163
|
});
|
|
990
1164
|
}
|
|
1165
|
+
if (searchChanged && this.cmEditor) {
|
|
1166
|
+
if (!next.search) {
|
|
1167
|
+
closeSearchPanel(this.cmEditor);
|
|
1168
|
+
}
|
|
1169
|
+
this.cmEditor.dispatch({
|
|
1170
|
+
effects: this.searchCompartment.reconfigure(next.search ? [search({ top: true }), keymap.of(searchKeymap)] : [])
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
991
1173
|
const snapshot = this.workspace?.snapshot();
|
|
992
1174
|
if (snapshot) {
|
|
993
1175
|
this.layout = this.validLayoutForSnapshot(this.layout, snapshot);
|
|
@@ -1170,6 +1352,10 @@ export class MdzipWorkspaceView {
|
|
|
1170
1352
|
mountPreviewHtml(html, snapshot, context, generation) {
|
|
1171
1353
|
this.elPreviewContent.innerHTML = html;
|
|
1172
1354
|
this.mountPreviewExtensions(context, generation);
|
|
1355
|
+
const codeBlockHandle = this.mountCodeBlockControls();
|
|
1356
|
+
if (codeBlockHandle) {
|
|
1357
|
+
this.previewHandles.push(codeBlockHandle);
|
|
1358
|
+
}
|
|
1173
1359
|
// No archive images to resolve on this path: the preview is ready now.
|
|
1174
1360
|
this.firePreviewRendered(snapshot, generation);
|
|
1175
1361
|
this.fireAssetsHydrated(snapshot, generation);
|
|
@@ -1186,9 +1372,14 @@ export class MdzipWorkspaceView {
|
|
|
1186
1372
|
const document = this.elPreviewContent.ownerDocument;
|
|
1187
1373
|
const pending = [];
|
|
1188
1374
|
for (const image of Array.from(this.elPreviewContent.querySelectorAll('img'))) {
|
|
1375
|
+
applyRawHtmlImageSizeAttributes(image);
|
|
1189
1376
|
const source = image.getAttribute('src');
|
|
1190
1377
|
// Leave external, protocol-relative, data, and fragment URLs untouched.
|
|
1191
1378
|
if (!source || /^(?:[a-z][a-z\d+.-]*:|\/\/|#)/i.test(source)) {
|
|
1379
|
+
const alignClass = rawHtmlImageAlignClass(image);
|
|
1380
|
+
if (alignClass) {
|
|
1381
|
+
image.classList.add(alignClass);
|
|
1382
|
+
}
|
|
1192
1383
|
continue;
|
|
1193
1384
|
}
|
|
1194
1385
|
// Drop the archive-relative src so the browser does not fetch the bad
|
|
@@ -1203,11 +1394,11 @@ export class MdzipWorkspaceView {
|
|
|
1203
1394
|
slot.className = animateImageHydration
|
|
1204
1395
|
? 'mdzip-image-slot'
|
|
1205
1396
|
: 'mdzip-image-slot mdzip-image-open mdzip-image-animation-off';
|
|
1206
|
-
const
|
|
1207
|
-
if (
|
|
1397
|
+
const alignClass = rawHtmlImageAlignClass(image);
|
|
1398
|
+
if (alignClass === 'mdzip-image-left') {
|
|
1208
1399
|
slot.classList.add('mdzip-image-align-left');
|
|
1209
1400
|
}
|
|
1210
|
-
else if (
|
|
1401
|
+
else if (alignClass === 'mdzip-image-right') {
|
|
1211
1402
|
slot.classList.add('mdzip-image-align-right');
|
|
1212
1403
|
}
|
|
1213
1404
|
image.parentNode?.insertBefore(slot, image);
|
|
@@ -1215,6 +1406,10 @@ export class MdzipWorkspaceView {
|
|
|
1215
1406
|
pending.push({ image, slot, source });
|
|
1216
1407
|
}
|
|
1217
1408
|
this.mountPreviewExtensions(context, generation);
|
|
1409
|
+
const codeBlockHandle = this.mountCodeBlockControls();
|
|
1410
|
+
if (codeBlockHandle) {
|
|
1411
|
+
this.previewHandles.push(codeBlockHandle);
|
|
1412
|
+
}
|
|
1218
1413
|
this.firePreviewRendered(snapshot, generation);
|
|
1219
1414
|
if (!session || pending.length === 0) {
|
|
1220
1415
|
this.fireAssetsHydrated(snapshot, generation);
|
|
@@ -1358,6 +1553,130 @@ export class MdzipWorkspaceView {
|
|
|
1358
1553
|
}
|
|
1359
1554
|
}
|
|
1360
1555
|
}
|
|
1556
|
+
/**
|
|
1557
|
+
* Built-in preview affordances for rendered code blocks: a language-name
|
|
1558
|
+
* header, a copy-to-clipboard button, and (on long enough blocks) a
|
|
1559
|
+
* collapse/expand toggle. Gated by `controlPolicy.codeBlockTools`.
|
|
1560
|
+
*
|
|
1561
|
+
* Deliberately not a `markdownExtensions` entry (unlike the Mermaid
|
|
1562
|
+
* extension) — every consumer gets this automatically, gated by policy
|
|
1563
|
+
* rather than opt-in wiring. Runs after `mountPreviewExtensions` so any
|
|
1564
|
+
* extension-provided `pre > code` blocks already exist in the DOM. See #29.
|
|
1565
|
+
*/
|
|
1566
|
+
mountCodeBlockControls() {
|
|
1567
|
+
if (!this.controlPolicy.codeBlockTools) {
|
|
1568
|
+
return null;
|
|
1569
|
+
}
|
|
1570
|
+
const codeEls = Array.from(this.elPreviewContent.querySelectorAll('pre > code'));
|
|
1571
|
+
if (codeEls.length === 0) {
|
|
1572
|
+
return null;
|
|
1573
|
+
}
|
|
1574
|
+
const doc = this.elPreviewContent.ownerDocument;
|
|
1575
|
+
// Resolve AbortController from the document's own realm, not the ambient
|
|
1576
|
+
// global: addEventListener's `signal` option is validated against the
|
|
1577
|
+
// listener target's realm, so a controller from a different realm (e.g.
|
|
1578
|
+
// Node's global AbortController against a jsdom-hosted element in a
|
|
1579
|
+
// server-side/test environment) fails that check even though both are
|
|
1580
|
+
// spec-compliant AbortControllers.
|
|
1581
|
+
const AbortControllerCtor = doc.defaultView?.AbortController ?? AbortController;
|
|
1582
|
+
const controller = new AbortControllerCtor();
|
|
1583
|
+
for (const code of codeEls) {
|
|
1584
|
+
const pre = code.parentElement;
|
|
1585
|
+
if (pre) {
|
|
1586
|
+
this.enhanceCodeBlock(pre, code, doc, controller.signal);
|
|
1587
|
+
}
|
|
1588
|
+
}
|
|
1589
|
+
return { destroy: () => controller.abort() };
|
|
1590
|
+
}
|
|
1591
|
+
/**
|
|
1592
|
+
* Wraps one `pre > code` block with a header (language label + action
|
|
1593
|
+
* buttons) and a collapsible body, in place. `pre` itself is relocated
|
|
1594
|
+
* (not cloned) into the new structure, so existing references to it and
|
|
1595
|
+
* its `code` child stay valid.
|
|
1596
|
+
*/
|
|
1597
|
+
enhanceCodeBlock(pre, code, doc, signal) {
|
|
1598
|
+
const language = /language-([\w-]+)/.exec(code.className)?.[1] ?? '';
|
|
1599
|
+
const wrapper = doc.createElement('div');
|
|
1600
|
+
wrapper.className = 'mdzip-code-block';
|
|
1601
|
+
const header = doc.createElement('div');
|
|
1602
|
+
header.className = 'mdzip-code-block-header';
|
|
1603
|
+
const label = doc.createElement('span');
|
|
1604
|
+
label.className = 'mdzip-code-block-lang';
|
|
1605
|
+
label.textContent = language || 'text';
|
|
1606
|
+
header.appendChild(label);
|
|
1607
|
+
const actions = doc.createElement('div');
|
|
1608
|
+
actions.className = 'mdzip-code-block-actions';
|
|
1609
|
+
header.appendChild(actions);
|
|
1610
|
+
const body = doc.createElement('div');
|
|
1611
|
+
body.className = 'mdzip-code-block-body';
|
|
1612
|
+
pre.replaceWith(wrapper);
|
|
1613
|
+
wrapper.append(header, body);
|
|
1614
|
+
body.appendChild(pre);
|
|
1615
|
+
// Collapse toggle: only shown when the block has enough lines that
|
|
1616
|
+
// collapsing is actually visible — the collapsed body still shows ~12
|
|
1617
|
+
// lines (240px, see .mdzip-code-block-collapsed in view-css.ts), so a
|
|
1618
|
+
// button that collapses a block shorter than that would visibly do
|
|
1619
|
+
// nothing, which is more confusing than not offering it at all. Blocks
|
|
1620
|
+
// past the longer auto-collapse threshold start pre-collapsed; anything
|
|
1621
|
+
// between the two thresholds is collapsible but starts open.
|
|
1622
|
+
const lineCount = (code.textContent ?? '').split('\n').length;
|
|
1623
|
+
if (lineCount > CODE_BLOCK_COLLAPSIBLE_MIN_LINES) {
|
|
1624
|
+
if (lineCount > CODE_BLOCK_AUTO_COLLAPSE_LINES) {
|
|
1625
|
+
wrapper.classList.add('mdzip-code-block-collapsed');
|
|
1626
|
+
}
|
|
1627
|
+
const collapseBtn = doc.createElement('button');
|
|
1628
|
+
collapseBtn.type = 'button';
|
|
1629
|
+
collapseBtn.className = 'mdzip-code-block-btn';
|
|
1630
|
+
collapseBtn.innerHTML = CODE_BLOCK_COLLAPSE_ICON_HTML;
|
|
1631
|
+
const syncCollapseLabel = () => {
|
|
1632
|
+
const collapsed = wrapper.classList.contains('mdzip-code-block-collapsed');
|
|
1633
|
+
collapseBtn.setAttribute('aria-expanded', collapsed ? 'false' : 'true');
|
|
1634
|
+
collapseBtn.setAttribute('aria-label', collapsed ? 'Expand code block' : 'Collapse code block');
|
|
1635
|
+
};
|
|
1636
|
+
syncCollapseLabel();
|
|
1637
|
+
collapseBtn.title = 'Collapse/expand';
|
|
1638
|
+
collapseBtn.addEventListener('click', () => {
|
|
1639
|
+
wrapper.classList.toggle('mdzip-code-block-collapsed');
|
|
1640
|
+
syncCollapseLabel();
|
|
1641
|
+
}, { signal });
|
|
1642
|
+
actions.appendChild(collapseBtn);
|
|
1643
|
+
}
|
|
1644
|
+
// Copy button: icon swaps to a confirmation state for a beat, then reverts.
|
|
1645
|
+
// The revert timer is cleared on unmount so it never touches a stale button
|
|
1646
|
+
// after the preview re-renders.
|
|
1647
|
+
const copyBtn = doc.createElement('button');
|
|
1648
|
+
copyBtn.type = 'button';
|
|
1649
|
+
copyBtn.className = 'mdzip-code-block-btn';
|
|
1650
|
+
copyBtn.innerHTML = CODE_BLOCK_COPY_ICON_HTML;
|
|
1651
|
+
copyBtn.setAttribute('aria-label', 'Copy code');
|
|
1652
|
+
copyBtn.title = 'Copy code';
|
|
1653
|
+
// Re-check clipboard availability at click time rather than capturing it
|
|
1654
|
+
// once at mount: a host can grant/attach clipboard access after the
|
|
1655
|
+
// preview first renders, and this way there is nothing to keep in sync.
|
|
1656
|
+
let copiedTimer;
|
|
1657
|
+
copyBtn.addEventListener('click', () => {
|
|
1658
|
+
const clip = doc.defaultView?.navigator.clipboard;
|
|
1659
|
+
if (!clip) {
|
|
1660
|
+
return;
|
|
1661
|
+
}
|
|
1662
|
+
void clip.writeText(code.textContent ?? '').then(() => {
|
|
1663
|
+
copyBtn.innerHTML = CODE_BLOCK_COPIED_ICON_HTML;
|
|
1664
|
+
copyBtn.classList.add('mdzip-code-block-btn-copied');
|
|
1665
|
+
copyBtn.setAttribute('aria-label', 'Copied');
|
|
1666
|
+
clearTimeout(copiedTimer);
|
|
1667
|
+
copiedTimer = setTimeout(() => {
|
|
1668
|
+
copyBtn.innerHTML = CODE_BLOCK_COPY_ICON_HTML;
|
|
1669
|
+
copyBtn.classList.remove('mdzip-code-block-btn-copied');
|
|
1670
|
+
copyBtn.setAttribute('aria-label', 'Copy code');
|
|
1671
|
+
}, 1500);
|
|
1672
|
+
}).catch(() => {
|
|
1673
|
+
// Write can fail (permissions, insecure context); leave the button
|
|
1674
|
+
// as-is rather than showing a false confirmation.
|
|
1675
|
+
});
|
|
1676
|
+
}, { signal });
|
|
1677
|
+
signal.addEventListener('abort', () => clearTimeout(copiedTimer), { once: true });
|
|
1678
|
+
actions.appendChild(copyBtn);
|
|
1679
|
+
}
|
|
1361
1680
|
firePreviewRendered(snapshot, generation) {
|
|
1362
1681
|
if (generation !== this.previewGeneration) {
|
|
1363
1682
|
return;
|
|
@@ -1579,6 +1898,7 @@ export class MdzipWorkspaceView {
|
|
|
1579
1898
|
doc: initialText,
|
|
1580
1899
|
extensions: [
|
|
1581
1900
|
this.lineNumbersCompartment.of(this.controlPolicy.lineNumbers ? lineNumbers() : []),
|
|
1901
|
+
this.searchCompartment.of(this.controlPolicy.search ? [search({ top: true }), keymap.of(searchKeymap)] : []),
|
|
1582
1902
|
history(),
|
|
1583
1903
|
keymap.of([
|
|
1584
1904
|
{ key: 'Mod-b', run: () => self.runFormatShortcut('bold') },
|
|
@@ -1589,6 +1909,7 @@ export class MdzipWorkspaceView {
|
|
|
1589
1909
|
markdown(),
|
|
1590
1910
|
syntaxHighlighting(mdzipMarkdownHighlight),
|
|
1591
1911
|
hardBreakMarkerHighlight,
|
|
1912
|
+
htmlTagMarkerHighlight,
|
|
1592
1913
|
EditorView.lineWrapping,
|
|
1593
1914
|
dropCursor(),
|
|
1594
1915
|
mdzipEditorTheme,
|
|
@@ -1682,24 +2003,28 @@ export class MdzipWorkspaceView {
|
|
|
1682
2003
|
const showSaveControl = this.controlPolicy.save && snapshot.mode !== 'read-only';
|
|
1683
2004
|
const showZoomControl = this.controlPolicy.zoom;
|
|
1684
2005
|
const showColorSchemeControl = this.controlPolicy.colorScheme;
|
|
2006
|
+
const showSearchControl = this.controlPolicy.search
|
|
2007
|
+
&& canShowSource && snapshot.currentPathType === 'markdown';
|
|
1685
2008
|
const showEditControls = canEdit
|
|
1686
2009
|
&& snapshot.currentPathType === 'markdown'
|
|
1687
2010
|
&& this.layout !== 'preview'
|
|
1688
2011
|
&& hasFormattingControls(this.controlPolicy.formatting);
|
|
1689
2012
|
const showToolbar = this.controlPolicy.toolbar
|
|
1690
|
-
&& (showNavigationControl || showLayoutControls
|
|
1691
|
-
||
|
|
2013
|
+
&& (showNavigationControl || showLayoutControls || showSaveControl
|
|
2014
|
+
|| showZoomControl || showColorSchemeControl || showSearchControl || showEditControls);
|
|
1692
2015
|
this.elDocumentStrip.hidden = !showTitleControl;
|
|
1693
2016
|
this.elToolbar.hidden = !showToolbar;
|
|
1694
2017
|
this.elToolbarLeft.hidden = !showNavigationControl;
|
|
1695
2018
|
this.elEditToolbar.hidden = !showEditControls;
|
|
1696
2019
|
this.elLayoutControls.hidden = !showLayoutControls;
|
|
1697
|
-
this.elToolbarControls.hidden = !showSaveControl && !showZoomControl
|
|
2020
|
+
this.elToolbarControls.hidden = !showSaveControl && !showZoomControl
|
|
2021
|
+
&& !showColorSchemeControl && !showSearchControl;
|
|
1698
2022
|
this.elNavBtn.hidden = !showNavigationControl;
|
|
1699
2023
|
this.elPreviewBtn.hidden = !this.controlPolicy.layout.preview;
|
|
1700
2024
|
this.elSplitBtn.hidden = !this.controlPolicy.layout.split;
|
|
1701
2025
|
this.elSourceBtn.hidden = !this.controlPolicy.layout.source;
|
|
1702
2026
|
this.elSaveBtn.hidden = !showSaveControl;
|
|
2027
|
+
this.elSearchBtn.hidden = !showSearchControl;
|
|
1703
2028
|
this.elZoomBtn.hidden = !showZoomControl;
|
|
1704
2029
|
this.elThemeControls.hidden = !showColorSchemeControl;
|
|
1705
2030
|
this.elRoot.style.setProperty('--mdz-zoom', String(this.zoom));
|
|
@@ -1984,6 +2309,9 @@ export class MdzipWorkspaceView {
|
|
|
1984
2309
|
void this.save();
|
|
1985
2310
|
}
|
|
1986
2311
|
});
|
|
2312
|
+
this.elSearchBtn.addEventListener('click', () => {
|
|
2313
|
+
void this.openSearch();
|
|
2314
|
+
});
|
|
1987
2315
|
this.elZoomBtn.addEventListener('click', (e) => {
|
|
1988
2316
|
if (!this.controlPolicy.zoom) {
|
|
1989
2317
|
return;
|
|
@@ -4117,267 +4445,270 @@ function formatMetadataValue(value) {
|
|
|
4117
4445
|
}
|
|
4118
4446
|
return 'Not available';
|
|
4119
4447
|
}
|
|
4120
|
-
const SHELL_HTML = `
|
|
4121
|
-
<section class="mdzip-root">
|
|
4122
|
-
<div class="document-strip" data-ref="document-strip" hidden>
|
|
4123
|
-
<button type="button" class="title-button" data-ref="title-btn"></button>
|
|
4124
|
-
<button type="button" class="document-info-button" data-ref="document-info-btn"
|
|
4125
|
-
title="Document information" aria-label="Document information">
|
|
4126
|
-
${INFO_ICON_HTML}
|
|
4127
|
-
</button>
|
|
4128
|
-
</div>
|
|
4129
|
-
|
|
4130
|
-
<header class="toolbar" data-ref="toolbar" hidden>
|
|
4131
|
-
<div class="toolbar-start">
|
|
4132
|
-
<div class="toolbar-left">
|
|
4133
|
-
<button type="button" class="icon-toggle nav-toggle" data-ref="nav-btn" title="Toggle contents" aria-label="Toggle contents">
|
|
4134
|
-
${NAV_TOGGLE_ICON_HTML}
|
|
4135
|
-
</button>
|
|
4136
|
-
</div>
|
|
4137
|
-
|
|
4138
|
-
<div class="edit-toolbar" data-ref="edit-toolbar" role="toolbar" aria-label="Markdown formatting">
|
|
4139
|
-
<div class="edit-toolbar-group">
|
|
4140
|
-
<button type="button" data-format="bold" data-format-control="bold" title="Bold" aria-label="Bold">${BOLD_ICON_HTML}</button>
|
|
4141
|
-
<button type="button" data-format="italic" data-format-control="italic" title="Italic" aria-label="Italic">${ITALIC_ICON_HTML}</button>
|
|
4142
|
-
<button type="button" data-format="strike" data-format-control="strikethrough" title="Strikethrough" aria-label="Strikethrough">${STRIKE_ICON_HTML}</button>
|
|
4143
|
-
<div class="format-menu" data-format-control="headings">
|
|
4144
|
-
<button type="button" class="format-menu-toggle" data-format-menu-toggle
|
|
4145
|
-
aria-label="Heading" aria-haspopup="menu" aria-expanded="false">
|
|
4146
|
-
${HEADING_ICON_HTML}${CHEVRON_ICON_HTML}
|
|
4147
|
-
</button>
|
|
4148
|
-
<div class="format-menu-popover" data-format-menu role="menu" aria-label="Heading level" hidden>
|
|
4149
|
-
<button type="button" role="menuitem" data-format="paragraph">Paragraph</button>
|
|
4150
|
-
<button type="button" role="menuitem" data-format="heading-1" data-heading-level="1"><strong>H1</strong> Heading 1</button>
|
|
4151
|
-
<button type="button" role="menuitem" data-format="heading-2" data-heading-level="2"><strong>H2</strong> Heading 2</button>
|
|
4152
|
-
<button type="button" role="menuitem" data-format="heading-3" data-heading-level="3"><strong>H3</strong> Heading 3</button>
|
|
4153
|
-
<button type="button" role="menuitem" data-format="heading-4" data-heading-level="4"><strong>H4</strong> Heading 4</button>
|
|
4154
|
-
<button type="button" role="menuitem" data-format="heading-5" data-heading-level="5"><strong>H5</strong> Heading 5</button>
|
|
4155
|
-
<button type="button" role="menuitem" data-format="heading-6" data-heading-level="6"><strong>H6</strong> Heading 6</button>
|
|
4156
|
-
</div>
|
|
4157
|
-
</div>
|
|
4158
|
-
</div>
|
|
4159
|
-
<span class="edit-toolbar-divider" aria-hidden="true"></span>
|
|
4160
|
-
<div class="edit-toolbar-group">
|
|
4161
|
-
<button type="button" data-format="bullet-list" data-format-control="bulletList" title="Bulleted list" aria-label="Bulleted list">${BULLET_LIST_ICON_HTML}</button>
|
|
4162
|
-
<button type="button" data-format="ordered-list" data-format-control="orderedList" title="Numbered list" aria-label="Numbered list">${ORDERED_LIST_ICON_HTML}</button>
|
|
4163
|
-
<div class="format-menu" data-format-control="code">
|
|
4164
|
-
<button type="button" class="format-menu-toggle" data-format-menu-toggle
|
|
4165
|
-
aria-label="Code" aria-haspopup="menu" aria-expanded="false">
|
|
4166
|
-
${CODE_ICON_HTML}${CHEVRON_ICON_HTML}
|
|
4167
|
-
</button>
|
|
4168
|
-
<div class="format-menu-popover" data-format-menu role="menu" aria-label="Code format" hidden>
|
|
4169
|
-
<button type="button" role="menuitem" data-format="code" data-code-kind="inline">Inline code</button>
|
|
4170
|
-
<button type="button" role="menuitem" data-format="code-block" data-code-kind="block">Code block</button>
|
|
4171
|
-
</div>
|
|
4172
|
-
</div>
|
|
4173
|
-
<button type="button" data-format="quote" data-format-control="blockquote" title="Blockquote" aria-label="Blockquote">${QUOTE_ICON_HTML}</button>
|
|
4174
|
-
<button type="button" data-format="line-break" data-format-control="lineBreak" title="Line break" aria-label="Line break">${LINE_BREAK_ICON_HTML}</button>
|
|
4175
|
-
</div>
|
|
4176
|
-
<span class="edit-toolbar-divider" aria-hidden="true"></span>
|
|
4177
|
-
<div class="edit-toolbar-group">
|
|
4178
|
-
<button type="button" data-format="link" data-format-control="link" title="Link" aria-label="Link">${LINK_ICON_HTML}</button>
|
|
4179
|
-
<button type="button" data-format="image" data-format-control="image" title="Image" aria-label="Image">${IMAGE_FORMAT_ICON_HTML}</button>
|
|
4180
|
-
<input type="file" data-ref="image-input" accept="image/*" hidden />
|
|
4181
|
-
</div>
|
|
4182
|
-
</div>
|
|
4183
|
-
</div>
|
|
4184
|
-
|
|
4185
|
-
<div class="toolbar-buttons view-mode-toggle-group" data-ref="layout-controls" role="group" aria-label="Editor layout">
|
|
4186
|
-
<button type="button" class="icon-toggle view-mode-toggle" data-ref="source-btn" title="Edit" aria-label="Edit" aria-pressed="false">
|
|
4187
|
-
<span class="commandbar-flex-container" data-ref="source-icon">${SOURCE_EDIT_ICON_HTML}</span>
|
|
4188
|
-
</button>
|
|
4189
|
-
<button type="button" class="icon-toggle view-mode-toggle" data-ref="split-btn" title="Split" aria-label="Split" aria-pressed="false">
|
|
4190
|
-
<span class="commandbar-flex-container">
|
|
4191
|
-
${SPLIT_ICON_HTML}
|
|
4192
|
-
</span>
|
|
4193
|
-
</button>
|
|
4194
|
-
<button type="button" class="icon-toggle view-mode-toggle" data-ref="preview-btn" title="View" aria-label="View" aria-pressed="false">
|
|
4195
|
-
<span class="commandbar-flex-container">
|
|
4196
|
-
${PREVIEW_ICON_HTML}
|
|
4197
|
-
</span>
|
|
4198
|
-
</button>
|
|
4199
|
-
</div>
|
|
4200
|
-
|
|
4201
|
-
<div class="toolbar-controls" data-ref="toolbar-controls">
|
|
4202
|
-
<button type="button" class="icon-toggle" data-ref="
|
|
4203
|
-
${
|
|
4204
|
-
</button>
|
|
4205
|
-
<button type="button" class="icon-toggle
|
|
4206
|
-
${
|
|
4207
|
-
</button>
|
|
4208
|
-
<
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
<
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
<div class="
|
|
4237
|
-
|
|
4238
|
-
|
|
4239
|
-
|
|
4240
|
-
<
|
|
4241
|
-
|
|
4242
|
-
|
|
4243
|
-
|
|
4244
|
-
|
|
4245
|
-
<section class="pane
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
<
|
|
4256
|
-
<p>
|
|
4257
|
-
<
|
|
4258
|
-
|
|
4259
|
-
|
|
4260
|
-
|
|
4261
|
-
|
|
4262
|
-
|
|
4263
|
-
|
|
4264
|
-
|
|
4265
|
-
|
|
4266
|
-
|
|
4267
|
-
|
|
4268
|
-
|
|
4269
|
-
|
|
4270
|
-
|
|
4271
|
-
|
|
4272
|
-
|
|
4273
|
-
|
|
4274
|
-
|
|
4275
|
-
|
|
4276
|
-
|
|
4277
|
-
|
|
4278
|
-
|
|
4279
|
-
|
|
4280
|
-
|
|
4281
|
-
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
|
|
4285
|
-
|
|
4286
|
-
|
|
4287
|
-
|
|
4288
|
-
|
|
4289
|
-
|
|
4290
|
-
|
|
4291
|
-
|
|
4292
|
-
|
|
4293
|
-
|
|
4294
|
-
|
|
4295
|
-
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
<
|
|
4305
|
-
|
|
4306
|
-
|
|
4307
|
-
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
<option value="
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4315
|
-
|
|
4316
|
-
|
|
4317
|
-
|
|
4318
|
-
|
|
4319
|
-
|
|
4320
|
-
|
|
4321
|
-
|
|
4322
|
-
|
|
4323
|
-
|
|
4324
|
-
<option value="
|
|
4325
|
-
<option value="
|
|
4326
|
-
<option value="
|
|
4327
|
-
|
|
4328
|
-
|
|
4329
|
-
|
|
4330
|
-
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
|
|
4334
|
-
|
|
4335
|
-
|
|
4336
|
-
|
|
4337
|
-
|
|
4338
|
-
|
|
4339
|
-
|
|
4340
|
-
|
|
4341
|
-
|
|
4342
|
-
<
|
|
4343
|
-
<
|
|
4344
|
-
|
|
4345
|
-
|
|
4346
|
-
|
|
4347
|
-
|
|
4348
|
-
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4352
|
-
|
|
4353
|
-
|
|
4354
|
-
|
|
4355
|
-
<
|
|
4356
|
-
|
|
4357
|
-
|
|
4358
|
-
|
|
4359
|
-
|
|
4360
|
-
|
|
4361
|
-
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
|
|
4448
|
+
const SHELL_HTML = `
|
|
4449
|
+
<section class="mdzip-root">
|
|
4450
|
+
<div class="document-strip" data-ref="document-strip" hidden>
|
|
4451
|
+
<button type="button" class="title-button" data-ref="title-btn"></button>
|
|
4452
|
+
<button type="button" class="document-info-button" data-ref="document-info-btn"
|
|
4453
|
+
title="Document information" aria-label="Document information">
|
|
4454
|
+
${INFO_ICON_HTML}
|
|
4455
|
+
</button>
|
|
4456
|
+
</div>
|
|
4457
|
+
|
|
4458
|
+
<header class="toolbar" data-ref="toolbar" hidden>
|
|
4459
|
+
<div class="toolbar-start">
|
|
4460
|
+
<div class="toolbar-left">
|
|
4461
|
+
<button type="button" class="icon-toggle nav-toggle" data-ref="nav-btn" title="Toggle contents" aria-label="Toggle contents">
|
|
4462
|
+
${NAV_TOGGLE_ICON_HTML}
|
|
4463
|
+
</button>
|
|
4464
|
+
</div>
|
|
4465
|
+
|
|
4466
|
+
<div class="edit-toolbar" data-ref="edit-toolbar" role="toolbar" aria-label="Markdown formatting">
|
|
4467
|
+
<div class="edit-toolbar-group">
|
|
4468
|
+
<button type="button" data-format="bold" data-format-control="bold" title="Bold" aria-label="Bold">${BOLD_ICON_HTML}</button>
|
|
4469
|
+
<button type="button" data-format="italic" data-format-control="italic" title="Italic" aria-label="Italic">${ITALIC_ICON_HTML}</button>
|
|
4470
|
+
<button type="button" data-format="strike" data-format-control="strikethrough" title="Strikethrough" aria-label="Strikethrough">${STRIKE_ICON_HTML}</button>
|
|
4471
|
+
<div class="format-menu" data-format-control="headings">
|
|
4472
|
+
<button type="button" class="format-menu-toggle" data-format-menu-toggle
|
|
4473
|
+
aria-label="Heading" aria-haspopup="menu" aria-expanded="false">
|
|
4474
|
+
${HEADING_ICON_HTML}${CHEVRON_ICON_HTML}
|
|
4475
|
+
</button>
|
|
4476
|
+
<div class="format-menu-popover" data-format-menu role="menu" aria-label="Heading level" hidden>
|
|
4477
|
+
<button type="button" role="menuitem" data-format="paragraph">Paragraph</button>
|
|
4478
|
+
<button type="button" role="menuitem" data-format="heading-1" data-heading-level="1"><strong>H1</strong> Heading 1</button>
|
|
4479
|
+
<button type="button" role="menuitem" data-format="heading-2" data-heading-level="2"><strong>H2</strong> Heading 2</button>
|
|
4480
|
+
<button type="button" role="menuitem" data-format="heading-3" data-heading-level="3"><strong>H3</strong> Heading 3</button>
|
|
4481
|
+
<button type="button" role="menuitem" data-format="heading-4" data-heading-level="4"><strong>H4</strong> Heading 4</button>
|
|
4482
|
+
<button type="button" role="menuitem" data-format="heading-5" data-heading-level="5"><strong>H5</strong> Heading 5</button>
|
|
4483
|
+
<button type="button" role="menuitem" data-format="heading-6" data-heading-level="6"><strong>H6</strong> Heading 6</button>
|
|
4484
|
+
</div>
|
|
4485
|
+
</div>
|
|
4486
|
+
</div>
|
|
4487
|
+
<span class="edit-toolbar-divider" aria-hidden="true"></span>
|
|
4488
|
+
<div class="edit-toolbar-group">
|
|
4489
|
+
<button type="button" data-format="bullet-list" data-format-control="bulletList" title="Bulleted list" aria-label="Bulleted list">${BULLET_LIST_ICON_HTML}</button>
|
|
4490
|
+
<button type="button" data-format="ordered-list" data-format-control="orderedList" title="Numbered list" aria-label="Numbered list">${ORDERED_LIST_ICON_HTML}</button>
|
|
4491
|
+
<div class="format-menu" data-format-control="code">
|
|
4492
|
+
<button type="button" class="format-menu-toggle" data-format-menu-toggle
|
|
4493
|
+
aria-label="Code" aria-haspopup="menu" aria-expanded="false">
|
|
4494
|
+
${CODE_ICON_HTML}${CHEVRON_ICON_HTML}
|
|
4495
|
+
</button>
|
|
4496
|
+
<div class="format-menu-popover" data-format-menu role="menu" aria-label="Code format" hidden>
|
|
4497
|
+
<button type="button" role="menuitem" data-format="code" data-code-kind="inline">Inline code</button>
|
|
4498
|
+
<button type="button" role="menuitem" data-format="code-block" data-code-kind="block">Code block</button>
|
|
4499
|
+
</div>
|
|
4500
|
+
</div>
|
|
4501
|
+
<button type="button" data-format="quote" data-format-control="blockquote" title="Blockquote" aria-label="Blockquote">${QUOTE_ICON_HTML}</button>
|
|
4502
|
+
<button type="button" data-format="line-break" data-format-control="lineBreak" title="Line break" aria-label="Line break">${LINE_BREAK_ICON_HTML}</button>
|
|
4503
|
+
</div>
|
|
4504
|
+
<span class="edit-toolbar-divider" aria-hidden="true"></span>
|
|
4505
|
+
<div class="edit-toolbar-group">
|
|
4506
|
+
<button type="button" data-format="link" data-format-control="link" title="Link" aria-label="Link">${LINK_ICON_HTML}</button>
|
|
4507
|
+
<button type="button" data-format="image" data-format-control="image" title="Image" aria-label="Image">${IMAGE_FORMAT_ICON_HTML}</button>
|
|
4508
|
+
<input type="file" data-ref="image-input" accept="image/*" hidden />
|
|
4509
|
+
</div>
|
|
4510
|
+
</div>
|
|
4511
|
+
</div>
|
|
4512
|
+
|
|
4513
|
+
<div class="toolbar-buttons view-mode-toggle-group" data-ref="layout-controls" role="group" aria-label="Editor layout">
|
|
4514
|
+
<button type="button" class="icon-toggle view-mode-toggle" data-ref="source-btn" title="Edit" aria-label="Edit" aria-pressed="false">
|
|
4515
|
+
<span class="commandbar-flex-container" data-ref="source-icon">${SOURCE_EDIT_ICON_HTML}</span>
|
|
4516
|
+
</button>
|
|
4517
|
+
<button type="button" class="icon-toggle view-mode-toggle" data-ref="split-btn" title="Split" aria-label="Split" aria-pressed="false">
|
|
4518
|
+
<span class="commandbar-flex-container">
|
|
4519
|
+
${SPLIT_ICON_HTML}
|
|
4520
|
+
</span>
|
|
4521
|
+
</button>
|
|
4522
|
+
<button type="button" class="icon-toggle view-mode-toggle" data-ref="preview-btn" title="View" aria-label="View" aria-pressed="false">
|
|
4523
|
+
<span class="commandbar-flex-container">
|
|
4524
|
+
${PREVIEW_ICON_HTML}
|
|
4525
|
+
</span>
|
|
4526
|
+
</button>
|
|
4527
|
+
</div>
|
|
4528
|
+
|
|
4529
|
+
<div class="toolbar-controls" data-ref="toolbar-controls">
|
|
4530
|
+
<button type="button" class="icon-toggle" data-ref="search-btn" title="Find/replace (Mod-F)" aria-label="Find/replace">
|
|
4531
|
+
${SEARCH_ICON_HTML}
|
|
4532
|
+
</button>
|
|
4533
|
+
<button type="button" class="icon-toggle" data-ref="save-btn" title="Save" aria-label="Save">
|
|
4534
|
+
${SAVE_ICON_HTML}
|
|
4535
|
+
</button>
|
|
4536
|
+
<button type="button" class="icon-toggle zoom-toggle" data-ref="zoom-btn" title="Zoom controls" aria-label="Zoom controls">
|
|
4537
|
+
${ZOOM_ICON_HTML}
|
|
4538
|
+
</button>
|
|
4539
|
+
<div class="theme-toggle-group" data-ref="theme-controls" role="group" aria-label="Color scheme">
|
|
4540
|
+
<button type="button" class="icon-toggle theme-toggle" data-ref="dark-theme-btn"
|
|
4541
|
+
title="Dark mode" aria-label="Dark mode" aria-pressed="false">
|
|
4542
|
+
${DARK_THEME_ICON_HTML}
|
|
4543
|
+
</button>
|
|
4544
|
+
<button type="button" class="icon-toggle theme-toggle" data-ref="light-theme-btn"
|
|
4545
|
+
title="Light mode" aria-label="Light mode" aria-pressed="false">
|
|
4546
|
+
${LIGHT_THEME_ICON_HTML}
|
|
4547
|
+
</button>
|
|
4548
|
+
</div>
|
|
4549
|
+
<div class="zoom-popover" data-ref="zoom-popover" hidden role="group" aria-label="Zoom">
|
|
4550
|
+
<span class="zoom-level" data-ref="zoom-level">100%</span>
|
|
4551
|
+
<span class="zoom-stepper">
|
|
4552
|
+
<button type="button" data-action="zoom-out" title="Zoom out" aria-label="Zoom out">-</button>
|
|
4553
|
+
<button type="button" data-action="zoom-in" title="Zoom in" aria-label="Zoom in">+</button>
|
|
4554
|
+
</span>
|
|
4555
|
+
<button type="button" class="zoom-reset" data-action="zoom-reset" title="Reset zoom">Reset</button>
|
|
4556
|
+
</div>
|
|
4557
|
+
</div>
|
|
4558
|
+
</header>
|
|
4559
|
+
|
|
4560
|
+
<div class="workspace-shell" data-ref="workspace-shell" hidden>
|
|
4561
|
+
<aside class="nav-pane" data-ref="nav-pane" aria-label="Package contents">
|
|
4562
|
+
<div class="nav-tree" data-ref="nav-tree"></div>
|
|
4563
|
+
</aside>
|
|
4564
|
+
<div class="nav-resizer" data-ref="nav-resizer"
|
|
4565
|
+
role="separator" aria-orientation="vertical" aria-label="Resize contents pane"></div>
|
|
4566
|
+
|
|
4567
|
+
<div class="pane-stack" data-ref="pane-stack">
|
|
4568
|
+
<section class="pane edit-pane" data-ref="edit-pane">
|
|
4569
|
+
<div class="editor-host" data-ref="editor-host"></div>
|
|
4570
|
+
</section>
|
|
4571
|
+
<div class="split-resizer" data-ref="split-resizer"
|
|
4572
|
+
role="separator" aria-orientation="vertical" aria-label="Resize split panes"></div>
|
|
4573
|
+
<section class="pane preview-pane" data-ref="preview-pane">
|
|
4574
|
+
<article class="preview-content" data-ref="preview-content"></article>
|
|
4575
|
+
</section>
|
|
4576
|
+
<section class="pane entry-pane" data-ref="entry-pane"></section>
|
|
4577
|
+
</div>
|
|
4578
|
+
</div>
|
|
4579
|
+
|
|
4580
|
+
<div class="title-dialog-backdrop" data-ref="title-dialog" hidden
|
|
4581
|
+
role="dialog" aria-modal="true" aria-labelledby="mdzip-title-dialog-heading">
|
|
4582
|
+
<div class="title-dialog">
|
|
4583
|
+
<h3 id="mdzip-title-dialog-heading">Set Document Title</h3>
|
|
4584
|
+
<p>This is the package-level title stored in manifest.json.</p>
|
|
4585
|
+
<input type="text" maxlength="120" data-ref="title-input" aria-label="Document title" />
|
|
4586
|
+
<p class="title-dialog-validation" data-ref="title-validation" hidden>Title cannot be empty.</p>
|
|
4587
|
+
<p>If unset, consumers may fall back to entry point, filename, or first heading.</p>
|
|
4588
|
+
<div class="title-dialog-actions">
|
|
4589
|
+
<button type="button" class="reset-title" data-ref="title-reset-btn">Reset</button>
|
|
4590
|
+
<button type="button" data-action="cancel-title">Cancel</button>
|
|
4591
|
+
<button type="button" class="save-title" data-ref="title-save-btn">Save</button>
|
|
4592
|
+
</div>
|
|
4593
|
+
</div>
|
|
4594
|
+
</div>
|
|
4595
|
+
|
|
4596
|
+
<div class="title-dialog-backdrop" data-ref="conversion-dialog" hidden
|
|
4597
|
+
role="dialog" aria-modal="true" aria-labelledby="mdzip-conversion-dialog-heading">
|
|
4598
|
+
<div class="title-dialog">
|
|
4599
|
+
<h3 id="mdzip-conversion-dialog-heading">Convert to MDZ?</h3>
|
|
4600
|
+
<p>
|
|
4601
|
+
Regular Markdown files contain only text. Convert this document to an
|
|
4602
|
+
MDZ package to add images, package navigation, and document metadata.
|
|
4603
|
+
</p>
|
|
4604
|
+
<p>The next save will produce an .mdz file.</p>
|
|
4605
|
+
<div class="title-dialog-actions">
|
|
4606
|
+
<button type="button" data-action="cancel-conversion">Cancel</button>
|
|
4607
|
+
<button type="button" class="save-title" data-ref="conversion-confirm-btn">Convert</button>
|
|
4608
|
+
</div>
|
|
4609
|
+
</div>
|
|
4610
|
+
</div>
|
|
4611
|
+
|
|
4612
|
+
<div class="title-dialog-backdrop" data-ref="image-insert-dialog" hidden
|
|
4613
|
+
role="dialog" aria-modal="true" aria-labelledby="mdzip-image-insert-dialog-heading">
|
|
4614
|
+
<div class="title-dialog image-insert-dialog">
|
|
4615
|
+
<h3 id="mdzip-image-insert-dialog-heading">Insert Image</h3>
|
|
4616
|
+
<p>Choose the Markdown inserted for this image.</p>
|
|
4617
|
+
<fieldset class="image-insert-options">
|
|
4618
|
+
<legend>Output</legend>
|
|
4619
|
+
<label>
|
|
4620
|
+
<input type="radio" name="mdzip-image-insert-mode" value="markdown"
|
|
4621
|
+
data-ref="image-insert-mode-markdown" checked />
|
|
4622
|
+
Markdown image
|
|
4623
|
+
</label>
|
|
4624
|
+
<label>
|
|
4625
|
+
<input type="radio" name="mdzip-image-insert-mode" value="html"
|
|
4626
|
+
data-ref="image-insert-mode-html" />
|
|
4627
|
+
HTML <img> with sizing
|
|
4628
|
+
</label>
|
|
4629
|
+
</fieldset>
|
|
4630
|
+
<label class="image-insert-field">
|
|
4631
|
+
<span>Alt text</span>
|
|
4632
|
+
<input type="text" data-ref="image-insert-alt" />
|
|
4633
|
+
</label>
|
|
4634
|
+
<div class="image-insert-grid">
|
|
4635
|
+
<label class="image-insert-field">
|
|
4636
|
+
<span>Size by</span>
|
|
4637
|
+
<select data-ref="image-insert-size-mode">
|
|
4638
|
+
<option value="original">Original size</option>
|
|
4639
|
+
<option value="width" selected>Width</option>
|
|
4640
|
+
<option value="height">Height</option>
|
|
4641
|
+
<option value="percent">Percent</option>
|
|
4642
|
+
</select>
|
|
4643
|
+
</label>
|
|
4644
|
+
<label class="image-insert-field">
|
|
4645
|
+
<span>Value</span>
|
|
4646
|
+
<input type="number" min="1" step="1" data-ref="image-insert-size-value" />
|
|
4647
|
+
</label>
|
|
4648
|
+
</div>
|
|
4649
|
+
<label class="image-insert-field">
|
|
4650
|
+
<span>Position</span>
|
|
4651
|
+
<select data-ref="image-insert-position">
|
|
4652
|
+
<option value="inline">Inline/default</option>
|
|
4653
|
+
<option value="left">Left</option>
|
|
4654
|
+
<option value="center">Center</option>
|
|
4655
|
+
<option value="right">Right</option>
|
|
4656
|
+
<option value="wrap-left">Wrap left</option>
|
|
4657
|
+
<option value="wrap-right">Wrap right</option>
|
|
4658
|
+
</select>
|
|
4659
|
+
</label>
|
|
4660
|
+
<div class="title-dialog-actions">
|
|
4661
|
+
<button type="button" data-action="cancel-image-insert">Cancel</button>
|
|
4662
|
+
<button type="button" class="save-title" data-ref="image-insert-confirm-btn">Insert</button>
|
|
4663
|
+
</div>
|
|
4664
|
+
</div>
|
|
4665
|
+
</div>
|
|
4666
|
+
|
|
4667
|
+
<div class="title-dialog-backdrop" data-ref="metadata-dialog" hidden
|
|
4668
|
+
role="dialog" aria-modal="true" aria-labelledby="mdzip-metadata-dialog-heading">
|
|
4669
|
+
<div class="title-dialog metadata-dialog">
|
|
4670
|
+
<h3 id="mdzip-metadata-dialog-heading">Document Information</h3>
|
|
4671
|
+
<dl data-ref="metadata-list"></dl>
|
|
4672
|
+
<h4>Libraries</h4>
|
|
4673
|
+
<dl data-ref="library-list"></dl>
|
|
4674
|
+
<div class="title-dialog-actions">
|
|
4675
|
+
<button type="button" class="save-title" data-action="close-metadata">Close</button>
|
|
4676
|
+
</div>
|
|
4677
|
+
</div>
|
|
4678
|
+
</div>
|
|
4679
|
+
|
|
4680
|
+
<div class="title-dialog-backdrop" data-ref="name-dialog" hidden
|
|
4681
|
+
role="dialog" aria-modal="true" aria-labelledby="mdzip-name-dialog-heading">
|
|
4682
|
+
<div class="title-dialog">
|
|
4683
|
+
<h3 id="mdzip-name-dialog-heading" data-ref="name-dialog-heading">New Markdown File</h3>
|
|
4684
|
+
<input type="text" maxlength="260" data-ref="name-input" aria-label="File name" />
|
|
4685
|
+
<p class="title-dialog-validation" data-ref="name-validation" hidden></p>
|
|
4686
|
+
<div class="title-dialog-actions">
|
|
4687
|
+
<button type="button" data-action="cancel-name">Cancel</button>
|
|
4688
|
+
<button type="button" class="save-title" data-ref="name-confirm-btn">Create</button>
|
|
4689
|
+
</div>
|
|
4690
|
+
</div>
|
|
4691
|
+
</div>
|
|
4692
|
+
|
|
4693
|
+
<div class="title-dialog-backdrop" data-ref="delete-dialog" hidden
|
|
4694
|
+
role="dialog" aria-modal="true" aria-labelledby="mdzip-delete-dialog-heading">
|
|
4695
|
+
<div class="title-dialog">
|
|
4696
|
+
<h3 id="mdzip-delete-dialog-heading">Delete File?</h3>
|
|
4697
|
+
<p data-ref="delete-dialog-text"></p>
|
|
4698
|
+
<div class="title-dialog-actions">
|
|
4699
|
+
<button type="button" data-action="cancel-delete">Cancel</button>
|
|
4700
|
+
<button type="button" class="danger-action" data-ref="delete-confirm-btn">Delete</button>
|
|
4701
|
+
</div>
|
|
4702
|
+
</div>
|
|
4703
|
+
</div>
|
|
4704
|
+
|
|
4705
|
+
<input type="file" data-ref="replace-input" hidden />
|
|
4706
|
+
|
|
4707
|
+
<div class="nav-context-menu" data-ref="nav-menu" hidden role="menu"></div>
|
|
4708
|
+
|
|
4709
|
+
<div class="mdzip-tooltip" data-ref="tooltip" role="tooltip" hidden></div>
|
|
4710
|
+
|
|
4711
|
+
<p class="mdzip-empty" data-ref="empty-state">No MDZip workspace loaded.</p>
|
|
4712
|
+
</section>
|
|
4382
4713
|
`;
|
|
4383
4714
|
//# sourceMappingURL=view.js.map
|