vitepress-plugin-filelist 0.6.2 → 0.7.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 +25 -2
- package/dist/client/browser/index.d.ts +25 -1
- package/dist/client/browser/index.js +425 -112
- package/dist/client/ssr/index.d.ts +25 -1
- package/dist/client/ssr/index.js +244 -14
- package/dist/client/style.css +95 -1
- package/package.json +8 -2
|
@@ -179,12 +179,29 @@ function previewKind(name) {
|
|
|
179
179
|
function totalSize(items) {
|
|
180
180
|
return items.reduce((sum, item) => sum + (Number.isFinite(item.size) && (item.size ?? 0) > 0 ? item.size : 0), 0);
|
|
181
181
|
}
|
|
182
|
-
|
|
182
|
+
const collators = /* @__PURE__ */ new Map();
|
|
183
|
+
/**
|
|
184
|
+
* Name order for a UI locale: pinyin for Chinese, alphabetical for English,
|
|
185
|
+
* with numbers in natural order (“2” before “10”) either way.
|
|
186
|
+
*/
|
|
187
|
+
function collatorFor(locale) {
|
|
188
|
+
const tag = locale.toLowerCase().startsWith("zh") ? "zh-Hans-CN" : "en";
|
|
189
|
+
let collator = collators.get(tag);
|
|
190
|
+
if (!collator) {
|
|
191
|
+
collator = new Intl.Collator(tag, {
|
|
192
|
+
numeric: true,
|
|
193
|
+
sensitivity: "base"
|
|
194
|
+
});
|
|
195
|
+
collators.set(tag, collator);
|
|
196
|
+
}
|
|
197
|
+
return collator;
|
|
198
|
+
}
|
|
199
|
+
function compareNodes(a, b, key, ascending = true, locale = "zh-CN") {
|
|
183
200
|
if (a.is_dir !== b.is_dir) return a.is_dir ? -1 : 1;
|
|
184
201
|
let result = 0;
|
|
185
202
|
if (key === "size") result = a.size - b.size;
|
|
186
203
|
else if (key === "modified") result = new Date(a.modified).getTime() - new Date(b.modified).getTime();
|
|
187
|
-
else result = a.name.
|
|
204
|
+
else result = collatorFor(locale).compare(a.name, b.name) || (a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
188
205
|
return ascending ? result : -result;
|
|
189
206
|
}
|
|
190
207
|
/**
|
|
@@ -899,6 +916,20 @@ const fileListLocales = {
|
|
|
899
916
|
forgetPassword: "忘记",
|
|
900
917
|
unlockFolder: "输入 {name} 的密码",
|
|
901
918
|
networkHint: "可能被跨域拦截:请检查 OpenList 的 cors.allow_origins,或 OpenList-Worker 的 ALLOW_URLS。",
|
|
919
|
+
deepHint: "只筛选了已加载的内容",
|
|
920
|
+
deepSearch: "深度搜索",
|
|
921
|
+
deepRunning: "正在深度搜索 · 已查找 {count} 个文件夹",
|
|
922
|
+
deepStop: "停止",
|
|
923
|
+
deepDone: "已搜索全部 {count} 个文件夹",
|
|
924
|
+
deepCapped: "已查找 {count} 个文件夹,还有未搜索的子目录",
|
|
925
|
+
deepContinue: "继续",
|
|
926
|
+
deepSkipped: "跳过 {count} 个加密文件夹",
|
|
927
|
+
deepFailed: "{count} 个文件夹读取失败",
|
|
928
|
+
viewMode: "显示方式",
|
|
929
|
+
viewSource: "源码",
|
|
930
|
+
viewRendered: "渲染",
|
|
931
|
+
htmlSandboxNote: "已禁用脚本;网页引用的相对路径资源不会加载",
|
|
932
|
+
imageOmitted: "[图片:{alt}]",
|
|
902
933
|
batchFailedTitle: "打包失败",
|
|
903
934
|
batchFailedHint: "可以减少勾选的文件后重试。",
|
|
904
935
|
downloadStarted: "已交给浏览器下载:{name}",
|
|
@@ -979,6 +1010,20 @@ const fileListLocales = {
|
|
|
979
1010
|
forgetPassword: "Forget",
|
|
980
1011
|
unlockFolder: "Enter the password for {name}",
|
|
981
1012
|
networkHint: "Possibly blocked by CORS: check cors.allow_origins in OpenList, or ALLOW_URLS in OpenList-Worker.",
|
|
1013
|
+
deepHint: "Only loaded folders are filtered",
|
|
1014
|
+
deepSearch: "Deep search",
|
|
1015
|
+
deepRunning: "Searching · {count} folders checked",
|
|
1016
|
+
deepStop: "Stop",
|
|
1017
|
+
deepDone: "Searched all {count} folders",
|
|
1018
|
+
deepCapped: "{count} folders checked; some sub-folders remain",
|
|
1019
|
+
deepContinue: "Continue",
|
|
1020
|
+
deepSkipped: "{count} locked folders skipped",
|
|
1021
|
+
deepFailed: "{count} folders could not be read",
|
|
1022
|
+
viewMode: "View",
|
|
1023
|
+
viewSource: "Source",
|
|
1024
|
+
viewRendered: "Rendered",
|
|
1025
|
+
htmlSandboxNote: "Scripts are disabled; resources at relative paths do not load",
|
|
1026
|
+
imageOmitted: "[Image: {alt}]",
|
|
982
1027
|
batchFailedTitle: "Could not create the ZIP",
|
|
983
1028
|
batchFailedHint: "Try again with fewer files selected.",
|
|
984
1029
|
downloadStarted: "Downloading {name} in your browser",
|
|
@@ -1007,6 +1052,45 @@ function resolveLabels(locale = "zh-CN", overrides) {
|
|
|
1007
1052
|
...overrides
|
|
1008
1053
|
};
|
|
1009
1054
|
}
|
|
1055
|
+
// src/client/markdown.ts
|
|
1056
|
+
/**
|
|
1057
|
+
* Markdown → safe HTML for the preview dialog. Loaded on demand, so pages that
|
|
1058
|
+
* never render Markdown do not download markdown-it or DOMPurify.
|
|
1059
|
+
*
|
|
1060
|
+
* - Raw HTML in the file is allowed, then sanitised (no scripts, handlers, iframes...)
|
|
1061
|
+
* - Only absolute http(s) / mailto links stay clickable, opening in a new tab;
|
|
1062
|
+
* relative links (to other files in the share) become plain text
|
|
1063
|
+
* - Images with a relative source are replaced by their alt text, because the
|
|
1064
|
+
* share's relative paths do not resolve on the documentation site
|
|
1065
|
+
*/
|
|
1066
|
+
async function renderMarkdown(source, imageLabel) {
|
|
1067
|
+
const [{ default: MarkdownIt }, { default: DOMPurify }] = await Promise.all([import("markdown-it"), import("dompurify")]);
|
|
1068
|
+
const probe = DOMPurify.isSupported ? DOMPurify.sanitize("<img src=\"x\" onerror=\"1\"><script>1<\/script>") : "<script";
|
|
1069
|
+
if (/<script|onerror/i.test(probe)) throw new Error("HTML sanitiser unavailable");
|
|
1070
|
+
const html = new MarkdownIt({
|
|
1071
|
+
html: true,
|
|
1072
|
+
linkify: true
|
|
1073
|
+
}).render(source);
|
|
1074
|
+
const template = document.createElement("template");
|
|
1075
|
+
template.innerHTML = DOMPurify.sanitize(html);
|
|
1076
|
+
const fragment = template.content;
|
|
1077
|
+
for (const link of fragment.querySelectorAll("a")) {
|
|
1078
|
+
const href = link.getAttribute("href") ?? "";
|
|
1079
|
+
if (/^(https?:|mailto:)/i.test(href)) {
|
|
1080
|
+
link.setAttribute("target", "_blank");
|
|
1081
|
+
link.setAttribute("rel", "noopener noreferrer");
|
|
1082
|
+
} else link.replaceWith(...link.childNodes);
|
|
1083
|
+
}
|
|
1084
|
+
for (const image of fragment.querySelectorAll("img")) {
|
|
1085
|
+
const src = image.getAttribute("src") ?? "";
|
|
1086
|
+
if (/^(https?:|data:image\/)/i.test(src)) continue;
|
|
1087
|
+
const placeholder = document.createElement("span");
|
|
1088
|
+
placeholder.className = "fl-md-image";
|
|
1089
|
+
placeholder.textContent = imageLabel(image.getAttribute("alt") || src.split("/").pop() || "");
|
|
1090
|
+
image.replaceWith(placeholder);
|
|
1091
|
+
}
|
|
1092
|
+
return template.innerHTML;
|
|
1093
|
+
}
|
|
1010
1094
|
// src/client/PreviewDialog.vue
|
|
1011
1095
|
const _hoisted_1$1 = ["aria-label"];
|
|
1012
1096
|
const _hoisted_2$1 = {
|
|
@@ -1031,33 +1115,40 @@ const _hoisted_13$1 = [
|
|
|
1031
1115
|
"aria-label",
|
|
1032
1116
|
"title"
|
|
1033
1117
|
];
|
|
1034
|
-
const _hoisted_14$1 =
|
|
1035
|
-
const _hoisted_15$1 = ["aria-
|
|
1036
|
-
const _hoisted_16$1 =
|
|
1037
|
-
const _hoisted_17$1 = ["
|
|
1038
|
-
const _hoisted_18$1 =
|
|
1118
|
+
const _hoisted_14$1 = ["aria-label"];
|
|
1119
|
+
const _hoisted_15$1 = ["aria-pressed", "onClick"];
|
|
1120
|
+
const _hoisted_16$1 = { class: "fl-preview-tools fl-preview-actions" };
|
|
1121
|
+
const _hoisted_17$1 = ["aria-label", "title"];
|
|
1122
|
+
const _hoisted_18$1 = ["aria-label", "title"];
|
|
1123
|
+
const _hoisted_19$1 = ["data-mode"];
|
|
1124
|
+
const _hoisted_20$1 = {
|
|
1039
1125
|
key: 0,
|
|
1040
1126
|
class: "fl-preview-status",
|
|
1041
1127
|
role: "status"
|
|
1042
1128
|
};
|
|
1043
|
-
const
|
|
1044
|
-
const
|
|
1045
|
-
const
|
|
1046
|
-
const
|
|
1047
|
-
key: 4,
|
|
1048
|
-
class: "fl-preview-text"
|
|
1049
|
-
};
|
|
1050
|
-
const _hoisted_23$1 = {
|
|
1129
|
+
const _hoisted_21$1 = ["src", "alt"];
|
|
1130
|
+
const _hoisted_22$1 = ["src"];
|
|
1131
|
+
const _hoisted_23$1 = ["src"];
|
|
1132
|
+
const _hoisted_24$1 = {
|
|
1051
1133
|
key: 0,
|
|
1052
1134
|
class: "fl-preview-note"
|
|
1053
1135
|
};
|
|
1054
|
-
const
|
|
1055
|
-
const
|
|
1136
|
+
const _hoisted_25$1 = ["innerHTML"];
|
|
1137
|
+
const _hoisted_26$1 = {
|
|
1138
|
+
key: 1,
|
|
1139
|
+
class: "fl-preview-status",
|
|
1140
|
+
role: "status"
|
|
1141
|
+
};
|
|
1142
|
+
const _hoisted_27$1 = { class: "fl-preview-note" };
|
|
1143
|
+
const _hoisted_28$1 = ["srcdoc", "title"];
|
|
1144
|
+
const _hoisted_29$1 = { key: 3 };
|
|
1145
|
+
const _hoisted_30$1 = ["src", "title"];
|
|
1146
|
+
const _hoisted_31$1 = {
|
|
1056
1147
|
key: 6,
|
|
1057
1148
|
class: "fl-preview-info"
|
|
1058
1149
|
};
|
|
1059
|
-
const
|
|
1060
|
-
const
|
|
1150
|
+
const _hoisted_32$1 = ["data-kind"];
|
|
1151
|
+
const _hoisted_33$1 = { class: "fl-preview-message" };
|
|
1061
1152
|
const _sfc_main$1 = /*@__PURE__*/ defineComponent({
|
|
1062
1153
|
__name: "PreviewDialog",
|
|
1063
1154
|
props: {
|
|
@@ -1090,7 +1181,9 @@ const _sfc_main$1 = /*@__PURE__*/ defineComponent({
|
|
|
1090
1181
|
/**
|
|
1091
1182
|
* File preview in a native <dialog>, without leaving the page.
|
|
1092
1183
|
*
|
|
1093
|
-
* image / video / audio: native elements; text: the first `maxTextBytes
|
|
1184
|
+
* image / video / audio: native elements; text: the first `maxTextBytes`,
|
|
1185
|
+
* with Markdown and HTML switchable between source (default) and rendered
|
|
1186
|
+
* (Markdown sanitised in VitePress' doc style, HTML in a script-less sandbox);
|
|
1094
1187
|
* through a Range request; pdf: the first matching OpenList `iframe_previews`
|
|
1095
1188
|
* viewer, else the browser's reader through a Blob. Anything else (Office
|
|
1096
1189
|
* included), failures, oversized PDFs and demo mode: file info + download.
|
|
@@ -1109,8 +1202,18 @@ const _sfc_main$1 = /*@__PURE__*/ defineComponent({
|
|
|
1109
1202
|
const blobUrl = ref("");
|
|
1110
1203
|
const rotation = ref(0);
|
|
1111
1204
|
const actualSize = ref(false);
|
|
1205
|
+
/** Markdown / HTML: show the source or render it. Kept while the page is open. */
|
|
1206
|
+
const view = ref("source");
|
|
1207
|
+
const renderedHtml = ref("");
|
|
1112
1208
|
let controller;
|
|
1113
1209
|
let loadSeq = 0;
|
|
1210
|
+
/** Text files that can also be rendered. */
|
|
1211
|
+
const renderAs = computed(() => {
|
|
1212
|
+
const name = props.file?.name ?? "";
|
|
1213
|
+
if (/\.(md|markdown)$/i.test(name)) return "markdown";
|
|
1214
|
+
if (/\.html?$/i.test(name)) return "html";
|
|
1215
|
+
return null;
|
|
1216
|
+
});
|
|
1114
1217
|
const tooLarge = computed(() => kind.value === "pdf" && !props.viewer && (props.file?.size ?? 0) > props.maxPdfBytes);
|
|
1115
1218
|
const mode = computed(() => {
|
|
1116
1219
|
if (props.demo) return "demo";
|
|
@@ -1120,6 +1223,7 @@ const _sfc_main$1 = /*@__PURE__*/ defineComponent({
|
|
|
1120
1223
|
return kind.value;
|
|
1121
1224
|
});
|
|
1122
1225
|
const busy = computed(() => !props.demo && kind.value !== "none" && !props.error && !bodyFailed.value && (props.resolving || loadingBody.value || !props.src && !tooLarge.value));
|
|
1226
|
+
const canRender = computed(() => !!renderAs.value && mode.value === "text" && !busy.value);
|
|
1123
1227
|
const infoMessage = computed(() => {
|
|
1124
1228
|
const file = props.file;
|
|
1125
1229
|
if (!file) return "";
|
|
@@ -1140,6 +1244,7 @@ const _sfc_main$1 = /*@__PURE__*/ defineComponent({
|
|
|
1140
1244
|
loadingBody.value = false;
|
|
1141
1245
|
bodyFailed.value = false;
|
|
1142
1246
|
textContent.value = "";
|
|
1247
|
+
renderedHtml.value = "";
|
|
1143
1248
|
truncated.value = false;
|
|
1144
1249
|
rotation.value = 0;
|
|
1145
1250
|
actualSize.value = false;
|
|
@@ -1221,6 +1326,20 @@ const _sfc_main$1 = /*@__PURE__*/ defineComponent({
|
|
|
1221
1326
|
props.error,
|
|
1222
1327
|
props.demo
|
|
1223
1328
|
], () => void loadBody(), { immediate: true });
|
|
1329
|
+
watch(() => [
|
|
1330
|
+
view.value,
|
|
1331
|
+
renderAs.value,
|
|
1332
|
+
textContent.value
|
|
1333
|
+
], async ([current, as, text]) => {
|
|
1334
|
+
if (current !== "rendered" || as !== "markdown" || !text) return;
|
|
1335
|
+
const seq = loadSeq;
|
|
1336
|
+
try {
|
|
1337
|
+
const html = await renderMarkdown(text, (alt) => t("imageOmitted", { alt }));
|
|
1338
|
+
if (seq === loadSeq) renderedHtml.value = html;
|
|
1339
|
+
} catch {
|
|
1340
|
+
if (seq === loadSeq) view.value = "source";
|
|
1341
|
+
}
|
|
1342
|
+
});
|
|
1224
1343
|
watch(() => props.open, (open) => {
|
|
1225
1344
|
const el = dialog.value;
|
|
1226
1345
|
if (!el) return;
|
|
@@ -1270,49 +1389,66 @@ const _sfc_main$1 = /*@__PURE__*/ defineComponent({
|
|
|
1270
1389
|
"aria-hidden": "true"
|
|
1271
1390
|
}, toDisplayString(unref(extOf)(__props.file.name) || "FILE"), 9, _hoisted_4$1),
|
|
1272
1391
|
createElementVNode("div", _hoisted_5$1, [createElementVNode("span", _hoisted_6$1, toDisplayString(__props.file.name), 1), createElementVNode("span", _hoisted_7$1, toDisplayString(unref(formatSize)(__props.file.size)) + " · " + toDisplayString(unref(formatDate)(__props.file.modified)), 1)]),
|
|
1273
|
-
__props.total > 1 || mode.value === "image" && !busy.value ? (openBlock(), createElementBlock("div", _hoisted_8$1, [
|
|
1274
|
-
|
|
1275
|
-
|
|
1392
|
+
__props.total > 1 || mode.value === "image" && !busy.value || canRender.value ? (openBlock(), createElementBlock("div", _hoisted_8$1, [
|
|
1393
|
+
__props.total > 1 ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
|
|
1394
|
+
createElementVNode("button", {
|
|
1395
|
+
class: "fl-preview-tool",
|
|
1396
|
+
type: "button",
|
|
1397
|
+
"aria-label": t("previous"),
|
|
1398
|
+
title: t("previous"),
|
|
1399
|
+
onClick: _cache[0] || (_cache[0] = ($event) => emit("prev"))
|
|
1400
|
+
}, [createVNode(_sfc_main$2, {
|
|
1401
|
+
name: "previous",
|
|
1402
|
+
size: 18
|
|
1403
|
+
})], 8, _hoisted_9$1),
|
|
1404
|
+
createElementVNode("span", _hoisted_10$1, toDisplayString(__props.position) + " / " + toDisplayString(__props.total), 1),
|
|
1405
|
+
createElementVNode("button", {
|
|
1406
|
+
class: "fl-preview-tool",
|
|
1407
|
+
type: "button",
|
|
1408
|
+
"aria-label": t("next"),
|
|
1409
|
+
title: t("next"),
|
|
1410
|
+
onClick: _cache[1] || (_cache[1] = ($event) => emit("next"))
|
|
1411
|
+
}, [createVNode(_sfc_main$2, {
|
|
1412
|
+
name: "next",
|
|
1413
|
+
size: 18
|
|
1414
|
+
})], 8, _hoisted_11$1)
|
|
1415
|
+
], 64)) : createCommentVNode("v-if", true),
|
|
1416
|
+
mode.value === "image" && !busy.value ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createElementVNode("button", {
|
|
1417
|
+
class: "fl-preview-tool fl-preview-rotate",
|
|
1276
1418
|
type: "button",
|
|
1277
|
-
"aria-label": t("
|
|
1278
|
-
title: t("
|
|
1279
|
-
onClick: _cache[
|
|
1419
|
+
"aria-label": t("rotate"),
|
|
1420
|
+
title: t("rotate"),
|
|
1421
|
+
onClick: _cache[2] || (_cache[2] = ($event) => rotation.value = (rotation.value + 90) % 360)
|
|
1280
1422
|
}, [createVNode(_sfc_main$2, {
|
|
1281
|
-
name: "
|
|
1282
|
-
size:
|
|
1283
|
-
})], 8,
|
|
1284
|
-
|
|
1285
|
-
createElementVNode("button", {
|
|
1286
|
-
class: "fl-preview-tool",
|
|
1423
|
+
name: "refresh",
|
|
1424
|
+
size: 17
|
|
1425
|
+
})], 8, _hoisted_12$1), createElementVNode("button", {
|
|
1426
|
+
class: "fl-preview-tool fl-preview-zoom",
|
|
1287
1427
|
type: "button",
|
|
1288
|
-
"aria-
|
|
1289
|
-
|
|
1290
|
-
|
|
1428
|
+
"aria-pressed": actualSize.value,
|
|
1429
|
+
"aria-label": t("actualSize"),
|
|
1430
|
+
title: t("actualSize"),
|
|
1431
|
+
onClick: _cache[3] || (_cache[3] = ($event) => actualSize.value = !actualSize.value)
|
|
1291
1432
|
}, [createVNode(_sfc_main$2, {
|
|
1292
|
-
name: "
|
|
1293
|
-
size:
|
|
1294
|
-
})], 8,
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
}, [createVNode(_sfc_main$2, {
|
|
1312
|
-
name: actualSize.value ? "zoomOut" : "zoomIn",
|
|
1313
|
-
size: 17
|
|
1314
|
-
}, null, 8, ["name"])], 8, _hoisted_13$1)], 64)) : createCommentVNode("v-if", true)])) : createCommentVNode("v-if", true),
|
|
1315
|
-
createElementVNode("div", _hoisted_14$1, [!__props.demo ? (openBlock(), createElementBlock("button", {
|
|
1433
|
+
name: actualSize.value ? "zoomOut" : "zoomIn",
|
|
1434
|
+
size: 17
|
|
1435
|
+
}, null, 8, ["name"])], 8, _hoisted_13$1)], 64)) : createCommentVNode("v-if", true),
|
|
1436
|
+
canRender.value ? (openBlock(), createElementBlock("span", {
|
|
1437
|
+
key: 2,
|
|
1438
|
+
class: "fl-preview-view",
|
|
1439
|
+
role: "group",
|
|
1440
|
+
"aria-label": t("viewMode")
|
|
1441
|
+
}, [(openBlock(), createElementBlock(Fragment, null, renderList(["source", "rendered"], (option) => {
|
|
1442
|
+
return createElementVNode("button", {
|
|
1443
|
+
key: option,
|
|
1444
|
+
class: "fl-preview-view-btn",
|
|
1445
|
+
type: "button",
|
|
1446
|
+
"aria-pressed": view.value === option,
|
|
1447
|
+
onClick: ($event) => view.value = option
|
|
1448
|
+
}, toDisplayString(t(option === "source" ? "viewSource" : "viewRendered")), 9, _hoisted_15$1);
|
|
1449
|
+
}), 64))], 8, _hoisted_14$1)) : createCommentVNode("v-if", true)
|
|
1450
|
+
])) : createCommentVNode("v-if", true),
|
|
1451
|
+
createElementVNode("div", _hoisted_16$1, [!__props.demo ? (openBlock(), createElementBlock("button", {
|
|
1316
1452
|
key: 0,
|
|
1317
1453
|
class: "fl-preview-tool fl-preview-download",
|
|
1318
1454
|
type: "button",
|
|
@@ -1322,7 +1458,7 @@ const _sfc_main$1 = /*@__PURE__*/ defineComponent({
|
|
|
1322
1458
|
}, [createVNode(_sfc_main$2, {
|
|
1323
1459
|
name: "download",
|
|
1324
1460
|
size: 17
|
|
1325
|
-
})], 8,
|
|
1461
|
+
})], 8, _hoisted_17$1)) : createCommentVNode("v-if", true), createElementVNode("button", {
|
|
1326
1462
|
class: "fl-preview-tool fl-preview-close",
|
|
1327
1463
|
type: "button",
|
|
1328
1464
|
autofocus: "",
|
|
@@ -1332,18 +1468,18 @@ const _sfc_main$1 = /*@__PURE__*/ defineComponent({
|
|
|
1332
1468
|
}, [createVNode(_sfc_main$2, {
|
|
1333
1469
|
name: "close",
|
|
1334
1470
|
size: 18
|
|
1335
|
-
})], 8,
|
|
1471
|
+
})], 8, _hoisted_18$1)])
|
|
1336
1472
|
]), createElementVNode("div", {
|
|
1337
1473
|
class: "fl-preview-body",
|
|
1338
1474
|
"data-mode": busy.value ? "loading" : mode.value
|
|
1339
|
-
}, [busy.value ? (openBlock(), createElementBlock("div",
|
|
1475
|
+
}, [busy.value ? (openBlock(), createElementBlock("div", _hoisted_20$1, toDisplayString(t("loading")), 1)) : mode.value === "image" ? (openBlock(), createElementBlock("img", {
|
|
1340
1476
|
key: 1,
|
|
1341
1477
|
class: normalizeClass(["fl-preview-image", { "fl-preview-actual": actualSize.value }]),
|
|
1342
1478
|
src: __props.src,
|
|
1343
1479
|
alt: __props.file.name,
|
|
1344
1480
|
style: normalizeStyle({ transform: rotation.value ? `rotate(${rotation.value}deg)` : void 0 }),
|
|
1345
1481
|
onError: markFailed
|
|
1346
|
-
}, null, 46,
|
|
1482
|
+
}, null, 46, _hoisted_21$1)) : mode.value === "video" ? (openBlock(), createElementBlock("video", {
|
|
1347
1483
|
key: 2,
|
|
1348
1484
|
class: "fl-preview-video",
|
|
1349
1485
|
src: __props.src,
|
|
@@ -1351,25 +1487,42 @@ const _sfc_main$1 = /*@__PURE__*/ defineComponent({
|
|
|
1351
1487
|
playsinline: "",
|
|
1352
1488
|
preload: "metadata",
|
|
1353
1489
|
onError: markFailed
|
|
1354
|
-
}, null, 40,
|
|
1490
|
+
}, null, 40, _hoisted_22$1)) : mode.value === "audio" ? (openBlock(), createElementBlock("audio", {
|
|
1355
1491
|
key: 3,
|
|
1356
1492
|
class: "fl-preview-audio",
|
|
1357
1493
|
src: __props.src,
|
|
1358
1494
|
controls: "",
|
|
1359
1495
|
preload: "metadata",
|
|
1360
1496
|
onError: markFailed
|
|
1361
|
-
}, null, 40,
|
|
1497
|
+
}, null, 40, _hoisted_23$1)) : mode.value === "text" ? (openBlock(), createElementBlock("div", {
|
|
1498
|
+
key: 4,
|
|
1499
|
+
class: normalizeClass(["fl-preview-text", { "fl-preview-rendered": renderAs.value && view.value === "rendered" }])
|
|
1500
|
+
}, [truncated.value ? (openBlock(), createElementBlock("p", _hoisted_24$1, toDisplayString(t("textTruncated", { size: unref(formatSize)(__props.maxTextBytes) })), 1)) : createCommentVNode("v-if", true), renderAs.value === "markdown" && view.value === "rendered" ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createCommentVNode(" sanitised by renderMarkdown (DOMPurify) "), renderedHtml.value ? (openBlock(), createElementBlock("div", {
|
|
1501
|
+
key: 0,
|
|
1502
|
+
class: "vp-doc fl-md",
|
|
1503
|
+
innerHTML: renderedHtml.value
|
|
1504
|
+
}, null, 8, _hoisted_25$1)) : (openBlock(), createElementBlock("div", _hoisted_26$1, toDisplayString(t("loading")), 1))], 64)) : renderAs.value === "html" && view.value === "rendered" ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [
|
|
1505
|
+
createElementVNode("p", _hoisted_27$1, toDisplayString(t("htmlSandboxNote")), 1),
|
|
1506
|
+
createCommentVNode(" empty sandbox: no scripts, no forms, no popups, an opaque origin "),
|
|
1507
|
+
createElementVNode("iframe", {
|
|
1508
|
+
class: "fl-preview-html",
|
|
1509
|
+
sandbox: "",
|
|
1510
|
+
referrerpolicy: "no-referrer",
|
|
1511
|
+
srcdoc: textContent.value,
|
|
1512
|
+
title: __props.file.name
|
|
1513
|
+
}, null, 8, _hoisted_28$1)
|
|
1514
|
+
], 64)) : (openBlock(), createElementBlock("pre", _hoisted_29$1, toDisplayString(textContent.value), 1))], 2)) : mode.value === "pdf" ? (openBlock(), createElementBlock("iframe", {
|
|
1362
1515
|
key: 5,
|
|
1363
1516
|
class: "fl-preview-frame",
|
|
1364
1517
|
src: __props.viewer || blobUrl.value,
|
|
1365
1518
|
title: __props.file.name
|
|
1366
|
-
}, null, 8,
|
|
1519
|
+
}, null, 8, _hoisted_30$1)) : (openBlock(), createElementBlock("div", _hoisted_31$1, [
|
|
1367
1520
|
createElementVNode("span", {
|
|
1368
1521
|
class: "fl-type fl-preview-badge",
|
|
1369
1522
|
"data-kind": unref(fileKind)(__props.file.name),
|
|
1370
1523
|
"aria-hidden": "true"
|
|
1371
|
-
}, toDisplayString(unref(extOf)(__props.file.name) || "FILE"), 9,
|
|
1372
|
-
createElementVNode("p",
|
|
1524
|
+
}, toDisplayString(unref(extOf)(__props.file.name) || "FILE"), 9, _hoisted_32$1),
|
|
1525
|
+
createElementVNode("p", _hoisted_33$1, toDisplayString(infoMessage.value), 1),
|
|
1373
1526
|
!__props.demo ? (openBlock(), createElementBlock("button", {
|
|
1374
1527
|
key: 0,
|
|
1375
1528
|
class: "fl-btn fl-btn-primary",
|
|
@@ -1379,7 +1532,7 @@ const _sfc_main$1 = /*@__PURE__*/ defineComponent({
|
|
|
1379
1532
|
name: "download",
|
|
1380
1533
|
size: 15
|
|
1381
1534
|
}), createTextVNode(" " + toDisplayString(t("download")), 1)])) : createCommentVNode("v-if", true)
|
|
1382
|
-
]))], 8,
|
|
1535
|
+
]))], 8, _hoisted_19$1)])) : createCommentVNode("v-if", true)], 40, _hoisted_1$1);
|
|
1383
1536
|
};
|
|
1384
1537
|
}
|
|
1385
1538
|
});
|
|
@@ -1406,9 +1559,9 @@ function toNodes(items, parent, password) {
|
|
|
1406
1559
|
zipPath: [...parent.zipPath, item.name]
|
|
1407
1560
|
}));
|
|
1408
1561
|
}
|
|
1409
|
-
function sortTree(nodes, key, ascending) {
|
|
1410
|
-
nodes.sort((a, b) => compareNodes(a, b, key, ascending));
|
|
1411
|
-
for (const node of nodes) if (node.children.length) sortTree(node.children, key, ascending);
|
|
1562
|
+
function sortTree(nodes, key, ascending, locale) {
|
|
1563
|
+
nodes.sort((a, b) => compareNodes(a, b, key, ascending, locale));
|
|
1564
|
+
for (const node of nodes) if (node.children.length) sortTree(node.children, key, ascending, locale);
|
|
1412
1565
|
}
|
|
1413
1566
|
/** Loaded files at or under a node. */
|
|
1414
1567
|
function descendantFiles(node) {
|
|
@@ -1724,24 +1877,28 @@ const _hoisted_52 = {
|
|
|
1724
1877
|
const _hoisted_53 = ["data-kind"];
|
|
1725
1878
|
const _hoisted_54 = { class: "fl-label" };
|
|
1726
1879
|
const _hoisted_55 = ["onClick"];
|
|
1727
|
-
const _hoisted_56 = {
|
|
1728
|
-
|
|
1880
|
+
const _hoisted_56 = {
|
|
1881
|
+
key: 0,
|
|
1882
|
+
class: "fl-hit"
|
|
1883
|
+
};
|
|
1884
|
+
const _hoisted_57 = { class: "fl-meta" };
|
|
1885
|
+
const _hoisted_58 = {
|
|
1729
1886
|
key: 5,
|
|
1730
1887
|
class: "fl-count"
|
|
1731
1888
|
};
|
|
1732
|
-
const
|
|
1733
|
-
const
|
|
1889
|
+
const _hoisted_59 = ["id"];
|
|
1890
|
+
const _hoisted_60 = [
|
|
1734
1891
|
"aria-label",
|
|
1735
1892
|
"title",
|
|
1736
1893
|
"onClick"
|
|
1737
1894
|
];
|
|
1738
|
-
const
|
|
1895
|
+
const _hoisted_61 = {
|
|
1739
1896
|
key: 8,
|
|
1740
1897
|
class: "fl-loading",
|
|
1741
1898
|
"aria-hidden": "true"
|
|
1742
1899
|
};
|
|
1743
|
-
const
|
|
1744
|
-
const
|
|
1900
|
+
const _hoisted_62 = ["onSubmit", "onKeydown"];
|
|
1901
|
+
const _hoisted_63 = [
|
|
1745
1902
|
"onUpdate:modelValue",
|
|
1746
1903
|
"data-unlock",
|
|
1747
1904
|
"placeholder",
|
|
@@ -1749,40 +1906,49 @@ const _hoisted_62 = [
|
|
|
1749
1906
|
"aria-invalid",
|
|
1750
1907
|
"aria-describedby"
|
|
1751
1908
|
];
|
|
1752
|
-
const
|
|
1909
|
+
const _hoisted_64 = [
|
|
1753
1910
|
"aria-pressed",
|
|
1754
1911
|
"aria-label",
|
|
1755
1912
|
"title",
|
|
1756
1913
|
"onClick"
|
|
1757
1914
|
];
|
|
1758
|
-
const
|
|
1759
|
-
const
|
|
1915
|
+
const _hoisted_65 = ["disabled"];
|
|
1916
|
+
const _hoisted_66 = [
|
|
1760
1917
|
"aria-label",
|
|
1761
1918
|
"title",
|
|
1762
1919
|
"onClick"
|
|
1763
1920
|
];
|
|
1764
|
-
const
|
|
1765
|
-
const
|
|
1766
|
-
const
|
|
1767
|
-
const
|
|
1768
|
-
const
|
|
1921
|
+
const _hoisted_67 = { class: "fl-cell fl-cell-size" };
|
|
1922
|
+
const _hoisted_68 = { class: "fl-cell fl-cell-date" };
|
|
1923
|
+
const _hoisted_69 = { class: "fl-cell fl-cell-op" };
|
|
1924
|
+
const _hoisted_70 = ["aria-label", "onClick"];
|
|
1925
|
+
const _hoisted_71 = [
|
|
1769
1926
|
"aria-label",
|
|
1770
1927
|
"aria-expanded",
|
|
1771
1928
|
"onClick"
|
|
1772
1929
|
];
|
|
1773
|
-
const
|
|
1930
|
+
const _hoisted_72 = [
|
|
1774
1931
|
"aria-label",
|
|
1775
1932
|
"title",
|
|
1776
1933
|
"onClick"
|
|
1777
1934
|
];
|
|
1778
|
-
const
|
|
1935
|
+
const _hoisted_73 = [
|
|
1779
1936
|
"aria-label",
|
|
1780
1937
|
"title",
|
|
1781
1938
|
"onClick"
|
|
1782
1939
|
];
|
|
1783
|
-
const _hoisted_73 = { class: "fl-foot" };
|
|
1784
1940
|
const _hoisted_74 = {
|
|
1785
1941
|
key: 4,
|
|
1942
|
+
class: "fl-row fl-deep",
|
|
1943
|
+
role: "status"
|
|
1944
|
+
};
|
|
1945
|
+
const _hoisted_75 = { class: "fl-cell fl-more-cell" };
|
|
1946
|
+
const _hoisted_76 = { class: "fl-more-count" };
|
|
1947
|
+
const _hoisted_77 = { class: "fl-more-count" };
|
|
1948
|
+
const _hoisted_78 = { class: "fl-more-count" };
|
|
1949
|
+
const _hoisted_79 = { class: "fl-foot" };
|
|
1950
|
+
const _hoisted_80 = {
|
|
1951
|
+
key: 5,
|
|
1786
1952
|
class: "fl-toast",
|
|
1787
1953
|
role: "status"
|
|
1788
1954
|
};
|
|
@@ -1806,6 +1972,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1806
1972
|
default: true
|
|
1807
1973
|
},
|
|
1808
1974
|
pageSize: { default: 200 },
|
|
1975
|
+
deepSearchLimit: { default: 500 },
|
|
1809
1976
|
zipWarnSize: {},
|
|
1810
1977
|
zipMaxSize: {},
|
|
1811
1978
|
locale: { default: "zh-CN" },
|
|
@@ -1870,7 +2037,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1870
2037
|
return isNetworkError(error) ? `${message} ${t("corsHint")}` : message;
|
|
1871
2038
|
}
|
|
1872
2039
|
function sortNodes(nodes) {
|
|
1873
|
-
sortTree(nodes, sortKey.value, sortAsc.value);
|
|
2040
|
+
sortTree(nodes, sortKey.value, sortAsc.value, props.locale);
|
|
1874
2041
|
}
|
|
1875
2042
|
function focusUnlock(path) {
|
|
1876
2043
|
nextTick(() => {
|
|
@@ -1975,7 +2142,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1975
2142
|
* Load a folder's children. A password error locks the folder instead of
|
|
1976
2143
|
* toasting; `prompt` also shows its same-row input (and focuses it).
|
|
1977
2144
|
*/
|
|
1978
|
-
async function loadChildren(node, prompt = false) {
|
|
2145
|
+
async function loadChildren(node, prompt = false, quiet = false) {
|
|
1979
2146
|
if (node.loaded) return true;
|
|
1980
2147
|
if (node.lock) {
|
|
1981
2148
|
if (prompt) startPrompt(node, prompt === "focus");
|
|
@@ -1991,7 +2158,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1991
2158
|
node.expanded = false;
|
|
1992
2159
|
node.lock = newLock(false, passwords.dropStale(rememberedAt) ? "stale" : "");
|
|
1993
2160
|
if (prompt) startPrompt(node, prompt === "focus");
|
|
1994
|
-
} else showToast(failureMessage("folderFailed", error));
|
|
2161
|
+
} else if (!quiet) showToast(failureMessage("folderFailed", error));
|
|
1995
2162
|
return false;
|
|
1996
2163
|
} finally {
|
|
1997
2164
|
node.loading = false;
|
|
@@ -2078,6 +2245,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
2078
2245
|
}
|
|
2079
2246
|
/** First load, or a retry after an error: shows the loading state. */
|
|
2080
2247
|
async function loadRoot() {
|
|
2248
|
+
stopDeepSearch();
|
|
2081
2249
|
refreshSeq += 1;
|
|
2082
2250
|
refreshing.value = false;
|
|
2083
2251
|
loadingRoot.value = true;
|
|
@@ -2101,6 +2269,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
2101
2269
|
*/
|
|
2102
2270
|
async function refresh() {
|
|
2103
2271
|
if (refreshing.value || loadingRoot.value) return;
|
|
2272
|
+
stopDeepSearch();
|
|
2104
2273
|
if (!roots.value.length || errorMsg.value || rootLock.value) {
|
|
2105
2274
|
await loadRoot();
|
|
2106
2275
|
return;
|
|
@@ -2200,6 +2369,124 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
2200
2369
|
return out;
|
|
2201
2370
|
});
|
|
2202
2371
|
const visible = computed(() => rows.value.filter((row) => !isMore(row)));
|
|
2372
|
+
/** A name split around the filter keyword, for highlighting. */
|
|
2373
|
+
function nameParts(name) {
|
|
2374
|
+
const query = keyword.value.trim().toLowerCase();
|
|
2375
|
+
if (!query) return [{
|
|
2376
|
+
text: name,
|
|
2377
|
+
hit: false
|
|
2378
|
+
}];
|
|
2379
|
+
const parts = [];
|
|
2380
|
+
const lower = name.toLowerCase();
|
|
2381
|
+
let from = 0;
|
|
2382
|
+
for (let at = lower.indexOf(query); at !== -1; at = lower.indexOf(query, from)) {
|
|
2383
|
+
if (at > from) parts.push({
|
|
2384
|
+
text: name.slice(from, at),
|
|
2385
|
+
hit: false
|
|
2386
|
+
});
|
|
2387
|
+
parts.push({
|
|
2388
|
+
text: name.slice(at, at + query.length),
|
|
2389
|
+
hit: true
|
|
2390
|
+
});
|
|
2391
|
+
from = at + query.length;
|
|
2392
|
+
}
|
|
2393
|
+
if (from < name.length) parts.push({
|
|
2394
|
+
text: name.slice(from),
|
|
2395
|
+
hit: false
|
|
2396
|
+
});
|
|
2397
|
+
return parts;
|
|
2398
|
+
}
|
|
2399
|
+
/**
|
|
2400
|
+
* The filter only sees loaded folders. Deep search loads the rest under the
|
|
2401
|
+
* mounted paths (four at a time, `deepSearchLimit` per run) so matches appear
|
|
2402
|
+
* in place, in their folders, like any other row. Locked folders are skipped.
|
|
2403
|
+
*/
|
|
2404
|
+
const deep = reactive({
|
|
2405
|
+
running: false,
|
|
2406
|
+
searched: 0,
|
|
2407
|
+
skipped: 0,
|
|
2408
|
+
failed: 0,
|
|
2409
|
+
capped: false,
|
|
2410
|
+
done: false
|
|
2411
|
+
});
|
|
2412
|
+
let deepSeq = 0;
|
|
2413
|
+
/** Folders that are known but not loaded yet (locked ones excluded). */
|
|
2414
|
+
function unloadedFolders() {
|
|
2415
|
+
const out = [];
|
|
2416
|
+
const walk = (nodes) => {
|
|
2417
|
+
for (const node of nodes) {
|
|
2418
|
+
if (!node.is_dir || node.lock) continue;
|
|
2419
|
+
if (!node.loaded) out.push(node);
|
|
2420
|
+
else walk(node.children);
|
|
2421
|
+
}
|
|
2422
|
+
};
|
|
2423
|
+
walk(roots.value);
|
|
2424
|
+
return out;
|
|
2425
|
+
}
|
|
2426
|
+
const hasUnloaded = computed(() => unloadedFolders().length > 0);
|
|
2427
|
+
const deepRow = computed(() => {
|
|
2428
|
+
if (!keyword.value.trim()) return null;
|
|
2429
|
+
if (deep.running) return "running";
|
|
2430
|
+
if (deep.capped) return "capped";
|
|
2431
|
+
if (hasUnloaded.value) return "idle";
|
|
2432
|
+
return deep.done ? "done" : null;
|
|
2433
|
+
});
|
|
2434
|
+
async function deepSearch() {
|
|
2435
|
+
const seq = ++deepSeq;
|
|
2436
|
+
const limit = Math.max(1, Math.floor(props.deepSearchLimit ?? 500));
|
|
2437
|
+
const runStart = deep.searched;
|
|
2438
|
+
Object.assign(deep, {
|
|
2439
|
+
running: true,
|
|
2440
|
+
capped: false,
|
|
2441
|
+
done: false,
|
|
2442
|
+
skipped: 0,
|
|
2443
|
+
failed: 0
|
|
2444
|
+
});
|
|
2445
|
+
let wave = unloadedFolders();
|
|
2446
|
+
while (wave.length && seq === deepSeq) {
|
|
2447
|
+
const next = [];
|
|
2448
|
+
const queue = [...wave];
|
|
2449
|
+
const worker = async () => {
|
|
2450
|
+
for (let node = queue.shift(); node && seq === deepSeq; node = queue.shift()) {
|
|
2451
|
+
if (deep.searched - runStart >= limit) return;
|
|
2452
|
+
deep.searched += 1;
|
|
2453
|
+
if (!await loadChildren(node, false, true)) {
|
|
2454
|
+
if (node.lock) deep.skipped += 1;
|
|
2455
|
+
else deep.failed += 1;
|
|
2456
|
+
continue;
|
|
2457
|
+
}
|
|
2458
|
+
for (const child of node.children) if (child.is_dir && !child.loaded && !child.lock) next.push(child);
|
|
2459
|
+
}
|
|
2460
|
+
};
|
|
2461
|
+
await Promise.all(Array.from({ length: Math.min(4, queue.length) }, worker));
|
|
2462
|
+
if (deep.searched - runStart >= limit) break;
|
|
2463
|
+
wave = next;
|
|
2464
|
+
}
|
|
2465
|
+
if (seq !== deepSeq) return;
|
|
2466
|
+
deep.running = false;
|
|
2467
|
+
deep.capped = hasUnloaded.value && deep.searched - runStart >= limit;
|
|
2468
|
+
deep.done = !deep.capped;
|
|
2469
|
+
}
|
|
2470
|
+
function stopDeepSearch() {
|
|
2471
|
+
deepSeq += 1;
|
|
2472
|
+
deep.running = false;
|
|
2473
|
+
}
|
|
2474
|
+
watch(keyword, (value) => {
|
|
2475
|
+
if (value.trim()) return;
|
|
2476
|
+
stopDeepSearch();
|
|
2477
|
+
Object.assign(deep, {
|
|
2478
|
+
searched: 0,
|
|
2479
|
+
skipped: 0,
|
|
2480
|
+
failed: 0,
|
|
2481
|
+
capped: false,
|
|
2482
|
+
done: false
|
|
2483
|
+
});
|
|
2484
|
+
});
|
|
2485
|
+
const deepSummary = computed(() => [
|
|
2486
|
+
deepRow.value === "capped" ? t("deepCapped", { count: deep.searched }) : t("deepDone", { count: deep.searched }),
|
|
2487
|
+
deep.skipped ? t("deepSkipped", { count: deep.skipped }) : "",
|
|
2488
|
+
deep.failed ? t("deepFailed", { count: deep.failed }) : ""
|
|
2489
|
+
].filter(Boolean).join(" · "));
|
|
2203
2490
|
const stats = computed(() => folderStats(roots.value, selected.value));
|
|
2204
2491
|
const noStats = {
|
|
2205
2492
|
files: 0,
|
|
@@ -2736,14 +3023,16 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
2736
3023
|
createElementVNode("span", _hoisted_54, [createElementVNode("span", {
|
|
2737
3024
|
class: normalizeClass(["fl-name", { "fl-name-dir": node.is_dir }]),
|
|
2738
3025
|
onClick: ($event) => node.lock || node.is_dir ? toggleExpand(node) : download(node)
|
|
2739
|
-
},
|
|
2740
|
-
|
|
3026
|
+
}, [(openBlock(true), createElementBlock(Fragment, null, renderList(nameParts(node.name), (part, at) => {
|
|
3027
|
+
return openBlock(), createElementBlock(Fragment, { key: at }, [part.hit ? (openBlock(), createElementBlock("mark", _hoisted_56, toDisplayString(part.text), 1)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(part.text), 1)], 64))], 64);
|
|
3028
|
+
}), 128))], 10, _hoisted_55), createElementVNode("span", _hoisted_57, [!node.is_dir ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createTextVNode(toDisplayString(unref(formatSize)(node.size)) + " · " + toDisplayString(unref(formatDate)(node.modified)), 1)], 64)) : node.loaded ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(t("folderItems", { count: statsOf(node).files })) + " · " + toDisplayString(unref(formatSize)(statsOf(node).bytes)), 1)], 64)) : createCommentVNode("v-if", true)])]),
|
|
3029
|
+
node.is_dir && node.loaded ? (openBlock(), createElementBlock("span", _hoisted_58, toDisplayString(t("folderItems", { count: statsOf(node).files })), 1)) : createCommentVNode("v-if", true),
|
|
2741
3030
|
node.lock?.prompting && node.lock.error ? (openBlock(), createElementBlock("span", {
|
|
2742
3031
|
key: 6,
|
|
2743
3032
|
id: `${unref(uid)}-error-${index}`,
|
|
2744
3033
|
class: "fl-unlock-message",
|
|
2745
3034
|
role: "alert"
|
|
2746
|
-
}, toDisplayString(unlockErrorText(node.lock.error)), 9,
|
|
3035
|
+
}, toDisplayString(unlockErrorText(node.lock.error)), 9, _hoisted_59)) : createCommentVNode("v-if", true),
|
|
2747
3036
|
!node.lock && unref(remembered).has(node.path) ? (openBlock(), createElementBlock("button", {
|
|
2748
3037
|
key: 7,
|
|
2749
3038
|
class: "fl-remembered",
|
|
@@ -2754,8 +3043,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
2754
3043
|
}, [createVNode(_sfc_main$2, {
|
|
2755
3044
|
name: "key",
|
|
2756
3045
|
size: 11
|
|
2757
|
-
}), createTextVNode(" " + toDisplayString(t("remembered")) + " · " + toDisplayString(t("forgetPassword")), 1)], 8,
|
|
2758
|
-
node.loading ? (openBlock(), createElementBlock("span",
|
|
3046
|
+
}), createTextVNode(" " + toDisplayString(t("remembered")) + " · " + toDisplayString(t("forgetPassword")), 1)], 8, _hoisted_60)) : createCommentVNode("v-if", true),
|
|
3047
|
+
node.loading ? (openBlock(), createElementBlock("span", _hoisted_61, "…")) : createCommentVNode("v-if", true)
|
|
2759
3048
|
], 8, _hoisted_48),
|
|
2760
3049
|
node.lock?.prompting ? (openBlock(), createElementBlock("form", {
|
|
2761
3050
|
key: 0,
|
|
@@ -2777,7 +3066,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
2777
3066
|
"aria-label": t("passwordFor", { name: node.name }),
|
|
2778
3067
|
"aria-invalid": !!node.lock.error,
|
|
2779
3068
|
"aria-describedby": node.lock.error ? `${unref(uid)}-error-${index}` : void 0
|
|
2780
|
-
}, null, 8,
|
|
3069
|
+
}, null, 8, _hoisted_63), [[vModelText, node.lock.input]]),
|
|
2781
3070
|
canRemember.value ? (openBlock(), createElementBlock("button", {
|
|
2782
3071
|
key: 0,
|
|
2783
3072
|
class: "fl-unlock-remember",
|
|
@@ -2786,12 +3075,12 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
2786
3075
|
"aria-label": t("rememberPassword"),
|
|
2787
3076
|
title: t("rememberPassword"),
|
|
2788
3077
|
onClick: ($event) => node.lock.remember = !node.lock.remember
|
|
2789
|
-
}, [createVNode(_sfc_main$2, { name: "key" })], 8,
|
|
3078
|
+
}, [createVNode(_sfc_main$2, { name: "key" })], 8, _hoisted_64)) : createCommentVNode("v-if", true),
|
|
2790
3079
|
createElementVNode("button", {
|
|
2791
3080
|
class: "fl-unlock-submit",
|
|
2792
3081
|
type: "submit",
|
|
2793
3082
|
disabled: node.lock.busy || !node.lock.input
|
|
2794
|
-
}, toDisplayString(t("open")), 9,
|
|
3083
|
+
}, toDisplayString(t("open")), 9, _hoisted_65),
|
|
2795
3084
|
createElementVNode("button", {
|
|
2796
3085
|
class: "fl-unlock-cancel",
|
|
2797
3086
|
type: "button",
|
|
@@ -2801,11 +3090,11 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
2801
3090
|
}, [createVNode(_sfc_main$2, {
|
|
2802
3091
|
name: "close",
|
|
2803
3092
|
size: 14
|
|
2804
|
-
})], 8,
|
|
2805
|
-
], 40,
|
|
2806
|
-
createElementVNode("span",
|
|
2807
|
-
createElementVNode("span",
|
|
2808
|
-
createElementVNode("span",
|
|
3093
|
+
})], 8, _hoisted_66)
|
|
3094
|
+
], 40, _hoisted_62)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
|
|
3095
|
+
createElementVNode("span", _hoisted_67, toDisplayString(node.is_dir ? "—" : unref(formatSize)(node.size)), 1),
|
|
3096
|
+
createElementVNode("span", _hoisted_68, toDisplayString(unref(formatDate)(node.modified)), 1),
|
|
3097
|
+
createElementVNode("span", _hoisted_69, [node.lock ? (openBlock(), createElementBlock("button", {
|
|
2809
3098
|
key: 0,
|
|
2810
3099
|
class: "fl-action fl-arrow-end fl-lock",
|
|
2811
3100
|
type: "button",
|
|
@@ -2814,7 +3103,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
2814
3103
|
}, [createVNode(_sfc_main$2, {
|
|
2815
3104
|
name: "lock",
|
|
2816
3105
|
size: 18
|
|
2817
|
-
})], 8,
|
|
3106
|
+
})], 8, _hoisted_70)) : node.is_dir ? (openBlock(), createElementBlock("button", {
|
|
2818
3107
|
key: 1,
|
|
2819
3108
|
class: normalizeClass(["fl-action fl-arrow-end", { "fl-arrow-open": node.expanded }]),
|
|
2820
3109
|
type: "button",
|
|
@@ -2824,25 +3113,49 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
2824
3113
|
}, [createVNode(_sfc_main$2, {
|
|
2825
3114
|
name: "next",
|
|
2826
3115
|
size: 18
|
|
2827
|
-
})], 10,
|
|
3116
|
+
})], 10, _hoisted_71)) : (openBlock(), createElementBlock(Fragment, { key: 2 }, [canPreview(node) ? (openBlock(), createElementBlock("button", {
|
|
2828
3117
|
key: 0,
|
|
2829
3118
|
class: "fl-action fl-preview-btn",
|
|
2830
3119
|
type: "button",
|
|
2831
3120
|
"aria-label": `${t("preview")} ${node.name}`,
|
|
2832
3121
|
title: t("preview"),
|
|
2833
3122
|
onClick: ($event) => preview(node)
|
|
2834
|
-
}, [createVNode(_sfc_main$2, { name: "eye" })], 8,
|
|
3123
|
+
}, [createVNode(_sfc_main$2, { name: "eye" })], 8, _hoisted_72)) : createCommentVNode("v-if", true), createElementVNode("button", {
|
|
2835
3124
|
class: "fl-action fl-download",
|
|
2836
3125
|
type: "button",
|
|
2837
3126
|
"aria-label": `${t("download")} ${node.name}`,
|
|
2838
3127
|
title: t("download"),
|
|
2839
3128
|
onClick: ($event) => download(node)
|
|
2840
|
-
}, [createVNode(_sfc_main$2, { name: "download" })], 8,
|
|
3129
|
+
}, [createVNode(_sfc_main$2, { name: "download" })], 8, _hoisted_73)], 64))])
|
|
2841
3130
|
], 64))
|
|
2842
3131
|
], 6))], 64);
|
|
2843
3132
|
}), 128)),
|
|
2844
|
-
|
|
2845
|
-
|
|
3133
|
+
deepRow.value ? (openBlock(), createElementBlock("div", _hoisted_74, [_cache[14] || (_cache[14] = createElementVNode("span", { class: "fl-cell fl-cell-check" }, null, -1)), createElementVNode("span", _hoisted_75, [_cache[13] || (_cache[13] = createElementVNode("span", {
|
|
3134
|
+
class: "fl-indent",
|
|
3135
|
+
"aria-hidden": "true"
|
|
3136
|
+
}, null, -1)), deepRow.value === "running" ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [
|
|
3137
|
+
createElementVNode("span", _hoisted_76, toDisplayString(t("deepRunning", { count: deep.searched })), 1),
|
|
3138
|
+
createElementVNode("button", {
|
|
3139
|
+
class: "fl-more-btn fl-more-all",
|
|
3140
|
+
type: "button",
|
|
3141
|
+
onClick: stopDeepSearch
|
|
3142
|
+
}, toDisplayString(t("deepStop")), 1),
|
|
3143
|
+
_cache[12] || (_cache[12] = createElementVNode("span", {
|
|
3144
|
+
class: "fl-deep-bar",
|
|
3145
|
+
"aria-hidden": "true"
|
|
3146
|
+
}, null, -1))
|
|
3147
|
+
], 64)) : deepRow.value === "idle" ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [createElementVNode("span", _hoisted_77, toDisplayString(deep.searched ? deepSummary.value : t("deepHint")), 1), createElementVNode("button", {
|
|
3148
|
+
class: "fl-more-btn",
|
|
3149
|
+
type: "button",
|
|
3150
|
+
onClick: deepSearch
|
|
3151
|
+
}, toDisplayString(t("deepSearch")), 1)], 64)) : (openBlock(), createElementBlock(Fragment, { key: 2 }, [createElementVNode("span", _hoisted_78, toDisplayString(deepSummary.value), 1), deepRow.value === "capped" ? (openBlock(), createElementBlock("button", {
|
|
3152
|
+
key: 0,
|
|
3153
|
+
class: "fl-more-btn",
|
|
3154
|
+
type: "button",
|
|
3155
|
+
onClick: deepSearch
|
|
3156
|
+
}, toDisplayString(t("deepContinue")), 1)) : createCommentVNode("v-if", true)], 64))])])) : createCommentVNode("v-if", true),
|
|
3157
|
+
createElementVNode("div", _hoisted_79, [createElementVNode("span", null, toDisplayString(t("loaded", { count: allFiles.value.length })) + " · " + toDisplayString(t("totalSize", { size: unref(formatSize)(unref(totalSize)(allFiles.value)) })), 1)]),
|
|
3158
|
+
toast.value ? (openBlock(), createElementBlock("div", _hoisted_80, toDisplayString(toast.value), 1)) : createCommentVNode("v-if", true),
|
|
2846
3159
|
createVNode(_sfc_main$3, {
|
|
2847
3160
|
open: !!zipDialog.value,
|
|
2848
3161
|
title: zipDialog.value?.title ?? "",
|