@mdzip/editor 1.4.4 → 1.4.6
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 +48 -46
- package/README.md +554 -547
- package/dist/library-info.d.ts +1 -1
- package/dist/library-info.js +1 -1
- package/dist/rendering.d.ts +23 -0
- package/dist/rendering.d.ts.map +1 -1
- package/dist/rendering.js +112 -4
- package/dist/rendering.js.map +1 -1
- package/dist/view.d.ts +63 -0
- package/dist/view.d.ts.map +1 -1
- package/dist/view.js +501 -352
- package/dist/view.js.map +1 -1
- package/dist/workspace-view.d.ts +1 -0
- package/dist/workspace-view.d.ts.map +1 -1
- package/dist/workspace-view.js +14 -3
- package/dist/workspace-view.js.map +1 -1
- package/package.json +1 -1
package/dist/view.js
CHANGED
|
@@ -12,9 +12,9 @@ import { MdzipAssetSession, mdzipArchiveSourceId, sniffImageSize } from './asset
|
|
|
12
12
|
import { MD_MARKDOWN_ICON } from './icons/md-markdown.js';
|
|
13
13
|
import { MDZIP_RUNTIME_LIBRARIES } from './library-info.js';
|
|
14
14
|
import { MdzipWorkspaceService, extensionForMime, normalizeArchivePath, relativeArchivePath } from './workspace.js';
|
|
15
|
-
import { buildMdzipNavTree, canEditMdzipPath, escapeHtml, isOrphanedMdzipAsset, mdzipEntryIconKind, isMdzipManifestPath, resolveMdzipArchiveLinkTarget, renderMdzipPreviewHtml } from './workspace-view.js';
|
|
15
|
+
import { buildMdzipNavTree, canEditMdzipPath, escapeHtml, isOrphanedMdzipAsset, mdzipEntryIconKind, isMdzipManifestPath, isMdzipWorkspaceRelativeLink, resolveMdzipArchiveLinkTarget, renderMdzipPreviewHtml } from './workspace-view.js';
|
|
16
16
|
import { escapeMarkdownImageAlt, findImageReferenceAtOffset, formatImageEditMarkdown } from './image-edit.js';
|
|
17
|
-
import { MdzipRenderingService, defaultSafeMarkdownRenderer, groupTokensIntoChunks, chunkSourceKey, tokenEmbedsImage, tokenIsHeading } from './rendering.js';
|
|
17
|
+
import { MdzipRenderingService, defaultSafeMarkdownRenderer, groupTokensIntoChunks, chunkSourceKey, collectMdzipHeadingIds, MDZIP_HEADING_ID_PREFIX, tokenEmbedsImage, tokenIsHeading } from './rendering.js';
|
|
18
18
|
import { mdzipFrontMatterExtension } from './front-matter-extension.js';
|
|
19
19
|
import { WORKSPACE_CSS } from './view-css.js';
|
|
20
20
|
const STYLE_ATTR = 'data-mdzip-ws-styles';
|
|
@@ -746,19 +746,19 @@ depth = 0) {
|
|
|
746
746
|
: isImageFile(node.entry.path)
|
|
747
747
|
? IMAGE_ICON_HTML
|
|
748
748
|
: FILE_ICON_HTML;
|
|
749
|
-
const orphanBtnHtml = isOrphaned && options.allowOrphanActions ? `
|
|
750
|
-
<span class="nav-orphan-button" role="button" tabindex="0"
|
|
751
|
-
title="Orphaned asset" aria-label="Orphaned asset actions"
|
|
752
|
-
data-orphan-path="${safePath}">
|
|
753
|
-
${ORPHAN_ICON_HTML}
|
|
749
|
+
const orphanBtnHtml = isOrphaned && options.allowOrphanActions ? `
|
|
750
|
+
<span class="nav-orphan-button" role="button" tabindex="0"
|
|
751
|
+
title="Orphaned asset" aria-label="Orphaned asset actions"
|
|
752
|
+
data-orphan-path="${safePath}">
|
|
753
|
+
${ORPHAN_ICON_HTML}
|
|
754
754
|
</span>` : '';
|
|
755
755
|
const draggable = options.allowDrag && !isManifest;
|
|
756
|
-
return `<button type="button" class="${classes}" title="${title}"
|
|
757
|
-
data-nav-path="${safePath}" data-orphan="${isOrphaned ? 'true' : ''}"${draggable ? ' draggable="true"' : ''}>
|
|
758
|
-
${guides}<span class="nav-caret"></span>
|
|
759
|
-
<span class="nav-file-icon ${iconKind}">${iconHtml}</span>
|
|
760
|
-
${orphanBtnHtml}
|
|
761
|
-
<span class="nav-label">${safeName}</span>
|
|
756
|
+
return `<button type="button" class="${classes}" title="${title}"
|
|
757
|
+
data-nav-path="${safePath}" data-orphan="${isOrphaned ? 'true' : ''}"${draggable ? ' draggable="true"' : ''}>
|
|
758
|
+
${guides}<span class="nav-caret"></span>
|
|
759
|
+
<span class="nav-file-icon ${iconKind}">${iconHtml}</span>
|
|
760
|
+
${orphanBtnHtml}
|
|
761
|
+
<span class="nav-label">${safeName}</span>
|
|
762
762
|
</button>`;
|
|
763
763
|
}
|
|
764
764
|
const childTrail = depth === 0 ? [] : [...trail, !isLast];
|
|
@@ -766,14 +766,14 @@ depth = 0) {
|
|
|
766
766
|
.map((child, index) => renderNavNode(child, state, options, childTrail, index === node.children.length - 1, depth + 1))
|
|
767
767
|
.join('');
|
|
768
768
|
const pending = options.pendingFolders.has(node.path.toLowerCase());
|
|
769
|
-
return `<details class="nav-directory${pending ? ' pending-folder' : ''}" open data-nav-dir="${escapeHtml(node.path)}">
|
|
770
|
-
<summary${pending ? ` title="${escapeHtml(node.path)} — not saved until it contains a file"` : ''}>
|
|
771
|
-
${guides}<span class="nav-caret" aria-hidden="true"></span>
|
|
772
|
-
<span class="nav-folder-icon closed">${FOLDER_CLOSED_ICON_HTML}</span>
|
|
773
|
-
<span class="nav-folder-icon open">${FOLDER_OPEN_ICON_HTML}</span>
|
|
774
|
-
<span class="nav-label">${escapeHtml(node.name)}</span>
|
|
775
|
-
</summary>
|
|
776
|
-
<div class="nav-directory-children">${children}</div>
|
|
769
|
+
return `<details class="nav-directory${pending ? ' pending-folder' : ''}" open data-nav-dir="${escapeHtml(node.path)}">
|
|
770
|
+
<summary${pending ? ` title="${escapeHtml(node.path)} — not saved until it contains a file"` : ''}>
|
|
771
|
+
${guides}<span class="nav-caret" aria-hidden="true"></span>
|
|
772
|
+
<span class="nav-folder-icon closed">${FOLDER_CLOSED_ICON_HTML}</span>
|
|
773
|
+
<span class="nav-folder-icon open">${FOLDER_OPEN_ICON_HTML}</span>
|
|
774
|
+
<span class="nav-label">${escapeHtml(node.name)}</span>
|
|
775
|
+
</summary>
|
|
776
|
+
<div class="nav-directory-children">${children}</div>
|
|
777
777
|
</details>`;
|
|
778
778
|
}
|
|
779
779
|
// Inserts view-local pending (not yet saved) folders into the nav tree so they
|
|
@@ -1002,6 +1002,10 @@ export class MdzipWorkspaceView {
|
|
|
1002
1002
|
// cold-start, progressive, eager, mermaid-triggered or not) already calls
|
|
1003
1003
|
// once its content is back in the DOM.
|
|
1004
1004
|
this.pendingPreviewScrollRestore = null;
|
|
1005
|
+
// A #fragment from a link into another document (`other.md#heading`), held
|
|
1006
|
+
// until that document's preview has mounted so there is a heading to scroll
|
|
1007
|
+
// to. Consumed by firePreviewRendered.
|
|
1008
|
+
this.pendingAnchorFragment = null;
|
|
1005
1009
|
// Guards syncScrollToPreviewBottom against overlapping drains: set to the
|
|
1006
1010
|
// chunkedRenderState generation currently being force-drained, null when
|
|
1007
1011
|
// none is in flight. A second bottom-edge sync that arrives mid-drain
|
|
@@ -2220,7 +2224,7 @@ export class MdzipWorkspaceView {
|
|
|
2220
2224
|
let cursor = middleStart;
|
|
2221
2225
|
let mountedRoots = [];
|
|
2222
2226
|
while (cursor < middleEnd) {
|
|
2223
|
-
const batch = await this.renderAndMountChunkBatch(records, cursor, context, generation, insertBeforeNode);
|
|
2227
|
+
const batch = await this.renderAndMountChunkBatch(records, cursor, context, generation, insertBeforeNode, middleEnd);
|
|
2224
2228
|
if (generation !== this.previewGeneration || context.signal.aborted)
|
|
2225
2229
|
return;
|
|
2226
2230
|
if (batch.cursor === cursor)
|
|
@@ -2390,7 +2394,12 @@ export class MdzipWorkspaceView {
|
|
|
2390
2394
|
* included here; see {@link mountChunkBatch} and
|
|
2391
2395
|
* {@link drainRemainingChunks} for the two different ways callers pace it.
|
|
2392
2396
|
*/
|
|
2393
|
-
async renderAndMountChunkBatch(records, startCursor, context, generation, insertBeforeNode = null
|
|
2397
|
+
async renderAndMountChunkBatch(records, startCursor, context, generation, insertBeforeNode = null,
|
|
2398
|
+
// Exclusive upper bound. Reconciliation mounts just its replacement
|
|
2399
|
+
// "middle"; the records after it are surviving suffix chunks that are
|
|
2400
|
+
// already in the DOM, and running on into them would mount each a second
|
|
2401
|
+
// time (orphaning the first copy's root, which nothing would ever remove).
|
|
2402
|
+
endCursor = records.length) {
|
|
2394
2403
|
const BATCH_CHAR_BUDGET = 4000;
|
|
2395
2404
|
const BATCH_TIME_BUDGET_MS = 10;
|
|
2396
2405
|
const clock = this.elPreviewContent.ownerDocument.defaultView?.performance ?? performance;
|
|
@@ -2399,7 +2408,7 @@ export class MdzipWorkspaceView {
|
|
|
2399
2408
|
let renderedChars = 0;
|
|
2400
2409
|
const mountedRoots = [];
|
|
2401
2410
|
const batchStartCursor = startCursor;
|
|
2402
|
-
while (cursor < records.length
|
|
2411
|
+
while (cursor < Math.min(endCursor, records.length)
|
|
2403
2412
|
&& renderedChars < BATCH_CHAR_BUDGET
|
|
2404
2413
|
&& (mountedRoots.length === 0 || clock.now() - batchStart < BATCH_TIME_BUDGET_MS)) {
|
|
2405
2414
|
if (generation !== this.previewGeneration || context.signal.aborted)
|
|
@@ -2798,6 +2807,7 @@ export class MdzipWorkspaceView {
|
|
|
2798
2807
|
return;
|
|
2799
2808
|
}
|
|
2800
2809
|
this.restorePendingPreviewScroll(generation);
|
|
2810
|
+
this.flushPendingAnchorSoon();
|
|
2801
2811
|
try {
|
|
2802
2812
|
this.options.onPreviewRendered?.(snapshot);
|
|
2803
2813
|
}
|
|
@@ -3819,7 +3829,27 @@ export class MdzipWorkspaceView {
|
|
|
3819
3829
|
const clampedTop = Math.max(margin, Math.min(naturalTop, win.innerHeight - margin - submenu.offsetHeight));
|
|
3820
3830
|
submenu.style.top = `${clampedTop - rect.top}px`;
|
|
3821
3831
|
});
|
|
3832
|
+
// Chromium treats a Shift+mousedown as "extend the selection", right
|
|
3833
|
+
// button included, so Shift+right-click would first stretch the selection
|
|
3834
|
+
// from the caret to the click — and the native menu reports no misspelled
|
|
3835
|
+
// word (hence no suggestions) unless the selection is collapsed or just
|
|
3836
|
+
// the word. Cancelling that mousedown leaves the selection alone and lets
|
|
3837
|
+
// the browser resolve the word under the pointer itself. Capture phase so
|
|
3838
|
+
// it runs before CodeMirror's own handlers; focus is restored by hand
|
|
3839
|
+
// since the cancelled mousedown no longer moves it.
|
|
3840
|
+
this.elEditorHost.addEventListener('mousedown', (e) => {
|
|
3841
|
+
if (e.button === 2 && e.shiftKey) {
|
|
3842
|
+
e.preventDefault();
|
|
3843
|
+
this.cmEditor?.focus();
|
|
3844
|
+
}
|
|
3845
|
+
}, true);
|
|
3822
3846
|
this.elEditorHost.addEventListener('contextmenu', (e) => {
|
|
3847
|
+
// Shift+right-click bypasses our own formatting menu so the host's
|
|
3848
|
+
// native context menu (spell-check suggestions, etc.) shows instead —
|
|
3849
|
+
// without this, preventDefault() below suppresses it unconditionally.
|
|
3850
|
+
if (e.shiftKey) {
|
|
3851
|
+
return;
|
|
3852
|
+
}
|
|
3823
3853
|
if (!this.controlPolicy.contextMenu.editor) {
|
|
3824
3854
|
return;
|
|
3825
3855
|
}
|
|
@@ -3927,12 +3957,24 @@ export class MdzipWorkspaceView {
|
|
|
3927
3957
|
if (!link || !snapshot) {
|
|
3928
3958
|
return;
|
|
3929
3959
|
}
|
|
3930
|
-
const
|
|
3931
|
-
if (
|
|
3960
|
+
const href = link.getAttribute('href') ?? '';
|
|
3961
|
+
if (href.startsWith('#')) {
|
|
3962
|
+
event.preventDefault();
|
|
3963
|
+
void this.scrollPreviewToAnchor(href.slice(1));
|
|
3932
3964
|
return;
|
|
3933
3965
|
}
|
|
3934
|
-
|
|
3935
|
-
|
|
3966
|
+
const targetPath = resolveMdzipArchiveLinkTarget(href, snapshot.currentPath, snapshot.content.paths);
|
|
3967
|
+
if (targetPath) {
|
|
3968
|
+
event.preventDefault();
|
|
3969
|
+
const hashIndex = href.indexOf('#');
|
|
3970
|
+
const fragment = hashIndex >= 0 ? href.slice(hashIndex + 1) : '';
|
|
3971
|
+
void this.openPathAndScrollToAnchor(targetPath, fragment);
|
|
3972
|
+
return;
|
|
3973
|
+
}
|
|
3974
|
+
if (this.options.onUnresolvedLinkClick && isMdzipWorkspaceRelativeLink(href)) {
|
|
3975
|
+
event.preventDefault();
|
|
3976
|
+
this.options.onUnresolvedLinkClick(href, snapshot);
|
|
3977
|
+
}
|
|
3936
3978
|
});
|
|
3937
3979
|
this.elRoot.addEventListener('pointerover', (event) => this.handleTooltipPointer(event));
|
|
3938
3980
|
this.elRoot.addEventListener('pointerout', (event) => {
|
|
@@ -3966,6 +4008,99 @@ export class MdzipWorkspaceView {
|
|
|
3966
4008
|
element.removeAttribute('title');
|
|
3967
4009
|
});
|
|
3968
4010
|
}
|
|
4011
|
+
async openPathAndScrollToAnchor(path, fragment) {
|
|
4012
|
+
const generationBefore = this.previewGeneration;
|
|
4013
|
+
this.pendingAnchorFragment = fragment || null;
|
|
4014
|
+
await this.openPath(path);
|
|
4015
|
+
// No new render started (already on that document, or the open failed):
|
|
4016
|
+
// nothing will call firePreviewRendered, so apply the anchor now.
|
|
4017
|
+
if (this.pendingAnchorFragment !== null && this.previewGeneration === generationBefore) {
|
|
4018
|
+
const pending = this.pendingAnchorFragment;
|
|
4019
|
+
this.pendingAnchorFragment = null;
|
|
4020
|
+
await this.scrollPreviewToAnchor(pending);
|
|
4021
|
+
}
|
|
4022
|
+
}
|
|
4023
|
+
// Deferred a frame: firePreviewRendered runs inside the first chunk batch's
|
|
4024
|
+
// completion callback, before the lazy-continuation sentinel for the rest is
|
|
4025
|
+
// armed. Scrolling then (which may need to drain those chunks) would race it.
|
|
4026
|
+
flushPendingAnchorSoon() {
|
|
4027
|
+
if (this.pendingAnchorFragment === null) {
|
|
4028
|
+
return;
|
|
4029
|
+
}
|
|
4030
|
+
const generation = this.previewGeneration;
|
|
4031
|
+
requestAnimationFrame(() => {
|
|
4032
|
+
if (generation !== this.previewGeneration || this.pendingAnchorFragment === null) {
|
|
4033
|
+
return;
|
|
4034
|
+
}
|
|
4035
|
+
const pending = this.pendingAnchorFragment;
|
|
4036
|
+
this.pendingAnchorFragment = null;
|
|
4037
|
+
void this.scrollPreviewToAnchor(pending);
|
|
4038
|
+
});
|
|
4039
|
+
}
|
|
4040
|
+
findPreviewAnchor(fragment) {
|
|
4041
|
+
const wanted = new Set([fragment, MDZIP_HEADING_ID_PREFIX + fragment]);
|
|
4042
|
+
const wantedLower = new Set([...wanted].map((value) => value.toLowerCase()));
|
|
4043
|
+
let caseInsensitiveMatch = null;
|
|
4044
|
+
for (const element of Array.from(this.elPreviewContent.querySelectorAll('[id],[name]'))) {
|
|
4045
|
+
for (const value of [element.getAttribute('id'), element.getAttribute('name')]) {
|
|
4046
|
+
if (!value)
|
|
4047
|
+
continue;
|
|
4048
|
+
if (wanted.has(value))
|
|
4049
|
+
return element;
|
|
4050
|
+
if (!caseInsensitiveMatch && wantedLower.has(value.toLowerCase()))
|
|
4051
|
+
caseInsensitiveMatch = element;
|
|
4052
|
+
}
|
|
4053
|
+
}
|
|
4054
|
+
return caseInsensitiveMatch;
|
|
4055
|
+
}
|
|
4056
|
+
recordMayContainAnchor(record, fragment) {
|
|
4057
|
+
const lower = fragment.toLowerCase();
|
|
4058
|
+
if (collectMdzipHeadingIds(record.tokens).some((id) => id.toLowerCase() === lower)) {
|
|
4059
|
+
return true;
|
|
4060
|
+
}
|
|
4061
|
+
// An explicit <a id="x"> / <a name="x"> anchor written in the source.
|
|
4062
|
+
const escaped = fragment.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
4063
|
+
return new RegExp(`(?:id|name)\\s*=\\s*["']${escaped}["']`, 'i').test(record.key);
|
|
4064
|
+
}
|
|
4065
|
+
/**
|
|
4066
|
+
* Scrolls the preview to the heading (or explicit id/name anchor) a
|
|
4067
|
+
* `#fragment` link names. Under progressive rendering the target may sit in
|
|
4068
|
+
* a chunk that hasn't been mounted yet, so this mounts everything up to and
|
|
4069
|
+
* including that chunk first. Returns whether an anchor was found.
|
|
4070
|
+
*/
|
|
4071
|
+
async scrollPreviewToAnchor(rawFragment) {
|
|
4072
|
+
let fragment = rawFragment;
|
|
4073
|
+
try {
|
|
4074
|
+
fragment = decodeURIComponent(rawFragment);
|
|
4075
|
+
}
|
|
4076
|
+
catch {
|
|
4077
|
+
// Malformed escape — use it as written.
|
|
4078
|
+
}
|
|
4079
|
+
let target = fragment ? this.findPreviewAnchor(fragment) : null;
|
|
4080
|
+
const pending = this.chunkedRenderState;
|
|
4081
|
+
if (!target && fragment && pending && pending.cursor < pending.records.length) {
|
|
4082
|
+
const index = pending.records.findIndex((record, i) => i >= pending.cursor && this.recordMayContainAnchor(record, fragment));
|
|
4083
|
+
if (index >= 0) {
|
|
4084
|
+
await this.drainRemainingChunks(pending, () => { }, new AbortController().signal, index);
|
|
4085
|
+
const remaining = this.chunkedRenderState;
|
|
4086
|
+
if (remaining && remaining.generation === pending.generation && !remaining.sentinelHandle
|
|
4087
|
+
&& remaining.cursor < remaining.records.length) {
|
|
4088
|
+
this.armChunkSentinel(remaining.records, remaining.cursor, remaining.context, remaining.generation, remaining.animateImageHydration);
|
|
4089
|
+
}
|
|
4090
|
+
target = this.findPreviewAnchor(fragment);
|
|
4091
|
+
}
|
|
4092
|
+
}
|
|
4093
|
+
const pane = this.elPreviewPane;
|
|
4094
|
+
if (!target) {
|
|
4095
|
+
// `#` and `#top` mean the top of the document, as in a browser.
|
|
4096
|
+
if (!fragment || fragment.toLowerCase() === 'top') {
|
|
4097
|
+
pane.scrollTop = 0;
|
|
4098
|
+
}
|
|
4099
|
+
return false;
|
|
4100
|
+
}
|
|
4101
|
+
pane.scrollTop += target.getBoundingClientRect().top - pane.getBoundingClientRect().top;
|
|
4102
|
+
return true;
|
|
4103
|
+
}
|
|
3969
4104
|
async openPath(path) {
|
|
3970
4105
|
if (!this.workspace) {
|
|
3971
4106
|
return;
|
|
@@ -4253,6 +4388,18 @@ export class MdzipWorkspaceView {
|
|
|
4253
4388
|
return captured;
|
|
4254
4389
|
};
|
|
4255
4390
|
return {
|
|
4391
|
+
promptImageInsert: async (image) => {
|
|
4392
|
+
if (!captured || consumed || this.workspace !== captured.workspace
|
|
4393
|
+
|| this.conversionDocumentGeneration !== captured.documentGeneration) {
|
|
4394
|
+
return null;
|
|
4395
|
+
}
|
|
4396
|
+
return this.resolveImageInsertDecision(image.bytes, image.mimeType || imageMimeTypeFromFileName(image.fileName ?? ''), {
|
|
4397
|
+
fileName: image.fileName,
|
|
4398
|
+
source: action.kind === 'image-file' ? (action.source ?? 'picker') : 'picker',
|
|
4399
|
+
altText: image.altText
|
|
4400
|
+
});
|
|
4401
|
+
},
|
|
4402
|
+
formatImageInsert: (src, decision) => formatImageInsertMarkdown(src, normalizeImageInsertDecision(decision) ?? { mode: 'markdown', altText: '' }, captured?.text ?? '', captured?.selectionStart ?? 0, captured?.selectionEnd ?? captured?.selectionStart ?? 0),
|
|
4256
4403
|
insertMarkdown: async (text) => {
|
|
4257
4404
|
const target = take();
|
|
4258
4405
|
if (!target || target.selectionStart === undefined || target.selectionEnd === undefined) {
|
|
@@ -4519,7 +4666,7 @@ export class MdzipWorkspaceView {
|
|
|
4519
4666
|
mimeType,
|
|
4520
4667
|
intrinsicWidth: size?.width,
|
|
4521
4668
|
intrinsicHeight: size?.height,
|
|
4522
|
-
defaultAltText: 'Pasted image',
|
|
4669
|
+
defaultAltText: options.altText ?? 'Pasted image',
|
|
4523
4670
|
source: options.source
|
|
4524
4671
|
};
|
|
4525
4672
|
const handler = this.options.imageInsertHandler;
|
|
@@ -4733,7 +4880,7 @@ export class MdzipWorkspaceView {
|
|
|
4733
4880
|
// spelling suggestions live — there's no API to read the browser's
|
|
4734
4881
|
// dictionary suggestions into a custom menu. Point at the escape hatch
|
|
4735
4882
|
// instead of silently dropping the feature.
|
|
4736
|
-
if (editable) {
|
|
4883
|
+
if (editable && this.options.showSpellingSuggestionsHint !== false) {
|
|
4737
4884
|
groups.push([{
|
|
4738
4885
|
action: 'editor-spelling-suggestions-hint',
|
|
4739
4886
|
label: 'Spelling Suggestions',
|
|
@@ -5256,7 +5403,7 @@ export class MdzipWorkspaceView {
|
|
|
5256
5403
|
* pass over every image at the end avoids the pile-up entirely, without
|
|
5257
5404
|
* making Copy All wait on it.
|
|
5258
5405
|
*/
|
|
5259
|
-
async drainRemainingChunks(state, onProgress, signal) {
|
|
5406
|
+
async drainRemainingChunks(state, onProgress, signal, stopAfterRecordIndex) {
|
|
5260
5407
|
const { records, context, generation, animateImageHydration } = state;
|
|
5261
5408
|
// Draining is instead of the scroll-driven continuation, not alongside
|
|
5262
5409
|
// it — tearing down any armed sentinel first stops the two from racing
|
|
@@ -5271,7 +5418,9 @@ export class MdzipWorkspaceView {
|
|
|
5271
5418
|
}
|
|
5272
5419
|
const allPending = [];
|
|
5273
5420
|
try {
|
|
5274
|
-
while (this.chunkedRenderState?.generation === generation
|
|
5421
|
+
while (this.chunkedRenderState?.generation === generation
|
|
5422
|
+
&& this.chunkedRenderState.cursor < records.length
|
|
5423
|
+
&& (stopAfterRecordIndex === undefined || this.chunkedRenderState.cursor <= stopAfterRecordIndex)) {
|
|
5275
5424
|
if (signal.aborted || generation !== this.previewGeneration || context.signal.aborted)
|
|
5276
5425
|
return;
|
|
5277
5426
|
const cursor = this.chunkedRenderState.cursor;
|
|
@@ -6587,325 +6736,325 @@ function formatMetadataValue(value) {
|
|
|
6587
6736
|
}
|
|
6588
6737
|
return 'Not available';
|
|
6589
6738
|
}
|
|
6590
|
-
const SHELL_HTML = `
|
|
6591
|
-
<section class="mdzip-root">
|
|
6592
|
-
<div class="document-strip" data-ref="document-strip" hidden>
|
|
6593
|
-
<button type="button" class="title-button" data-ref="title-btn"></button>
|
|
6594
|
-
<button type="button" class="document-info-button" data-ref="document-info-btn"
|
|
6595
|
-
title="Document information" aria-label="Document information">
|
|
6596
|
-
${INFO_ICON_HTML}
|
|
6597
|
-
</button>
|
|
6598
|
-
</div>
|
|
6599
|
-
|
|
6600
|
-
<header class="toolbar" data-ref="toolbar" hidden>
|
|
6601
|
-
<div class="toolbar-start">
|
|
6602
|
-
<div class="toolbar-left">
|
|
6603
|
-
<button type="button" class="icon-toggle nav-toggle" data-ref="nav-btn" title="Toggle contents" aria-label="Toggle contents">
|
|
6604
|
-
${NAV_TOGGLE_ICON_HTML}
|
|
6605
|
-
</button>
|
|
6606
|
-
</div>
|
|
6607
|
-
|
|
6608
|
-
<div class="edit-toolbar" data-ref="edit-toolbar" role="toolbar" aria-label="Markdown formatting">
|
|
6609
|
-
<div class="edit-toolbar-group">
|
|
6610
|
-
<button type="button" data-format="bold" data-format-control="bold" title="Bold" aria-label="Bold">${BOLD_ICON_HTML}</button>
|
|
6611
|
-
<button type="button" data-format="italic" data-format-control="italic" title="Italic" aria-label="Italic">${ITALIC_ICON_HTML}</button>
|
|
6612
|
-
<button type="button" data-format="strike" data-format-control="strikethrough" title="Strikethrough" aria-label="Strikethrough">${STRIKE_ICON_HTML}</button>
|
|
6613
|
-
<div class="format-menu" data-format-control="headings">
|
|
6614
|
-
<button type="button" class="format-menu-toggle" data-format-menu-toggle
|
|
6615
|
-
aria-label="Heading" aria-haspopup="menu" aria-expanded="false">
|
|
6616
|
-
${HEADING_ICON_HTML}${CHEVRON_ICON_HTML}
|
|
6617
|
-
</button>
|
|
6618
|
-
<div class="format-menu-popover" data-format-menu role="menu" aria-label="Heading level" hidden>
|
|
6619
|
-
<button type="button" role="menuitem" data-format="paragraph">Paragraph</button>
|
|
6620
|
-
<button type="button" role="menuitem" data-format="heading-1" data-heading-level="1"><strong>H1</strong> Heading 1</button>
|
|
6621
|
-
<button type="button" role="menuitem" data-format="heading-2" data-heading-level="2"><strong>H2</strong> Heading 2</button>
|
|
6622
|
-
<button type="button" role="menuitem" data-format="heading-3" data-heading-level="3"><strong>H3</strong> Heading 3</button>
|
|
6623
|
-
<button type="button" role="menuitem" data-format="heading-4" data-heading-level="4"><strong>H4</strong> Heading 4</button>
|
|
6624
|
-
<button type="button" role="menuitem" data-format="heading-5" data-heading-level="5"><strong>H5</strong> Heading 5</button>
|
|
6625
|
-
<button type="button" role="menuitem" data-format="heading-6" data-heading-level="6"><strong>H6</strong> Heading 6</button>
|
|
6626
|
-
</div>
|
|
6627
|
-
</div>
|
|
6628
|
-
</div>
|
|
6629
|
-
<span class="edit-toolbar-divider" aria-hidden="true"></span>
|
|
6630
|
-
<div class="edit-toolbar-group">
|
|
6631
|
-
<button type="button" data-format="bullet-list" data-format-control="bulletList" title="Bulleted list" aria-label="Bulleted list">${BULLET_LIST_ICON_HTML}</button>
|
|
6632
|
-
<button type="button" data-format="ordered-list" data-format-control="orderedList" title="Numbered list" aria-label="Numbered list">${ORDERED_LIST_ICON_HTML}</button>
|
|
6633
|
-
<div class="format-menu" data-format-control="code">
|
|
6634
|
-
<button type="button" class="format-menu-toggle" data-format-menu-toggle
|
|
6635
|
-
aria-label="Code" aria-haspopup="menu" aria-expanded="false">
|
|
6636
|
-
${CODE_ICON_HTML}${CHEVRON_ICON_HTML}
|
|
6637
|
-
</button>
|
|
6638
|
-
<div class="format-menu-popover" data-format-menu role="menu" aria-label="Code format" hidden>
|
|
6639
|
-
<button type="button" role="menuitem" data-format="code" data-code-kind="inline">Inline code</button>
|
|
6640
|
-
<button type="button" role="menuitem" data-format="code-block" data-code-kind="block">Code block</button>
|
|
6641
|
-
</div>
|
|
6642
|
-
</div>
|
|
6643
|
-
<button type="button" data-format="quote" data-format-control="blockquote" title="Blockquote" aria-label="Blockquote">${QUOTE_ICON_HTML}</button>
|
|
6644
|
-
<button type="button" data-format="line-break" data-format-control="lineBreak" title="Line break" aria-label="Line break">${LINE_BREAK_ICON_HTML}</button>
|
|
6645
|
-
</div>
|
|
6646
|
-
<span class="edit-toolbar-divider" aria-hidden="true"></span>
|
|
6647
|
-
<div class="edit-toolbar-group">
|
|
6648
|
-
<button type="button" data-format="link" data-format-control="link" title="Link" aria-label="Link">${LINK_ICON_HTML}</button>
|
|
6649
|
-
<button type="button" data-format="image" data-format-control="image" title="Image" aria-label="Image">${IMAGE_FORMAT_ICON_HTML}</button>
|
|
6650
|
-
<input type="file" data-ref="image-input" accept="image/*" hidden />
|
|
6651
|
-
</div>
|
|
6652
|
-
</div>
|
|
6653
|
-
</div>
|
|
6654
|
-
|
|
6655
|
-
<div class="toolbar-buttons view-mode-toggle-group" data-ref="layout-controls" role="group" aria-label="Editor layout">
|
|
6656
|
-
<button type="button" class="icon-toggle view-mode-toggle" data-ref="source-btn" title="Edit" aria-label="Edit" aria-pressed="false">
|
|
6657
|
-
<span class="commandbar-flex-container" data-ref="source-icon">${SOURCE_EDIT_ICON_HTML}</span>
|
|
6658
|
-
</button>
|
|
6659
|
-
<button type="button" class="icon-toggle view-mode-toggle" data-ref="split-btn" title="Split" aria-label="Split" aria-pressed="false">
|
|
6660
|
-
<span class="commandbar-flex-container">
|
|
6661
|
-
${SPLIT_ICON_HTML}
|
|
6662
|
-
</span>
|
|
6663
|
-
</button>
|
|
6664
|
-
<button type="button" class="icon-toggle view-mode-toggle" data-ref="preview-btn" title="View" aria-label="View" aria-pressed="false">
|
|
6665
|
-
<span class="commandbar-flex-container">
|
|
6666
|
-
${PREVIEW_ICON_HTML}
|
|
6667
|
-
</span>
|
|
6668
|
-
</button>
|
|
6669
|
-
</div>
|
|
6670
|
-
|
|
6671
|
-
<div class="toolbar-controls" data-ref="toolbar-controls">
|
|
6672
|
-
<button type="button" class="icon-toggle" data-ref="search-btn" title="Find/replace (Mod-F)" aria-label="Find/replace">
|
|
6673
|
-
${SEARCH_ICON_HTML}
|
|
6674
|
-
</button>
|
|
6675
|
-
<button type="button" class="icon-toggle" data-ref="save-btn" title="Save" aria-label="Save">
|
|
6676
|
-
${SAVE_ICON_HTML}
|
|
6677
|
-
</button>
|
|
6678
|
-
<button type="button" class="icon-toggle zoom-toggle" data-ref="zoom-btn" title="Zoom controls" aria-label="Zoom controls">
|
|
6679
|
-
${ZOOM_ICON_HTML}
|
|
6680
|
-
</button>
|
|
6681
|
-
<div class="theme-toggle-group" data-ref="theme-controls" role="group" aria-label="Color scheme">
|
|
6682
|
-
<button type="button" class="icon-toggle theme-toggle" data-ref="dark-theme-btn"
|
|
6683
|
-
title="Dark mode" aria-label="Dark mode" aria-pressed="false">
|
|
6684
|
-
${DARK_THEME_ICON_HTML}
|
|
6685
|
-
</button>
|
|
6686
|
-
<button type="button" class="icon-toggle theme-toggle" data-ref="light-theme-btn"
|
|
6687
|
-
title="Light mode" aria-label="Light mode" aria-pressed="false">
|
|
6688
|
-
${LIGHT_THEME_ICON_HTML}
|
|
6689
|
-
</button>
|
|
6690
|
-
</div>
|
|
6691
|
-
<div class="zoom-popover" data-ref="zoom-popover" hidden role="group" aria-label="Zoom">
|
|
6692
|
-
<span class="zoom-level" data-ref="zoom-level">100%</span>
|
|
6693
|
-
<span class="zoom-stepper">
|
|
6694
|
-
<button type="button" data-action="zoom-out" title="Zoom out" aria-label="Zoom out">-</button>
|
|
6695
|
-
<button type="button" data-action="zoom-in" title="Zoom in" aria-label="Zoom in">+</button>
|
|
6696
|
-
</span>
|
|
6697
|
-
<button type="button" class="zoom-reset" data-action="zoom-reset" title="Reset zoom">Reset</button>
|
|
6698
|
-
</div>
|
|
6699
|
-
</div>
|
|
6700
|
-
</header>
|
|
6701
|
-
|
|
6702
|
-
<div class="workspace-shell" data-ref="workspace-shell" hidden>
|
|
6703
|
-
<aside class="nav-pane" data-ref="nav-pane" aria-label="Package contents">
|
|
6704
|
-
<div class="nav-tree" data-ref="nav-tree"></div>
|
|
6705
|
-
</aside>
|
|
6706
|
-
<div class="nav-resizer" data-ref="nav-resizer"
|
|
6707
|
-
role="separator" aria-orientation="vertical" aria-label="Resize contents pane"></div>
|
|
6708
|
-
|
|
6709
|
-
<div class="pane-stack" data-ref="pane-stack">
|
|
6710
|
-
<section class="pane edit-pane" data-ref="edit-pane">
|
|
6711
|
-
<div class="editor-host" data-ref="editor-host"></div>
|
|
6712
|
-
</section>
|
|
6713
|
-
<div class="split-resizer" data-ref="split-resizer"
|
|
6714
|
-
role="separator" aria-orientation="vertical" aria-label="Resize split panes"></div>
|
|
6715
|
-
<section class="pane preview-pane" data-ref="preview-pane" tabindex="-1">
|
|
6716
|
-
<article class="preview-content" data-ref="preview-content"></article>
|
|
6717
|
-
</section>
|
|
6718
|
-
<section class="pane entry-pane" data-ref="entry-pane"></section>
|
|
6719
|
-
</div>
|
|
6720
|
-
</div>
|
|
6721
|
-
|
|
6722
|
-
<div class="title-dialog-backdrop" data-ref="title-dialog" hidden
|
|
6723
|
-
role="dialog" aria-modal="true" aria-labelledby="mdzip-title-dialog-heading">
|
|
6724
|
-
<div class="title-dialog">
|
|
6725
|
-
<h3 id="mdzip-title-dialog-heading">Set Document Title</h3>
|
|
6726
|
-
<p>This is the package-level title stored in manifest.json.</p>
|
|
6727
|
-
<input type="text" maxlength="120" data-ref="title-input" aria-label="Document title" />
|
|
6728
|
-
<p class="title-dialog-validation" data-ref="title-validation" hidden>Title cannot be empty.</p>
|
|
6729
|
-
<p>If unset, consumers may fall back to entry point, filename, or first heading.</p>
|
|
6730
|
-
<div class="title-dialog-actions">
|
|
6731
|
-
<button type="button" class="reset-title" data-ref="title-reset-btn">Reset</button>
|
|
6732
|
-
<button type="button" data-action="cancel-title">Cancel</button>
|
|
6733
|
-
<button type="button" class="save-title" data-ref="title-save-btn">Save</button>
|
|
6734
|
-
</div>
|
|
6735
|
-
</div>
|
|
6736
|
-
</div>
|
|
6737
|
-
|
|
6738
|
-
<div class="title-dialog-backdrop" data-ref="conversion-dialog" hidden
|
|
6739
|
-
role="dialog" aria-modal="true" aria-labelledby="mdzip-conversion-dialog-heading">
|
|
6740
|
-
<div class="title-dialog">
|
|
6741
|
-
<h3 id="mdzip-conversion-dialog-heading">Convert to MDZ?</h3>
|
|
6742
|
-
<p>
|
|
6743
|
-
Regular Markdown files contain only text. Convert this document to an
|
|
6744
|
-
MDZ package to add images, package navigation, and document metadata.
|
|
6745
|
-
</p>
|
|
6746
|
-
<p>The next save will produce an .mdz file.</p>
|
|
6747
|
-
<div class="title-dialog-actions">
|
|
6748
|
-
<button type="button" data-action="cancel-conversion">Cancel</button>
|
|
6749
|
-
<button type="button" class="save-title" data-ref="conversion-confirm-btn">Convert</button>
|
|
6750
|
-
</div>
|
|
6751
|
-
</div>
|
|
6752
|
-
</div>
|
|
6753
|
-
|
|
6754
|
-
<div class="title-dialog-backdrop" data-ref="image-insert-dialog" hidden
|
|
6755
|
-
role="dialog" aria-modal="true" aria-labelledby="mdzip-image-insert-dialog-heading">
|
|
6756
|
-
<div class="title-dialog image-insert-dialog">
|
|
6757
|
-
<h3 id="mdzip-image-insert-dialog-heading">Insert Image</h3>
|
|
6758
|
-
<p>Choose the Markdown inserted for this image.</p>
|
|
6759
|
-
<fieldset class="image-insert-options">
|
|
6760
|
-
<legend>Output</legend>
|
|
6761
|
-
<label>
|
|
6762
|
-
<input type="radio" name="mdzip-image-insert-mode" value="markdown"
|
|
6763
|
-
data-ref="image-insert-mode-markdown" checked />
|
|
6764
|
-
Markdown image
|
|
6765
|
-
</label>
|
|
6766
|
-
<label>
|
|
6767
|
-
<input type="radio" name="mdzip-image-insert-mode" value="html"
|
|
6768
|
-
data-ref="image-insert-mode-html" />
|
|
6769
|
-
HTML <img> with sizing
|
|
6770
|
-
</label>
|
|
6771
|
-
</fieldset>
|
|
6772
|
-
<label class="image-insert-field">
|
|
6773
|
-
<span>Alt text</span>
|
|
6774
|
-
<input type="text" data-ref="image-insert-alt" />
|
|
6775
|
-
</label>
|
|
6776
|
-
<div class="image-insert-grid">
|
|
6777
|
-
<label class="image-insert-field">
|
|
6778
|
-
<span>Size by</span>
|
|
6779
|
-
<select data-ref="image-insert-size-mode">
|
|
6780
|
-
<option value="original">Original size</option>
|
|
6781
|
-
<option value="width" selected>Width</option>
|
|
6782
|
-
<option value="height">Height</option>
|
|
6783
|
-
<option value="percent">Percent</option>
|
|
6784
|
-
</select>
|
|
6785
|
-
</label>
|
|
6786
|
-
<label class="image-insert-field">
|
|
6787
|
-
<span>Value</span>
|
|
6788
|
-
<input type="number" min="1" step="1" data-ref="image-insert-size-value" />
|
|
6789
|
-
</label>
|
|
6790
|
-
</div>
|
|
6791
|
-
<label class="image-insert-field">
|
|
6792
|
-
<span>Position</span>
|
|
6793
|
-
<select data-ref="image-insert-position">
|
|
6794
|
-
<option value="inline">Inline/default</option>
|
|
6795
|
-
<option value="left">Left</option>
|
|
6796
|
-
<option value="center">Center</option>
|
|
6797
|
-
<option value="right">Right</option>
|
|
6798
|
-
<option value="wrap-left">Wrap left</option>
|
|
6799
|
-
<option value="wrap-right">Wrap right</option>
|
|
6800
|
-
</select>
|
|
6801
|
-
</label>
|
|
6802
|
-
<div class="title-dialog-actions">
|
|
6803
|
-
<button type="button" data-action="cancel-image-insert">Cancel</button>
|
|
6804
|
-
<button type="button" class="save-title" data-ref="image-insert-confirm-btn">Insert</button>
|
|
6805
|
-
</div>
|
|
6806
|
-
</div>
|
|
6807
|
-
</div>
|
|
6808
|
-
|
|
6809
|
-
<div class="title-dialog-backdrop" data-ref="pack-files-dialog" hidden
|
|
6810
|
-
role="dialog" aria-modal="true" aria-labelledby="mdzip-pack-files-dialog-heading">
|
|
6811
|
-
<div class="title-dialog pack-files-dialog">
|
|
6812
|
-
<h3 id="mdzip-pack-files-dialog-heading">Package Markdown Files</h3>
|
|
6813
|
-
<p>These files contain more than one Markdown document. Choose how to package them.</p>
|
|
6814
|
-
<fieldset class="pack-files-options">
|
|
6815
|
-
<legend>Mode</legend>
|
|
6816
|
-
<label>
|
|
6817
|
-
<input type="radio" name="mdzip-pack-files-mode" value="document"
|
|
6818
|
-
data-ref="pack-files-mode-document" checked />
|
|
6819
|
-
Document — one primary page; the rest are attached
|
|
6820
|
-
</label>
|
|
6821
|
-
<label>
|
|
6822
|
-
<input type="radio" name="mdzip-pack-files-mode" value="project"
|
|
6823
|
-
data-ref="pack-files-mode-project" />
|
|
6824
|
-
Project — a set of related documents
|
|
6825
|
-
</label>
|
|
6826
|
-
</fieldset>
|
|
6827
|
-
<label class="pack-files-field">
|
|
6828
|
-
<span>Entry point</span>
|
|
6829
|
-
<select data-ref="pack-files-entry"></select>
|
|
6830
|
-
</label>
|
|
6831
|
-
<div class="title-dialog-actions">
|
|
6832
|
-
<button type="button" data-action="cancel-pack-files">Cancel</button>
|
|
6833
|
-
<button type="button" class="save-title" data-ref="pack-files-confirm-btn">Package</button>
|
|
6834
|
-
</div>
|
|
6835
|
-
</div>
|
|
6836
|
-
</div>
|
|
6837
|
-
|
|
6838
|
-
<div class="title-dialog-backdrop" data-ref="copy-render-dialog" hidden
|
|
6839
|
-
role="dialog" aria-modal="true" aria-labelledby="mdzip-copy-render-dialog-heading">
|
|
6840
|
-
<div class="title-dialog copy-render-dialog">
|
|
6841
|
-
<h3 id="mdzip-copy-render-dialog-heading" data-ref="copy-render-heading">Copying document...</h3>
|
|
6842
|
-
<div data-ref="copy-render-progress-section">
|
|
6843
|
-
<p data-ref="copy-render-progress-text">Rendering the full document...</p>
|
|
6844
|
-
<div class="copy-render-progress-track">
|
|
6845
|
-
<div class="copy-render-progress-bar" data-ref="copy-render-progress-bar"></div>
|
|
6846
|
-
</div>
|
|
6847
|
-
</div>
|
|
6848
|
-
<p data-ref="copy-render-ready-text" hidden>
|
|
6849
|
-
The document is ready. Browsers only allow a clipboard write right after a click, so this needs one more —
|
|
6850
|
-
click Copy to finish.
|
|
6851
|
-
</p>
|
|
6852
|
-
<p data-ref="copy-render-done-text" hidden></p>
|
|
6853
|
-
<div class="title-dialog-actions">
|
|
6854
|
-
<button type="button" data-action="cancel-copy-render" data-ref="copy-render-cancel-btn">Cancel</button>
|
|
6855
|
-
<button type="button" data-action="cancel-copy-ready" data-ref="copy-render-ready-cancel-btn" hidden>Cancel</button>
|
|
6856
|
-
<button type="button" class="save-title" data-action="confirm-copy-ready" data-ref="copy-render-confirm-btn" hidden>Copy</button>
|
|
6857
|
-
<button type="button" class="save-title" data-action="dismiss-copy-render" data-ref="copy-render-dismiss-btn" hidden>Dismiss</button>
|
|
6858
|
-
</div>
|
|
6859
|
-
</div>
|
|
6860
|
-
</div>
|
|
6861
|
-
|
|
6862
|
-
<div class="title-dialog-backdrop" data-ref="metadata-dialog" hidden
|
|
6863
|
-
role="dialog" aria-modal="true" aria-labelledby="mdzip-metadata-dialog-heading">
|
|
6864
|
-
<div class="title-dialog metadata-dialog">
|
|
6865
|
-
<h3 id="mdzip-metadata-dialog-heading">Document Information</h3>
|
|
6866
|
-
<dl data-ref="metadata-list"></dl>
|
|
6867
|
-
<h4>Libraries</h4>
|
|
6868
|
-
<dl data-ref="library-list"></dl>
|
|
6869
|
-
<div class="title-dialog-actions">
|
|
6870
|
-
<button type="button" class="save-title" data-action="close-metadata">Close</button>
|
|
6871
|
-
</div>
|
|
6872
|
-
</div>
|
|
6873
|
-
</div>
|
|
6874
|
-
|
|
6875
|
-
<div class="title-dialog-backdrop" data-ref="name-dialog" hidden
|
|
6876
|
-
role="dialog" aria-modal="true" aria-labelledby="mdzip-name-dialog-heading">
|
|
6877
|
-
<div class="title-dialog">
|
|
6878
|
-
<h3 id="mdzip-name-dialog-heading" data-ref="name-dialog-heading">New Markdown File</h3>
|
|
6879
|
-
<input type="text" maxlength="260" data-ref="name-input" aria-label="File name" />
|
|
6880
|
-
<p class="title-dialog-validation" data-ref="name-validation" hidden></p>
|
|
6881
|
-
<div class="title-dialog-actions">
|
|
6882
|
-
<button type="button" data-action="cancel-name">Cancel</button>
|
|
6883
|
-
<button type="button" class="save-title" data-ref="name-confirm-btn">Create</button>
|
|
6884
|
-
</div>
|
|
6885
|
-
</div>
|
|
6886
|
-
</div>
|
|
6887
|
-
|
|
6888
|
-
<div class="title-dialog-backdrop" data-ref="delete-dialog" hidden
|
|
6889
|
-
role="dialog" aria-modal="true" aria-labelledby="mdzip-delete-dialog-heading">
|
|
6890
|
-
<div class="title-dialog">
|
|
6891
|
-
<h3 id="mdzip-delete-dialog-heading">Delete File?</h3>
|
|
6892
|
-
<p data-ref="delete-dialog-text"></p>
|
|
6893
|
-
<div class="title-dialog-actions">
|
|
6894
|
-
<button type="button" data-action="cancel-delete">Cancel</button>
|
|
6895
|
-
<button type="button" class="danger-action" data-ref="delete-confirm-btn">Delete</button>
|
|
6896
|
-
</div>
|
|
6897
|
-
</div>
|
|
6898
|
-
</div>
|
|
6899
|
-
|
|
6900
|
-
<input type="file" data-ref="replace-input" hidden />
|
|
6901
|
-
|
|
6902
|
-
<div class="nav-context-menu" data-ref="nav-menu" hidden role="menu"></div>
|
|
6903
|
-
|
|
6904
|
-
<div class="mdzip-tooltip" data-ref="tooltip" role="tooltip" hidden></div>
|
|
6905
|
-
|
|
6906
|
-
<div class="mdzip-copy-toast" data-ref="copy-toast" role="status" aria-live="polite" hidden></div>
|
|
6907
|
-
|
|
6908
|
-
<p class="mdzip-empty" data-ref="empty-state">No MDZip workspace loaded.</p>
|
|
6909
|
-
</section>
|
|
6739
|
+
const SHELL_HTML = `
|
|
6740
|
+
<section class="mdzip-root">
|
|
6741
|
+
<div class="document-strip" data-ref="document-strip" hidden>
|
|
6742
|
+
<button type="button" class="title-button" data-ref="title-btn"></button>
|
|
6743
|
+
<button type="button" class="document-info-button" data-ref="document-info-btn"
|
|
6744
|
+
title="Document information" aria-label="Document information">
|
|
6745
|
+
${INFO_ICON_HTML}
|
|
6746
|
+
</button>
|
|
6747
|
+
</div>
|
|
6748
|
+
|
|
6749
|
+
<header class="toolbar" data-ref="toolbar" hidden>
|
|
6750
|
+
<div class="toolbar-start">
|
|
6751
|
+
<div class="toolbar-left">
|
|
6752
|
+
<button type="button" class="icon-toggle nav-toggle" data-ref="nav-btn" title="Toggle contents" aria-label="Toggle contents">
|
|
6753
|
+
${NAV_TOGGLE_ICON_HTML}
|
|
6754
|
+
</button>
|
|
6755
|
+
</div>
|
|
6756
|
+
|
|
6757
|
+
<div class="edit-toolbar" data-ref="edit-toolbar" role="toolbar" aria-label="Markdown formatting">
|
|
6758
|
+
<div class="edit-toolbar-group">
|
|
6759
|
+
<button type="button" data-format="bold" data-format-control="bold" title="Bold" aria-label="Bold">${BOLD_ICON_HTML}</button>
|
|
6760
|
+
<button type="button" data-format="italic" data-format-control="italic" title="Italic" aria-label="Italic">${ITALIC_ICON_HTML}</button>
|
|
6761
|
+
<button type="button" data-format="strike" data-format-control="strikethrough" title="Strikethrough" aria-label="Strikethrough">${STRIKE_ICON_HTML}</button>
|
|
6762
|
+
<div class="format-menu" data-format-control="headings">
|
|
6763
|
+
<button type="button" class="format-menu-toggle" data-format-menu-toggle
|
|
6764
|
+
aria-label="Heading" aria-haspopup="menu" aria-expanded="false">
|
|
6765
|
+
${HEADING_ICON_HTML}${CHEVRON_ICON_HTML}
|
|
6766
|
+
</button>
|
|
6767
|
+
<div class="format-menu-popover" data-format-menu role="menu" aria-label="Heading level" hidden>
|
|
6768
|
+
<button type="button" role="menuitem" data-format="paragraph">Paragraph</button>
|
|
6769
|
+
<button type="button" role="menuitem" data-format="heading-1" data-heading-level="1"><strong>H1</strong> Heading 1</button>
|
|
6770
|
+
<button type="button" role="menuitem" data-format="heading-2" data-heading-level="2"><strong>H2</strong> Heading 2</button>
|
|
6771
|
+
<button type="button" role="menuitem" data-format="heading-3" data-heading-level="3"><strong>H3</strong> Heading 3</button>
|
|
6772
|
+
<button type="button" role="menuitem" data-format="heading-4" data-heading-level="4"><strong>H4</strong> Heading 4</button>
|
|
6773
|
+
<button type="button" role="menuitem" data-format="heading-5" data-heading-level="5"><strong>H5</strong> Heading 5</button>
|
|
6774
|
+
<button type="button" role="menuitem" data-format="heading-6" data-heading-level="6"><strong>H6</strong> Heading 6</button>
|
|
6775
|
+
</div>
|
|
6776
|
+
</div>
|
|
6777
|
+
</div>
|
|
6778
|
+
<span class="edit-toolbar-divider" aria-hidden="true"></span>
|
|
6779
|
+
<div class="edit-toolbar-group">
|
|
6780
|
+
<button type="button" data-format="bullet-list" data-format-control="bulletList" title="Bulleted list" aria-label="Bulleted list">${BULLET_LIST_ICON_HTML}</button>
|
|
6781
|
+
<button type="button" data-format="ordered-list" data-format-control="orderedList" title="Numbered list" aria-label="Numbered list">${ORDERED_LIST_ICON_HTML}</button>
|
|
6782
|
+
<div class="format-menu" data-format-control="code">
|
|
6783
|
+
<button type="button" class="format-menu-toggle" data-format-menu-toggle
|
|
6784
|
+
aria-label="Code" aria-haspopup="menu" aria-expanded="false">
|
|
6785
|
+
${CODE_ICON_HTML}${CHEVRON_ICON_HTML}
|
|
6786
|
+
</button>
|
|
6787
|
+
<div class="format-menu-popover" data-format-menu role="menu" aria-label="Code format" hidden>
|
|
6788
|
+
<button type="button" role="menuitem" data-format="code" data-code-kind="inline">Inline code</button>
|
|
6789
|
+
<button type="button" role="menuitem" data-format="code-block" data-code-kind="block">Code block</button>
|
|
6790
|
+
</div>
|
|
6791
|
+
</div>
|
|
6792
|
+
<button type="button" data-format="quote" data-format-control="blockquote" title="Blockquote" aria-label="Blockquote">${QUOTE_ICON_HTML}</button>
|
|
6793
|
+
<button type="button" data-format="line-break" data-format-control="lineBreak" title="Line break" aria-label="Line break">${LINE_BREAK_ICON_HTML}</button>
|
|
6794
|
+
</div>
|
|
6795
|
+
<span class="edit-toolbar-divider" aria-hidden="true"></span>
|
|
6796
|
+
<div class="edit-toolbar-group">
|
|
6797
|
+
<button type="button" data-format="link" data-format-control="link" title="Link" aria-label="Link">${LINK_ICON_HTML}</button>
|
|
6798
|
+
<button type="button" data-format="image" data-format-control="image" title="Image" aria-label="Image">${IMAGE_FORMAT_ICON_HTML}</button>
|
|
6799
|
+
<input type="file" data-ref="image-input" accept="image/*" hidden />
|
|
6800
|
+
</div>
|
|
6801
|
+
</div>
|
|
6802
|
+
</div>
|
|
6803
|
+
|
|
6804
|
+
<div class="toolbar-buttons view-mode-toggle-group" data-ref="layout-controls" role="group" aria-label="Editor layout">
|
|
6805
|
+
<button type="button" class="icon-toggle view-mode-toggle" data-ref="source-btn" title="Edit" aria-label="Edit" aria-pressed="false">
|
|
6806
|
+
<span class="commandbar-flex-container" data-ref="source-icon">${SOURCE_EDIT_ICON_HTML}</span>
|
|
6807
|
+
</button>
|
|
6808
|
+
<button type="button" class="icon-toggle view-mode-toggle" data-ref="split-btn" title="Split" aria-label="Split" aria-pressed="false">
|
|
6809
|
+
<span class="commandbar-flex-container">
|
|
6810
|
+
${SPLIT_ICON_HTML}
|
|
6811
|
+
</span>
|
|
6812
|
+
</button>
|
|
6813
|
+
<button type="button" class="icon-toggle view-mode-toggle" data-ref="preview-btn" title="View" aria-label="View" aria-pressed="false">
|
|
6814
|
+
<span class="commandbar-flex-container">
|
|
6815
|
+
${PREVIEW_ICON_HTML}
|
|
6816
|
+
</span>
|
|
6817
|
+
</button>
|
|
6818
|
+
</div>
|
|
6819
|
+
|
|
6820
|
+
<div class="toolbar-controls" data-ref="toolbar-controls">
|
|
6821
|
+
<button type="button" class="icon-toggle" data-ref="search-btn" title="Find/replace (Mod-F)" aria-label="Find/replace">
|
|
6822
|
+
${SEARCH_ICON_HTML}
|
|
6823
|
+
</button>
|
|
6824
|
+
<button type="button" class="icon-toggle" data-ref="save-btn" title="Save" aria-label="Save">
|
|
6825
|
+
${SAVE_ICON_HTML}
|
|
6826
|
+
</button>
|
|
6827
|
+
<button type="button" class="icon-toggle zoom-toggle" data-ref="zoom-btn" title="Zoom controls" aria-label="Zoom controls">
|
|
6828
|
+
${ZOOM_ICON_HTML}
|
|
6829
|
+
</button>
|
|
6830
|
+
<div class="theme-toggle-group" data-ref="theme-controls" role="group" aria-label="Color scheme">
|
|
6831
|
+
<button type="button" class="icon-toggle theme-toggle" data-ref="dark-theme-btn"
|
|
6832
|
+
title="Dark mode" aria-label="Dark mode" aria-pressed="false">
|
|
6833
|
+
${DARK_THEME_ICON_HTML}
|
|
6834
|
+
</button>
|
|
6835
|
+
<button type="button" class="icon-toggle theme-toggle" data-ref="light-theme-btn"
|
|
6836
|
+
title="Light mode" aria-label="Light mode" aria-pressed="false">
|
|
6837
|
+
${LIGHT_THEME_ICON_HTML}
|
|
6838
|
+
</button>
|
|
6839
|
+
</div>
|
|
6840
|
+
<div class="zoom-popover" data-ref="zoom-popover" hidden role="group" aria-label="Zoom">
|
|
6841
|
+
<span class="zoom-level" data-ref="zoom-level">100%</span>
|
|
6842
|
+
<span class="zoom-stepper">
|
|
6843
|
+
<button type="button" data-action="zoom-out" title="Zoom out" aria-label="Zoom out">-</button>
|
|
6844
|
+
<button type="button" data-action="zoom-in" title="Zoom in" aria-label="Zoom in">+</button>
|
|
6845
|
+
</span>
|
|
6846
|
+
<button type="button" class="zoom-reset" data-action="zoom-reset" title="Reset zoom">Reset</button>
|
|
6847
|
+
</div>
|
|
6848
|
+
</div>
|
|
6849
|
+
</header>
|
|
6850
|
+
|
|
6851
|
+
<div class="workspace-shell" data-ref="workspace-shell" hidden>
|
|
6852
|
+
<aside class="nav-pane" data-ref="nav-pane" aria-label="Package contents">
|
|
6853
|
+
<div class="nav-tree" data-ref="nav-tree"></div>
|
|
6854
|
+
</aside>
|
|
6855
|
+
<div class="nav-resizer" data-ref="nav-resizer"
|
|
6856
|
+
role="separator" aria-orientation="vertical" aria-label="Resize contents pane"></div>
|
|
6857
|
+
|
|
6858
|
+
<div class="pane-stack" data-ref="pane-stack">
|
|
6859
|
+
<section class="pane edit-pane" data-ref="edit-pane">
|
|
6860
|
+
<div class="editor-host" data-ref="editor-host"></div>
|
|
6861
|
+
</section>
|
|
6862
|
+
<div class="split-resizer" data-ref="split-resizer"
|
|
6863
|
+
role="separator" aria-orientation="vertical" aria-label="Resize split panes"></div>
|
|
6864
|
+
<section class="pane preview-pane" data-ref="preview-pane" tabindex="-1">
|
|
6865
|
+
<article class="preview-content" data-ref="preview-content"></article>
|
|
6866
|
+
</section>
|
|
6867
|
+
<section class="pane entry-pane" data-ref="entry-pane"></section>
|
|
6868
|
+
</div>
|
|
6869
|
+
</div>
|
|
6870
|
+
|
|
6871
|
+
<div class="title-dialog-backdrop" data-ref="title-dialog" hidden
|
|
6872
|
+
role="dialog" aria-modal="true" aria-labelledby="mdzip-title-dialog-heading">
|
|
6873
|
+
<div class="title-dialog">
|
|
6874
|
+
<h3 id="mdzip-title-dialog-heading">Set Document Title</h3>
|
|
6875
|
+
<p>This is the package-level title stored in manifest.json.</p>
|
|
6876
|
+
<input type="text" maxlength="120" data-ref="title-input" aria-label="Document title" />
|
|
6877
|
+
<p class="title-dialog-validation" data-ref="title-validation" hidden>Title cannot be empty.</p>
|
|
6878
|
+
<p>If unset, consumers may fall back to entry point, filename, or first heading.</p>
|
|
6879
|
+
<div class="title-dialog-actions">
|
|
6880
|
+
<button type="button" class="reset-title" data-ref="title-reset-btn">Reset</button>
|
|
6881
|
+
<button type="button" data-action="cancel-title">Cancel</button>
|
|
6882
|
+
<button type="button" class="save-title" data-ref="title-save-btn">Save</button>
|
|
6883
|
+
</div>
|
|
6884
|
+
</div>
|
|
6885
|
+
</div>
|
|
6886
|
+
|
|
6887
|
+
<div class="title-dialog-backdrop" data-ref="conversion-dialog" hidden
|
|
6888
|
+
role="dialog" aria-modal="true" aria-labelledby="mdzip-conversion-dialog-heading">
|
|
6889
|
+
<div class="title-dialog">
|
|
6890
|
+
<h3 id="mdzip-conversion-dialog-heading">Convert to MDZ?</h3>
|
|
6891
|
+
<p>
|
|
6892
|
+
Regular Markdown files contain only text. Convert this document to an
|
|
6893
|
+
MDZ package to add images, package navigation, and document metadata.
|
|
6894
|
+
</p>
|
|
6895
|
+
<p>The next save will produce an .mdz file.</p>
|
|
6896
|
+
<div class="title-dialog-actions">
|
|
6897
|
+
<button type="button" data-action="cancel-conversion">Cancel</button>
|
|
6898
|
+
<button type="button" class="save-title" data-ref="conversion-confirm-btn">Convert</button>
|
|
6899
|
+
</div>
|
|
6900
|
+
</div>
|
|
6901
|
+
</div>
|
|
6902
|
+
|
|
6903
|
+
<div class="title-dialog-backdrop" data-ref="image-insert-dialog" hidden
|
|
6904
|
+
role="dialog" aria-modal="true" aria-labelledby="mdzip-image-insert-dialog-heading">
|
|
6905
|
+
<div class="title-dialog image-insert-dialog">
|
|
6906
|
+
<h3 id="mdzip-image-insert-dialog-heading">Insert Image</h3>
|
|
6907
|
+
<p>Choose the Markdown inserted for this image.</p>
|
|
6908
|
+
<fieldset class="image-insert-options">
|
|
6909
|
+
<legend>Output</legend>
|
|
6910
|
+
<label>
|
|
6911
|
+
<input type="radio" name="mdzip-image-insert-mode" value="markdown"
|
|
6912
|
+
data-ref="image-insert-mode-markdown" checked />
|
|
6913
|
+
Markdown image
|
|
6914
|
+
</label>
|
|
6915
|
+
<label>
|
|
6916
|
+
<input type="radio" name="mdzip-image-insert-mode" value="html"
|
|
6917
|
+
data-ref="image-insert-mode-html" />
|
|
6918
|
+
HTML <img> with sizing
|
|
6919
|
+
</label>
|
|
6920
|
+
</fieldset>
|
|
6921
|
+
<label class="image-insert-field">
|
|
6922
|
+
<span>Alt text</span>
|
|
6923
|
+
<input type="text" data-ref="image-insert-alt" />
|
|
6924
|
+
</label>
|
|
6925
|
+
<div class="image-insert-grid">
|
|
6926
|
+
<label class="image-insert-field">
|
|
6927
|
+
<span>Size by</span>
|
|
6928
|
+
<select data-ref="image-insert-size-mode">
|
|
6929
|
+
<option value="original">Original size</option>
|
|
6930
|
+
<option value="width" selected>Width</option>
|
|
6931
|
+
<option value="height">Height</option>
|
|
6932
|
+
<option value="percent">Percent</option>
|
|
6933
|
+
</select>
|
|
6934
|
+
</label>
|
|
6935
|
+
<label class="image-insert-field">
|
|
6936
|
+
<span>Value</span>
|
|
6937
|
+
<input type="number" min="1" step="1" data-ref="image-insert-size-value" />
|
|
6938
|
+
</label>
|
|
6939
|
+
</div>
|
|
6940
|
+
<label class="image-insert-field">
|
|
6941
|
+
<span>Position</span>
|
|
6942
|
+
<select data-ref="image-insert-position">
|
|
6943
|
+
<option value="inline">Inline/default</option>
|
|
6944
|
+
<option value="left">Left</option>
|
|
6945
|
+
<option value="center">Center</option>
|
|
6946
|
+
<option value="right">Right</option>
|
|
6947
|
+
<option value="wrap-left">Wrap left</option>
|
|
6948
|
+
<option value="wrap-right">Wrap right</option>
|
|
6949
|
+
</select>
|
|
6950
|
+
</label>
|
|
6951
|
+
<div class="title-dialog-actions">
|
|
6952
|
+
<button type="button" data-action="cancel-image-insert">Cancel</button>
|
|
6953
|
+
<button type="button" class="save-title" data-ref="image-insert-confirm-btn">Insert</button>
|
|
6954
|
+
</div>
|
|
6955
|
+
</div>
|
|
6956
|
+
</div>
|
|
6957
|
+
|
|
6958
|
+
<div class="title-dialog-backdrop" data-ref="pack-files-dialog" hidden
|
|
6959
|
+
role="dialog" aria-modal="true" aria-labelledby="mdzip-pack-files-dialog-heading">
|
|
6960
|
+
<div class="title-dialog pack-files-dialog">
|
|
6961
|
+
<h3 id="mdzip-pack-files-dialog-heading">Package Markdown Files</h3>
|
|
6962
|
+
<p>These files contain more than one Markdown document. Choose how to package them.</p>
|
|
6963
|
+
<fieldset class="pack-files-options">
|
|
6964
|
+
<legend>Mode</legend>
|
|
6965
|
+
<label>
|
|
6966
|
+
<input type="radio" name="mdzip-pack-files-mode" value="document"
|
|
6967
|
+
data-ref="pack-files-mode-document" checked />
|
|
6968
|
+
Document — one primary page; the rest are attached
|
|
6969
|
+
</label>
|
|
6970
|
+
<label>
|
|
6971
|
+
<input type="radio" name="mdzip-pack-files-mode" value="project"
|
|
6972
|
+
data-ref="pack-files-mode-project" />
|
|
6973
|
+
Project — a set of related documents
|
|
6974
|
+
</label>
|
|
6975
|
+
</fieldset>
|
|
6976
|
+
<label class="pack-files-field">
|
|
6977
|
+
<span>Entry point</span>
|
|
6978
|
+
<select data-ref="pack-files-entry"></select>
|
|
6979
|
+
</label>
|
|
6980
|
+
<div class="title-dialog-actions">
|
|
6981
|
+
<button type="button" data-action="cancel-pack-files">Cancel</button>
|
|
6982
|
+
<button type="button" class="save-title" data-ref="pack-files-confirm-btn">Package</button>
|
|
6983
|
+
</div>
|
|
6984
|
+
</div>
|
|
6985
|
+
</div>
|
|
6986
|
+
|
|
6987
|
+
<div class="title-dialog-backdrop" data-ref="copy-render-dialog" hidden
|
|
6988
|
+
role="dialog" aria-modal="true" aria-labelledby="mdzip-copy-render-dialog-heading">
|
|
6989
|
+
<div class="title-dialog copy-render-dialog">
|
|
6990
|
+
<h3 id="mdzip-copy-render-dialog-heading" data-ref="copy-render-heading">Copying document...</h3>
|
|
6991
|
+
<div data-ref="copy-render-progress-section">
|
|
6992
|
+
<p data-ref="copy-render-progress-text">Rendering the full document...</p>
|
|
6993
|
+
<div class="copy-render-progress-track">
|
|
6994
|
+
<div class="copy-render-progress-bar" data-ref="copy-render-progress-bar"></div>
|
|
6995
|
+
</div>
|
|
6996
|
+
</div>
|
|
6997
|
+
<p data-ref="copy-render-ready-text" hidden>
|
|
6998
|
+
The document is ready. Browsers only allow a clipboard write right after a click, so this needs one more —
|
|
6999
|
+
click Copy to finish.
|
|
7000
|
+
</p>
|
|
7001
|
+
<p data-ref="copy-render-done-text" hidden></p>
|
|
7002
|
+
<div class="title-dialog-actions">
|
|
7003
|
+
<button type="button" data-action="cancel-copy-render" data-ref="copy-render-cancel-btn">Cancel</button>
|
|
7004
|
+
<button type="button" data-action="cancel-copy-ready" data-ref="copy-render-ready-cancel-btn" hidden>Cancel</button>
|
|
7005
|
+
<button type="button" class="save-title" data-action="confirm-copy-ready" data-ref="copy-render-confirm-btn" hidden>Copy</button>
|
|
7006
|
+
<button type="button" class="save-title" data-action="dismiss-copy-render" data-ref="copy-render-dismiss-btn" hidden>Dismiss</button>
|
|
7007
|
+
</div>
|
|
7008
|
+
</div>
|
|
7009
|
+
</div>
|
|
7010
|
+
|
|
7011
|
+
<div class="title-dialog-backdrop" data-ref="metadata-dialog" hidden
|
|
7012
|
+
role="dialog" aria-modal="true" aria-labelledby="mdzip-metadata-dialog-heading">
|
|
7013
|
+
<div class="title-dialog metadata-dialog">
|
|
7014
|
+
<h3 id="mdzip-metadata-dialog-heading">Document Information</h3>
|
|
7015
|
+
<dl data-ref="metadata-list"></dl>
|
|
7016
|
+
<h4>Libraries</h4>
|
|
7017
|
+
<dl data-ref="library-list"></dl>
|
|
7018
|
+
<div class="title-dialog-actions">
|
|
7019
|
+
<button type="button" class="save-title" data-action="close-metadata">Close</button>
|
|
7020
|
+
</div>
|
|
7021
|
+
</div>
|
|
7022
|
+
</div>
|
|
7023
|
+
|
|
7024
|
+
<div class="title-dialog-backdrop" data-ref="name-dialog" hidden
|
|
7025
|
+
role="dialog" aria-modal="true" aria-labelledby="mdzip-name-dialog-heading">
|
|
7026
|
+
<div class="title-dialog">
|
|
7027
|
+
<h3 id="mdzip-name-dialog-heading" data-ref="name-dialog-heading">New Markdown File</h3>
|
|
7028
|
+
<input type="text" maxlength="260" data-ref="name-input" aria-label="File name" />
|
|
7029
|
+
<p class="title-dialog-validation" data-ref="name-validation" hidden></p>
|
|
7030
|
+
<div class="title-dialog-actions">
|
|
7031
|
+
<button type="button" data-action="cancel-name">Cancel</button>
|
|
7032
|
+
<button type="button" class="save-title" data-ref="name-confirm-btn">Create</button>
|
|
7033
|
+
</div>
|
|
7034
|
+
</div>
|
|
7035
|
+
</div>
|
|
7036
|
+
|
|
7037
|
+
<div class="title-dialog-backdrop" data-ref="delete-dialog" hidden
|
|
7038
|
+
role="dialog" aria-modal="true" aria-labelledby="mdzip-delete-dialog-heading">
|
|
7039
|
+
<div class="title-dialog">
|
|
7040
|
+
<h3 id="mdzip-delete-dialog-heading">Delete File?</h3>
|
|
7041
|
+
<p data-ref="delete-dialog-text"></p>
|
|
7042
|
+
<div class="title-dialog-actions">
|
|
7043
|
+
<button type="button" data-action="cancel-delete">Cancel</button>
|
|
7044
|
+
<button type="button" class="danger-action" data-ref="delete-confirm-btn">Delete</button>
|
|
7045
|
+
</div>
|
|
7046
|
+
</div>
|
|
7047
|
+
</div>
|
|
7048
|
+
|
|
7049
|
+
<input type="file" data-ref="replace-input" hidden />
|
|
7050
|
+
|
|
7051
|
+
<div class="nav-context-menu" data-ref="nav-menu" hidden role="menu"></div>
|
|
7052
|
+
|
|
7053
|
+
<div class="mdzip-tooltip" data-ref="tooltip" role="tooltip" hidden></div>
|
|
7054
|
+
|
|
7055
|
+
<div class="mdzip-copy-toast" data-ref="copy-toast" role="status" aria-live="polite" hidden></div>
|
|
7056
|
+
|
|
7057
|
+
<p class="mdzip-empty" data-ref="empty-state">No MDZip workspace loaded.</p>
|
|
7058
|
+
</section>
|
|
6910
7059
|
`;
|
|
6911
7060
|
//# sourceMappingURL=view.js.map
|