@brftech/filex-core 0.42.1 → 0.43.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -2
- package/dist/ArchiveViewer-BqU761Wk.js +149 -0
- package/dist/ArchiveViewer-BqU761Wk.js.map +1 -0
- package/dist/CsvViewer-ByHVK5ga.js +172 -0
- package/dist/CsvViewer-ByHVK5ga.js.map +1 -0
- package/dist/{DrawioViewer-BuhZOAx6.js → DrawioViewer-Bgrj8-zG.js} +45 -44
- package/dist/DrawioViewer-Bgrj8-zG.js.map +1 -0
- package/dist/{EpubViewer-DS3mb3k8.js → EpubViewer-DJwUKlHW.js} +50 -50
- package/dist/EpubViewer-DJwUKlHW.js.map +1 -0
- package/dist/IpynbViewer-Bz0eJ4NS.js +184 -0
- package/dist/IpynbViewer-Bz0eJ4NS.js.map +1 -0
- package/dist/MermaidViewer-CEDTD_pp.js +136 -0
- package/dist/MermaidViewer-CEDTD_pp.js.map +1 -0
- package/dist/PsdViewer-CZcxUpZO.js +121 -0
- package/dist/PsdViewer-CZcxUpZO.js.map +1 -0
- package/dist/TiffViewer-BwI62CbQ.js +141 -0
- package/dist/TiffViewer-BwI62CbQ.js.map +1 -0
- package/dist/{Viewer3D-CIrOn63I.js → Viewer3D-DoeZcuMm.js} +16 -16
- package/dist/Viewer3D-DoeZcuMm.js.map +1 -0
- package/dist/filex-core.js +475 -219
- package/dist/filex-core.umd.cjs +165 -108
- package/dist/filex-core.umd.cjs.map +1 -1
- package/dist/fonts/caveat-latin-ext.woff2 +0 -0
- package/dist/fonts/caveat-latin.woff2 +0 -0
- package/dist/fonts/dancing-script-latin-ext.woff2 +0 -0
- package/dist/fonts/dancing-script-latin.woff2 +0 -0
- package/dist/fonts/homemade-apple-latin.woff2 +0 -0
- package/dist/fonts/source-serif-4-latin-ext.woff2 +0 -0
- package/dist/fonts/source-serif-4-latin.woff2 +0 -0
- package/dist/index-DuWnGuv5.js +35901 -0
- package/dist/index-DuWnGuv5.js.map +1 -0
- package/dist/index.d.ts +5241 -553
- package/dist/pdf-CaPYsOUo.js +21302 -0
- package/dist/pdf-CaPYsOUo.js.map +1 -0
- package/dist/style.css +1 -1
- package/package.json +1 -1
- package/src/FileExplorer.vue +1207 -343
- package/src/assets/fonts/LICENSE-Apache-2.0.txt +202 -0
- package/src/assets/fonts/LICENSE-OFL-1.1.txt +93 -0
- package/src/assets/fonts/README.md +58 -0
- package/src/assets/fonts/caveat-latin-ext.woff2 +0 -0
- package/src/assets/fonts/caveat-latin.woff2 +0 -0
- package/src/assets/fonts/dancing-script-latin-ext.woff2 +0 -0
- package/src/assets/fonts/dancing-script-latin.woff2 +0 -0
- package/src/assets/fonts/homemade-apple-latin.woff2 +0 -0
- package/src/assets/fonts/source-serif-4-latin-ext.woff2 +0 -0
- package/src/assets/fonts/source-serif-4-latin.woff2 +0 -0
- package/src/components/AdvancedSearch.vue +49 -0
- package/src/components/Breadcrumb.vue +5 -5
- package/src/components/ChoiceButtons.vue +152 -0
- package/src/components/CommandPalette.vue +5 -5
- package/src/components/ConnectionGuideView.vue +1 -1
- package/src/components/ConnectionNotice.vue +59 -0
- package/src/components/ConnectionsPanel.vue +30 -568
- package/src/components/ContextMenu.vue +31 -5
- package/src/components/DataTable.vue +1331 -0
- package/src/components/FilePane.vue +3 -0
- package/src/components/FilterBar.vue +12 -5
- package/src/components/GalleryView.vue +50 -2
- package/src/components/GridView.vue +51 -3
- package/src/components/HomeView.vue +18 -6
- package/src/components/InspectorPanel.vue +134 -17
- package/src/components/ListView.vue +366 -900
- package/src/components/LogoMark.vue +57 -0
- package/src/components/NFSExportsPanel.vue +76 -28
- package/src/components/OnboardingTour.vue +19 -7
- package/src/components/OperationsCenter.vue +77 -1
- package/src/components/PendingOpsTray.vue +59 -5
- package/src/components/PresenceBar.vue +7 -7
- package/src/components/ProductVersion.vue +31 -0
- package/src/components/QuickLook.vue +10 -14
- package/src/components/RecentlyOpened.vue +47 -17
- package/src/components/RecoveryKeyModal.vue +1 -1
- package/src/components/RowActions.vue +134 -0
- package/src/components/S3KeysPanel.vue +98 -56
- package/src/components/SSHKeysPanel.vue +79 -26
- package/src/components/SideNav.vue +260 -96
- package/src/components/StarButton.vue +1 -0
- package/src/components/StorageFields.vue +74 -6
- package/src/components/StorageTags.vue +62 -0
- package/src/components/TabBar.vue +1 -1
- package/src/components/TagKindIcon.vue +56 -0
- package/src/components/TagPicker.vue +226 -40
- package/src/components/ThemePalette.vue +4 -4
- package/src/components/TimeZonePicker.vue +29 -10
- package/src/components/TokensPanel.vue +82 -27
- package/src/components/Toolbar.vue +28 -6
- package/src/components/plugin/PluginConfirmModal.vue +54 -0
- package/src/components/plugin/PluginInspectorSection.vue +149 -0
- package/src/components/plugin/PluginPageView.vue +339 -0
- package/src/components/plugin/PluginViewModal.vue +159 -0
- package/src/components/plugin/SurfaceConversation.vue +76 -0
- package/src/components/plugin/SurfaceFooterButtons.vue +73 -0
- package/src/components/plugin/SurfaceRenderer.vue +299 -0
- package/src/components/plugin/SurfaceSections.vue +91 -0
- package/src/components/plugin/nodes/PdfFieldEditor.vue +509 -0
- package/src/components/plugin/nodes/SurfaceFileChooser.vue +94 -0
- package/src/components/plugin/nodes/SurfaceForm.vue +82 -0
- package/src/components/plugin/nodes/SurfaceList.vue +127 -0
- package/src/components/plugin/nodes/SurfacePdfFields.vue +1285 -0
- package/src/components/plugin/nodes/SurfacePeoplePicker.vue +213 -0
- package/src/components/plugin/nodes/SurfacePinInput.vue +57 -0
- package/src/components/plugin/nodes/SurfacePreview.vue +119 -0
- package/src/components/plugin/nodes/SurfaceProgress.vue +48 -0
- package/src/components/plugin/nodes/SurfaceSignaturePad.vue +472 -0
- package/src/components/plugin/nodes/SurfaceSteps.vue +53 -0
- package/src/components/public/PublicLanguagePicker.vue +58 -0
- package/src/components/public/PublicLinkPage.vue +286 -0
- package/src/components/public/PublicLinkPreview.vue +85 -0
- package/src/components/public/PublicPinGate.vue +108 -0
- package/src/components/public/PublicRequestBody.vue +204 -0
- package/src/components/public/PublicShareBody.vue +188 -0
- package/src/components/public/PublicShell.vue +332 -0
- package/src/composables/useConnections.ts +8 -2
- package/src/composables/useFileApi.ts +183 -44
- package/src/composables/useLocale.ts +277 -41
- package/src/composables/useNFSExports.ts +8 -10
- package/src/composables/useOperations.ts +44 -3
- package/src/composables/usePendingOps.ts +59 -8
- package/src/composables/usePluginActions.ts +121 -0
- package/src/composables/usePluginSurface.ts +223 -0
- package/src/composables/usePublicBranding.ts +172 -0
- package/src/composables/usePublicLink.ts +573 -0
- package/src/composables/usePublicPage.ts +61 -0
- package/src/composables/useS3Keys.ts +17 -12
- package/src/composables/useSSHKeys.ts +8 -10
- package/src/composables/useTokens.ts +8 -12
- package/src/composables/useUploadChunked.ts +18 -8
- package/src/composables/useViewerFetch.ts +6 -3
- package/src/index.ts +404 -8
- package/src/lib/actionIcons.ts +46 -1
- package/src/lib/advSearch.ts +14 -7
- package/src/lib/appLock.ts +130 -0
- package/src/lib/connection.ts +110 -0
- package/src/lib/destinationTree.ts +19 -3
- package/src/lib/direction.ts +353 -0
- package/src/lib/dragGhost.ts +6 -0
- package/src/lib/dropLimits.ts +69 -0
- package/src/lib/errorWords.ts +394 -0
- package/src/lib/externalReach.ts +5 -1
- package/src/lib/fileFilters.ts +7 -2
- package/src/lib/fileIcons.ts +4 -0
- package/src/lib/internalPaths.ts +77 -0
- package/src/lib/listInput.ts +64 -0
- package/src/lib/listing.ts +58 -23
- package/src/lib/modalStack.ts +26 -0
- package/src/lib/nodeRow.ts +121 -0
- package/src/lib/pdfFieldRules.ts +126 -0
- package/src/lib/pdfFields.ts +589 -0
- package/src/lib/pdfFieldsGeom.ts +203 -0
- package/src/lib/pdfjsLoader.ts +51 -0
- package/src/lib/personName.ts +47 -0
- package/src/lib/pluginApplies.ts +123 -0
- package/src/lib/pluginLabel.ts +72 -0
- package/src/lib/pluginMenu.ts +253 -0
- package/src/lib/pluginPage.ts +58 -0
- package/src/lib/plural.ts +181 -0
- package/src/lib/popupLayer.ts +103 -0
- package/src/lib/prefs.ts +563 -0
- package/src/lib/productVersion.ts +35 -0
- package/src/lib/publicLayout.ts +39 -0
- package/src/lib/serviceGate.ts +104 -0
- package/src/lib/shareTtl.ts +25 -11
- package/src/lib/signFonts.ts +85 -0
- package/src/lib/signaturePad.ts +111 -0
- package/src/lib/sortOrder.ts +100 -38
- package/src/lib/star.ts +7 -1
- package/src/lib/surfaceCell.ts +41 -0
- package/src/lib/surfaceConditions.ts +156 -0
- package/src/lib/surfaceOpen.ts +106 -0
- package/src/lib/surfaceSteps.ts +68 -0
- package/src/lib/surfaceValues.ts +191 -0
- package/src/lib/symlink.ts +150 -0
- package/src/lib/tableColumns.ts +493 -0
- package/src/lib/tableEnv.ts +34 -0
- package/src/lib/tablePrefs.ts +84 -0
- package/src/lib/tags.ts +121 -12
- package/src/lib/themes.ts +286 -18
- package/src/lib/tour.ts +152 -0
- package/src/lib/trashEmpty.ts +111 -0
- package/src/lib/trashTimeLeft.ts +23 -0
- package/src/lib/uiLocales.ts +460 -0
- package/src/lib/viewPrefs.ts +696 -660
- package/src/lib/viewPrefsHttp.ts +78 -0
- package/src/locales/en.ts +522 -119
- package/src/locales/resolve.ts +17 -8
- package/src/locales/tr.ts +539 -155
- package/src/modals/ConvertModal.vue +62 -11
- package/src/modals/DestinationPickerModal.vue +59 -16
- package/src/modals/Modal.vue +113 -23
- package/src/modals/NewDocumentModal.vue +16 -6
- package/src/modals/NewFolderModal.vue +8 -0
- package/src/modals/PermissionsModal.vue +272 -163
- package/src/modals/PreviewModal.vue +119 -20
- package/src/modals/RenameModal.vue +37 -1
- package/src/styles/base.css +2895 -241
- package/src/styles/sign-fonts.css +118 -0
- package/src/styles/variables.css +60 -0
- package/src/types/Connections.ts +17 -0
- package/src/types/ExplorerConfig.ts +117 -1
- package/src/types/FileNode.ts +58 -0
- package/src/types/Plugins.ts +494 -0
- package/src/types/Public.ts +212 -0
- package/src/viewers/ArchiveViewer.vue +93 -48
- package/src/viewers/CsvViewer.vue +99 -53
- package/src/viewers/DrawioViewer.vue +35 -9
- package/src/viewers/EpubViewer.vue +7 -8
- package/src/viewers/IpynbViewer.vue +3 -1
- package/src/viewers/MermaidViewer.vue +4 -5
- package/src/viewers/PdfViewer.vue +8 -17
- package/src/viewers/PsdViewer.vue +2 -4
- package/src/viewers/TiffViewer.vue +4 -5
- package/src/viewers/Viewer3D.vue +1 -1
- package/LICENSE +0 -21
- package/dist/ArchiveViewer-CLNevfPE.js +0 -124
- package/dist/ArchiveViewer-CLNevfPE.js.map +0 -1
- package/dist/CsvViewer-K8XA3z7N.js +0 -141
- package/dist/CsvViewer-K8XA3z7N.js.map +0 -1
- package/dist/DrawioViewer-BuhZOAx6.js.map +0 -1
- package/dist/EpubViewer-DS3mb3k8.js.map +0 -1
- package/dist/IpynbViewer-BTk7p4Dn.js +0 -184
- package/dist/IpynbViewer-BTk7p4Dn.js.map +0 -1
- package/dist/MermaidViewer-DqucH_io.js +0 -137
- package/dist/MermaidViewer-DqucH_io.js.map +0 -1
- package/dist/PsdViewer-CwiVENmq.js +0 -122
- package/dist/PsdViewer-CwiVENmq.js.map +0 -1
- package/dist/TiffViewer-CpewSVmQ.js +0 -142
- package/dist/TiffViewer-CpewSVmQ.js.map +0 -1
- package/dist/Viewer3D-CIrOn63I.js.map +0 -1
- package/dist/index-Dx0IbBcI.js +0 -26831
- package/dist/index-Dx0IbBcI.js.map +0 -1
- package/dist/useViewerFetch-czqbd2Lj.js +0 -25
- package/dist/useViewerFetch-czqbd2Lj.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DrawioViewer-Bgrj8-zG.js","sources":["../src/viewers/DrawioViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * DrawioViewer — embed diagrams.net via iframe + postMessage handshake.\n *\n * The diagrams.net embed mode (`?embed=1&proto=json`) handshakes via\n * window.postMessage:\n *\n * 1. iframe sends {event:'init'} ← bootstrap\n * 2. parent sends {action:'load', xml} ← our payload\n * 3. iframe sends {event:'save', xml} on save ← we POST back\n *\n * No external library required — diagrams.net hosts the entire editor\n * inside the iframe. We just fetch the source XML on mount and route\n * `save` events back to the configured `pdfSaveUrl`-style endpoint\n * (drawio uses the same shape: POST `{path, content}` body).\n */\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';\nimport { fileIconTile } from '../lib/fileIcons'; /* ikon:emoji */\nimport { fetchViewerText } from '../composables/useViewerFetch';\n\nconst props = defineProps<{\n url: string;\n filePath: string;\n ext: string;\n drawioUrl?: string;\n /** Optional save endpoint. When unset the iframe stays read-only. */\n saveUrl?: string;\n readOnly?: boolean;\n t?: (key: string) => string;\n authHeaders?: () => Record<string, string> | Promise<Record<string, string>>;\n authCredentials?: RequestCredentials;\n /** Could this person set up draw.io (`capabilities.caller_admin`)? Picks\n * which sentence the \"not configured\" pane says — see `bootIfReady`. */\n canConfigure?: boolean;\n}>();\n\nconst iframeRef = ref<HTMLIFrameElement | null>(null);\nconst error = ref<string | null>(null);\nconst status = ref<'loading' | 'ready' | 'saving' | 'saved' | 'error'>('loading');\nconst readOnly = ref(!!props.readOnly || !props.saveUrl);\n\n// drawioUrl=null is the operator's \"off\" signal — FileExplorer wipes it\n// when the capabilities probe reports drawio offline. Don't silently fall\n// back to the public embed.diagrams.net iframe, that defeats the point of\n// gating: render a \"not configured\" pane instead so the user understands\n// why the editor isn't loading.\n//\n// `drawioBase` MUST be a computed (not a const), otherwise a stale null\n// at mount time (capabilities probe still inflight) gets cached for the\n// component's lifetime — leading to the spurious\n// \"viewer.drawio.disabled\" fallback after the capability flips to \"ok\".\nconst drawioBase = computed<string | null>(() =>\n props.drawioUrl ? props.drawioUrl.replace(/\\/$/, '') : null,\n);\nconst iframeSrc = computed<string>(() => {\n if (!drawioBase.value) return '';\n const params = new URLSearchParams({\n embed: '1',\n proto: 'json',\n spin: '1',\n saveAndExit: '0',\n noSaveBtn: readOnly.value ? '1' : '0',\n noExitBtn: '1',\n ui: 'kennedy',\n modified: 'unsavedChanges',\n });\n return `${drawioBase.value}/?${params.toString()}`;\n});\n\nlet pendingXml: string = '';\n\nasync function loadXml(): Promise<void> {\n status.value = 'loading';\n error.value = null;\n try {\n pendingXml = await fetchViewerText({\n url: props.url,\n headers: (await props.authHeaders?.()) ?? {},\n credentials: props.authCredentials,\n });\n } catch (err) {\n /* ⚠ A sentence, never `${status} ${statusText} — <body>` (which is what\n fetchViewerText's error carries). The detail goes to the console. */\n console.warn('[filex] diagram could not be read', err);\n error.value = tt('viewer.drawio.load_failed', 'This diagram could not be read. Download it to open it elsewhere.');\n disabledPane = false;\n status.value = 'error';\n }\n}\n\nfunction send(msg: unknown): void {\n iframeRef.value?.contentWindow?.postMessage(JSON.stringify(msg), '*');\n}\n\nasync function persist(xml: string): Promise<void> {\n if (!props.saveUrl) return;\n status.value = 'saving';\n try {\n const headers: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...((await props.authHeaders?.()) ?? {}),\n };\n const res = await fetch(props.saveUrl, {\n method: 'POST',\n headers,\n credentials: props.authCredentials || 'same-origin',\n body: JSON.stringify({ path: props.filePath, content: xml }),\n });\n if (!res.ok) {\n /* ⚠ Never the HTTP layer on screen (\"503 Service Unavailable\" is what\n this used to say when a save could not take its version snapshot). */\n console.warn('[filex] diagram save failed', res.status, res.statusText);\n throw new Error('save');\n }\n status.value = 'saved';\n setTimeout(() => {\n if (status.value === 'saved') status.value = 'ready';\n }, 2500);\n } catch (err) {\n console.warn('[filex] diagram save failed', err);\n error.value = tt('viewer.drawio.save_failed', 'The diagram could not be saved. Your changes are still in the editor — try again.');\n disabledPane = false;\n status.value = 'error';\n }\n}\n\nfunction onMessage(ev: MessageEvent): void {\n if (typeof ev.data !== 'string' || ev.data.length === 0) return;\n // Drawio messages always start with '{' or '<'. Ignore anything else\n // (devtools / unrelated postMessage senders inside the same window).\n const first = ev.data[0];\n if (first !== '{' && first !== '<') return;\n let payload: any;\n try {\n payload = JSON.parse(ev.data);\n } catch {\n return;\n }\n if (!payload || typeof payload !== 'object') return;\n switch (payload.event) {\n case 'init':\n send({\n action: 'load',\n xml: pendingXml,\n autosave: 0,\n });\n status.value = 'ready';\n break;\n case 'save':\n if (typeof payload.xml === 'string') {\n persist(payload.xml);\n }\n break;\n case 'export':\n // Could persist a PNG/SVG render; out of V1 scope.\n break;\n case 'autosave':\n if (typeof payload.xml === 'string' && !readOnly.value) {\n persist(payload.xml);\n }\n break;\n default:\n break;\n }\n}\n\n/** Is the pane on screen the \"not configured\" one (so a later answer that\n * draw.io IS there can clear it)? A flag, not a comparison with the text:\n * the text now depends on who is looking. */\nlet disabledPane = false;\n\nfunction bootIfReady(): void {\n if (!drawioBase.value) {\n /* The owner's rule for a missing service (2026-09-21): whoever can fix\n it is told where; everybody else is told what they can do instead.\n ⚠ The old sentence named an ENVIRONMENT VARIABLE to every reader —\n \"operator must wire FILEX_DRAWIO_URL\" — which is a riddle to a person\n who only wanted to look at a diagram. */\n error.value = props.canConfigure\n ? tt('viewer.drawio.disabled_admin', 'draw.io is not set up on this server. Set it up in the admin panel under External services.')\n : tt('viewer.drawio.disabled', 'Diagrams cannot be opened here: this server has no draw.io. Download the file to open it elsewhere.');\n disabledPane = true;\n status.value = 'error';\n return;\n }\n // Clear a previous \"disabled\" pane in case the prop just became available\n // (capability probe finished after mount).\n if (disabledPane) {\n disabledPane = false;\n error.value = null;\n status.value = 'loading';\n }\n loadXml();\n}\n\nonMounted(() => {\n window.addEventListener('message', onMessage);\n bootIfReady();\n});\n\nwatch(() => props.drawioUrl, bootIfReady);\n\nonBeforeUnmount(() => {\n window.removeEventListener('message', onMessage);\n});\n\nfunction tt(key: string, fallback: string): string {\n return props.t ? props.t(key) : fallback;\n}\n\n/* === ikon:emoji — the fallback screen's mark ==========================\n * Every viewer opened its \"cannot show this\" / \"still loading\" screen with a\n * 48px colour emoji, one per format, each from whatever emoji font the OS\n * shipped. The format mark is `lib/fileIcons`'s tile — the SAME tile the row\n * the person just clicked is wearing, so the fallback is recognisably about\n * that file — and \"loading\" is the stroked ring, spun by CSS, because no\n * still picture can say \"still going\". */\nconst typeTile = computed(() => fileIconTile({ type: 'file', extension: props.ext }));\n</script>\n\n<template>\n <div class=\"filex-viewer-drawio\">\n <div v-if=\"error\" class=\"filex-viewer-fallback\">\n <!-- eslint-disable-next-line vue/no-v-html -- static markup from lib/fileIcons + lib/actionIcons -->\n <span class=\"filex-viewer-fallback__icon\" aria-hidden=\"true\" v-html=\"typeTile\"></span>\n <p>{{ error }}</p>\n </div>\n <iframe\n v-else\n ref=\"iframeRef\"\n :src=\"iframeSrc\"\n class=\"filex-viewer-drawio__frame\"\n title=\"draw.io\"\n />\n </div>\n</template>\n\n<style>\n/* ⚠ NOT `scoped`, deliberately. Vue's scoped styles compile to\n `.cls[data-v-HASH]`, and in the web-component build the hash baked into\n this CSS does not match the one Vue stamps onto the DOM — so every rule\n here silently stopped applying. Measured in the desktop app: the share\n dialog had `position: static`, no background and no radius, i.e. raw\n unstyled HTML, in EVERY embedded surface.\n Safe to drop: every selector below is prefixed (fx-/fe-/filex-), so\n there is nothing here that can leak into a host page. */\n.filex-viewer-drawio {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 70vh;\n background: var(--fe-bg, #fff);\n}\n.filex-viewer-drawio__bar {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 6px 12px;\n background: var(--fe-bg-elev, #f7f8fa);\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\n font-size: 12px;\n color: var(--fe-text-muted, #5a6475);\n}\n.filex-viewer-drawio__status[data-state=\"error\"] { color: var(--fe-danger, #dc2626); }\n.filex-viewer-drawio__status[data-state=\"saved\"] { color: #059669; }\n.filex-viewer-drawio__readonly {\n font-style: italic;\n margin-inline-start: auto;\n}\n.filex-viewer-drawio__frame {\n flex: 1;\n width: 100%;\n border: 0;\n background: #fafafa;\n min-height: 0;\n}\n.filex-viewer-fallback {\n text-align: center;\n padding: 32px;\n color: var(--fe-text-muted, #5a6475);\n}\n.filex-viewer-fallback__icon {\n font-size: 48px;\n display: block;\n margin-bottom: 12px;\n}\n</style>\n"],"names":["props","__props","iframeRef","ref","error","status","readOnly","drawioBase","computed","iframeSrc","params","pendingXml","loadXml","fetchViewerText","_a","err","tt","disabledPane","send","msg","_b","persist","xml","headers","res","onMessage","ev","first","payload","bootIfReady","onMounted","watch","onBeforeUnmount","key","fallback","typeTile","fileIconTile","_openBlock","_createElementBlock","_hoisted_1","_hoisted_2","_createElementVNode"],"mappings":"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"}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { defineComponent as
|
|
2
|
-
import { f as V } from "./index-
|
|
3
|
-
const
|
|
1
|
+
import { defineComponent as F, ref as o, onMounted as H, onBeforeUnmount as M, watch as S, computed as D, openBlock as u, createElementBlock as c, createElementVNode as d, toDisplayString as b, Fragment as R, createCommentVNode as E } from "vue";
|
|
2
|
+
import { f as V, r as z } from "./index-DuWnGuv5.js";
|
|
3
|
+
const A = {
|
|
4
4
|
key: 0,
|
|
5
5
|
class: "filex-viewer-fallback"
|
|
6
|
-
},
|
|
6
|
+
}, I = ["innerHTML"], N = {
|
|
7
7
|
key: 0,
|
|
8
8
|
class: "filex-viewer-epub__nav"
|
|
9
|
-
},
|
|
9
|
+
}, $ = ["disabled"], q = ["disabled"], K = {
|
|
10
10
|
key: 1,
|
|
11
11
|
class: "filex-viewer-epub__loading"
|
|
12
|
-
}, T = 15e3,
|
|
12
|
+
}, T = 15e3, G = /* @__PURE__ */ F({
|
|
13
13
|
__name: "EpubViewer",
|
|
14
14
|
props: {
|
|
15
15
|
url: {},
|
|
@@ -20,24 +20,24 @@ const z = {
|
|
|
20
20
|
authCredentials: {}
|
|
21
21
|
},
|
|
22
22
|
setup(P) {
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
const C =
|
|
23
|
+
const n = P, B = o(null), y = o(null), r = o(null), U = o([]);
|
|
24
|
+
o(!1);
|
|
25
|
+
const C = o(100), i = o(!1), f = o(!0);
|
|
26
26
|
let a = null, e = null;
|
|
27
|
-
function
|
|
27
|
+
function h(t, l) {
|
|
28
28
|
let s;
|
|
29
29
|
return Promise.race([
|
|
30
30
|
t,
|
|
31
|
-
new Promise((v,
|
|
31
|
+
new Promise((v, p) => {
|
|
32
32
|
s = setTimeout(
|
|
33
|
-
() =>
|
|
33
|
+
() => p(new Error(`EPUB ${l} timed out after ${T}ms`)),
|
|
34
34
|
T
|
|
35
35
|
);
|
|
36
36
|
})
|
|
37
37
|
]).finally(() => clearTimeout(s));
|
|
38
38
|
}
|
|
39
39
|
async function m() {
|
|
40
|
-
f.value = !0, i.value = !1,
|
|
40
|
+
f.value = !0, i.value = !1, r.value = null;
|
|
41
41
|
let t = null;
|
|
42
42
|
try {
|
|
43
43
|
t = await import(
|
|
@@ -45,63 +45,63 @@ const z = {
|
|
|
45
45
|
"epubjs"
|
|
46
46
|
);
|
|
47
47
|
} catch {
|
|
48
|
-
|
|
48
|
+
r.value = _("viewer.peer_not_installed", "This kind of file cannot be shown here. Download it to open it on your device."), f.value = !1;
|
|
49
49
|
return;
|
|
50
50
|
}
|
|
51
51
|
try {
|
|
52
|
-
const
|
|
53
|
-
let s =
|
|
54
|
-
if (
|
|
55
|
-
const
|
|
56
|
-
headers:
|
|
57
|
-
credentials:
|
|
52
|
+
const l = t.default ?? t;
|
|
53
|
+
let s = n.url;
|
|
54
|
+
if (n.authHeaders) {
|
|
55
|
+
const p = await n.authHeaders(), w = await fetch(n.url, {
|
|
56
|
+
headers: p,
|
|
57
|
+
credentials: n.authCredentials || "same-origin"
|
|
58
58
|
});
|
|
59
|
-
if (!w.ok) throw
|
|
59
|
+
if (!w.ok) throw z(w.status, await w.text().catch(() => ""), void 0);
|
|
60
60
|
s = await w.arrayBuffer();
|
|
61
61
|
}
|
|
62
|
-
if (a =
|
|
62
|
+
if (a = l(s), !y.value)
|
|
63
63
|
throw new Error("EPUB mount target missing");
|
|
64
64
|
e = a.renderTo(y.value, {
|
|
65
65
|
width: "100%",
|
|
66
66
|
height: "100%",
|
|
67
67
|
flow: "paginated",
|
|
68
68
|
manager: "default"
|
|
69
|
-
}), await
|
|
70
|
-
const v = await
|
|
69
|
+
}), await h(e.display(), "display"), e.themes.fontSize(C.value + "%");
|
|
70
|
+
const v = await h(a.loaded.navigation, "navigation");
|
|
71
71
|
U.value = (v == null ? void 0 : v.toc) ?? [], i.value = !0;
|
|
72
|
-
} catch (
|
|
73
|
-
console.warn("[filex] EPUB load failed:",
|
|
72
|
+
} catch (l) {
|
|
73
|
+
console.warn("[filex] EPUB load failed:", l), r.value = _("viewer.failed_to_load", "Failed to load file");
|
|
74
74
|
} finally {
|
|
75
75
|
f.value = !1;
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
|
-
function
|
|
78
|
+
function g() {
|
|
79
79
|
var t;
|
|
80
80
|
(t = e == null ? void 0 : e.next) == null || t.call(e);
|
|
81
81
|
}
|
|
82
|
-
function
|
|
82
|
+
function k() {
|
|
83
83
|
var t;
|
|
84
84
|
(t = e == null ? void 0 : e.prev) == null || t.call(e);
|
|
85
85
|
}
|
|
86
86
|
function x(t) {
|
|
87
|
-
t.key === "ArrowRight" || t.key === "PageDown" ?
|
|
87
|
+
t.key === "ArrowRight" || t.key === "PageDown" ? g() : (t.key === "ArrowLeft" || t.key === "PageUp") && k();
|
|
88
88
|
}
|
|
89
|
-
|
|
89
|
+
H(() => {
|
|
90
90
|
m(), window.addEventListener("keydown", x);
|
|
91
|
-
}),
|
|
92
|
-
var t,
|
|
91
|
+
}), M(() => {
|
|
92
|
+
var t, l;
|
|
93
93
|
window.removeEventListener("keydown", x);
|
|
94
94
|
try {
|
|
95
95
|
(t = e == null ? void 0 : e.destroy) == null || t.call(e);
|
|
96
96
|
} catch {
|
|
97
97
|
}
|
|
98
98
|
try {
|
|
99
|
-
(
|
|
99
|
+
(l = a == null ? void 0 : a.destroy) == null || l.call(a);
|
|
100
100
|
} catch {
|
|
101
101
|
}
|
|
102
102
|
e = null, a = null;
|
|
103
|
-
}),
|
|
104
|
-
() =>
|
|
103
|
+
}), S(
|
|
104
|
+
() => n.url,
|
|
105
105
|
() => {
|
|
106
106
|
if (e)
|
|
107
107
|
try {
|
|
@@ -116,48 +116,48 @@ const z = {
|
|
|
116
116
|
a = null, e = null, m();
|
|
117
117
|
}
|
|
118
118
|
);
|
|
119
|
-
function
|
|
120
|
-
return
|
|
119
|
+
function _(t, l) {
|
|
120
|
+
return n.t ? n.t(t) : l;
|
|
121
121
|
}
|
|
122
|
-
const L =
|
|
123
|
-
return (t,
|
|
122
|
+
const L = D(() => V({ type: "file", extension: n.ext }));
|
|
123
|
+
return (t, l) => (u(), c("div", {
|
|
124
124
|
ref_key: "root",
|
|
125
125
|
ref: B,
|
|
126
126
|
class: "filex-viewer-epub"
|
|
127
127
|
}, [
|
|
128
|
-
|
|
128
|
+
r.value ? (u(), c("div", A, [
|
|
129
129
|
d("span", {
|
|
130
130
|
class: "filex-viewer-fallback__icon",
|
|
131
131
|
"aria-hidden": "true",
|
|
132
132
|
innerHTML: L.value
|
|
133
|
-
}, null, 8,
|
|
134
|
-
d("p", null,
|
|
133
|
+
}, null, 8, I),
|
|
134
|
+
d("p", null, b(r.value), 1)
|
|
135
135
|
])) : (u(), c(R, { key: 1 }, [
|
|
136
136
|
d("div", {
|
|
137
137
|
ref_key: "containerRef",
|
|
138
138
|
ref: y,
|
|
139
139
|
class: "filex-viewer-epub__rendition"
|
|
140
140
|
}, null, 512),
|
|
141
|
-
i.value ? (u(), c("div",
|
|
141
|
+
i.value ? (u(), c("div", N, [
|
|
142
142
|
d("button", {
|
|
143
143
|
type: "button",
|
|
144
144
|
class: "filex-viewer-btn",
|
|
145
|
-
onClick:
|
|
145
|
+
onClick: k,
|
|
146
146
|
disabled: !i.value
|
|
147
|
-
}, "‹", 8,
|
|
147
|
+
}, "‹", 8, $),
|
|
148
148
|
d("button", {
|
|
149
149
|
type: "button",
|
|
150
150
|
class: "filex-viewer-btn",
|
|
151
|
-
onClick:
|
|
151
|
+
onClick: g,
|
|
152
152
|
disabled: !i.value
|
|
153
|
-
}, "›", 8,
|
|
153
|
+
}, "›", 8, q)
|
|
154
154
|
])) : E("", !0),
|
|
155
|
-
f.value ? (u(), c("div",
|
|
155
|
+
f.value ? (u(), c("div", K, b(_("viewer.loading", "Loading…")), 1)) : E("", !0)
|
|
156
156
|
], 64))
|
|
157
157
|
], 512));
|
|
158
158
|
}
|
|
159
159
|
});
|
|
160
160
|
export {
|
|
161
|
-
|
|
161
|
+
G as default
|
|
162
162
|
};
|
|
163
|
-
//# sourceMappingURL=EpubViewer-
|
|
163
|
+
//# sourceMappingURL=EpubViewer-DJwUKlHW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"EpubViewer-DJwUKlHW.js","sources":["../src/viewers/EpubViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { requestFailure } from '../lib/errorWords';\n/**\n * EpubViewer — flowable EPUB reader via `epubjs`.\n *\n * Lazy-imports `epubjs` (~80 KB gzipped). epub.js renders the publication\n * inside an iframe (default `flow: 'paginated'`), but we use it in\n * scrolled-doc mode only when the user toggles the \"fit-width\" flag — by\n * default we keep paginated since that matches reader-app expectations.\n *\n * UX:\n * - prev/next page buttons (also keyboard arrow keys via composable)\n * - collapsible TOC sidebar (built from `book.loaded.navigation`)\n * - font size +/- (Themes API)\n * - graceful fallback if peer not installed\n */\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';\nimport { fileIconTile } from '../lib/fileIcons'; /* ikon:emoji */\n\nconst props = defineProps<{\n url: string;\n mime?: string;\n ext: string;\n t?: (key: string) => string;\n authHeaders?: () => Record<string, string> | Promise<Record<string, string>>;\n authCredentials?: RequestCredentials;\n}>();\n\ninterface TocNode {\n href: string;\n label: string;\n subitems?: TocNode[];\n}\n\nconst root = ref<HTMLDivElement | null>(null);\nconst containerRef = ref<HTMLDivElement | null>(null);\nconst error = ref<string | null>(null);\nconst toc = ref<TocNode[]>([]);\nconst tocOpen = ref(false);\nconst fontSize = ref(100);\nconst ready = ref(false);\nconst loading = ref(true);\n\nlet book: any = null;\nlet rendition: any = null;\n\n/**\n * How long an epub.js step may hang before we call it a failure.\n *\n * Generous on purpose: a large publication on a slow disk legitimately takes\n * seconds, and a false \"cannot open\" on a book that would have rendered is a\n * worse bug than the one this guards against.\n */\nconst EPUB_STEP_TIMEOUT_MS = 15000;\n\n/** Reject if `p` has not settled within `EPUB_STEP_TIMEOUT_MS`. */\nfunction withTimeout<T>(p: Promise<T>, label: string): Promise<T> {\n let timer: ReturnType<typeof setTimeout>;\n return Promise.race([\n p,\n new Promise<never>((_, reject) => {\n timer = setTimeout(\n () => reject(new Error(`EPUB ${label} timed out after ${EPUB_STEP_TIMEOUT_MS}ms`)),\n EPUB_STEP_TIMEOUT_MS,\n );\n }),\n ]).finally(() => clearTimeout(timer)) as Promise<T>;\n}\n\nasync function load(): Promise<void> {\n loading.value = true;\n ready.value = false;\n error.value = null;\n let mod: any = null;\n try {\n mod = await import(/* @vite-ignore */ 'epubjs');\n } catch {\n error.value = tt('viewer.peer_not_installed', 'This kind of file cannot be shown here. Download it to open it on your device.');\n loading.value = false;\n return;\n }\n try {\n const Epub = mod.default ?? mod;\n // epub.js wants a URL (it then fetches with XHR). When the host\n // site requires auth headers we have to load the file ourselves\n // and pass an ArrayBuffer instead.\n let source: string | ArrayBuffer = props.url;\n if (props.authHeaders) {\n const headers = await props.authHeaders();\n const res = await fetch(props.url, {\n headers,\n credentials: props.authCredentials || 'same-origin',\n });\n if (!res.ok) throw requestFailure(res.status, await res.text().catch(() => ''), undefined);\n source = await res.arrayBuffer();\n }\n book = Epub(source);\n if (!containerRef.value) {\n throw new Error('EPUB mount target missing');\n }\n rendition = book.renderTo(containerRef.value, {\n width: '100%',\n height: '100%',\n flow: 'paginated',\n manager: 'default',\n });\n // ⚠⚠ Both of these have to be raced against a clock. epub.js resolves\n // `display()` and `loaded.navigation` from its own internal promises, and\n // when the archive is not a readable EPUB it simply NEVER settles —\n // neither resolve nor reject — so the `catch` below can't fire and\n // `finally` never runs. Measured 2026-09-13 on an 8-byte `handbook.epub`:\n // the pane sat on \"Yükleniyor…\" forever with no error anywhere.\n await withTimeout(rendition.display(), 'display');\n rendition.themes.fontSize(fontSize.value + '%');\n // `<any>` explicitly: `book` is `any`, so without it `T` infers as `{}`\n // and `nav.toc` stops type-checking.\n const nav = await withTimeout<any>(book.loaded.navigation, 'navigation');\n toc.value = (nav?.toc ?? []) as TocNode[];\n ready.value = true;\n } catch (err) {\n // The reader gets the localized sentence; epub.js's own wording (and the\n // timeout marker) goes to the console for whoever is debugging.\n console.warn('[filex] EPUB load failed:', err);\n error.value = tt('viewer.failed_to_load', 'Failed to load file');\n } finally {\n loading.value = false;\n }\n}\n\nfunction next(): void {\n rendition?.next?.();\n}\nfunction prev(): void {\n rendition?.prev?.();\n}\nfunction gotoHref(href: string): void {\n rendition?.display?.(href);\n tocOpen.value = false;\n}\nfunction bigger(): void {\n fontSize.value = Math.min(200, fontSize.value + 10);\n rendition?.themes?.fontSize(fontSize.value + '%');\n}\nfunction smaller(): void {\n fontSize.value = Math.max(60, fontSize.value - 10);\n rendition?.themes?.fontSize(fontSize.value + '%');\n}\n\nfunction onKey(ev: KeyboardEvent): void {\n if (ev.key === 'ArrowRight' || ev.key === 'PageDown') next();\n else if (ev.key === 'ArrowLeft' || ev.key === 'PageUp') prev();\n}\n\nonMounted(() => {\n load();\n window.addEventListener('keydown', onKey);\n});\n\nonBeforeUnmount(() => {\n window.removeEventListener('keydown', onKey);\n try {\n rendition?.destroy?.();\n } catch {\n /* ignore */\n }\n try {\n book?.destroy?.();\n } catch {\n /* ignore */\n }\n rendition = null;\n book = null;\n});\n\nwatch(\n () => props.url,\n () => {\n if (rendition) {\n try {\n rendition.destroy();\n } catch {\n /* ignore */\n }\n }\n if (book) {\n try {\n book.destroy();\n } catch {\n /* ignore */\n }\n }\n book = null;\n rendition = null;\n load();\n },\n);\n\nfunction tt(key: string, fallback: string): string {\n return props.t ? props.t(key) : fallback;\n}\n\n/* === ikon:emoji — the fallback screen's mark ==========================\n * Every viewer opened its \"cannot show this\" / \"still loading\" screen with a\n * 48px colour emoji, one per format, each from whatever emoji font the OS\n * shipped. The format mark is `lib/fileIcons`'s tile — the SAME tile the row\n * the person just clicked is wearing, so the fallback is recognisably about\n * that file — and \"loading\" is the stroked ring, spun by CSS, because no\n * still picture can say \"still going\". */\nconst typeTile = computed(() => fileIconTile({ type: 'file', extension: props.ext }));\n</script>\n\n<template>\n <div ref=\"root\" class=\"filex-viewer-epub\">\n <div v-if=\"error\" class=\"filex-viewer-fallback\">\n <!-- eslint-disable-next-line vue/no-v-html -- static markup from lib/fileIcons + lib/actionIcons -->\n <span class=\"filex-viewer-fallback__icon\" aria-hidden=\"true\" v-html=\"typeTile\"></span>\n <p>{{ error }}</p>\n </div>\n <template v-else>\n <div ref=\"containerRef\" class=\"filex-viewer-epub__rendition\" />\n <div v-if=\"ready\" class=\"filex-viewer-epub__nav\">\n <button type=\"button\" class=\"filex-viewer-btn\" @click=\"prev\" :disabled=\"!ready\">‹</button>\n <button type=\"button\" class=\"filex-viewer-btn\" @click=\"next\" :disabled=\"!ready\">›</button>\n </div>\n <div v-if=\"loading\" class=\"filex-viewer-epub__loading\">\n {{ tt('viewer.loading', 'Loading…') }}\n </div>\n </template>\n </div>\n</template>\n\n<style>\n/* ⚠ NOT `scoped`, deliberately. Vue's scoped styles compile to\n `.cls[data-v-HASH]`, and in the web-component build the hash baked into\n this CSS does not match the one Vue stamps onto the DOM — so every rule\n here silently stopped applying. Measured in the desktop app: the share\n dialog had `position: static`, no background and no radius, i.e. raw\n unstyled HTML, in EVERY embedded surface.\n Safe to drop: every selector below is prefixed (fx-/fe-/filex-), so\n there is nothing here that can leak into a host page. */\n.filex-viewer-epub__nav {\n position: absolute;\n bottom: 12px;\n left: 50%; /* rtl-physical: centred by translate(-50%) — the same place in both directions */\n transform: translateX(-50%);\n display: flex;\n gap: 8px;\n padding: 4px 8px;\n background: var(--fe-bg-elev, rgba(255, 255, 255, 0.9));\n border: 1px solid var(--fe-border, #e2e6ed);\n border-radius: 6px;\n backdrop-filter: blur(4px);\n}\n.filex-viewer-epub {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 70vh;\n background: var(--fe-bg, #fff);\n color: var(--fe-text, #1a1e27);\n position: relative;\n}\n.filex-viewer-epub__bar {\n display: flex;\n align-items: center;\n gap: 6px;\n padding: 8px 12px;\n background: var(--fe-bg-elev, #f7f8fa);\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\n font-size: 13px;\n}\n.filex-viewer-spacer { flex: 1; }\n.filex-viewer-epub__fs {\n display: inline-block;\n min-width: 40px;\n text-align: center;\n font-variant-numeric: tabular-nums;\n font-size: 12px;\n color: var(--fe-text-muted, #5a6475);\n}\n.filex-viewer-epub__main {\n flex: 1;\n min-height: 0;\n display: flex;\n}\n.filex-viewer-epub__rendition {\n flex: 1;\n min-height: 0;\n}\n.filex-viewer-epub__toc {\n width: 260px;\n border-inline-end: 1px solid var(--fe-border, #e2e6ed);\n overflow-y: auto;\n padding: 12px 0;\n background: var(--fe-bg-elev, #f7f8fa);\n}\n.filex-viewer-epub__toc ul {\n list-style: none;\n margin: 0;\n padding: 0;\n}\n.filex-viewer-epub__toc-link {\n display: block;\n width: 100%;\n text-align: start;\n background: transparent;\n border: 0;\n padding: 6px 14px;\n font: inherit;\n color: inherit;\n cursor: pointer;\n}\n.filex-viewer-epub__toc-link:hover {\n background: var(--fe-bg-hover, #edf0f5);\n}\n.filex-viewer-epub__toc-link.is-child {\n padding-inline-start: 28px;\n color: var(--fe-text-muted, #5a6475);\n font-size: 12px;\n}\n.filex-viewer-epub__loading {\n position: absolute;\n inset: auto 0 0 0;\n text-align: center;\n padding: 6px;\n background: rgba(0, 0, 0, 0.05);\n font-size: 12px;\n color: var(--fe-text-muted, #5a6475);\n}\n.filex-viewer-fallback {\n text-align: center;\n padding: 32px;\n color: var(--fe-text-muted, #5a6475);\n}\n.filex-viewer-fallback__icon {\n font-size: 48px;\n display: block;\n margin-bottom: 12px;\n}\n.filex-viewer-btn {\n border: 1px solid var(--fe-border, #e2e6ed);\n background: var(--fe-bg, #fff);\n color: var(--fe-text, #1a1e27);\n padding: 4px 10px;\n border-radius: 4px;\n cursor: pointer;\n font: inherit;\n font-size: 12px;\n}\n.filex-viewer-btn:hover:not(:disabled) {\n background: var(--fe-bg-hover, #edf0f5);\n}\n.filex-viewer-btn:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n}\n</style>\n"],"names":["EPUB_STEP_TIMEOUT_MS","props","__props","root","ref","containerRef","error","toc","fontSize","ready","loading","book","rendition","withTimeout","p","label","timer","_","reject","load","mod","tt","Epub","source","headers","res","requestFailure","nav","err","next","_a","prev","onKey","ev","onMounted","onBeforeUnmount","_b","watch","key","fallback","typeTile","computed","fileIconTile","_createElementBlock","_openBlock","_hoisted_1","_createElementVNode","_Fragment","_hoisted_3","_hoisted_4","_hoisted_5","_hoisted_6","_toDisplayString"],"mappings":"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"}
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { defineComponent as U, ref as p, onMounted as D, onBeforeUnmount as q, watch as z, computed as B, openBlock as n, createElementBlock as a, createElementVNode as d, toDisplayString as _, unref as G, Fragment as m, renderList as E, createCommentVNode as N } from "vue";
|
|
2
|
+
import { f as K, a as P, b as Q, s as W, e as X } from "./index-DuWnGuv5.js";
|
|
3
|
+
const Y = { class: "filex-viewer-ipynb" }, Z = { class: "filex-viewer-ipynb__pane" }, ee = {
|
|
4
|
+
key: 0,
|
|
5
|
+
class: "filex-viewer-fallback"
|
|
6
|
+
}, te = ["innerHTML"], ne = {
|
|
7
|
+
key: 1,
|
|
8
|
+
class: "filex-viewer-fallback"
|
|
9
|
+
}, ae = ["innerHTML"], le = { key: 2 }, re = ["data-type"], ie = { class: "filex-viewer-ipynb__exec" }, se = { class: "filex-viewer-ipynb__src hljs" }, ue = ["innerHTML"], oe = { key: 1 }, ce = {
|
|
10
|
+
key: 0,
|
|
11
|
+
class: "filex-viewer-ipynb__outputs"
|
|
12
|
+
}, de = ["src", "alt"], _e = ["innerHTML"], pe = ["data-type"], fe = ["innerHTML"], ve = {
|
|
13
|
+
key: 1,
|
|
14
|
+
class: "filex-viewer-ipynb__md-raw"
|
|
15
|
+
}, ye = {
|
|
16
|
+
key: 2,
|
|
17
|
+
class: "filex-viewer-ipynb__src"
|
|
18
|
+
}, me = /* @__PURE__ */ U({
|
|
19
|
+
__name: "IpynbViewer",
|
|
20
|
+
props: {
|
|
21
|
+
url: {},
|
|
22
|
+
ext: {},
|
|
23
|
+
t: { type: Function },
|
|
24
|
+
authHeaders: { type: Function },
|
|
25
|
+
authCredentials: {}
|
|
26
|
+
},
|
|
27
|
+
setup(V) {
|
|
28
|
+
const i = V, o = p([]), M = p("python"), f = p(null), v = p(!0), w = p(/* @__PURE__ */ new Map()), k = p(/* @__PURE__ */ new Map());
|
|
29
|
+
let y = 0, x = null, h = null;
|
|
30
|
+
async function $() {
|
|
31
|
+
if (h !== null) return h || null;
|
|
32
|
+
try {
|
|
33
|
+
const e = await import(
|
|
34
|
+
/* @vite-ignore */
|
|
35
|
+
"markdown-it"
|
|
36
|
+
), l = e.default ?? e;
|
|
37
|
+
return h = new l({ html: !1, linkify: !0, breaks: !0 }), h;
|
|
38
|
+
} catch {
|
|
39
|
+
return h = !1, null;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
function u(e) {
|
|
43
|
+
return Array.isArray(e) ? e.join("") : e ?? "";
|
|
44
|
+
}
|
|
45
|
+
async function T() {
|
|
46
|
+
var s, g, S, j;
|
|
47
|
+
v.value = !0, f.value = null, o.value = [], w.value = /* @__PURE__ */ new Map(), k.value = /* @__PURE__ */ new Map();
|
|
48
|
+
const e = ++y;
|
|
49
|
+
let l;
|
|
50
|
+
try {
|
|
51
|
+
l = await Q({
|
|
52
|
+
url: i.url,
|
|
53
|
+
headers: await ((s = i.authHeaders) == null ? void 0 : s.call(i)) ?? {},
|
|
54
|
+
credentials: i.authCredentials
|
|
55
|
+
});
|
|
56
|
+
} catch (r) {
|
|
57
|
+
f.value = W(r, C("viewer.failed_to_load", "Failed to load file"), { t: i.t }).text, v.value = !1;
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
if (e !== y) return;
|
|
61
|
+
let t;
|
|
62
|
+
try {
|
|
63
|
+
t = JSON.parse(l);
|
|
64
|
+
} catch {
|
|
65
|
+
f.value = "Invalid notebook JSON", v.value = !1;
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
if (o.value = Array.isArray(t.cells) ? t.cells : [], M.value = ((S = (g = t.metadata) == null ? void 0 : g.kernelspec) == null ? void 0 : S.language) || "python", x = await X(), e !== y) return;
|
|
69
|
+
if (x) {
|
|
70
|
+
const r = x.default ?? x, b = (j = r.getLanguage) != null && j.call(r, M.value) ? M.value : null;
|
|
71
|
+
o.value.forEach((A, J) => {
|
|
72
|
+
if (A.cell_type === "code") {
|
|
73
|
+
const F = u(A.source);
|
|
74
|
+
try {
|
|
75
|
+
const R = b ? r.highlight(F, { language: b, ignoreIllegals: !0 }) : r.highlightAuto(F);
|
|
76
|
+
w.value.set(J, R.value);
|
|
77
|
+
} catch {
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
const c = await $();
|
|
83
|
+
e === y && (c && o.value.forEach((r, b) => {
|
|
84
|
+
if (r.cell_type === "markdown")
|
|
85
|
+
try {
|
|
86
|
+
k.value.set(b, c.render(u(r.source)));
|
|
87
|
+
} catch {
|
|
88
|
+
}
|
|
89
|
+
}), v.value = !1);
|
|
90
|
+
}
|
|
91
|
+
function H(e) {
|
|
92
|
+
var l;
|
|
93
|
+
return e ? e.output_type === "stream" ? u(e.text) : e.output_type === "error" ? [e.ename, e.evalue, ...e.traceback || []].filter(Boolean).join(`
|
|
94
|
+
`) : (e.output_type === "execute_result" || e.output_type === "display_data") && (l = e.data) != null && l["text/plain"] ? u(e.data["text/plain"]) : null : null;
|
|
95
|
+
}
|
|
96
|
+
function L(e) {
|
|
97
|
+
if (!(e != null && e.data)) return null;
|
|
98
|
+
if (e.data["image/png"]) return `data:image/png;base64,${e.data["image/png"]}`;
|
|
99
|
+
if (e.data["image/jpeg"]) return `data:image/jpeg;base64,${e.data["image/jpeg"]}`;
|
|
100
|
+
if (e.data["image/svg+xml"]) {
|
|
101
|
+
const l = u(e.data["image/svg+xml"]);
|
|
102
|
+
return `data:image/svg+xml;utf8,${encodeURIComponent(l)}`;
|
|
103
|
+
}
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
function I(e) {
|
|
107
|
+
return e != null && e.data && e.data["text/html"] ? u(e.data["text/html"]).replace(/<script[\s\S]*?<\/script>/gi, "") : null;
|
|
108
|
+
}
|
|
109
|
+
D(T), q(() => {
|
|
110
|
+
y++;
|
|
111
|
+
}), z(() => i.url, T), B(() => {
|
|
112
|
+
const e = o.value.filter((t) => t.cell_type === "code").length, l = o.value.filter((t) => t.cell_type === "markdown").length;
|
|
113
|
+
return { code: e, md: l, total: o.value.length };
|
|
114
|
+
});
|
|
115
|
+
function C(e, l) {
|
|
116
|
+
return i.t ? i.t(e) : l;
|
|
117
|
+
}
|
|
118
|
+
const O = B(() => K({ type: "file", extension: i.ext }));
|
|
119
|
+
return (e, l) => (n(), a("div", Y, [
|
|
120
|
+
d("div", Z, [
|
|
121
|
+
f.value ? (n(), a("div", ee, [
|
|
122
|
+
d("span", {
|
|
123
|
+
class: "filex-viewer-fallback__icon",
|
|
124
|
+
"aria-hidden": "true",
|
|
125
|
+
innerHTML: O.value
|
|
126
|
+
}, null, 8, te),
|
|
127
|
+
d("p", null, _(f.value), 1)
|
|
128
|
+
])) : v.value ? (n(), a("div", ne, [
|
|
129
|
+
d("span", {
|
|
130
|
+
class: "filex-viewer-fallback__icon filex-viewer-fallback__icon--spin",
|
|
131
|
+
"aria-hidden": "true",
|
|
132
|
+
innerHTML: G(P)("progress")
|
|
133
|
+
}, null, 8, ae),
|
|
134
|
+
d("p", null, _(C("viewer.loading", "Loading…")), 1)
|
|
135
|
+
])) : (n(), a("div", le, [
|
|
136
|
+
(n(!0), a(m, null, E(o.value, (t, c) => (n(), a("div", {
|
|
137
|
+
key: c,
|
|
138
|
+
class: "filex-viewer-ipynb__cell",
|
|
139
|
+
"data-type": t.cell_type
|
|
140
|
+
}, [
|
|
141
|
+
t.cell_type === "code" ? (n(), a(m, { key: 0 }, [
|
|
142
|
+
d("div", ie, " In [" + _(t.execution_count ?? " ") + "]: ", 1),
|
|
143
|
+
d("pre", se, [
|
|
144
|
+
w.value.get(c) ? (n(), a("code", {
|
|
145
|
+
key: 0,
|
|
146
|
+
innerHTML: w.value.get(c)
|
|
147
|
+
}, null, 8, ue)) : (n(), a("code", oe, _(u(t.source)), 1))
|
|
148
|
+
]),
|
|
149
|
+
t.outputs && t.outputs.length ? (n(), a("div", ce, [
|
|
150
|
+
(n(!0), a(m, null, E(t.outputs, (s, g) => (n(), a(m, { key: g }, [
|
|
151
|
+
L(s) ? (n(), a("img", {
|
|
152
|
+
key: 0,
|
|
153
|
+
src: L(s) || "",
|
|
154
|
+
class: "filex-viewer-ipynb__img",
|
|
155
|
+
alt: `output ${g}`
|
|
156
|
+
}, null, 8, de)) : I(s) ? (n(), a("div", {
|
|
157
|
+
key: 1,
|
|
158
|
+
class: "filex-viewer-ipynb__html",
|
|
159
|
+
innerHTML: I(s)
|
|
160
|
+
}, null, 8, _e)) : H(s) ? (n(), a("pre", {
|
|
161
|
+
key: 2,
|
|
162
|
+
class: "filex-viewer-ipynb__out",
|
|
163
|
+
"data-type": s.output_type
|
|
164
|
+
}, _(H(s)), 9, pe)) : N("", !0)
|
|
165
|
+
], 64))), 128))
|
|
166
|
+
])) : N("", !0)
|
|
167
|
+
], 64)) : t.cell_type === "markdown" ? (n(), a(m, { key: 1 }, [
|
|
168
|
+
k.value.get(c) ? (n(), a("div", {
|
|
169
|
+
key: 0,
|
|
170
|
+
class: "filex-viewer-ipynb__md",
|
|
171
|
+
dir: "auto",
|
|
172
|
+
innerHTML: k.value.get(c)
|
|
173
|
+
}, null, 8, fe)) : (n(), a("pre", ve, _(u(t.source)), 1))
|
|
174
|
+
], 64)) : (n(), a("pre", ye, _(u(t.source)), 1))
|
|
175
|
+
], 8, re))), 128))
|
|
176
|
+
]))
|
|
177
|
+
])
|
|
178
|
+
]));
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
export {
|
|
182
|
+
me as default
|
|
183
|
+
};
|
|
184
|
+
//# sourceMappingURL=IpynbViewer-Bz0eJ4NS.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"IpynbViewer-Bz0eJ4NS.js","sources":["../src/viewers/IpynbViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { sayFailure } from '../lib/errorWords';\n/**\n * IpynbViewer — Jupyter notebook (.ipynb JSON) renderer.\n *\n * Pure-JS render — no peer dependency required:\n * - code cells → `<pre><code>` (highlight.js when available)\n * - markdown cells → markdown-it when available, plain `<pre>` otherwise\n * - output cells → text (stream / display_data 'text/plain'),\n * images (display_data 'image/png' base64),\n * HTML (display_data 'text/html', sanitized via\n * element-only insertion — no script tags)\n *\n * Source list / output count counters at the top so a 200-cell\n * notebook doesn't surprise the user.\n */\nimport { computed, onBeforeUnmount, onMounted, ref, watch } from 'vue';\nimport { actionIconSvg } from '../lib/actionIcons'; /* ikon:emoji */\nimport { fileIconTile } from '../lib/fileIcons'; /* ikon:emoji */\nimport { fetchViewerText } from '../composables/useViewerFetch';\nimport { ensureHighlight } from '../composables/useMonacoLoader';\n\nconst props = defineProps<{\n url: string;\n ext: string;\n t?: (key: string) => string;\n authHeaders?: () => Record<string, string> | Promise<Record<string, string>>;\n authCredentials?: RequestCredentials;\n}>();\n\ninterface Cell {\n cell_type: 'code' | 'markdown' | 'raw' | string;\n source: string | string[];\n outputs?: any[];\n execution_count?: number | null;\n metadata?: Record<string, unknown>;\n}\n\ninterface Notebook {\n cells: Cell[];\n metadata?: { kernelspec?: { language?: string; name?: string } };\n}\n\nconst cells = ref<Cell[]>([]);\nconst language = ref<string>('python');\nconst error = ref<string | null>(null);\nconst loading = ref(true);\nconst renderedSources = ref<Map<number, string>>(new Map());\nconst renderedMarkdown = ref<Map<number, string>>(new Map());\n\nlet renderToken = 0;\nlet highlight: any = null;\nlet mdRenderer: any = null;\n\nasync function ensureMd(): Promise<any | null> {\n if (mdRenderer !== null) return mdRenderer || null;\n try {\n const mod = await import(/* @vite-ignore */ 'markdown-it');\n const Md = (mod as any).default ?? mod;\n mdRenderer = new Md({ html: false, linkify: true, breaks: true });\n return mdRenderer;\n } catch {\n mdRenderer = false;\n return null;\n }\n}\n\nfunction joinSource(source: string | string[]): string {\n return Array.isArray(source) ? source.join('') : (source ?? '');\n}\n\nasync function load(): Promise<void> {\n loading.value = true;\n error.value = null;\n cells.value = [];\n renderedSources.value = new Map();\n renderedMarkdown.value = new Map();\n const myToken = ++renderToken;\n\n let raw: string;\n try {\n raw = await fetchViewerText({\n url: props.url,\n headers: (await props.authHeaders?.()) ?? {},\n credentials: props.authCredentials,\n });\n } catch (err) {\n error.value = sayFailure(err, tt('viewer.failed_to_load', 'Failed to load file'), { t: props.t }).text;\n loading.value = false;\n return;\n }\n\n if (myToken !== renderToken) return;\n\n let nb: Notebook;\n try {\n nb = JSON.parse(raw);\n } catch (err) {\n error.value = 'Invalid notebook JSON';\n loading.value = false;\n return;\n }\n cells.value = Array.isArray(nb.cells) ? nb.cells : [];\n language.value = nb.metadata?.kernelspec?.language || 'python';\n\n // Best-effort hljs highlight per code cell.\n highlight = (await ensureHighlight()) as any;\n if (myToken !== renderToken) return;\n if (highlight) {\n const hljs = highlight.default ?? highlight;\n const langOk = hljs.getLanguage?.(language.value) ? language.value : null;\n cells.value.forEach((cell, idx) => {\n if (cell.cell_type === 'code') {\n const text = joinSource(cell.source);\n try {\n const result = langOk\n ? hljs.highlight(text, { language: langOk, ignoreIllegals: true })\n : hljs.highlightAuto(text);\n renderedSources.value.set(idx, result.value);\n } catch {\n /* leave unrendered */\n }\n }\n });\n }\n\n const md = await ensureMd();\n if (myToken !== renderToken) return;\n if (md) {\n cells.value.forEach((cell, idx) => {\n if (cell.cell_type === 'markdown') {\n try {\n renderedMarkdown.value.set(idx, md.render(joinSource(cell.source)));\n } catch {\n /* leave plain */\n }\n }\n });\n }\n\n loading.value = false;\n}\n\nfunction outputText(out: any): string | null {\n if (!out) return null;\n if (out.output_type === 'stream') {\n return joinSource(out.text);\n }\n if (out.output_type === 'error') {\n return [out.ename, out.evalue, ...(out.traceback || [])]\n .filter(Boolean)\n .join('\\n');\n }\n if (out.output_type === 'execute_result' || out.output_type === 'display_data') {\n if (out.data?.['text/plain']) {\n return joinSource(out.data['text/plain']);\n }\n }\n return null;\n}\n\nfunction outputImage(out: any): string | null {\n if (!out?.data) return null;\n if (out.data['image/png']) return `data:image/png;base64,${out.data['image/png']}`;\n if (out.data['image/jpeg']) return `data:image/jpeg;base64,${out.data['image/jpeg']}`;\n if (out.data['image/svg+xml']) {\n const svg = joinSource(out.data['image/svg+xml']);\n return `data:image/svg+xml;utf8,${encodeURIComponent(svg)}`;\n }\n return null;\n}\n\nfunction outputHtml(out: any): string | null {\n if (!out?.data) return null;\n if (out.data['text/html']) {\n const html = joinSource(out.data['text/html']);\n // Strip <script> for safety — outputs from arbitrary notebooks.\n return html.replace(/<script[\\s\\S]*?<\\/script>/gi, '');\n }\n return null;\n}\n\nonMounted(load);\nonBeforeUnmount(() => {\n renderToken++;\n});\nwatch(() => props.url, load);\n\nconst stats = computed(() => {\n const codeCount = cells.value.filter((c) => c.cell_type === 'code').length;\n const mdCount = cells.value.filter((c) => c.cell_type === 'markdown').length;\n return { code: codeCount, md: mdCount, total: cells.value.length };\n});\n\nfunction tt(key: string, fallback: string): string {\n return props.t ? props.t(key) : fallback;\n}\n\n/* === ikon:emoji — the fallback screen's mark ==========================\n * Every viewer opened its \"cannot show this\" / \"still loading\" screen with a\n * 48px colour emoji, one per format, each from whatever emoji font the OS\n * shipped. The format mark is `lib/fileIcons`'s tile — the SAME tile the row\n * the person just clicked is wearing, so the fallback is recognisably about\n * that file — and \"loading\" is the stroked ring, spun by CSS, because no\n * still picture can say \"still going\". */\nconst typeTile = computed(() => fileIconTile({ type: 'file', extension: props.ext }));\n</script>\n\n<template>\n <div class=\"filex-viewer-ipynb\">\n <div class=\"filex-viewer-ipynb__pane\">\n <div v-if=\"error\" class=\"filex-viewer-fallback\">\n <!-- eslint-disable-next-line vue/no-v-html -- static markup from lib/fileIcons + lib/actionIcons -->\n <span class=\"filex-viewer-fallback__icon\" aria-hidden=\"true\" v-html=\"typeTile\"></span>\n <p>{{ error }}</p>\n </div>\n <div v-else-if=\"loading\" class=\"filex-viewer-fallback\">\n <!-- eslint-disable-next-line vue/no-v-html -- static markup from lib/fileIcons + lib/actionIcons -->\n <span\n class=\"filex-viewer-fallback__icon filex-viewer-fallback__icon--spin\"\n aria-hidden=\"true\"\n v-html=\"actionIconSvg('progress')\"\n ></span>\n <p>{{ tt('viewer.loading', 'Loading…') }}</p>\n </div>\n <div v-else>\n <div\n v-for=\"(cell, idx) in cells\"\n :key=\"idx\"\n class=\"filex-viewer-ipynb__cell\"\n :data-type=\"cell.cell_type\"\n >\n <template v-if=\"cell.cell_type === 'code'\">\n <div class=\"filex-viewer-ipynb__exec\">\n In [{{ cell.execution_count ?? ' ' }}]:\n </div>\n <pre class=\"filex-viewer-ipynb__src hljs\"><code\n v-if=\"renderedSources.get(idx)\"\n v-html=\"renderedSources.get(idx)\"\n /><code v-else>{{ joinSource(cell.source) }}</code></pre>\n <div v-if=\"cell.outputs && cell.outputs.length\" class=\"filex-viewer-ipynb__outputs\">\n <template v-for=\"(out, j) in cell.outputs\" :key=\"j\">\n <img\n v-if=\"outputImage(out)\"\n :src=\"outputImage(out) || ''\"\n class=\"filex-viewer-ipynb__img\"\n :alt=\"`output ${j}`\"\n />\n <div\n v-else-if=\"outputHtml(out)\"\n class=\"filex-viewer-ipynb__html\"\n v-html=\"outputHtml(out)\"\n />\n <pre\n v-else-if=\"outputText(out)\"\n class=\"filex-viewer-ipynb__out\"\n :data-type=\"out.output_type\"\n >{{ outputText(out) }}</pre>\n </template>\n </div>\n </template>\n\n <template v-else-if=\"cell.cell_type === 'markdown'\">\n <div\n v-if=\"renderedMarkdown.get(idx)\"\n class=\"filex-viewer-ipynb__md\"\n dir=\"auto\"\n v-html=\"renderedMarkdown.get(idx)\"\n />\n <pre v-else class=\"filex-viewer-ipynb__md-raw\">{{ joinSource(cell.source) }}</pre>\n </template>\n\n <template v-else>\n <pre class=\"filex-viewer-ipynb__src\">{{ joinSource(cell.source) }}</pre>\n </template>\n </div>\n </div>\n </div>\n </div>\n</template>\n\n<style>\n/* ⚠ NOT `scoped`, deliberately. Vue's scoped styles compile to\n `.cls[data-v-HASH]`, and in the web-component build the hash baked into\n this CSS does not match the one Vue stamps onto the DOM — so every rule\n here silently stopped applying. Measured in the desktop app: the share\n dialog had `position: static`, no background and no radius, i.e. raw\n unstyled HTML, in EVERY embedded surface.\n Safe to drop: every selector below is prefixed (fx-/fe-/filex-), so\n there is nothing here that can leak into a host page. */\n.filex-viewer-ipynb {\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n min-height: 70vh;\n background: var(--fe-bg, #fff);\n color: var(--fe-text, #1a1e27);\n}\n.filex-viewer-ipynb__bar {\n display: flex;\n align-items: center;\n gap: 12px;\n padding: 8px 12px;\n background: var(--fe-bg-elev, #f7f8fa);\n border-bottom: 1px solid var(--fe-border, #e2e6ed);\n font-size: 12px;\n color: var(--fe-text-muted, #5a6475);\n}\n.filex-viewer-ipynb__lang {\n font-family: var(--fe-font-mono, monospace);\n text-transform: uppercase;\n letter-spacing: 0.04em;\n}\n.filex-viewer-ipynb__pane {\n flex: 1;\n overflow: auto;\n padding: 16px 24px;\n}\n.filex-viewer-ipynb__cell {\n border: 1px solid var(--fe-border, #e2e6ed);\n border-radius: 6px;\n margin-bottom: 16px;\n overflow: hidden;\n}\n.filex-viewer-ipynb__cell[data-type=\"code\"] {\n background: var(--fe-bg-elev, #f7f8fa);\n}\n.filex-viewer-ipynb__exec {\n padding: 4px 12px;\n font-family: var(--fe-font-mono, monospace);\n font-size: 11px;\n color: var(--fe-text-muted, #5a6475);\n background: rgba(0, 0, 0, 0.04);\n}\n.filex-viewer-ipynb__src {\n margin: 0;\n padding: 12px;\n font-family: var(--fe-font-mono, monospace);\n font-size: 12px;\n line-height: 1.5;\n white-space: pre;\n overflow-x: auto;\n}\n.filex-viewer-ipynb__outputs {\n border-top: 1px dashed var(--fe-border, #e2e6ed);\n background: var(--fe-bg, #fff);\n padding: 8px 12px;\n}\n.filex-viewer-ipynb__out {\n margin: 0;\n padding: 4px 0;\n font-family: var(--fe-font-mono, monospace);\n font-size: 12px;\n white-space: pre-wrap;\n word-wrap: break-word;\n}\n.filex-viewer-ipynb__out[data-type=\"error\"] {\n color: var(--fe-danger, #dc2626);\n}\n.filex-viewer-ipynb__img {\n display: block;\n max-width: 100%;\n height: auto;\n margin: 8px 0;\n}\n.filex-viewer-ipynb__html {\n font-size: 13px;\n}\n.filex-viewer-ipynb__md {\n padding: 12px 16px;\n font-size: 14px;\n line-height: 1.6;\n}\n.filex-viewer-ipynb__md-raw {\n padding: 12px;\n margin: 0;\n font-family: var(--fe-font-mono, monospace);\n font-size: 12px;\n white-space: pre-wrap;\n}\n.filex-viewer-fallback {\n text-align: center;\n padding: 32px;\n color: var(--fe-text-muted, #5a6475);\n}\n.filex-viewer-fallback__icon {\n font-size: 48px;\n display: block;\n margin-bottom: 12px;\n}\n</style>\n"],"names":["props","__props","cells","ref","language","error","loading","renderedSources","renderedMarkdown","renderToken","highlight","mdRenderer","ensureMd","mod","Md","joinSource","source","load","myToken","raw","fetchViewerText","_a","err","sayFailure","tt","nb","_c","_b","ensureHighlight","hljs","langOk","_d","cell","idx","text","result","md","outputText","out","outputImage","svg","outputHtml","onMounted","onBeforeUnmount","watch","computed","codeCount","c","mdCount","key","fallback","typeTile","fileIconTile","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_hoisted_5","_unref","actionIconSvg","_hoisted_7","_Fragment","_renderList","_hoisted_9","_hoisted_10","_hoisted_12","_toDisplayString","_hoisted_13","j","_hoisted_16","_hoisted_18","_hoisted_19"],"mappings":"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"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { defineComponent as V, ref as s, onMounted as $, onBeforeUnmount as B, computed as E, openBlock as w, createElementBlock as x, createElementVNode as u, toDisplayString as M, unref as I, createCommentVNode as Y, withDirectives as z, normalizeStyle as K, vShow as N } from "vue";
|
|
2
|
+
import { f as U, a as W, b as X, s as T } from "./index-DuWnGuv5.js";
|
|
3
|
+
const q = { class: "filex-viewer-mermaid" }, O = {
|
|
4
|
+
key: 0,
|
|
5
|
+
class: "filex-viewer-fallback"
|
|
6
|
+
}, j = ["innerHTML"], A = {
|
|
7
|
+
key: 1,
|
|
8
|
+
class: "filex-viewer-fallback"
|
|
9
|
+
}, G = ["innerHTML"], R = /* @__PURE__ */ V({
|
|
10
|
+
__name: "MermaidViewer",
|
|
11
|
+
props: {
|
|
12
|
+
url: {},
|
|
13
|
+
mime: {},
|
|
14
|
+
ext: {},
|
|
15
|
+
t: { type: Function },
|
|
16
|
+
authHeaders: { type: Function },
|
|
17
|
+
authCredentials: {}
|
|
18
|
+
},
|
|
19
|
+
setup(L) {
|
|
20
|
+
const n = L, f = s(null), l = s(null), o = s(!0), m = s(1), _ = s(0), h = s(0);
|
|
21
|
+
let p = !1, i = null, c = 0, r = null;
|
|
22
|
+
async function P() {
|
|
23
|
+
var e, t;
|
|
24
|
+
if (r) return r;
|
|
25
|
+
try {
|
|
26
|
+
const a = await import(
|
|
27
|
+
/* @vite-ignore */
|
|
28
|
+
"mermaid"
|
|
29
|
+
);
|
|
30
|
+
return r = a.default ?? a, (t = r.initialize) == null || t.call(r, {
|
|
31
|
+
startOnLoad: !1,
|
|
32
|
+
securityLevel: "strict",
|
|
33
|
+
theme: (e = window.matchMedia) != null && e.call(window, "(prefers-color-scheme: dark)").matches ? "dark" : "default"
|
|
34
|
+
}), r;
|
|
35
|
+
} catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
async function b() {
|
|
40
|
+
var k;
|
|
41
|
+
o.value = !0, l.value = null;
|
|
42
|
+
const e = ++c, t = await P();
|
|
43
|
+
if (e !== c) return;
|
|
44
|
+
if (!t) {
|
|
45
|
+
l.value = v("viewer.peer_not_installed", "This kind of file cannot be shown here. Download it to open it on your device."), o.value = !1;
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
let a;
|
|
49
|
+
try {
|
|
50
|
+
a = await X({
|
|
51
|
+
url: n.url,
|
|
52
|
+
headers: await ((k = n.authHeaders) == null ? void 0 : k.call(n)) ?? {},
|
|
53
|
+
credentials: n.authCredentials
|
|
54
|
+
});
|
|
55
|
+
} catch (d) {
|
|
56
|
+
l.value = T(d, v("viewer.failed_to_load", "Failed to load file"), { t: n.t }).text, o.value = !1;
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (e === c)
|
|
60
|
+
try {
|
|
61
|
+
const d = `filex-mermaid-${Date.now()}`, { svg: F } = await t.render(d, a);
|
|
62
|
+
if (e !== c) return;
|
|
63
|
+
if (f.value) {
|
|
64
|
+
f.value.innerHTML = F;
|
|
65
|
+
const y = f.value.querySelector("svg");
|
|
66
|
+
y && (y.style.maxWidth = "100%", y.style.height = "auto");
|
|
67
|
+
}
|
|
68
|
+
} catch (d) {
|
|
69
|
+
l.value = T(d, v("viewer.failed_to_load", "Failed to load file"), { t: n.t }).text;
|
|
70
|
+
} finally {
|
|
71
|
+
o.value = !1;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
function H(e) {
|
|
75
|
+
if (!e.ctrlKey && !e.metaKey) return;
|
|
76
|
+
e.preventDefault();
|
|
77
|
+
const a = -e.deltaY > 0 ? 1.1 : 1 / 1.1;
|
|
78
|
+
m.value = Math.max(0.2, Math.min(8, m.value * a));
|
|
79
|
+
}
|
|
80
|
+
function D(e) {
|
|
81
|
+
var t, a;
|
|
82
|
+
p = !0, i = { x: e.clientX, y: e.clientY, tx: _.value, ty: h.value }, (a = (t = e.target).setPointerCapture) == null || a.call(t, e.pointerId);
|
|
83
|
+
}
|
|
84
|
+
function S(e) {
|
|
85
|
+
!p || !i || (_.value = i.tx + (e.clientX - i.x), h.value = i.ty + (e.clientY - i.y));
|
|
86
|
+
}
|
|
87
|
+
function g() {
|
|
88
|
+
p = !1, i = null;
|
|
89
|
+
}
|
|
90
|
+
$(b), B(() => {
|
|
91
|
+
c++;
|
|
92
|
+
});
|
|
93
|
+
function v(e, t) {
|
|
94
|
+
return n.t ? n.t(e) : t;
|
|
95
|
+
}
|
|
96
|
+
const C = E(() => U({ type: "file", extension: n.ext }));
|
|
97
|
+
return (e, t) => (w(), x("div", q, [
|
|
98
|
+
u("div", {
|
|
99
|
+
class: "filex-viewer-mermaid__pane",
|
|
100
|
+
onWheel: H,
|
|
101
|
+
onPointerdown: D,
|
|
102
|
+
onPointermove: S,
|
|
103
|
+
onPointerup: g,
|
|
104
|
+
onPointercancel: g
|
|
105
|
+
}, [
|
|
106
|
+
l.value ? (w(), x("div", O, [
|
|
107
|
+
u("span", {
|
|
108
|
+
class: "filex-viewer-fallback__icon",
|
|
109
|
+
"aria-hidden": "true",
|
|
110
|
+
innerHTML: C.value
|
|
111
|
+
}, null, 8, j),
|
|
112
|
+
u("p", null, M(l.value), 1)
|
|
113
|
+
])) : o.value ? (w(), x("div", A, [
|
|
114
|
+
u("span", {
|
|
115
|
+
class: "filex-viewer-fallback__icon filex-viewer-fallback__icon--spin",
|
|
116
|
+
"aria-hidden": "true",
|
|
117
|
+
innerHTML: I(W)("progress")
|
|
118
|
+
}, null, 8, G),
|
|
119
|
+
u("p", null, M(v("viewer.loading", "Loading…")), 1)
|
|
120
|
+
])) : Y("", !0),
|
|
121
|
+
z(u("div", {
|
|
122
|
+
ref_key: "surface",
|
|
123
|
+
ref: f,
|
|
124
|
+
class: "filex-viewer-mermaid__surface",
|
|
125
|
+
style: K({ transform: `translate(${_.value}px, ${h.value}px) scale(${m.value})` })
|
|
126
|
+
}, null, 4), [
|
|
127
|
+
[N, !o.value && !l.value]
|
|
128
|
+
])
|
|
129
|
+
], 32)
|
|
130
|
+
]));
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
export {
|
|
134
|
+
R as default
|
|
135
|
+
};
|
|
136
|
+
//# sourceMappingURL=MermaidViewer-CEDTD_pp.js.map
|