@brftech/filex-core 0.42.2 → 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-CC6rJXeP.js → DrawioViewer-Bgrj8-zG.js} +45 -44
- package/dist/DrawioViewer-Bgrj8-zG.js.map +1 -0
- package/dist/{EpubViewer-CAoTSXTO.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-CdZeK4j4.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 +5227 -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 +1055 -253
- 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 +31 -15
- package/src/components/RecoveryKeyModal.vue +1 -1
- package/src/components/RowActions.vue +134 -0
- package/src/components/S3KeysPanel.vue +98 -62
- package/src/components/SSHKeysPanel.vue +79 -30
- 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 -31
- 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 +18 -3
- 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 +515 -117
- package/src/locales/resolve.ts +17 -8
- package/src/locales/tr.ts +536 -152
- 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 +2890 -260
- 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 +50 -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-BUQWLhwX.js +0 -124
- package/dist/ArchiveViewer-BUQWLhwX.js.map +0 -1
- package/dist/CsvViewer-Bg2_aqzc.js +0 -141
- package/dist/CsvViewer-Bg2_aqzc.js.map +0 -1
- package/dist/DrawioViewer-CC6rJXeP.js.map +0 -1
- package/dist/EpubViewer-CAoTSXTO.js.map +0 -1
- package/dist/IpynbViewer-D0GwGpnE.js +0 -184
- package/dist/IpynbViewer-D0GwGpnE.js.map +0 -1
- package/dist/MermaidViewer-DGwAvRZg.js +0 -137
- package/dist/MermaidViewer-DGwAvRZg.js.map +0 -1
- package/dist/PsdViewer-DhGweA0m.js +0 -122
- package/dist/PsdViewer-DhGweA0m.js.map +0 -1
- package/dist/TiffViewer-D0AurvAh.js +0 -142
- package/dist/TiffViewer-D0AurvAh.js.map +0 -1
- package/dist/Viewer3D-CdZeK4j4.js.map +0 -1
- package/dist/index-BArI-B1M.js +0 -26911
- package/dist/index-BArI-B1M.js.map +0 -1
- package/dist/useViewerFetch-czqbd2Lj.js +0 -25
- package/dist/useViewerFetch-czqbd2Lj.js.map +0 -1
- package/src/composables/useScrolledX.ts +0 -21
package/README.md
CHANGED
|
@@ -115,8 +115,10 @@ means draw a moving indicator, not 0%.
|
|
|
115
115
|
|
|
116
116
|
The explorer ships a left navigation panel — the primary **+ New** menu
|
|
117
117
|
(upload files · new folder · new document · request files), the destinations
|
|
118
|
-
**Home · Shared with me · Recent · Starred · Trash** (plus **My
|
|
119
|
-
the caller reaches at most one storage),
|
|
118
|
+
**Home · Shared with me · My shares · Recent · Starred · Trash** (plus **My
|
|
119
|
+
files** when the caller reaches at most one storage), your tags in two groups
|
|
120
|
+
(**Personal** and **Team**), an **Apps** section with one row per installed
|
|
121
|
+
app's own page, and the storages the
|
|
120
122
|
caller can see (a storage reached through a grant is marked *Shared*). It is on
|
|
121
123
|
by default on every surface; the viewer collapses it to an icon rail from the
|
|
122
124
|
control at the far left of the **top bar** — above the panel rather than inside
|
|
@@ -130,9 +132,19 @@ const config = {
|
|
|
130
132
|
auth: { kind: 'bearer', token },
|
|
131
133
|
sideNav: true, // default; `rootPath` flips it off
|
|
132
134
|
uiProfile: 'simple', // 'standard' (default) | 'simple'
|
|
135
|
+
mySharesVisible: true, // draw the "My shares" row — only if you handle @open-my-shares
|
|
136
|
+
appHomePage: true, // an app's home view opens as YOUR page — handle @open-app-home
|
|
133
137
|
};
|
|
134
138
|
```
|
|
135
139
|
|
|
140
|
+
⚠ `mySharesVisible` and `appHomePage` are **off by default**, and not because
|
|
141
|
+
the surfaces are optional: each needs the host to take an event and open a
|
|
142
|
+
page of its own — `@open-my-shares` for the links this person made, and
|
|
143
|
+
`@open-app-home` for an app's `home` view (`{base}app/{plugin}/{view}`, with
|
|
144
|
+
the open section in `?section=`). Only this Vue component emits them; the web
|
|
145
|
+
component and the React adapter do not forward them yet, so switching the keys
|
|
146
|
+
on there would draw a row that goes nowhere.
|
|
147
|
+
|
|
136
148
|
The panel's last section is how **How to connect** (the per-protocol guides,
|
|
137
149
|
built from your deployment) and **API keys** (mint and revoke the tokens
|
|
138
150
|
WebDAV, FTPS and `filex mount` sign in with) become reachable from inside the
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { defineComponent as z, ref as h, onMounted as H, watch as C, computed as d, openBlock as c, createElementBlock as u, createElementVNode as n, toDisplayString as l, unref as M, createVNode as S, withCtx as E } from "vue";
|
|
2
|
+
import { u as P, f as x, a as N, _ as V } from "./index-DuWnGuv5.js";
|
|
3
|
+
const j = { class: "filex-viewer-archive" }, A = {
|
|
4
|
+
key: 0,
|
|
5
|
+
class: "filex-viewer-fallback"
|
|
6
|
+
}, D = ["innerHTML"], I = {
|
|
7
|
+
key: 1,
|
|
8
|
+
class: "filex-viewer-fallback"
|
|
9
|
+
}, O = ["innerHTML"], B = {
|
|
10
|
+
key: 2,
|
|
11
|
+
class: "filex-viewer-fallback"
|
|
12
|
+
}, F = ["innerHTML"], U = {
|
|
13
|
+
key: 3,
|
|
14
|
+
class: "filex-viewer-archive__pane"
|
|
15
|
+
}, $ = { class: "filex-viewer-archive__summary" }, J = ["innerHTML"], q = { class: "fe-list__cell-text" }, Q = /* @__PURE__ */ z({
|
|
16
|
+
__name: "ArchiveViewer",
|
|
17
|
+
props: {
|
|
18
|
+
url: {},
|
|
19
|
+
filePath: {},
|
|
20
|
+
ext: {},
|
|
21
|
+
t: { type: Function },
|
|
22
|
+
locale: {},
|
|
23
|
+
authHeaders: { type: Function },
|
|
24
|
+
authCredentials: {},
|
|
25
|
+
archiveListUrl: {}
|
|
26
|
+
},
|
|
27
|
+
setup(y) {
|
|
28
|
+
const a = y, s = h([]), v = h(!0), o = h(null);
|
|
29
|
+
function r(e, t, i) {
|
|
30
|
+
return a.t ? a.t(e, i) : t;
|
|
31
|
+
}
|
|
32
|
+
const { formatSize: g } = P(() => a.locale ?? "en");
|
|
33
|
+
function f(e) {
|
|
34
|
+
return g(e);
|
|
35
|
+
}
|
|
36
|
+
async function _() {
|
|
37
|
+
if (v.value = !0, o.value = null, s.value = [], !a.filePath) {
|
|
38
|
+
o.value = r("viewer.archive.error", "Could not read archive contents."), v.value = !1;
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const e = await fetch(a.archiveListUrl || "/api/files/archive/list", {
|
|
43
|
+
method: "POST",
|
|
44
|
+
credentials: a.authCredentials || "same-origin",
|
|
45
|
+
headers: {
|
|
46
|
+
"Content-Type": "application/json",
|
|
47
|
+
...a.authHeaders ? await a.authHeaders() : {}
|
|
48
|
+
},
|
|
49
|
+
body: JSON.stringify({ path: a.filePath })
|
|
50
|
+
});
|
|
51
|
+
if (!e.ok)
|
|
52
|
+
throw new w(await k(e));
|
|
53
|
+
const t = await e.json();
|
|
54
|
+
s.value = t.entries ?? [];
|
|
55
|
+
} catch (e) {
|
|
56
|
+
o.value = e instanceof w ? e.message : r("viewer.archive.error", "Could not read archive contents.");
|
|
57
|
+
} finally {
|
|
58
|
+
v.value = !1;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
class w extends Error {
|
|
62
|
+
}
|
|
63
|
+
async function k(e) {
|
|
64
|
+
let t = "";
|
|
65
|
+
try {
|
|
66
|
+
const i = await e.json();
|
|
67
|
+
t = String((i == null ? void 0 : i.code) ?? (i == null ? void 0 : i.error) ?? "");
|
|
68
|
+
} catch {
|
|
69
|
+
}
|
|
70
|
+
return /not a zip|unsupported|not supported|format/i.test(t) ? r("viewer.archive.unsupported", "This kind of archive cannot be listed here. Download it to see what is inside.") : e.status === 413 || /too large|too big/i.test(t) ? r("viewer.archive.too_large", "This archive is too large to list here. Download it to see what is inside.") : r("viewer.archive.error", "Could not read archive contents.");
|
|
71
|
+
}
|
|
72
|
+
H(_), C(() => a.filePath, _);
|
|
73
|
+
const T = d(() => [
|
|
74
|
+
{
|
|
75
|
+
id: "name",
|
|
76
|
+
label: r("viewer.name", "Name"),
|
|
77
|
+
sortable: !0,
|
|
78
|
+
width: 360,
|
|
79
|
+
class: "filex-viewer-archive__name",
|
|
80
|
+
title: (e) => e.name
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: "size",
|
|
84
|
+
label: r("viewer.size", "Size"),
|
|
85
|
+
sortable: !0,
|
|
86
|
+
width: 110,
|
|
87
|
+
align: "right",
|
|
88
|
+
class: "filex-viewer-archive__size",
|
|
89
|
+
format: (e) => e.is_dir ? "" : f(e.size),
|
|
90
|
+
sortValue: (e) => e.is_dir ? -1 : e.size
|
|
91
|
+
}
|
|
92
|
+
]), b = d(() => s.value.reduce((e, t) => e + (t.size || 0), 0)), p = d(() => s.value.filter((e) => !e.is_dir).length), m = d(() => x({ type: "file", extension: a.ext }));
|
|
93
|
+
function L(e) {
|
|
94
|
+
const t = e.name || "", i = t.lastIndexOf(".");
|
|
95
|
+
return x({
|
|
96
|
+
type: e.is_dir ? "dir" : "file",
|
|
97
|
+
extension: i > 0 ? t.slice(i + 1) : "",
|
|
98
|
+
basename: t
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return (e, t) => (c(), u("div", j, [
|
|
102
|
+
o.value ? (c(), u("div", A, [
|
|
103
|
+
n("span", {
|
|
104
|
+
class: "filex-viewer-fallback__icon",
|
|
105
|
+
"aria-hidden": "true",
|
|
106
|
+
innerHTML: m.value
|
|
107
|
+
}, null, 8, D),
|
|
108
|
+
n("p", null, l(o.value), 1)
|
|
109
|
+
])) : v.value ? (c(), u("div", I, [
|
|
110
|
+
n("span", {
|
|
111
|
+
class: "filex-viewer-fallback__icon filex-viewer-fallback__icon--spin",
|
|
112
|
+
"aria-hidden": "true",
|
|
113
|
+
innerHTML: M(N)("progress")
|
|
114
|
+
}, null, 8, O),
|
|
115
|
+
n("p", null, l(r("viewer.loading", "Loading…")), 1)
|
|
116
|
+
])) : s.value.length === 0 ? (c(), u("div", B, [
|
|
117
|
+
n("span", {
|
|
118
|
+
class: "filex-viewer-fallback__icon",
|
|
119
|
+
"aria-hidden": "true",
|
|
120
|
+
innerHTML: m.value
|
|
121
|
+
}, null, 8, F),
|
|
122
|
+
n("p", null, l(r("viewer.archive.empty", "Archive is empty.")), 1)
|
|
123
|
+
])) : (c(), u("div", U, [
|
|
124
|
+
n("div", $, l(r("viewer.archive.entries", `${p.value} files`, { n: p.value })) + " · " + l(f(b.value)), 1),
|
|
125
|
+
S(V, {
|
|
126
|
+
"table-id": "viewer.archive",
|
|
127
|
+
columns: T.value,
|
|
128
|
+
rows: s.value,
|
|
129
|
+
"row-key": (i) => i.name,
|
|
130
|
+
"row-attrs": (i) => ({ "data-dir": i.is_dir ? "1" : "0" })
|
|
131
|
+
}, {
|
|
132
|
+
"cell-name": E(({ row: i }) => [
|
|
133
|
+
n("span", {
|
|
134
|
+
class: "filex-viewer-archive__icon",
|
|
135
|
+
"aria-hidden": "true",
|
|
136
|
+
innerHTML: L(i)
|
|
137
|
+
}, null, 8, J),
|
|
138
|
+
n("span", q, l(i.name), 1)
|
|
139
|
+
]),
|
|
140
|
+
_: 1
|
|
141
|
+
}, 8, ["columns", "rows", "row-key", "row-attrs"])
|
|
142
|
+
]))
|
|
143
|
+
]));
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
export {
|
|
147
|
+
Q as default
|
|
148
|
+
};
|
|
149
|
+
//# sourceMappingURL=ArchiveViewer-BqU761Wk.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ArchiveViewer-BqU761Wk.js","sources":["../src/viewers/ArchiveViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\n/**\n * ArchiveViewer — minimal zip / archive contents preview.\n *\n * Hits the configured archive-list endpoint (`archiveListUrl`, default\n * `POST /api/files/archive/list`) with the adapter-qualified path\n * and renders the member list as a flat table (name, size, mtime).\n * Read-only — extraction is exposed elsewhere (context menu / actions\n * panel). The viewer's job is just \"what's inside?\" so the user can\n * decide whether to extract or download.\n */\nimport { computed, onMounted, ref, watch } from 'vue';\nimport { actionIconSvg } from '../lib/actionIcons'; /* ikon:emoji */\nimport { fileIconTile } from '../lib/fileIcons'; /* ikon:emoji */\nimport DataTable, { type DataColumn } from '../components/DataTable.vue';\nimport { useLocale } from '../composables/useLocale';\n\ninterface ArchiveEntry {\n name: string;\n size: number;\n mtime?: string;\n is_dir?: boolean;\n}\n\nconst props = defineProps<{\n url: string;\n filePath?: string;\n ext: string;\n t?: (key: string, vars?: Record<string, string | number>) => string;\n /** The interface language — the size column is written the way it writes\n * numbers (\"1,96 KB\"), like every other size in the product. */\n locale?: string;\n authHeaders?: () => Record<string, string> | Promise<Record<string, string>>;\n authCredentials?: RequestCredentials;\n /** ⚠ Where to ask. This used to be the literal '/api/files/archive/list',\n * which is the ONE thing an embed cannot assume: with `apiBase` pointing at\n * another origin the request went to the host page instead and 404'd, while\n * every other call in the package honoured the configured base. The default\n * keeps a same-origin install working unchanged. */\n archiveListUrl?: string;\n}>();\n\nconst entries = ref<ArchiveEntry[]>([]);\nconst loading = ref(true);\nconst error = ref<string | null>(null);\n\n/** ⚠ `vars` go THROUGH `t()`, not into a `.replace()` afterwards: `t()` is what\n * picks the singular (`viewer.archive.entries_one`) from the count, and it can\n * only do that if it is told the count. Same shape CsvViewer's helper has. */\nfunction tt(key: string, fallback: string, vars?: Record<string, string | number>): string {\n return props.t ? props.t(key, vars) : fallback;\n}\n\n/* ⚠ The product's one byte formatter (useLocale.formatSize). This file had\n its own — base 1024, a dot, English units — so a zip's member read\n \"1.9 KB\" beside the explorer's \"1,96 KB\" for the same bytes (QA,\n 2026-09-21). */\nconst { formatSize } = useLocale(() => props.locale ?? 'en');\nfunction fmtSize(n: number): string {\n return formatSize(n);\n}\n\nasync function load(): Promise<void> {\n loading.value = true;\n error.value = null;\n entries.value = [];\n // The viewer is mounted with the resolved file path. Hit the API\n // endpoint with the same adapter-qualified path the preview URL\n // points at — the backend resolves storage + relative path itself.\n if (!props.filePath) {\n error.value = tt('viewer.archive.error', 'Could not read archive contents.');\n loading.value = false;\n return;\n }\n try {\n const res = await fetch(props.archiveListUrl || '/api/files/archive/list', {\n method: 'POST',\n credentials: props.authCredentials || 'same-origin',\n headers: {\n 'Content-Type': 'application/json',\n ...(props.authHeaders ? await props.authHeaders() : {}),\n },\n body: JSON.stringify({ path: props.filePath }),\n });\n if (!res.ok) {\n /* ⚠ Never the raw status. This printed \"503 Service Unavailable\" (or a\n * JSON body) straight into the preview — the same failure the owner\n * reported for ONLYOFFICE (\"Config fetch 503: {…}\"): a person is shown\n * the HTTP layer instead of what happened. The server's reason, when it\n * sent one we know, becomes a sentence; anything else is the generic\n * \"could not read the archive\". */\n throw new ArchiveError(await archiveErrorText(res));\n }\n const body = (await res.json()) as { entries?: ArchiveEntry[] };\n entries.value = body.entries ?? [];\n } catch (err) {\n error.value =\n err instanceof ArchiveError ? err.message : tt('viewer.archive.error', 'Could not read archive contents.');\n } finally {\n loading.value = false;\n }\n}\n\n/** A failure already worded for a person. Anything else that throws (the\n * network, a JSON parse) reads as the generic sentence. */\nclass ArchiveError extends Error {}\n\nasync function archiveErrorText(res: Response): Promise<string> {\n let code = '';\n try {\n const body = (await res.json()) as { error?: unknown; code?: unknown };\n code = String(body?.code ?? body?.error ?? '');\n } catch {\n /* not JSON — the generic sentence below */\n }\n if (/not a zip|unsupported|not supported|format/i.test(code)) {\n return tt('viewer.archive.unsupported', 'This kind of archive cannot be listed here. Download it to see what is inside.');\n }\n if (res.status === 413 || /too large|too big/i.test(code)) {\n return tt('viewer.archive.too_large', 'This archive is too large to list here. Download it to see what is inside.');\n }\n return tt('viewer.archive.error', 'Could not read archive contents.');\n}\n\nonMounted(load);\nwatch(() => props.filePath, load);\n\n/**\n * The entries, in THE table (DataTable — the explorer's own). ⚠ It used to be\n * the one table in the package allowed to be its own, with the reasoning that\n * a file's contents answer to the viewer's layout. The owner's rule since\n * 2026-09-21 has no such exception — \"bir yere tablo gerekiyorsa bu tabloyu\n * koymak zorundayız\" — and an archive's listing is a file listing: it wants\n * to be sorted by size and have its Name column widened exactly the way the\n * folder it came from does.\n */\nconst columns = computed<DataColumn<ArchiveEntry>[]>(() => [\n {\n id: 'name',\n label: tt('viewer.name', 'Name'),\n sortable: true,\n width: 360,\n class: 'filex-viewer-archive__name',\n title: (e) => e.name,\n },\n {\n id: 'size',\n label: tt('viewer.size', 'Size'),\n sortable: true,\n width: 110,\n align: 'right',\n class: 'filex-viewer-archive__size',\n format: (e) => (e.is_dir ? '' : fmtSize(e.size)),\n sortValue: (e) => (e.is_dir ? -1 : e.size),\n },\n]);\n\nconst totalSize = computed(() => entries.value.reduce((sum, e) => sum + (e.size || 0), 0));\nconst fileCount = computed(() => entries.value.filter((e) => !e.is_dir).length);\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\n/** A row inside the archive, drawn the way the listing draws the same kind. */\nfunction entryTile(e: ArchiveEntry): string {\n const name = e.name || '';\n const dot = name.lastIndexOf('.');\n return fileIconTile({\n type: e.is_dir ? 'dir' : 'file',\n extension: dot > 0 ? name.slice(dot + 1) : '',\n basename: name,\n });\n}\n</script>\n\n<template>\n <div class=\"filex-viewer-archive\">\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-if=\"entries.length === 0\" 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>{{ tt('viewer.archive.empty', 'Archive is empty.') }}</p>\n </div>\n <div v-else class=\"filex-viewer-archive__pane\">\n <div class=\"filex-viewer-archive__summary\">\n <!-- ⚠ The count is IN the message (\"{n} files\"). A `{{ fileCount }}`\n printed in front of it read \"3 3 files\". -->\n {{ tt('viewer.archive.entries', `${fileCount} files`, { n: fileCount }) }}\n · {{ fmtSize(totalSize) }}\n </div>\n <DataTable\n table-id=\"viewer.archive\"\n :columns=\"columns\"\n :rows=\"entries\"\n :row-key=\"(e: ArchiveEntry) => e.name\"\n :row-attrs=\"(e: ArchiveEntry) => ({ 'data-dir': e.is_dir ? '1' : '0' })\"\n >\n <template #cell-name=\"{ row }\">\n <!-- ikon:emoji — the same tile the listing draws for the same kind\n of file, so an archive's contents and the folder it came from\n read as one product. -->\n <!-- eslint-disable-next-line vue/no-v-html -- static markup from lib/fileIcons -->\n <span class=\"filex-viewer-archive__icon\" aria-hidden=\"true\" v-html=\"entryTile(row)\"></span>\n <span class=\"fe-list__cell-text\">{{ row.name }}</span>\n </template>\n </DataTable>\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-archive {\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-archive__pane {\n flex: 1;\n overflow: auto;\n padding: 16px 20px;\n}\n.filex-viewer-archive__summary {\n font-size: 12px;\n color: var(--fe-text-muted, #5a6475);\n margin-bottom: 12px;\n font-variant-numeric: tabular-nums;\n}\n/* The table itself is DataTable's (styles/base.css); only the viewer's own\n touches stay here — tabular figures and muted sizes, a folder row read as\n quieter than a file. */\n.filex-viewer-archive__size {\n text-align: end;\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n color: var(--fe-text-muted, #5a6475);\n}\n.filex-viewer-archive__icon {\n margin-inline-end: 6px;\n}\n.filex-viewer-archive .fe-list__row[data-dir=\"1\"] {\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</style>\n"],"names":["props","__props","entries","ref","loading","error","tt","key","fallback","vars","formatSize","useLocale","fmtSize","n","load","res","ArchiveError","archiveErrorText","body","err","code","onMounted","watch","columns","computed","totalSize","sum","e","fileCount","typeTile","fileIconTile","entryTile","name","dot","_openBlock","_createElementBlock","_hoisted_1","_hoisted_2","_createElementVNode","_hoisted_4","_unref","actionIconSvg","_hoisted_6","_hoisted_8","_hoisted_9","_toDisplayString","_createVNode","DataTable","_withCtx","row","_hoisted_11"],"mappings":"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"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { defineComponent as q, ref as i, onMounted as A, watch as C, computed as c, openBlock as m, createElementBlock as w, createElementVNode as o, toDisplayString as _, unref as G, createBlock as Z, createTextVNode as z, createCommentVNode as J } from "vue";
|
|
2
|
+
import { f as K, a as Q, _ as U, b as X, s as Y } from "./index-DuWnGuv5.js";
|
|
3
|
+
const ee = { class: "filex-viewer-csv" }, te = { class: "filex-viewer-csv__pane" }, ne = {
|
|
4
|
+
key: 0,
|
|
5
|
+
class: "filex-viewer-fallback"
|
|
6
|
+
}, le = ["innerHTML"], ae = {
|
|
7
|
+
key: 1,
|
|
8
|
+
class: "filex-viewer-fallback"
|
|
9
|
+
}, se = ["innerHTML"], re = {
|
|
10
|
+
key: 0,
|
|
11
|
+
class: "filex-viewer-csv__pager"
|
|
12
|
+
}, ie = ["disabled"], oe = { class: "filex-viewer-csv__pageno" }, ue = { dir: "ltr" }, ce = ["disabled"], T = 100, I = 1e3, fe = /* @__PURE__ */ q({
|
|
13
|
+
__name: "CsvViewer",
|
|
14
|
+
props: {
|
|
15
|
+
url: {},
|
|
16
|
+
ext: {},
|
|
17
|
+
t: { type: Function },
|
|
18
|
+
authHeaders: { type: Function },
|
|
19
|
+
authCredentials: {}
|
|
20
|
+
},
|
|
21
|
+
setup(S) {
|
|
22
|
+
const a = S, r = i([]), d = i(null), f = i(!0), L = i(!0), M = i(""), u = i(1), b = i(","), g = i("auto");
|
|
23
|
+
let N = 0;
|
|
24
|
+
function V(t) {
|
|
25
|
+
const e = t.split(/\r?\n/).slice(0, 5).join(`
|
|
26
|
+
`), n = (e.match(/\t/g) || []).length, l = (e.match(/;/g) || []).length, s = (e.match(/,/g) || []).length;
|
|
27
|
+
return n > s && n > l ? " " : l > s && l > n ? ";" : ",";
|
|
28
|
+
}
|
|
29
|
+
async function D(t, e) {
|
|
30
|
+
try {
|
|
31
|
+
const n = await import(
|
|
32
|
+
/* @vite-ignore */
|
|
33
|
+
"./papaparse.min-VB1HBwYX.js"
|
|
34
|
+
).then((v) => v.p);
|
|
35
|
+
return (n.default ?? n).parse(t, {
|
|
36
|
+
delimiter: e,
|
|
37
|
+
skipEmptyLines: !0,
|
|
38
|
+
header: !1
|
|
39
|
+
}).data.slice(0, I);
|
|
40
|
+
} catch {
|
|
41
|
+
return t.split(/\r?\n/).filter((n) => n.length > 0).slice(0, I).map((n) => n.split(e));
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
async function y() {
|
|
45
|
+
var l;
|
|
46
|
+
f.value = !0, d.value = null, r.value = [], u.value = 1;
|
|
47
|
+
const t = ++N;
|
|
48
|
+
let e;
|
|
49
|
+
try {
|
|
50
|
+
e = await X({
|
|
51
|
+
url: a.url,
|
|
52
|
+
headers: await ((l = a.authHeaders) == null ? void 0 : l.call(a)) ?? {},
|
|
53
|
+
credentials: a.authCredentials
|
|
54
|
+
});
|
|
55
|
+
} catch (s) {
|
|
56
|
+
d.value = Y(s, k("viewer.failed_to_load", "Failed to load file"), { t: a.t }).text, f.value = !1;
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (t !== N) return;
|
|
60
|
+
a.ext === "tsv" ? b.value = " " : b.value = V(e.slice(0, 4096));
|
|
61
|
+
const n = g.value === "auto" ? b.value : g.value;
|
|
62
|
+
r.value = await D(e, n), f.value = !1;
|
|
63
|
+
}
|
|
64
|
+
A(y), C(() => a.url, y), C(() => g.value, () => {
|
|
65
|
+
r.value.length !== 0 && y();
|
|
66
|
+
});
|
|
67
|
+
const P = c(() => !L.value || r.value.length === 0 ? r.value.length === 0 ? [] : r.value[0].map((t, e) => `Col ${e + 1}`) : r.value[0]), R = c(() => L.value ? r.value.slice(1) : r.value), p = c(() => {
|
|
68
|
+
const t = M.value.trim().toLowerCase(), e = R.value.map((n, l) => ({ n: l + 1, cells: n }));
|
|
69
|
+
return t ? e.filter((n) => n.cells.some((l) => (l || "").toLowerCase().includes(t))) : e;
|
|
70
|
+
}), h = i(null);
|
|
71
|
+
function H(t, e) {
|
|
72
|
+
return e === "n" ? String(t.n) : t.cells[Number(e.slice(1))] ?? "";
|
|
73
|
+
}
|
|
74
|
+
const F = c(() => {
|
|
75
|
+
const t = h.value;
|
|
76
|
+
if (!t) return p.value;
|
|
77
|
+
const e = t.dir === "asc" ? 1 : -1;
|
|
78
|
+
return [...p.value].sort((n, l) => {
|
|
79
|
+
if (t.key === "n") return e * (n.n - l.n);
|
|
80
|
+
const s = H(n, t.key), v = H(l, t.key);
|
|
81
|
+
if (!s != !v) return s ? -1 : 1;
|
|
82
|
+
const $ = Number(s), E = Number(v);
|
|
83
|
+
return s && v && Number.isFinite($) && Number.isFinite(E) ? e * ($ - E) || n.n - l.n : e * s.localeCompare(v, void 0, { numeric: !0, sensitivity: "base" }) || n.n - l.n;
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
function B(t) {
|
|
87
|
+
h.value = t;
|
|
88
|
+
}
|
|
89
|
+
const x = c(
|
|
90
|
+
() => Math.max(1, Math.ceil(F.value.length / T))
|
|
91
|
+
), O = c(() => {
|
|
92
|
+
const t = (u.value - 1) * T;
|
|
93
|
+
return F.value.slice(t, t + T);
|
|
94
|
+
});
|
|
95
|
+
C([M, h], () => {
|
|
96
|
+
u.value = 1;
|
|
97
|
+
});
|
|
98
|
+
const W = c(() => [
|
|
99
|
+
{
|
|
100
|
+
id: "n",
|
|
101
|
+
label: "#",
|
|
102
|
+
lead: !0,
|
|
103
|
+
width: 64,
|
|
104
|
+
min: 48,
|
|
105
|
+
align: "right",
|
|
106
|
+
sortable: !0,
|
|
107
|
+
class: "filex-viewer-csv__rownum",
|
|
108
|
+
format: (t) => t.n
|
|
109
|
+
},
|
|
110
|
+
...P.value.map((t, e) => ({
|
|
111
|
+
id: `c${e}`,
|
|
112
|
+
label: t,
|
|
113
|
+
width: 140,
|
|
114
|
+
sortable: !0,
|
|
115
|
+
format: (n) => n.cells[e] ?? ""
|
|
116
|
+
}))
|
|
117
|
+
]);
|
|
118
|
+
function k(t, e, n) {
|
|
119
|
+
return a.t ? a.t(t, n) : e;
|
|
120
|
+
}
|
|
121
|
+
const j = c(() => K({ type: "file", extension: a.ext }));
|
|
122
|
+
return (t, e) => (m(), w("div", ee, [
|
|
123
|
+
o("div", te, [
|
|
124
|
+
d.value ? (m(), w("div", ne, [
|
|
125
|
+
o("span", {
|
|
126
|
+
class: "filex-viewer-fallback__icon",
|
|
127
|
+
"aria-hidden": "true",
|
|
128
|
+
innerHTML: j.value
|
|
129
|
+
}, null, 8, le),
|
|
130
|
+
o("p", null, _(d.value), 1)
|
|
131
|
+
])) : f.value ? (m(), w("div", ae, [
|
|
132
|
+
o("span", {
|
|
133
|
+
class: "filex-viewer-fallback__icon filex-viewer-fallback__icon--spin",
|
|
134
|
+
"aria-hidden": "true",
|
|
135
|
+
innerHTML: G(Q)("progress")
|
|
136
|
+
}, null, 8, se),
|
|
137
|
+
o("p", null, _(k("viewer.loading", "Loading…")), 1)
|
|
138
|
+
])) : (m(), Z(U, {
|
|
139
|
+
key: 2,
|
|
140
|
+
"table-id": void 0,
|
|
141
|
+
columns: W.value,
|
|
142
|
+
rows: O.value,
|
|
143
|
+
"row-key": (n) => n.n,
|
|
144
|
+
sort: h.value,
|
|
145
|
+
onSort: B
|
|
146
|
+
}, null, 8, ["columns", "rows", "row-key", "sort"]))
|
|
147
|
+
]),
|
|
148
|
+
!f.value && !d.value && x.value > 1 ? (m(), w("div", re, [
|
|
149
|
+
o("button", {
|
|
150
|
+
type: "button",
|
|
151
|
+
class: "filex-viewer-btn",
|
|
152
|
+
disabled: u.value <= 1,
|
|
153
|
+
onClick: e[0] || (e[0] = (n) => u.value--)
|
|
154
|
+
}, "‹", 8, ie),
|
|
155
|
+
o("span", oe, [
|
|
156
|
+
o("bdi", ue, _(u.value) + " / " + _(x.value), 1),
|
|
157
|
+
z(" (" + _(k("viewer.csv_rows", `${p.value.length} rows`, { n: p.value.length })) + ")", 1)
|
|
158
|
+
]),
|
|
159
|
+
o("button", {
|
|
160
|
+
type: "button",
|
|
161
|
+
class: "filex-viewer-btn",
|
|
162
|
+
disabled: u.value >= x.value,
|
|
163
|
+
onClick: e[1] || (e[1] = (n) => u.value++)
|
|
164
|
+
}, "›", 8, ce)
|
|
165
|
+
])) : J("", !0)
|
|
166
|
+
]));
|
|
167
|
+
}
|
|
168
|
+
});
|
|
169
|
+
export {
|
|
170
|
+
fe as default
|
|
171
|
+
};
|
|
172
|
+
//# sourceMappingURL=CsvViewer-ByHVK5ga.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CsvViewer-ByHVK5ga.js","sources":["../src/viewers/CsvViewer.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { sayFailure } from '../lib/errorWords';\n/**\n * CsvViewer — lightweight CSV / TSV table preview.\n *\n * Lazy-imports `papaparse` when available (best-quality parser — handles\n * embedded quotes, multi-line cells, etc). Falls back to a simple\n * `split` parser when the peer is missing — workable for the trivial\n * \"first 1000 rows\" preview case but loses fidelity on complex files.\n *\n * UX:\n * - first-row-as-header toggle\n * - filter input that case-insensitively matches any cell\n * - 100-rows-per-page pagination\n * - tab vs comma auto-detection (manual override via toolbar)\n */\nimport { computed, 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 DataTable, { type DataColumn } from '../components/DataTable.vue';\n\nconst props = defineProps<{\n url: string;\n ext: string;\n t?: (key: string, vars?: Record<string, string | number>) => string;\n authHeaders?: () => Record<string, string> | Promise<Record<string, string>>;\n authCredentials?: RequestCredentials;\n}>();\n\nconst PAGE_SIZE = 100;\nconst ROW_LIMIT = 1000;\n\nconst rows = ref<string[][]>([]);\nconst error = ref<string | null>(null);\nconst loading = ref(true);\nconst firstRowHeader = ref(true);\nconst filter = ref('');\nconst page = ref(1);\nconst detectedDelim = ref<',' | '\\t' | ';'>(',');\nconst userDelim = ref<'auto' | ',' | '\\t' | ';'>('auto');\n\nlet renderToken = 0;\n\nfunction detectDelimiter(sample: string): ',' | '\\t' | ';' {\n const sampleLines = sample.split(/\\r?\\n/).slice(0, 5).join('\\n');\n const tab = (sampleLines.match(/\\t/g) || []).length;\n const semi = (sampleLines.match(/;/g) || []).length;\n const comma = (sampleLines.match(/,/g) || []).length;\n if (tab > comma && tab > semi) return '\\t';\n if (semi > comma && semi > tab) return ';';\n return ',';\n}\n\nasync function parseWith(text: string, delim: string): Promise<string[][]> {\n try {\n const mod = await import(/* @vite-ignore */ 'papaparse');\n const Papa = (mod as any).default ?? mod;\n const result = Papa.parse(text, {\n delimiter: delim,\n skipEmptyLines: true,\n header: false,\n });\n return (result.data as string[][]).slice(0, ROW_LIMIT);\n } catch {\n // Fallback: naive line/column split. Loses quoted-comma support\n // but renders something reasonable.\n return text\n .split(/\\r?\\n/)\n .filter((l) => l.length > 0)\n .slice(0, ROW_LIMIT)\n .map((line) => line.split(delim));\n }\n}\n\nasync function load(): Promise<void> {\n loading.value = true;\n error.value = null;\n rows.value = [];\n page.value = 1;\n const myToken = ++renderToken;\n\n let text: string;\n try {\n text = 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 if (props.ext === 'tsv') {\n detectedDelim.value = '\\t';\n } else {\n detectedDelim.value = detectDelimiter(text.slice(0, 4096));\n }\n\n const delim = userDelim.value === 'auto' ? detectedDelim.value : userDelim.value;\n rows.value = await parseWith(text, delim);\n loading.value = false;\n}\n\nonMounted(load);\nwatch(() => props.url, load);\nwatch(() => userDelim.value, () => {\n if (rows.value.length === 0) return;\n // Re-parse with the new delimiter using the cached source — but we\n // didn't keep it. Cheapest path is a refetch.\n load();\n});\n\nconst headers = computed<string[]>(() => {\n if (!firstRowHeader.value || rows.value.length === 0) {\n if (rows.value.length === 0) return [];\n return rows.value[0].map((_, i) => `Col ${i + 1}`);\n }\n return rows.value[0];\n});\n\nconst dataRows = computed<string[][]>(() => {\n return firstRowHeader.value ? rows.value.slice(1) : rows.value;\n});\n\n/** A parsed row with the line it came from, so `#` keeps naming the row in\n * the FILE after a sort re-orders the screen. */\ninterface CsvRow {\n n: number;\n cells: string[];\n}\n\nconst filtered = computed<CsvRow[]>(() => {\n const q = filter.value.trim().toLowerCase();\n const all = dataRows.value.map((cells, i) => ({ n: i + 1, cells }));\n if (!q) return all;\n return all.filter((r) => r.cells.some((c) => (c || '').toLowerCase().includes(q)));\n});\n\n/**\n * THE SORT, done here and handed to the table as CONTROLLED.\n *\n * ⚠⚠ Here and not in the table, because the table only ever holds one page\n * (100 rows) of the parsed file, and a table that sorts the page it holds\n * would call a re-ordered 100 of 1000 \"sorted\" — so it rightly closes its\n * headers over a paged list. This component holds EVERY parsed row, so it can\n * sort all of them and then page, which is the honest order.\n */\nconst sort = ref<{ key: string; dir: 'asc' | 'desc' } | null>(null);\n\nfunction cellOf(r: CsvRow, key: string): string {\n if (key === 'n') return String(r.n);\n return r.cells[Number(key.slice(1))] ?? '';\n}\n\nconst sorted = computed<CsvRow[]>(() => {\n const s = sort.value;\n if (!s) return filtered.value;\n const dir = s.dir === 'asc' ? 1 : -1;\n return [...filtered.value].sort((a, b) => {\n if (s.key === 'n') return dir * (a.n - b.n);\n const x = cellOf(a, s.key);\n const y = cellOf(b, s.key);\n // Empty cells last in both directions; numbers as numbers.\n if (!x !== !y) return x ? -1 : 1;\n const nx = Number(x);\n const ny = Number(y);\n if (x && y && Number.isFinite(nx) && Number.isFinite(ny)) return dir * (nx - ny) || a.n - b.n;\n return dir * x.localeCompare(y, undefined, { numeric: true, sensitivity: 'base' }) || a.n - b.n;\n });\n});\n\nfunction onSort(next: { key: string; dir: 'asc' | 'desc' }) {\n sort.value = next;\n}\n\nconst totalPages = computed(() =>\n Math.max(1, Math.ceil(sorted.value.length / PAGE_SIZE)),\n);\n\nconst visibleRows = computed<CsvRow[]>(() => {\n const start = (page.value - 1) * PAGE_SIZE;\n return sorted.value.slice(start, start + PAGE_SIZE);\n});\n\nwatch([filter, sort], () => {\n page.value = 1;\n});\n\n/** The file's columns, as THE table (DataTable — the explorer's own) draws\n * them. `#` is the lead: it is what names a row of a spreadsheet. */\nconst columns = computed<DataColumn<CsvRow>[]>(() => [\n {\n id: 'n',\n label: '#',\n lead: true,\n width: 64,\n min: 48,\n align: 'right',\n sortable: true,\n class: 'filex-viewer-csv__rownum',\n format: (r) => r.n,\n },\n ...headers.value.map((h, i) => ({\n id: `c${i}`,\n label: h,\n width: 140,\n sortable: true,\n format: (r: CsvRow) => r.cells[i] ?? '',\n })),\n]);\n\nfunction tt(key: string, fallback: string, vars?: Record<string, string | number>): string {\n return props.t ? props.t(key, vars) : 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-csv\">\n <div class=\"filex-viewer-csv__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 <!-- ⚠ No table id: a spreadsheet's columns are whatever THIS file has\n (`c0`, `c1`, …), so widths remembered against them would land on a\n different file's different columns next time. The arrangement\n lives for this preview. -->\n <DataTable\n v-else\n :table-id=\"undefined\"\n :columns=\"columns\"\n :rows=\"visibleRows\"\n :row-key=\"(r: CsvRow) => r.n\"\n :sort=\"sort\"\n @sort=\"onSort\"\n />\n </div>\n <div v-if=\"!loading && !error && totalPages > 1\" class=\"filex-viewer-csv__pager\">\n <button\n type=\"button\"\n class=\"filex-viewer-btn\"\n :disabled=\"page <= 1\"\n @click=\"page--\"\n >‹</button>\n <span class=\"filex-viewer-csv__pageno\"><bdi dir=\"ltr\">{{ page }} / {{ totalPages }}</bdi> ({{ tt('viewer.csv_rows', `${filtered.length} rows`, { n: filtered.length }) }})</span>\n <button\n type=\"button\"\n class=\"filex-viewer-btn\"\n :disabled=\"page >= totalPages\"\n @click=\"page++\"\n >›</button>\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-csv {\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-csv__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}\n.filex-viewer-csv__check {\n display: flex;\n align-items: center;\n gap: 4px;\n font-size: 12px;\n}\n.filex-viewer-csv__select,\n.filex-viewer-csv__filter {\n border: 1px solid var(--fe-border, #e2e6ed);\n background: var(--fe-bg, #fff);\n color: inherit;\n padding: 4px 8px;\n border-radius: 4px;\n font: inherit;\n font-size: 12px;\n}\n.filex-viewer-csv__filter {\n flex: 0 1 240px;\n}\n.filex-viewer-spacer { flex: 1; }\n.filex-viewer-csv__count {\n font-size: 11px;\n color: var(--fe-text-muted, #5a6475);\n font-variant-numeric: tabular-nums;\n}\n.filex-viewer-csv__pane {\n flex: 1;\n overflow: auto;\n}\n.filex-viewer-csv__pane .fe-list__cell {\n font-family: var(--fe-font-mono, monospace);\n font-size: 12px;\n}\n/* The table itself is DataTable's (styles/base.css) — the product's one table.\n ⚠ The row number used to pin itself (`position: sticky; left: 0`) because\n this was a table of its own; it is the table's LEAD now, and the table\n freezes its lead itself, only while there is room to (a pin written here\n would fight that gate). What stays is the look of a row number. */\n.filex-viewer-csv__rownum {\n color: var(--fe-text-muted, #5a6475);\n font-variant-numeric: tabular-nums;\n}\n.filex-viewer-csv__pager {\n display: flex;\n justify-content: center;\n align-items: center;\n gap: 8px;\n padding: 6px;\n background: var(--fe-bg-elev, #f7f8fa);\n border-top: 1px solid var(--fe-border, #e2e6ed);\n font-size: 12px;\n}\n.filex-viewer-csv__pageno {\n font-variant-numeric: tabular-nums;\n font-size: 12px;\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.4;\n cursor: not-allowed;\n}\n</style>\n"],"names":["PAGE_SIZE","ROW_LIMIT","props","__props","rows","ref","error","loading","firstRowHeader","filter","page","detectedDelim","userDelim","renderToken","detectDelimiter","sample","sampleLines","tab","semi","comma","parseWith","text","delim","mod","n","l","line","load","myToken","fetchViewerText","_a","err","sayFailure","tt","onMounted","watch","headers","computed","_","i","dataRows","filtered","q","all","cells","r","c","sort","cellOf","key","sorted","s","dir","a","b","x","y","nx","ny","onSort","next","totalPages","visibleRows","start","columns","h","fallback","vars","typeTile","fileIconTile","_openBlock","_createElementBlock","_hoisted_1","_createElementVNode","_hoisted_2","_hoisted_3","_hoisted_5","_unref","actionIconSvg","_createBlock","DataTable","_hoisted_7","_hoisted_8","_hoisted_9","_hoisted_10","_toDisplayString","_hoisted_11"],"mappings":"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"}
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { defineComponent as
|
|
2
|
-
import { f as
|
|
3
|
-
import { f as H } from "./useViewerFetch-czqbd2Lj.js";
|
|
1
|
+
import { defineComponent as U, ref as s, computed as c, onMounted as B, watch as C, onBeforeUnmount as E, openBlock as f, createElementBlock as v, createElementVNode as x, toDisplayString as O } from "vue";
|
|
2
|
+
import { f as D, b as H } from "./index-DuWnGuv5.js";
|
|
4
3
|
const L = { class: "filex-viewer-drawio" }, M = {
|
|
5
4
|
key: 0,
|
|
6
5
|
class: "filex-viewer-fallback"
|
|
7
|
-
},
|
|
6
|
+
}, P = ["innerHTML"], N = ["src"], J = /* @__PURE__ */ U({
|
|
8
7
|
__name: "DrawioViewer",
|
|
9
8
|
props: {
|
|
10
9
|
url: {},
|
|
@@ -15,24 +14,25 @@ const L = { class: "filex-viewer-drawio" }, M = {
|
|
|
15
14
|
readOnly: { type: Boolean },
|
|
16
15
|
t: { type: Function },
|
|
17
16
|
authHeaders: { type: Function },
|
|
18
|
-
authCredentials: {}
|
|
17
|
+
authCredentials: {},
|
|
18
|
+
canConfigure: { type: Boolean }
|
|
19
19
|
},
|
|
20
|
-
setup(
|
|
21
|
-
const e =
|
|
20
|
+
setup(_) {
|
|
21
|
+
const e = _, w = s(null), i = s(null), n = s("loading"), h = s(!!e.readOnly || !e.saveUrl), d = c(
|
|
22
22
|
() => e.drawioUrl ? e.drawioUrl.replace(/\/$/, "") : null
|
|
23
|
-
),
|
|
24
|
-
if (!
|
|
23
|
+
), b = c(() => {
|
|
24
|
+
if (!d.value) return "";
|
|
25
25
|
const a = new URLSearchParams({
|
|
26
26
|
embed: "1",
|
|
27
27
|
proto: "json",
|
|
28
28
|
spin: "1",
|
|
29
29
|
saveAndExit: "0",
|
|
30
|
-
noSaveBtn:
|
|
30
|
+
noSaveBtn: h.value ? "1" : "0",
|
|
31
31
|
noExitBtn: "1",
|
|
32
32
|
ui: "kennedy",
|
|
33
33
|
modified: "unsavedChanges"
|
|
34
34
|
});
|
|
35
|
-
return `${
|
|
35
|
+
return `${d.value}/?${a.toString()}`;
|
|
36
36
|
});
|
|
37
37
|
let m = "";
|
|
38
38
|
async function k() {
|
|
@@ -45,14 +45,14 @@ const L = { class: "filex-viewer-drawio" }, M = {
|
|
|
45
45
|
credentials: e.authCredentials
|
|
46
46
|
});
|
|
47
47
|
} catch (r) {
|
|
48
|
-
i.value =
|
|
48
|
+
console.warn("[filex] diagram could not be read", r), i.value = l("viewer.drawio.load_failed", "This diagram could not be read. Download it to open it elsewhere."), o = !1, n.value = "error";
|
|
49
49
|
}
|
|
50
50
|
}
|
|
51
|
-
function
|
|
51
|
+
function T(a) {
|
|
52
52
|
var r, t;
|
|
53
|
-
(t = (r =
|
|
53
|
+
(t = (r = w.value) == null ? void 0 : r.contentWindow) == null || t.postMessage(JSON.stringify(a), "*");
|
|
54
54
|
}
|
|
55
|
-
async function
|
|
55
|
+
async function p(a) {
|
|
56
56
|
var r;
|
|
57
57
|
if (e.saveUrl) {
|
|
58
58
|
n.value = "saving";
|
|
@@ -60,23 +60,23 @@ const L = { class: "filex-viewer-drawio" }, M = {
|
|
|
60
60
|
const t = {
|
|
61
61
|
"Content-Type": "application/json",
|
|
62
62
|
...await ((r = e.authHeaders) == null ? void 0 : r.call(e)) ?? {}
|
|
63
|
-
},
|
|
63
|
+
}, u = await fetch(e.saveUrl, {
|
|
64
64
|
method: "POST",
|
|
65
65
|
headers: t,
|
|
66
66
|
credentials: e.authCredentials || "same-origin",
|
|
67
67
|
body: JSON.stringify({ path: e.filePath, content: a })
|
|
68
68
|
});
|
|
69
|
-
if (!
|
|
70
|
-
throw
|
|
69
|
+
if (!u.ok)
|
|
70
|
+
throw console.warn("[filex] diagram save failed", u.status, u.statusText), new Error("save");
|
|
71
71
|
n.value = "saved", setTimeout(() => {
|
|
72
72
|
n.value === "saved" && (n.value = "ready");
|
|
73
73
|
}, 2500);
|
|
74
74
|
} catch (t) {
|
|
75
|
-
i.value =
|
|
75
|
+
console.warn("[filex] diagram save failed", t), i.value = l("viewer.drawio.save_failed", "The diagram could not be saved. Your changes are still in the editor — try again."), o = !1, n.value = "error";
|
|
76
76
|
}
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
|
-
function
|
|
79
|
+
function y(a) {
|
|
80
80
|
if (typeof a.data != "string" || a.data.length === 0) return;
|
|
81
81
|
const r = a.data[0];
|
|
82
82
|
if (r !== "{" && r !== "<") return;
|
|
@@ -89,53 +89,54 @@ const L = { class: "filex-viewer-drawio" }, M = {
|
|
|
89
89
|
if (!(!t || typeof t != "object"))
|
|
90
90
|
switch (t.event) {
|
|
91
91
|
case "init":
|
|
92
|
-
|
|
92
|
+
T({
|
|
93
93
|
action: "load",
|
|
94
94
|
xml: m,
|
|
95
95
|
autosave: 0
|
|
96
96
|
}), n.value = "ready";
|
|
97
97
|
break;
|
|
98
98
|
case "save":
|
|
99
|
-
typeof t.xml == "string" &&
|
|
99
|
+
typeof t.xml == "string" && p(t.xml);
|
|
100
100
|
break;
|
|
101
101
|
case "export":
|
|
102
102
|
break;
|
|
103
103
|
case "autosave":
|
|
104
|
-
typeof t.xml == "string" && !
|
|
104
|
+
typeof t.xml == "string" && !h.value && p(t.xml);
|
|
105
105
|
break;
|
|
106
106
|
}
|
|
107
107
|
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
108
|
+
let o = !1;
|
|
109
|
+
function g() {
|
|
110
|
+
if (!d.value) {
|
|
111
|
+
i.value = e.canConfigure ? l("viewer.drawio.disabled_admin", "draw.io is not set up on this server. Set it up in the admin panel under External services.") : l("viewer.drawio.disabled", "Diagrams cannot be opened here: this server has no draw.io. Download the file to open it elsewhere."), o = !0, n.value = "error";
|
|
111
112
|
return;
|
|
112
113
|
}
|
|
113
|
-
|
|
114
|
+
o && (o = !1, i.value = null, n.value = "loading"), k();
|
|
114
115
|
}
|
|
115
|
-
|
|
116
|
-
window.addEventListener("message",
|
|
117
|
-
}),
|
|
118
|
-
window.removeEventListener("message",
|
|
116
|
+
B(() => {
|
|
117
|
+
window.addEventListener("message", y), g();
|
|
118
|
+
}), C(() => e.drawioUrl, g), E(() => {
|
|
119
|
+
window.removeEventListener("message", y);
|
|
119
120
|
});
|
|
120
|
-
function
|
|
121
|
+
function l(a, r) {
|
|
121
122
|
return e.t ? e.t(a) : r;
|
|
122
123
|
}
|
|
123
|
-
const
|
|
124
|
-
return (a, r) => (
|
|
125
|
-
i.value ? (
|
|
126
|
-
|
|
124
|
+
const S = c(() => D({ type: "file", extension: e.ext }));
|
|
125
|
+
return (a, r) => (f(), v("div", L, [
|
|
126
|
+
i.value ? (f(), v("div", M, [
|
|
127
|
+
x("span", {
|
|
127
128
|
class: "filex-viewer-fallback__icon",
|
|
128
129
|
"aria-hidden": "true",
|
|
129
|
-
innerHTML:
|
|
130
|
-
}, null, 8,
|
|
131
|
-
|
|
132
|
-
])) : (
|
|
130
|
+
innerHTML: S.value
|
|
131
|
+
}, null, 8, P),
|
|
132
|
+
x("p", null, O(i.value), 1)
|
|
133
|
+
])) : (f(), v("iframe", {
|
|
133
134
|
key: 1,
|
|
134
135
|
ref_key: "iframeRef",
|
|
135
|
-
ref:
|
|
136
|
-
src:
|
|
136
|
+
ref: w,
|
|
137
|
+
src: b.value,
|
|
137
138
|
class: "filex-viewer-drawio__frame",
|
|
138
|
-
title: "
|
|
139
|
+
title: "draw.io"
|
|
139
140
|
}, null, 8, N))
|
|
140
141
|
]));
|
|
141
142
|
}
|
|
@@ -143,4 +144,4 @@ const L = { class: "filex-viewer-drawio" }, M = {
|
|
|
143
144
|
export {
|
|
144
145
|
J as default
|
|
145
146
|
};
|
|
146
|
-
//# sourceMappingURL=DrawioViewer-
|
|
147
|
+
//# sourceMappingURL=DrawioViewer-Bgrj8-zG.js.map
|