vitepress-plugin-filelist 0.4.0 → 0.5.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 +13 -2
- package/dist/client/browser/index.d.ts +26 -0
- package/dist/client/browser/index.js +948 -233
- package/dist/client/ssr/index.d.ts +26 -0
- package/dist/client/ssr/index.js +378 -74
- package/dist/client/style.css +310 -25
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import "../style.css";
|
|
2
|
-
import { Fragment, computed, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, openBlock, ref, renderList, toDisplayString, unref, vModelSelect, vModelText, watch, withDirectives, withKeys } from "vue";
|
|
2
|
+
import { Fragment, computed, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, openBlock, reactive, ref, renderList, toDisplayString, unref, vModelSelect, vModelText, watch, withDirectives, withKeys, withModifiers } from "vue";
|
|
3
3
|
// src/client/locales.ts
|
|
4
4
|
const fileListLocales = {
|
|
5
5
|
"zh-CN": {
|
|
@@ -11,7 +11,7 @@ const fileListLocales = {
|
|
|
11
11
|
batchCount: "批量下载({count})",
|
|
12
12
|
batching: "打包中 {percent}%",
|
|
13
13
|
passwordPrompt: "该目录受密码保护:",
|
|
14
|
-
passwordPlaceholder: "
|
|
14
|
+
passwordPlaceholder: "输入密码",
|
|
15
15
|
open: "打开",
|
|
16
16
|
columnName: "文件名",
|
|
17
17
|
columnSize: "文件大小",
|
|
@@ -19,7 +19,7 @@ const fileListLocales = {
|
|
|
19
19
|
loading: "加载中…",
|
|
20
20
|
loadFailed: "加载失败:{message}",
|
|
21
21
|
guestHint: "在 OpenList 后台启用 guest,或给组件传一个只读 token。",
|
|
22
|
-
corsHint: "
|
|
22
|
+
corsHint: "可能是跨域或混合内容被拦截:检查 OpenList 的 cors.allow_origins(OpenList-Worker 为 ALLOW_URLS)与页面协议。",
|
|
23
23
|
retry: "重试",
|
|
24
24
|
empty: "没有文件",
|
|
25
25
|
preview: "预览",
|
|
@@ -52,7 +52,18 @@ const fileListLocales = {
|
|
|
52
52
|
previewUnsupported: "该类型暂不支持在线预览,可下载后查看",
|
|
53
53
|
previewUnavailable: "该文件无法在页面内预览,可下载后查看",
|
|
54
54
|
previewTooLarge: "文件较大({size}),请下载后查看",
|
|
55
|
-
textTruncated: "仅显示前 {size},完整内容请下载"
|
|
55
|
+
textTruncated: "仅显示前 {size},完整内容请下载",
|
|
56
|
+
refreshing: "刷新中",
|
|
57
|
+
refreshFailed: "刷新失败:{message}",
|
|
58
|
+
cancel: "取消",
|
|
59
|
+
passwordFor: "{name} 的密码",
|
|
60
|
+
passwordWrong: "密码不正确或无权访问",
|
|
61
|
+
passwordStale: "已保存的密码已失效,请重新输入",
|
|
62
|
+
rememberPassword: "在此标签页中记住(关闭标签页后失效)",
|
|
63
|
+
remembered: "已记住",
|
|
64
|
+
forgetPassword: "忘记",
|
|
65
|
+
unlockFolder: "输入 {name} 的密码",
|
|
66
|
+
networkHint: "可能被跨域拦截:请检查 OpenList 的 cors.allow_origins,或 OpenList-Worker 的 ALLOW_URLS。"
|
|
56
67
|
},
|
|
57
68
|
"en-US": {
|
|
58
69
|
allFiles: "All files",
|
|
@@ -71,7 +82,7 @@ const fileListLocales = {
|
|
|
71
82
|
loading: "Loading…",
|
|
72
83
|
loadFailed: "Failed to load: {message}",
|
|
73
84
|
guestHint: "Enable the guest user in OpenList, or pass a read-only token.",
|
|
74
|
-
corsHint: "Possibly blocked by CORS or mixed content. Check OpenList
|
|
85
|
+
corsHint: "Possibly blocked by CORS or mixed content. Check cors.allow_origins in OpenList (ALLOW_URLS in OpenList-Worker) and the page protocol.",
|
|
75
86
|
retry: "Retry",
|
|
76
87
|
empty: "No files",
|
|
77
88
|
preview: "Preview",
|
|
@@ -104,7 +115,18 @@ const fileListLocales = {
|
|
|
104
115
|
previewUnsupported: "This file type cannot be previewed here. Download it to view.",
|
|
105
116
|
previewUnavailable: "This file cannot be previewed in the page. Download it to view.",
|
|
106
117
|
previewTooLarge: "This file is large ({size}). Download it to view.",
|
|
107
|
-
textTruncated: "Showing the first {size} only. Download for the full file."
|
|
118
|
+
textTruncated: "Showing the first {size} only. Download for the full file.",
|
|
119
|
+
refreshing: "Refreshing",
|
|
120
|
+
refreshFailed: "Refresh failed: {message}",
|
|
121
|
+
cancel: "Cancel",
|
|
122
|
+
passwordFor: "Password for {name}",
|
|
123
|
+
passwordWrong: "Wrong password or no permission",
|
|
124
|
+
passwordStale: "The saved password no longer works. Enter it again.",
|
|
125
|
+
rememberPassword: "Remember in this tab (cleared when the tab closes)",
|
|
126
|
+
remembered: "Remembered",
|
|
127
|
+
forgetPassword: "Forget",
|
|
128
|
+
unlockFolder: "Enter the password for {name}",
|
|
129
|
+
networkHint: "Possibly blocked by CORS: check cors.allow_origins in OpenList, or ALLOW_URLS in OpenList-Worker."
|
|
108
130
|
}
|
|
109
131
|
};
|
|
110
132
|
function formatLabel(template, values = {}) {
|
|
@@ -875,37 +897,112 @@ const _sfc_main$1 = /*@__PURE__*/ defineComponent({
|
|
|
875
897
|
};
|
|
876
898
|
}
|
|
877
899
|
});
|
|
900
|
+
// src/client/passwords.ts
|
|
901
|
+
/**
|
|
902
|
+
* Folder passwords remembered for the current browser tab.
|
|
903
|
+
*
|
|
904
|
+
* Stored in `sessionStorage`, so they live only in this tab and are gone when
|
|
905
|
+
* it closes. Keyed by OpenList base URL, then by folder path; a remembered
|
|
906
|
+
* folder also covers its sub-folders. Every access is guarded: private mode
|
|
907
|
+
* or blocked storage simply means nothing is remembered.
|
|
908
|
+
*/
|
|
909
|
+
const PREFIX = "vitepress-plugin-filelist:passwords:";
|
|
910
|
+
function store() {
|
|
911
|
+
try {
|
|
912
|
+
return typeof sessionStorage === "undefined" ? null : sessionStorage;
|
|
913
|
+
} catch {
|
|
914
|
+
return null;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
917
|
+
function read(base) {
|
|
918
|
+
try {
|
|
919
|
+
const raw = store()?.getItem(PREFIX + base);
|
|
920
|
+
const parsed = raw ? JSON.parse(raw) : {};
|
|
921
|
+
return parsed && typeof parsed === "object" ? parsed : {};
|
|
922
|
+
} catch {
|
|
923
|
+
return {};
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
function write(base, map) {
|
|
927
|
+
try {
|
|
928
|
+
const target = store();
|
|
929
|
+
if (!target) return;
|
|
930
|
+
if (Object.keys(map).length) target.setItem(PREFIX + base, JSON.stringify(map));
|
|
931
|
+
else target.removeItem(PREFIX + base);
|
|
932
|
+
} catch {}
|
|
933
|
+
}
|
|
934
|
+
function normalise(path) {
|
|
935
|
+
return path.replace(/\/+$/, "") || "/";
|
|
936
|
+
}
|
|
937
|
+
/** Whether `path` is `folder` itself or inside it. */
|
|
938
|
+
function isWithin(path, folder) {
|
|
939
|
+
const p = normalise(path);
|
|
940
|
+
const f = normalise(folder);
|
|
941
|
+
return f === "/" || p === f || p.startsWith(`${f}/`);
|
|
942
|
+
}
|
|
943
|
+
/** The closest remembered folder at or above `path`, if any. */
|
|
944
|
+
function findRememberedPassword(base, path) {
|
|
945
|
+
let best = null;
|
|
946
|
+
for (const [folder, password] of Object.entries(read(base))) {
|
|
947
|
+
if (typeof password !== "string" || !isWithin(path, folder)) continue;
|
|
948
|
+
if (!best || folder.length > best.path.length) best = {
|
|
949
|
+
path: folder,
|
|
950
|
+
password
|
|
951
|
+
};
|
|
952
|
+
}
|
|
953
|
+
return best;
|
|
954
|
+
}
|
|
955
|
+
function rememberFolderPassword(base, path, password) {
|
|
956
|
+
write(base, {
|
|
957
|
+
...read(base),
|
|
958
|
+
[normalise(path)]: password
|
|
959
|
+
});
|
|
960
|
+
}
|
|
961
|
+
function forgetFolderPassword(base, path) {
|
|
962
|
+
const map = read(base);
|
|
963
|
+
delete map[normalise(path)];
|
|
964
|
+
write(base, map);
|
|
965
|
+
}
|
|
966
|
+
/** Folders with a remembered password, for showing the "remembered" tag. */
|
|
967
|
+
function rememberedFolders(base) {
|
|
968
|
+
return Object.keys(read(base));
|
|
969
|
+
}
|
|
878
970
|
// src/client/FileList.vue
|
|
879
|
-
const _hoisted_1 =
|
|
880
|
-
const _hoisted_2 = {
|
|
971
|
+
const _hoisted_1 = ["aria-busy"];
|
|
972
|
+
const _hoisted_2 = { class: "fl-bar" };
|
|
973
|
+
const _hoisted_3 = {
|
|
881
974
|
key: 0,
|
|
882
975
|
class: "fl-selection",
|
|
883
976
|
role: "status"
|
|
884
977
|
};
|
|
885
|
-
const
|
|
886
|
-
const
|
|
887
|
-
const
|
|
978
|
+
const _hoisted_4 = { class: "fl-selection-count" };
|
|
979
|
+
const _hoisted_5 = { class: "fl-selection-size" };
|
|
980
|
+
const _hoisted_6 = {
|
|
888
981
|
key: 1,
|
|
889
982
|
class: "fl-title"
|
|
890
983
|
};
|
|
891
|
-
const
|
|
892
|
-
const
|
|
984
|
+
const _hoisted_7 = { class: "fl-title-text" };
|
|
985
|
+
const _hoisted_8 = {
|
|
893
986
|
key: 0,
|
|
894
987
|
class: "fl-demo-badge"
|
|
895
988
|
};
|
|
896
|
-
const
|
|
897
|
-
const
|
|
898
|
-
const
|
|
899
|
-
const
|
|
900
|
-
const
|
|
901
|
-
const
|
|
902
|
-
|
|
903
|
-
|
|
989
|
+
const _hoisted_9 = ["aria-label", "title"];
|
|
990
|
+
const _hoisted_10 = { class: "fl-clear-text" };
|
|
991
|
+
const _hoisted_11 = { class: "fl-tools" };
|
|
992
|
+
const _hoisted_12 = { class: "fl-search" };
|
|
993
|
+
const _hoisted_13 = ["placeholder", "aria-label"];
|
|
994
|
+
const _hoisted_14 = [
|
|
995
|
+
"disabled",
|
|
996
|
+
"aria-label",
|
|
997
|
+
"title"
|
|
998
|
+
];
|
|
999
|
+
const _hoisted_15 = ["disabled"];
|
|
1000
|
+
const _hoisted_16 = { class: "fl-row fl-head" };
|
|
1001
|
+
const _hoisted_17 = {
|
|
904
1002
|
key: 0,
|
|
905
|
-
class: "fl-
|
|
1003
|
+
class: "fl-progress",
|
|
1004
|
+
"aria-hidden": "true"
|
|
906
1005
|
};
|
|
907
|
-
const _hoisted_16 = ["placeholder", "aria-label"];
|
|
908
|
-
const _hoisted_17 = { class: "fl-row fl-head" };
|
|
909
1006
|
const _hoisted_18 = { class: "fl-cell fl-cell-check" };
|
|
910
1007
|
const _hoisted_19 = [
|
|
911
1008
|
"aria-label",
|
|
@@ -937,84 +1034,139 @@ const _hoisted_29 = {
|
|
|
937
1034
|
const _hoisted_30 = ["aria-label"];
|
|
938
1035
|
const _hoisted_31 = ["value"];
|
|
939
1036
|
const _hoisted_32 = {
|
|
940
|
-
key:
|
|
1037
|
+
key: 0,
|
|
941
1038
|
class: "fl-status"
|
|
942
1039
|
};
|
|
943
|
-
const _hoisted_33 =
|
|
1040
|
+
const _hoisted_33 = ["for"];
|
|
1041
|
+
const _hoisted_34 = {
|
|
1042
|
+
key: 0,
|
|
1043
|
+
id: "fl-root-unlock-error",
|
|
1044
|
+
class: "fl-unlock-message",
|
|
1045
|
+
role: "alert"
|
|
1046
|
+
};
|
|
1047
|
+
const _hoisted_35 = { class: "fl-unlock" };
|
|
1048
|
+
const _hoisted_36 = [
|
|
1049
|
+
"id",
|
|
1050
|
+
"data-unlock",
|
|
1051
|
+
"placeholder",
|
|
1052
|
+
"aria-invalid",
|
|
1053
|
+
"aria-describedby"
|
|
1054
|
+
];
|
|
1055
|
+
const _hoisted_37 = [
|
|
1056
|
+
"aria-pressed",
|
|
1057
|
+
"aria-label",
|
|
1058
|
+
"title"
|
|
1059
|
+
];
|
|
1060
|
+
const _hoisted_38 = ["disabled"];
|
|
1061
|
+
const _hoisted_39 = {
|
|
944
1062
|
key: 2,
|
|
945
1063
|
class: "fl-status fl-error"
|
|
946
1064
|
};
|
|
947
|
-
const
|
|
1065
|
+
const _hoisted_40 = {
|
|
948
1066
|
key: 0,
|
|
949
1067
|
class: "fl-hint"
|
|
950
1068
|
};
|
|
951
|
-
const
|
|
1069
|
+
const _hoisted_41 = {
|
|
952
1070
|
key: 1,
|
|
953
1071
|
class: "fl-hint"
|
|
954
1072
|
};
|
|
955
|
-
const
|
|
1073
|
+
const _hoisted_42 = {
|
|
956
1074
|
key: 3,
|
|
957
1075
|
class: "fl-status"
|
|
958
1076
|
};
|
|
959
|
-
const
|
|
960
|
-
const
|
|
1077
|
+
const _hoisted_43 = { class: "fl-cell fl-cell-check" };
|
|
1078
|
+
const _hoisted_44 = [
|
|
1079
|
+
"disabled",
|
|
961
1080
|
"aria-label",
|
|
962
1081
|
"checked",
|
|
963
1082
|
".indeterminate",
|
|
964
1083
|
"onChange"
|
|
965
1084
|
];
|
|
966
|
-
const
|
|
967
|
-
const
|
|
1085
|
+
const _hoisted_45 = ["title"];
|
|
1086
|
+
const _hoisted_46 = [
|
|
1087
|
+
"aria-label",
|
|
1088
|
+
"title",
|
|
1089
|
+
"onClick"
|
|
1090
|
+
];
|
|
1091
|
+
const _hoisted_47 = [
|
|
968
1092
|
"aria-label",
|
|
969
1093
|
"aria-expanded",
|
|
970
1094
|
"onClick"
|
|
971
1095
|
];
|
|
972
|
-
const
|
|
973
|
-
key:
|
|
1096
|
+
const _hoisted_48 = {
|
|
1097
|
+
key: 2,
|
|
974
1098
|
class: "fl-arrow-placeholder",
|
|
975
1099
|
"aria-hidden": "true"
|
|
976
1100
|
};
|
|
977
|
-
const
|
|
978
|
-
key:
|
|
1101
|
+
const _hoisted_49 = {
|
|
1102
|
+
key: 3,
|
|
979
1103
|
class: "fl-folder-icon",
|
|
980
1104
|
viewBox: "0 0 24 24",
|
|
981
1105
|
width: "18",
|
|
982
1106
|
height: "18",
|
|
983
1107
|
"aria-hidden": "true"
|
|
984
1108
|
};
|
|
985
|
-
const
|
|
986
|
-
const
|
|
987
|
-
const
|
|
988
|
-
const
|
|
989
|
-
const
|
|
990
|
-
key:
|
|
1109
|
+
const _hoisted_50 = ["data-kind"];
|
|
1110
|
+
const _hoisted_51 = { class: "fl-label" };
|
|
1111
|
+
const _hoisted_52 = ["onClick"];
|
|
1112
|
+
const _hoisted_53 = { class: "fl-meta" };
|
|
1113
|
+
const _hoisted_54 = {
|
|
1114
|
+
key: 5,
|
|
991
1115
|
class: "fl-count"
|
|
992
1116
|
};
|
|
993
|
-
const
|
|
994
|
-
|
|
1117
|
+
const _hoisted_55 = ["id"];
|
|
1118
|
+
const _hoisted_56 = [
|
|
1119
|
+
"aria-label",
|
|
1120
|
+
"title",
|
|
1121
|
+
"onClick"
|
|
1122
|
+
];
|
|
1123
|
+
const _hoisted_57 = {
|
|
1124
|
+
key: 8,
|
|
995
1125
|
class: "fl-loading",
|
|
996
1126
|
"aria-hidden": "true"
|
|
997
1127
|
};
|
|
998
|
-
const
|
|
999
|
-
const
|
|
1000
|
-
|
|
1001
|
-
|
|
1128
|
+
const _hoisted_58 = ["onSubmit", "onKeydown"];
|
|
1129
|
+
const _hoisted_59 = [
|
|
1130
|
+
"onUpdate:modelValue",
|
|
1131
|
+
"data-unlock",
|
|
1132
|
+
"placeholder",
|
|
1133
|
+
"aria-label",
|
|
1134
|
+
"aria-invalid",
|
|
1135
|
+
"aria-describedby"
|
|
1136
|
+
];
|
|
1137
|
+
const _hoisted_60 = [
|
|
1138
|
+
"aria-pressed",
|
|
1139
|
+
"aria-label",
|
|
1140
|
+
"title",
|
|
1141
|
+
"onClick"
|
|
1142
|
+
];
|
|
1143
|
+
const _hoisted_61 = ["disabled"];
|
|
1144
|
+
const _hoisted_62 = [
|
|
1145
|
+
"aria-label",
|
|
1146
|
+
"title",
|
|
1147
|
+
"onClick"
|
|
1148
|
+
];
|
|
1149
|
+
const _hoisted_63 = { class: "fl-cell fl-cell-size" };
|
|
1150
|
+
const _hoisted_64 = { class: "fl-cell fl-cell-date" };
|
|
1151
|
+
const _hoisted_65 = { class: "fl-cell fl-cell-op" };
|
|
1152
|
+
const _hoisted_66 = ["aria-label", "onClick"];
|
|
1153
|
+
const _hoisted_67 = [
|
|
1002
1154
|
"aria-label",
|
|
1003
1155
|
"aria-expanded",
|
|
1004
1156
|
"onClick"
|
|
1005
1157
|
];
|
|
1006
|
-
const
|
|
1158
|
+
const _hoisted_68 = [
|
|
1007
1159
|
"aria-label",
|
|
1008
1160
|
"title",
|
|
1009
1161
|
"onClick"
|
|
1010
1162
|
];
|
|
1011
|
-
const
|
|
1163
|
+
const _hoisted_69 = [
|
|
1012
1164
|
"aria-label",
|
|
1013
1165
|
"title",
|
|
1014
1166
|
"onClick"
|
|
1015
1167
|
];
|
|
1016
|
-
const
|
|
1017
|
-
const
|
|
1168
|
+
const _hoisted_70 = { class: "fl-foot" };
|
|
1169
|
+
const _hoisted_71 = {
|
|
1018
1170
|
key: 4,
|
|
1019
1171
|
class: "fl-toast",
|
|
1020
1172
|
role: "status"
|
|
@@ -1032,6 +1184,10 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1032
1184
|
token: { default: "" },
|
|
1033
1185
|
password: { default: "" },
|
|
1034
1186
|
title: { default: "" },
|
|
1187
|
+
rememberPassword: {
|
|
1188
|
+
type: Boolean,
|
|
1189
|
+
default: true
|
|
1190
|
+
},
|
|
1035
1191
|
locale: { default: "zh-CN" },
|
|
1036
1192
|
labels: {}
|
|
1037
1193
|
},
|
|
@@ -1050,12 +1206,22 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1050
1206
|
}
|
|
1051
1207
|
const demo = computed(() => !props.base);
|
|
1052
1208
|
const baseUrl = computed(() => props.base.replace(/\/+$/, ""));
|
|
1053
|
-
const
|
|
1209
|
+
const rootEl = ref();
|
|
1054
1210
|
const roots = ref([]);
|
|
1055
1211
|
const loadingRoot = ref(false);
|
|
1056
1212
|
const errorMsg = ref("");
|
|
1057
|
-
const
|
|
1058
|
-
|
|
1213
|
+
const refreshing = ref(false);
|
|
1214
|
+
let refreshSeq = 0;
|
|
1215
|
+
/** Single-path mode: the listed folder itself needs a password. */
|
|
1216
|
+
const rootLock = reactive({
|
|
1217
|
+
active: false,
|
|
1218
|
+
input: "",
|
|
1219
|
+
error: "",
|
|
1220
|
+
remember: false,
|
|
1221
|
+
busy: false
|
|
1222
|
+
});
|
|
1223
|
+
/** Password the visitor typed for the listed folder (single-path mode). */
|
|
1224
|
+
const rootPassword = ref("");
|
|
1059
1225
|
const keyword = ref("");
|
|
1060
1226
|
const selected = ref(/* @__PURE__ */ new Set());
|
|
1061
1227
|
const toast = ref("");
|
|
@@ -1079,6 +1245,90 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1079
1245
|
function isPasswordError(error) {
|
|
1080
1246
|
return /password|密码/i.test(errorText(error));
|
|
1081
1247
|
}
|
|
1248
|
+
function isNetworkError(error) {
|
|
1249
|
+
return /failed to fetch|networkerror|load failed|network request failed/i.test(errorText(error));
|
|
1250
|
+
}
|
|
1251
|
+
/** A failure toast; browser network errors are usually CORS, so say where to look. */
|
|
1252
|
+
function failureMessage(key, error) {
|
|
1253
|
+
const message = t(key, { message: errorText(error) });
|
|
1254
|
+
return isNetworkError(error) ? `${message} ${t("networkHint")}` : message;
|
|
1255
|
+
}
|
|
1256
|
+
/** Total size for display: an empty total reads `0 B`, not `-`. */
|
|
1257
|
+
function formatTotal(bytes) {
|
|
1258
|
+
return bytes > 0 ? formatSize(bytes) : "0 B";
|
|
1259
|
+
}
|
|
1260
|
+
const canRemember = computed(() => props.rememberPassword !== false);
|
|
1261
|
+
const passwordScope = computed(() => baseUrl.value || "demo");
|
|
1262
|
+
/** Passwords typed on this page (not necessarily remembered), so a refresh keeps folders open. */
|
|
1263
|
+
const typedPasswords = /* @__PURE__ */ new Map();
|
|
1264
|
+
function typedPasswordFor(path) {
|
|
1265
|
+
let best = "";
|
|
1266
|
+
let bestPath = "";
|
|
1267
|
+
for (const [folder, password] of typedPasswords) if (isWithin(path, folder) && folder.length > bestPath.length) {
|
|
1268
|
+
best = password;
|
|
1269
|
+
bestPath = folder;
|
|
1270
|
+
}
|
|
1271
|
+
return best;
|
|
1272
|
+
}
|
|
1273
|
+
/** Folders with a remembered password (mirrors sessionStorage so the template reacts). */
|
|
1274
|
+
const rememberedPaths = ref(/* @__PURE__ */ new Set());
|
|
1275
|
+
function syncRemembered() {
|
|
1276
|
+
rememberedPaths.value = new Set(canRemember.value ? rememberedFolders(passwordScope.value) : []);
|
|
1277
|
+
}
|
|
1278
|
+
function storedPassword(path) {
|
|
1279
|
+
return canRemember.value ? findRememberedPassword(passwordScope.value, path) : null;
|
|
1280
|
+
}
|
|
1281
|
+
/**
|
|
1282
|
+
* Password for an item: its own or inherited one first (site-configured or
|
|
1283
|
+
* typed), then one remembered in this tab, then the component's `password`.
|
|
1284
|
+
*/
|
|
1285
|
+
function passwordFor(node) {
|
|
1286
|
+
if (node.password) return { password: node.password };
|
|
1287
|
+
const typed = typedPasswordFor(node.path);
|
|
1288
|
+
if (typed) return { password: typed };
|
|
1289
|
+
const stored = storedPassword(node.path);
|
|
1290
|
+
if (stored) return {
|
|
1291
|
+
password: stored.password,
|
|
1292
|
+
rememberedAt: stored.path
|
|
1293
|
+
};
|
|
1294
|
+
return { password: props.password };
|
|
1295
|
+
}
|
|
1296
|
+
function rootPasswordFor() {
|
|
1297
|
+
if (rootPassword.value) return { password: rootPassword.value };
|
|
1298
|
+
const stored = storedPassword(props.path);
|
|
1299
|
+
if (stored) return {
|
|
1300
|
+
password: stored.password,
|
|
1301
|
+
rememberedAt: stored.path
|
|
1302
|
+
};
|
|
1303
|
+
return { password: props.password };
|
|
1304
|
+
}
|
|
1305
|
+
/** A remembered password stopped working: drop it so we do not keep retrying it. */
|
|
1306
|
+
function dropStale(path) {
|
|
1307
|
+
if (!path) return false;
|
|
1308
|
+
forgetFolderPassword(passwordScope.value, path);
|
|
1309
|
+
syncRemembered();
|
|
1310
|
+
return true;
|
|
1311
|
+
}
|
|
1312
|
+
function focusUnlock(path) {
|
|
1313
|
+
nextTick(() => {
|
|
1314
|
+
(rootEl.value?.querySelector(`input[data-unlock="${CSS.escape(path)}"]`))?.focus();
|
|
1315
|
+
});
|
|
1316
|
+
}
|
|
1317
|
+
/** Show the same-row password input; `focus` only for user actions, never on page load. */
|
|
1318
|
+
function startPrompt(node, focus) {
|
|
1319
|
+
node.prompting = true;
|
|
1320
|
+
if (focus) focusUnlock(node.path);
|
|
1321
|
+
}
|
|
1322
|
+
function cancelUnlock(node) {
|
|
1323
|
+
node.prompting = false;
|
|
1324
|
+
node.unlockInput = "";
|
|
1325
|
+
node.unlockError = "";
|
|
1326
|
+
}
|
|
1327
|
+
function unlockErrorText(error) {
|
|
1328
|
+
if (error === "wrong") return t("passwordWrong");
|
|
1329
|
+
if (error === "stale") return t("passwordStale");
|
|
1330
|
+
return "";
|
|
1331
|
+
}
|
|
1082
1332
|
const DEMO_TREE = {
|
|
1083
1333
|
"/": [
|
|
1084
1334
|
{
|
|
@@ -1110,6 +1360,12 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1110
1360
|
size: 0,
|
|
1111
1361
|
is_dir: true,
|
|
1112
1362
|
modified: "2026-09-01T08:00:00+08:00"
|
|
1363
|
+
},
|
|
1364
|
+
{
|
|
1365
|
+
name: "加密示例(密码 1234)",
|
|
1366
|
+
size: 0,
|
|
1367
|
+
is_dir: true,
|
|
1368
|
+
modified: "2026-10-20T18:00:00+08:00"
|
|
1113
1369
|
}
|
|
1114
1370
|
],
|
|
1115
1371
|
"/assignments": [{
|
|
@@ -1200,6 +1456,17 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1200
1456
|
is_dir: false,
|
|
1201
1457
|
modified: "2026-01-05T19:02:00+08:00"
|
|
1202
1458
|
}],
|
|
1459
|
+
"/加密示例(密码 1234)": [{
|
|
1460
|
+
name: "期末答案(教师版).pdf",
|
|
1461
|
+
size: 2621440,
|
|
1462
|
+
is_dir: false,
|
|
1463
|
+
modified: "2026-10-20T18:00:00+08:00"
|
|
1464
|
+
}, {
|
|
1465
|
+
name: "成绩登记表.xlsx",
|
|
1466
|
+
size: 48128,
|
|
1467
|
+
is_dir: false,
|
|
1468
|
+
modified: "2026-10-21T09:12:00+08:00"
|
|
1469
|
+
}],
|
|
1203
1470
|
"/slides": [{
|
|
1204
1471
|
name: "第一章 行列式.pptx",
|
|
1205
1472
|
size: 3145728,
|
|
@@ -1212,6 +1479,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1212
1479
|
modified: "2026-09-15T13:30:00+08:00"
|
|
1213
1480
|
}]
|
|
1214
1481
|
};
|
|
1482
|
+
/** Demo-only folder passwords, so the demo can show the password flow. */
|
|
1483
|
+
const DEMO_PASSWORDS = { "/加密示例(密码 1234)": "1234" };
|
|
1215
1484
|
class ApiError extends Error {
|
|
1216
1485
|
code;
|
|
1217
1486
|
constructor(message, code) {
|
|
@@ -1219,16 +1488,17 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1219
1488
|
this.code = code;
|
|
1220
1489
|
}
|
|
1221
1490
|
}
|
|
1222
|
-
|
|
1491
|
+
/** JSON content type only when there is a body: a bare GET then needs no CORS preflight. */
|
|
1492
|
+
function authHeaders(json) {
|
|
1223
1493
|
return {
|
|
1224
|
-
"Content-Type": "application/json",
|
|
1494
|
+
...json ? { "Content-Type": "application/json" } : {},
|
|
1225
1495
|
...props.token ? { Authorization: props.token } : {}
|
|
1226
1496
|
};
|
|
1227
1497
|
}
|
|
1228
1498
|
async function request(apiPath, body) {
|
|
1229
1499
|
const response = await fetch(`${baseUrl.value}${apiPath}`, {
|
|
1230
1500
|
method: body === void 0 ? "GET" : "POST",
|
|
1231
|
-
headers: authHeaders(),
|
|
1501
|
+
headers: authHeaders(body !== void 0),
|
|
1232
1502
|
body: body === void 0 ? void 0 : JSON.stringify(body)
|
|
1233
1503
|
});
|
|
1234
1504
|
const payload = await response.json().catch(() => null);
|
|
@@ -1236,9 +1506,11 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1236
1506
|
if (payload.code !== 200) throw new ApiError(payload.message || `HTTP ${response.status}`, payload.code ?? response.status);
|
|
1237
1507
|
return payload.data;
|
|
1238
1508
|
}
|
|
1239
|
-
async function listDir(path, password
|
|
1509
|
+
async function listDir(path, password) {
|
|
1240
1510
|
if (demo.value) {
|
|
1241
1511
|
await new Promise((resolve) => setTimeout(resolve, 220));
|
|
1512
|
+
const guard = Object.entries(DEMO_PASSWORDS).find(([folder]) => isWithin(path, folder));
|
|
1513
|
+
if (guard && guard[1] !== password) throw new ApiError("password is incorrect or you have no permission", 403);
|
|
1242
1514
|
return DEMO_TREE[path] ?? [];
|
|
1243
1515
|
}
|
|
1244
1516
|
return (await request("/api/fs/list", {
|
|
@@ -1268,7 +1540,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1268
1540
|
try {
|
|
1269
1541
|
url = absoluteUrl((await request("/api/fs/get", {
|
|
1270
1542
|
path: node.path,
|
|
1271
|
-
password: node.password
|
|
1543
|
+
password: passwordFor(node).password
|
|
1272
1544
|
}))?.raw_url ?? "");
|
|
1273
1545
|
} catch {
|
|
1274
1546
|
url = "";
|
|
@@ -1326,95 +1598,297 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1326
1598
|
const parts = path.split("/").filter(Boolean);
|
|
1327
1599
|
return parts[parts.length - 1] || path;
|
|
1328
1600
|
}
|
|
1329
|
-
|
|
1601
|
+
/**
|
|
1602
|
+
* Load a folder's children. A password error marks the folder locked instead of
|
|
1603
|
+
* toasting; `prompt` also shows its same-row input (and focuses it).
|
|
1604
|
+
*/
|
|
1605
|
+
async function loadChildren(node, prompt = false) {
|
|
1330
1606
|
if (node.loaded) return true;
|
|
1607
|
+
if (node.locked) {
|
|
1608
|
+
if (prompt) startPrompt(node, prompt === "focus");
|
|
1609
|
+
return false;
|
|
1610
|
+
}
|
|
1331
1611
|
node.loading = true;
|
|
1612
|
+
const { password, rememberedAt } = passwordFor(node);
|
|
1332
1613
|
try {
|
|
1333
|
-
node.children = toNodes(await listDir(node.path,
|
|
1614
|
+
node.children = toNodes(await listDir(node.path, password), node.path, node.depth + 1, node.password, node.zipPath);
|
|
1334
1615
|
sortTree(node.children);
|
|
1335
1616
|
node.loaded = true;
|
|
1336
1617
|
return true;
|
|
1337
1618
|
} catch (error) {
|
|
1338
|
-
if (isPasswordError(error))
|
|
1339
|
-
|
|
1619
|
+
if (isPasswordError(error)) {
|
|
1620
|
+
node.locked = true;
|
|
1621
|
+
node.expanded = false;
|
|
1622
|
+
node.unlockError = dropStale(rememberedAt) ? "stale" : "";
|
|
1623
|
+
if (prompt) startPrompt(node, prompt === "focus");
|
|
1624
|
+
} else showToast(failureMessage("folderFailed", error));
|
|
1340
1625
|
return false;
|
|
1341
1626
|
} finally {
|
|
1342
1627
|
node.loading = false;
|
|
1343
1628
|
}
|
|
1344
1629
|
}
|
|
1345
|
-
|
|
1630
|
+
/** Submit the same-row password for a locked folder (or a locked root of unknown type). */
|
|
1631
|
+
async function submitUnlock(node) {
|
|
1632
|
+
const password = node.unlockInput ?? "";
|
|
1633
|
+
if (!password || node.unlockBusy) return;
|
|
1634
|
+
node.unlockBusy = true;
|
|
1635
|
+
try {
|
|
1636
|
+
if (node.unresolved) {
|
|
1637
|
+
const data = await request("/api/fs/get", {
|
|
1638
|
+
path: node.path,
|
|
1639
|
+
password
|
|
1640
|
+
});
|
|
1641
|
+
const name = node.name;
|
|
1642
|
+
Object.assign(node, data, { name });
|
|
1643
|
+
if (node.is_dir) node.zipPath = [name];
|
|
1644
|
+
else node.zipPath = [data.name || node.zipPath[0]];
|
|
1645
|
+
node.unresolved = false;
|
|
1646
|
+
}
|
|
1647
|
+
if (node.is_dir) {
|
|
1648
|
+
node.children = toNodes(await listDir(node.path, password), node.path, node.depth + 1, password, node.zipPath);
|
|
1649
|
+
sortTree(node.children);
|
|
1650
|
+
node.loaded = true;
|
|
1651
|
+
node.expanded = true;
|
|
1652
|
+
}
|
|
1653
|
+
node.password = password;
|
|
1654
|
+
typedPasswords.set(node.path, password);
|
|
1655
|
+
if (node.unlockRemember && canRemember.value) {
|
|
1656
|
+
rememberFolderPassword(passwordScope.value, node.path, password);
|
|
1657
|
+
syncRemembered();
|
|
1658
|
+
}
|
|
1659
|
+
node.locked = false;
|
|
1660
|
+
node.prompting = false;
|
|
1661
|
+
node.unlockError = "";
|
|
1662
|
+
node.unlockInput = "";
|
|
1663
|
+
node.unlockRemember = false;
|
|
1664
|
+
} catch (error) {
|
|
1665
|
+
if (isPasswordError(error)) {
|
|
1666
|
+
node.unlockError = "wrong";
|
|
1667
|
+
node.unlockInput = "";
|
|
1668
|
+
focusUnlock(node.path);
|
|
1669
|
+
} else showToast(failureMessage("folderFailed", error));
|
|
1670
|
+
} finally {
|
|
1671
|
+
node.unlockBusy = false;
|
|
1672
|
+
}
|
|
1673
|
+
}
|
|
1674
|
+
/** Forget a remembered password: the folder folds up and asks again next time. */
|
|
1675
|
+
function forgetPassword(node) {
|
|
1676
|
+
forgetFolderPassword(passwordScope.value, node.path);
|
|
1677
|
+
typedPasswords.delete(node.path);
|
|
1678
|
+
syncRemembered();
|
|
1679
|
+
node.password = node.configuredPassword || "";
|
|
1680
|
+
node.expanded = false;
|
|
1681
|
+
node.loaded = false;
|
|
1682
|
+
node.children = [];
|
|
1683
|
+
node.locked = false;
|
|
1684
|
+
selected.value = new Set([...selected.value].filter((path) => !isWithin(path, node.path)));
|
|
1685
|
+
for (const key of [...downloadCache.keys()]) if (isWithin(key, node.path)) downloadCache.delete(key);
|
|
1686
|
+
}
|
|
1687
|
+
/** When OpenList cannot tell us, guess from the name: a known file extension means a file. */
|
|
1688
|
+
function looksLikeFile(path) {
|
|
1689
|
+
const name = sourceName(path);
|
|
1690
|
+
return fileKind(name) !== "other" || previewKind(name) !== "none";
|
|
1691
|
+
}
|
|
1692
|
+
async function loadSourceRoot(source, expanded) {
|
|
1346
1693
|
const path = source.path;
|
|
1347
|
-
const
|
|
1694
|
+
const configured = source.password ?? "";
|
|
1348
1695
|
let item = {
|
|
1349
1696
|
name: sourceName(path),
|
|
1350
1697
|
size: 0,
|
|
1351
|
-
is_dir:
|
|
1698
|
+
is_dir: !looksLikeFile(path),
|
|
1352
1699
|
modified: ""
|
|
1353
1700
|
};
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1701
|
+
let locked = false;
|
|
1702
|
+
let unlockError = "";
|
|
1703
|
+
if (!demo.value) {
|
|
1704
|
+
const { password, rememberedAt } = configured ? {
|
|
1705
|
+
password: configured,
|
|
1706
|
+
rememberedAt: void 0
|
|
1707
|
+
} : (() => {
|
|
1708
|
+
const stored = storedPassword(path);
|
|
1709
|
+
return stored ? {
|
|
1710
|
+
password: stored.password,
|
|
1711
|
+
rememberedAt: stored.path
|
|
1712
|
+
} : {
|
|
1713
|
+
password: props.password,
|
|
1714
|
+
rememberedAt: void 0
|
|
1715
|
+
};
|
|
1716
|
+
})();
|
|
1717
|
+
try {
|
|
1718
|
+
const data = await request("/api/fs/get", {
|
|
1719
|
+
path,
|
|
1720
|
+
password
|
|
1721
|
+
});
|
|
1722
|
+
item = {
|
|
1723
|
+
...item,
|
|
1724
|
+
...data
|
|
1725
|
+
};
|
|
1726
|
+
} catch (error) {
|
|
1727
|
+
if (isPasswordError(error)) {
|
|
1728
|
+
locked = true;
|
|
1729
|
+
unlockError = dropStale(rememberedAt) ? "stale" : "";
|
|
1730
|
+
}
|
|
1731
|
+
}
|
|
1732
|
+
}
|
|
1370
1733
|
const name = source.title || item.name || sourceName(path);
|
|
1371
1734
|
return {
|
|
1372
1735
|
...item,
|
|
1373
1736
|
name,
|
|
1374
1737
|
path,
|
|
1375
1738
|
depth: 0,
|
|
1376
|
-
expanded
|
|
1739
|
+
expanded,
|
|
1377
1740
|
loaded: false,
|
|
1378
1741
|
loading: false,
|
|
1379
1742
|
children: [],
|
|
1380
|
-
password,
|
|
1743
|
+
password: configured,
|
|
1744
|
+
configuredPassword: configured,
|
|
1381
1745
|
isRoot: true,
|
|
1746
|
+
locked,
|
|
1747
|
+
unresolved: locked,
|
|
1748
|
+
unlockError,
|
|
1749
|
+
prompting: locked && expanded,
|
|
1382
1750
|
zipPath: [item.is_dir ? name : item.name || sourceName(path)]
|
|
1383
1751
|
};
|
|
1384
1752
|
}
|
|
1753
|
+
class RootLockedError extends Error {
|
|
1754
|
+
rememberedAt;
|
|
1755
|
+
constructor(rememberedAt) {
|
|
1756
|
+
super("root locked");
|
|
1757
|
+
this.rememberedAt = rememberedAt;
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
/**
|
|
1761
|
+
* Build a fresh tree. `expandedPaths` re-opens those folders (refresh keeps
|
|
1762
|
+
* what was open); without it the configured `expanded` defaults apply.
|
|
1763
|
+
*/
|
|
1764
|
+
async function buildTree(expandedPaths) {
|
|
1765
|
+
let nodes;
|
|
1766
|
+
if (props.sources.length) nodes = await Promise.all(props.sources.map((source) => loadSourceRoot(source, expandedPaths ? expandedPaths.has(source.path) : source.expanded ?? props.expanded)));
|
|
1767
|
+
else {
|
|
1768
|
+
const { password, rememberedAt } = rootPasswordFor();
|
|
1769
|
+
let items;
|
|
1770
|
+
try {
|
|
1771
|
+
items = await listDir(props.path, password);
|
|
1772
|
+
} catch (error) {
|
|
1773
|
+
if (isPasswordError(error)) throw new RootLockedError(rememberedAt);
|
|
1774
|
+
throw error;
|
|
1775
|
+
}
|
|
1776
|
+
nodes = toNodes(items, props.path, 0, rootPassword.value);
|
|
1777
|
+
sortTree(nodes);
|
|
1778
|
+
}
|
|
1779
|
+
const open = async (list) => {
|
|
1780
|
+
for (const node of list) {
|
|
1781
|
+
if (!node.is_dir || node.locked || !node.expanded && !expandedPaths?.has(node.path)) continue;
|
|
1782
|
+
node.expanded = await loadChildren(node, "show");
|
|
1783
|
+
if (node.expanded && expandedPaths) await open(node.children);
|
|
1784
|
+
}
|
|
1785
|
+
};
|
|
1786
|
+
await open(nodes);
|
|
1787
|
+
return nodes;
|
|
1788
|
+
}
|
|
1789
|
+
/** First load, or a retry after an error: shows the loading state. */
|
|
1385
1790
|
async function loadRoot() {
|
|
1791
|
+
refreshSeq += 1;
|
|
1792
|
+
refreshing.value = false;
|
|
1386
1793
|
loadingRoot.value = true;
|
|
1387
1794
|
errorMsg.value = "";
|
|
1388
|
-
needsPassword.value = false;
|
|
1389
1795
|
try {
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1796
|
+
roots.value = await buildTree();
|
|
1797
|
+
rootLock.active = false;
|
|
1798
|
+
selected.value = /* @__PURE__ */ new Set();
|
|
1799
|
+
downloadCache.clear();
|
|
1800
|
+
} catch (error) {
|
|
1801
|
+
if (error instanceof RootLockedError) {
|
|
1802
|
+
roots.value = [];
|
|
1803
|
+
rootLock.active = true;
|
|
1804
|
+
rootLock.error = dropStale(error.rememberedAt) ? "stale" : "";
|
|
1805
|
+
} else errorMsg.value = errorText(error);
|
|
1806
|
+
} finally {
|
|
1807
|
+
loadingRoot.value = false;
|
|
1808
|
+
}
|
|
1809
|
+
}
|
|
1810
|
+
function expandedPathsOf(nodes, out = /* @__PURE__ */ new Set()) {
|
|
1811
|
+
for (const node of nodes) if (node.is_dir && node.expanded) {
|
|
1812
|
+
out.add(node.path);
|
|
1813
|
+
expandedPathsOf(node.children, out);
|
|
1814
|
+
}
|
|
1815
|
+
return out;
|
|
1816
|
+
}
|
|
1817
|
+
/**
|
|
1818
|
+
* Refresh keeps the old rows in place (dimmed) until the new tree is ready, then
|
|
1819
|
+
* swaps it in. Open folders stay open; selected files that still exist stay selected.
|
|
1820
|
+
*/
|
|
1821
|
+
async function refresh() {
|
|
1822
|
+
if (refreshing.value || loadingRoot.value) return;
|
|
1823
|
+
if (!roots.value.length || errorMsg.value || rootLock.active) {
|
|
1824
|
+
await loadRoot();
|
|
1825
|
+
return;
|
|
1826
|
+
}
|
|
1827
|
+
const seq = ++refreshSeq;
|
|
1828
|
+
refreshing.value = true;
|
|
1829
|
+
try {
|
|
1830
|
+
const fresh = await buildTree(expandedPathsOf(roots.value));
|
|
1831
|
+
if (seq !== refreshSeq) return;
|
|
1832
|
+
roots.value = fresh;
|
|
1833
|
+
const existing = new Set(fresh.flatMap(descendantFiles).map((file) => file.path));
|
|
1834
|
+
selected.value = new Set([...selected.value].filter((path) => existing.has(path)));
|
|
1835
|
+
downloadCache.clear();
|
|
1836
|
+
} catch (error) {
|
|
1837
|
+
if (seq !== refreshSeq) return;
|
|
1838
|
+
if (error instanceof RootLockedError) {
|
|
1839
|
+
roots.value = [];
|
|
1840
|
+
rootLock.active = true;
|
|
1841
|
+
rootLock.error = dropStale(error.rememberedAt) ? "stale" : "wrong";
|
|
1394
1842
|
selected.value = /* @__PURE__ */ new Set();
|
|
1395
|
-
|
|
1396
|
-
|
|
1843
|
+
} else showToast(failureMessage("refreshFailed", error));
|
|
1844
|
+
} finally {
|
|
1845
|
+
if (seq === refreshSeq) refreshing.value = false;
|
|
1846
|
+
}
|
|
1847
|
+
}
|
|
1848
|
+
/** Single-path mode: unlock the listed folder itself. */
|
|
1849
|
+
async function submitRootUnlock() {
|
|
1850
|
+
const password = rootLock.input;
|
|
1851
|
+
if (!password || rootLock.busy) return;
|
|
1852
|
+
rootLock.busy = true;
|
|
1853
|
+
try {
|
|
1854
|
+
const items = await listDir(props.path, password);
|
|
1855
|
+
rootPassword.value = password;
|
|
1856
|
+
if (rootLock.remember && canRemember.value) {
|
|
1857
|
+
rememberFolderPassword(passwordScope.value, props.path, password);
|
|
1858
|
+
syncRemembered();
|
|
1397
1859
|
}
|
|
1398
|
-
const
|
|
1399
|
-
|
|
1400
|
-
|
|
1860
|
+
const nodes = toNodes(items, props.path, 0, password);
|
|
1861
|
+
sortTree(nodes);
|
|
1862
|
+
roots.value = nodes;
|
|
1863
|
+
Object.assign(rootLock, {
|
|
1864
|
+
active: false,
|
|
1865
|
+
input: "",
|
|
1866
|
+
error: "",
|
|
1867
|
+
remember: false
|
|
1868
|
+
});
|
|
1401
1869
|
selected.value = /* @__PURE__ */ new Set();
|
|
1402
1870
|
downloadCache.clear();
|
|
1403
1871
|
} catch (error) {
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1872
|
+
if (isPasswordError(error)) {
|
|
1873
|
+
rootLock.error = "wrong";
|
|
1874
|
+
rootLock.input = "";
|
|
1875
|
+
focusUnlock(props.path);
|
|
1876
|
+
} else showToast(failureMessage("loadFailed", error));
|
|
1407
1877
|
} finally {
|
|
1408
|
-
|
|
1878
|
+
rootLock.busy = false;
|
|
1409
1879
|
}
|
|
1410
1880
|
}
|
|
1411
1881
|
async function toggleExpand(node) {
|
|
1882
|
+
if (node.locked) {
|
|
1883
|
+
startPrompt(node, true);
|
|
1884
|
+
return;
|
|
1885
|
+
}
|
|
1412
1886
|
if (!node.is_dir) return;
|
|
1413
1887
|
if (node.expanded) {
|
|
1414
1888
|
node.expanded = false;
|
|
1415
1889
|
return;
|
|
1416
1890
|
}
|
|
1417
|
-
if (!await loadChildren(node)) return;
|
|
1891
|
+
if (!await loadChildren(node, "focus")) return;
|
|
1418
1892
|
node.expanded = true;
|
|
1419
1893
|
}
|
|
1420
1894
|
const visible = computed(() => {
|
|
@@ -1444,18 +1918,33 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1444
1918
|
const hit = files.filter((file) => selected.value.has(file.path)).length;
|
|
1445
1919
|
return hit > 0 && hit < files.length;
|
|
1446
1920
|
}
|
|
1447
|
-
/**
|
|
1921
|
+
/**
|
|
1922
|
+
* Load a directory and all of its sub-directories. Stops at the first folder
|
|
1923
|
+
* that needs a password and returns it, so nothing is silently left out.
|
|
1924
|
+
*/
|
|
1448
1925
|
async function loadTree(node) {
|
|
1449
|
-
if (!node.is_dir) return true;
|
|
1450
|
-
if (!await loadChildren(node)) return
|
|
1451
|
-
|
|
1452
|
-
|
|
1926
|
+
if (!node.is_dir) return { ok: true };
|
|
1927
|
+
if (!await loadChildren(node)) return node.locked ? {
|
|
1928
|
+
ok: false,
|
|
1929
|
+
locked: node
|
|
1930
|
+
} : { ok: false };
|
|
1931
|
+
for (const child of node.children) {
|
|
1932
|
+
if (!child.is_dir) continue;
|
|
1933
|
+
const result = await loadTree(child);
|
|
1934
|
+
if (!result.ok) {
|
|
1935
|
+
node.expanded = true;
|
|
1936
|
+
return result;
|
|
1937
|
+
}
|
|
1938
|
+
}
|
|
1939
|
+
return { ok: true };
|
|
1453
1940
|
}
|
|
1454
1941
|
async function toggleCheck(node, event) {
|
|
1455
1942
|
const input = event?.target;
|
|
1456
1943
|
if (node.is_dir && !isChecked(node)) {
|
|
1457
|
-
|
|
1944
|
+
const result = await loadTree(node);
|
|
1945
|
+
if (result.ok) node.expanded = true;
|
|
1458
1946
|
else {
|
|
1947
|
+
if (result.locked) startPrompt(result.locked, true);
|
|
1459
1948
|
if (input) input.checked = isChecked(node);
|
|
1460
1949
|
return;
|
|
1461
1950
|
}
|
|
@@ -1628,11 +2117,6 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1628
2117
|
batchBusy.value = false;
|
|
1629
2118
|
}
|
|
1630
2119
|
}
|
|
1631
|
-
function submitPassword() {
|
|
1632
|
-
activePassword.value = passwordInput.value;
|
|
1633
|
-
downloadCache.clear();
|
|
1634
|
-
loadRoot();
|
|
1635
|
-
}
|
|
1636
2120
|
const displayTitle = computed(() => props.title || siteTitle.value || (props.path === "/" ? t("allFiles") : props.path));
|
|
1637
2121
|
const stickyTop = ref(0);
|
|
1638
2122
|
function measureStickyTop() {
|
|
@@ -1646,6 +2130,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1646
2130
|
stickyTop.value = top;
|
|
1647
2131
|
}
|
|
1648
2132
|
onMounted(() => {
|
|
2133
|
+
syncRemembered();
|
|
1649
2134
|
loadRoot();
|
|
1650
2135
|
loadSiteTitle();
|
|
1651
2136
|
measureStickyTop();
|
|
@@ -1657,11 +2142,17 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1657
2142
|
});
|
|
1658
2143
|
return (_ctx, _cache) => {
|
|
1659
2144
|
return openBlock(), createElementBlock("div", {
|
|
1660
|
-
|
|
1661
|
-
|
|
2145
|
+
ref_key: "rootEl",
|
|
2146
|
+
ref: rootEl,
|
|
2147
|
+
class: normalizeClass(["fl-root", {
|
|
2148
|
+
"fl-selecting": selected.value.size > 0,
|
|
2149
|
+
"fl-refreshing": refreshing.value
|
|
2150
|
+
}]),
|
|
2151
|
+
style: normalizeStyle({ "--fl-sticky-top-auto": `${stickyTop.value}px` }),
|
|
2152
|
+
"aria-busy": refreshing.value || loadingRoot.value
|
|
1662
2153
|
}, [
|
|
1663
|
-
createElementVNode("div",
|
|
1664
|
-
selected.value.size ? (openBlock(), createElementBlock("div",
|
|
2154
|
+
createElementVNode("div", _hoisted_2, [
|
|
2155
|
+
selected.value.size ? (openBlock(), createElementBlock("div", _hoisted_3, [createElementVNode("span", _hoisted_4, toDisplayString(t("selected", { count: selected.value.size })), 1), createElementVNode("span", _hoisted_5, toDisplayString(t("totalSize", { size: formatTotal(selectedBytes.value) })), 1)])) : (openBlock(), createElementBlock("div", _hoisted_6, [createElementVNode("span", _hoisted_7, toDisplayString(displayTitle.value), 1), demo.value ? (openBlock(), createElementBlock("span", _hoisted_8, toDisplayString(t("demoBadge")), 1)) : createCommentVNode("v-if", true)])),
|
|
1665
2156
|
selected.value.size ? (openBlock(), createElementBlock("button", {
|
|
1666
2157
|
key: 2,
|
|
1667
2158
|
class: "fl-clear",
|
|
@@ -1669,7 +2160,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1669
2160
|
"aria-label": t("clearSelection"),
|
|
1670
2161
|
title: t("clearSelection"),
|
|
1671
2162
|
onClick: clearSelection
|
|
1672
|
-
}, [_cache[
|
|
2163
|
+
}, [_cache[10] || (_cache[10] = createElementVNode("svg", {
|
|
1673
2164
|
class: "fl-clear-icon",
|
|
1674
2165
|
viewBox: "0 0 24 24",
|
|
1675
2166
|
width: "18",
|
|
@@ -1679,8 +2170,8 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1679
2170
|
"stroke-width": "2.2",
|
|
1680
2171
|
"stroke-linecap": "round",
|
|
1681
2172
|
"aria-hidden": "true"
|
|
1682
|
-
}, [createElementVNode("path", { d: "M6 6l12 12" }), createElementVNode("path", { d: "M18 6 6 18" })], -1)), createElementVNode("span",
|
|
1683
|
-
createElementVNode("div",
|
|
2173
|
+
}, [createElementVNode("path", { d: "M6 6l12 12" }), createElementVNode("path", { d: "M18 6 6 18" })], -1)), createElementVNode("span", _hoisted_10, toDisplayString(t("clear")), 1)], 8, _hoisted_9)) : createCommentVNode("v-if", true),
|
|
2174
|
+
createElementVNode("div", _hoisted_11, [createElementVNode("label", _hoisted_12, [_cache[11] || (_cache[11] = createElementVNode("svg", {
|
|
1684
2175
|
viewBox: "0 0 24 24",
|
|
1685
2176
|
width: "15",
|
|
1686
2177
|
height: "15",
|
|
@@ -1698,13 +2189,14 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1698
2189
|
type: "text",
|
|
1699
2190
|
placeholder: t("filter"),
|
|
1700
2191
|
"aria-label": t("filter")
|
|
1701
|
-
}, null, 8,
|
|
1702
|
-
class: "fl-icon-btn",
|
|
2192
|
+
}, null, 8, _hoisted_13), [[vModelText, keyword.value]])]), createElementVNode("button", {
|
|
2193
|
+
class: normalizeClass(["fl-icon-btn fl-refresh", { "fl-spinning": refreshing.value }]),
|
|
1703
2194
|
type: "button",
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
2195
|
+
disabled: refreshing.value || loadingRoot.value,
|
|
2196
|
+
"aria-label": refreshing.value ? t("refreshing") : t("refresh"),
|
|
2197
|
+
title: refreshing.value ? t("refreshing") : t("refresh"),
|
|
2198
|
+
onClick: refresh
|
|
2199
|
+
}, [..._cache[12] || (_cache[12] = [createElementVNode("svg", {
|
|
1708
2200
|
viewBox: "0 0 24 24",
|
|
1709
2201
|
width: "15",
|
|
1710
2202
|
height: "15",
|
|
@@ -1714,14 +2206,14 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1714
2206
|
"stroke-linecap": "round",
|
|
1715
2207
|
"stroke-linejoin": "round",
|
|
1716
2208
|
"aria-hidden": "true"
|
|
1717
|
-
}, [createElementVNode("path", { d: "M21 12a9 9 0 1 1-3-6.7" }), createElementVNode("path", { d: "M21 4v5h-5" })], -1)])],
|
|
2209
|
+
}, [createElementVNode("path", { d: "M21 12a9 9 0 1 1-3-6.7" }), createElementVNode("path", { d: "M21 4v5h-5" })], -1)])], 10, _hoisted_14)]),
|
|
1718
2210
|
selected.value.size ? (openBlock(), createElementBlock("button", {
|
|
1719
2211
|
key: 3,
|
|
1720
2212
|
class: "fl-btn fl-btn-primary",
|
|
1721
2213
|
type: "button",
|
|
1722
2214
|
disabled: batchBusy.value,
|
|
1723
2215
|
onClick: batchDownload
|
|
1724
|
-
}, [_cache[
|
|
2216
|
+
}, [_cache[13] || (_cache[13] = createElementVNode("svg", {
|
|
1725
2217
|
viewBox: "0 0 24 24",
|
|
1726
2218
|
width: "15",
|
|
1727
2219
|
height: "15",
|
|
@@ -1735,24 +2227,10 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1735
2227
|
createElementVNode("path", { d: "M12 3v12" }),
|
|
1736
2228
|
createElementVNode("path", { d: "m7 10 5 5 5-5" }),
|
|
1737
2229
|
createElementVNode("path", { d: "M5 21h14" })
|
|
1738
|
-
], -1)), createTextVNode(" " + toDisplayString(batchBusy.value ? t("batching", { percent: batchProgress.value }) : t("batch")), 1)], 8,
|
|
2230
|
+
], -1)), createTextVNode(" " + toDisplayString(batchBusy.value ? t("batching", { percent: batchProgress.value }) : t("batch")), 1)], 8, _hoisted_15)) : createCommentVNode("v-if", true)
|
|
1739
2231
|
]),
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
withDirectives(createElementVNode("input", {
|
|
1743
|
-
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => passwordInput.value = $event),
|
|
1744
|
-
type: "password",
|
|
1745
|
-
placeholder: t("passwordPlaceholder"),
|
|
1746
|
-
"aria-label": t("passwordPlaceholder"),
|
|
1747
|
-
onKeyup: withKeys(submitPassword, ["enter"])
|
|
1748
|
-
}, null, 40, _hoisted_16), [[vModelText, passwordInput.value]]),
|
|
1749
|
-
createElementVNode("button", {
|
|
1750
|
-
class: "fl-btn fl-btn-primary",
|
|
1751
|
-
type: "button",
|
|
1752
|
-
onClick: submitPassword
|
|
1753
|
-
}, toDisplayString(t("open")), 1)
|
|
1754
|
-
])) : createCommentVNode("v-if", true),
|
|
1755
|
-
createElementVNode("div", _hoisted_17, [
|
|
2232
|
+
createElementVNode("div", _hoisted_16, [
|
|
2233
|
+
refreshing.value ? (openBlock(), createElementBlock("span", _hoisted_17)) : createCommentVNode("v-if", true),
|
|
1756
2234
|
createElementVNode("label", _hoisted_18, [createElementVNode("input", {
|
|
1757
2235
|
type: "checkbox",
|
|
1758
2236
|
"aria-label": t("selectAll"),
|
|
@@ -1764,23 +2242,23 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1764
2242
|
class: "fl-sort-btn",
|
|
1765
2243
|
type: "button",
|
|
1766
2244
|
"aria-sort": sortKey.value === "name" ? sortAsc.value ? "ascending" : "descending" : void 0,
|
|
1767
|
-
onClick: _cache[
|
|
2245
|
+
onClick: _cache[1] || (_cache[1] = ($event) => setSort("name"))
|
|
1768
2246
|
}, [createTextVNode(toDisplayString(t("columnName")), 1), createElementVNode("span", _hoisted_22, toDisplayString(sortKey.value === "name" ? sortAsc.value ? "▲" : "▼" : ""), 1)], 8, _hoisted_21)]),
|
|
1769
2247
|
createElementVNode("span", _hoisted_23, [createElementVNode("button", {
|
|
1770
2248
|
class: "fl-sort-btn",
|
|
1771
2249
|
type: "button",
|
|
1772
|
-
onClick: _cache[
|
|
2250
|
+
onClick: _cache[2] || (_cache[2] = ($event) => setSort("size"))
|
|
1773
2251
|
}, [createTextVNode(toDisplayString(t("columnSize")), 1), createElementVNode("span", _hoisted_24, toDisplayString(sortKey.value === "size" ? sortAsc.value ? "▲" : "▼" : ""), 1)])]),
|
|
1774
2252
|
createElementVNode("span", _hoisted_25, [createElementVNode("button", {
|
|
1775
2253
|
class: "fl-sort-btn",
|
|
1776
2254
|
type: "button",
|
|
1777
|
-
onClick: _cache[
|
|
2255
|
+
onClick: _cache[3] || (_cache[3] = ($event) => setSort("modified"))
|
|
1778
2256
|
}, [createTextVNode(toDisplayString(t("columnDate")), 1), createElementVNode("span", _hoisted_26, toDisplayString(sortKey.value === "modified" ? sortAsc.value ? "▲" : "▼" : ""), 1)])]),
|
|
1779
2257
|
createElementVNode("span", _hoisted_27, [createElementVNode("label", _hoisted_28, [
|
|
1780
2258
|
createElementVNode("span", null, toDisplayString(t("sortBy")), 1),
|
|
1781
2259
|
createElementVNode("span", _hoisted_29, toDisplayString(sortOptions.value.find((option) => option.value === sortValue.value)?.label), 1),
|
|
1782
2260
|
withDirectives(createElementVNode("select", {
|
|
1783
|
-
"onUpdate:modelValue": _cache[
|
|
2261
|
+
"onUpdate:modelValue": _cache[4] || (_cache[4] = ($event) => sortValue.value = $event),
|
|
1784
2262
|
"aria-label": t("sortBy")
|
|
1785
2263
|
}, [(openBlock(true), createElementBlock(Fragment, null, renderList(sortOptions.value, (option) => {
|
|
1786
2264
|
return openBlock(), createElementBlock("option", {
|
|
@@ -1790,49 +2268,148 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1790
2268
|
}), 128))], 8, _hoisted_30), [[vModelSelect, sortValue.value]])
|
|
1791
2269
|
])])
|
|
1792
2270
|
]),
|
|
1793
|
-
loadingRoot.value ? (openBlock(), createElementBlock("div", _hoisted_32, toDisplayString(t("loading")), 1)) :
|
|
2271
|
+
loadingRoot.value ? (openBlock(), createElementBlock("div", _hoisted_32, toDisplayString(t("loading")), 1)) : rootLock.active ? (openBlock(), createElementBlock("form", {
|
|
2272
|
+
key: 1,
|
|
2273
|
+
class: normalizeClass(["fl-unlock-root", { "fl-unlock-error": rootLock.error }]),
|
|
2274
|
+
onSubmit: withModifiers(submitRootUnlock, ["prevent"])
|
|
2275
|
+
}, [
|
|
2276
|
+
_cache[15] || (_cache[15] = createElementVNode("svg", {
|
|
2277
|
+
class: "fl-unlock-lock",
|
|
2278
|
+
viewBox: "0 0 24 24",
|
|
2279
|
+
width: "16",
|
|
2280
|
+
height: "16",
|
|
2281
|
+
fill: "none",
|
|
2282
|
+
stroke: "currentColor",
|
|
2283
|
+
"stroke-width": "2.2",
|
|
2284
|
+
"stroke-linecap": "round",
|
|
2285
|
+
"stroke-linejoin": "round",
|
|
2286
|
+
"aria-hidden": "true"
|
|
2287
|
+
}, [createElementVNode("rect", {
|
|
2288
|
+
x: "5",
|
|
2289
|
+
y: "11",
|
|
2290
|
+
width: "14",
|
|
2291
|
+
height: "10",
|
|
2292
|
+
rx: "2"
|
|
2293
|
+
}), createElementVNode("path", { d: "M8 11V8a4 4 0 0 1 8 0v3" })], -1)),
|
|
2294
|
+
createElementVNode("label", {
|
|
2295
|
+
class: "fl-unlock-label",
|
|
2296
|
+
for: `fl-root-unlock-${__props.path}`
|
|
2297
|
+
}, toDisplayString(t("passwordPrompt")), 9, _hoisted_33),
|
|
2298
|
+
rootLock.error ? (openBlock(), createElementBlock("span", _hoisted_34, toDisplayString(unlockErrorText(rootLock.error)), 1)) : createCommentVNode("v-if", true),
|
|
2299
|
+
createElementVNode("span", _hoisted_35, [
|
|
2300
|
+
withDirectives(createElementVNode("input", {
|
|
2301
|
+
id: `fl-root-unlock-${__props.path}`,
|
|
2302
|
+
"onUpdate:modelValue": _cache[5] || (_cache[5] = ($event) => rootLock.input = $event),
|
|
2303
|
+
type: "password",
|
|
2304
|
+
autocomplete: "off",
|
|
2305
|
+
"data-unlock": __props.path,
|
|
2306
|
+
placeholder: t("passwordPlaceholder"),
|
|
2307
|
+
"aria-invalid": !!rootLock.error,
|
|
2308
|
+
"aria-describedby": rootLock.error ? "fl-root-unlock-error" : void 0
|
|
2309
|
+
}, null, 8, _hoisted_36), [[vModelText, rootLock.input]]),
|
|
2310
|
+
canRemember.value ? (openBlock(), createElementBlock("button", {
|
|
2311
|
+
key: 0,
|
|
2312
|
+
class: "fl-unlock-remember",
|
|
2313
|
+
type: "button",
|
|
2314
|
+
"aria-pressed": rootLock.remember,
|
|
2315
|
+
"aria-label": t("rememberPassword"),
|
|
2316
|
+
title: t("rememberPassword"),
|
|
2317
|
+
onClick: _cache[6] || (_cache[6] = ($event) => rootLock.remember = !rootLock.remember)
|
|
2318
|
+
}, [..._cache[14] || (_cache[14] = [createElementVNode("svg", {
|
|
2319
|
+
viewBox: "0 0 24 24",
|
|
2320
|
+
width: "16",
|
|
2321
|
+
height: "16",
|
|
2322
|
+
fill: "none",
|
|
2323
|
+
stroke: "currentColor",
|
|
2324
|
+
"stroke-width": "2",
|
|
2325
|
+
"stroke-linecap": "round",
|
|
2326
|
+
"stroke-linejoin": "round",
|
|
2327
|
+
"aria-hidden": "true"
|
|
2328
|
+
}, [
|
|
2329
|
+
createElementVNode("circle", {
|
|
2330
|
+
cx: "8",
|
|
2331
|
+
cy: "15",
|
|
2332
|
+
r: "4"
|
|
2333
|
+
}),
|
|
2334
|
+
createElementVNode("path", { d: "m11 12 9-9" }),
|
|
2335
|
+
createElementVNode("path", { d: "m17 6 3 3" })
|
|
2336
|
+
], -1)])], 8, _hoisted_37)) : createCommentVNode("v-if", true),
|
|
2337
|
+
createElementVNode("button", {
|
|
2338
|
+
class: "fl-unlock-submit",
|
|
2339
|
+
type: "submit",
|
|
2340
|
+
disabled: rootLock.busy || !rootLock.input
|
|
2341
|
+
}, toDisplayString(t("open")), 9, _hoisted_38)
|
|
2342
|
+
])
|
|
2343
|
+
], 34)) : errorMsg.value ? (openBlock(), createElementBlock("div", _hoisted_39, [
|
|
1794
2344
|
createTextVNode(toDisplayString(t("loadFailed", { message: errorMsg.value })) + " ", 1),
|
|
1795
|
-
/guest/i.test(errorMsg.value) ? (openBlock(), createElementBlock("p",
|
|
1796
|
-
/failed to fetch|networkerror/i.test(errorMsg.value) ? (openBlock(), createElementBlock("p",
|
|
2345
|
+
/guest/i.test(errorMsg.value) ? (openBlock(), createElementBlock("p", _hoisted_40, toDisplayString(t("guestHint")), 1)) : createCommentVNode("v-if", true),
|
|
2346
|
+
/failed to fetch|networkerror/i.test(errorMsg.value) ? (openBlock(), createElementBlock("p", _hoisted_41, toDisplayString(t("corsHint")), 1)) : createCommentVNode("v-if", true),
|
|
1797
2347
|
createElementVNode("button", {
|
|
1798
2348
|
class: "fl-btn",
|
|
1799
2349
|
type: "button",
|
|
1800
2350
|
onClick: loadRoot
|
|
1801
2351
|
}, toDisplayString(t("retry")), 1)
|
|
1802
|
-
])) : visible.value.length === 0 ? (openBlock(), createElementBlock("div",
|
|
2352
|
+
])) : visible.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_42, toDisplayString(t("empty")), 1)) : createCommentVNode("v-if", true),
|
|
1803
2353
|
(openBlock(true), createElementBlock(Fragment, null, renderList(visible.value, (node) => {
|
|
1804
2354
|
return openBlock(), createElementBlock("div", {
|
|
1805
2355
|
key: node.path,
|
|
1806
2356
|
class: normalizeClass(["fl-row", {
|
|
1807
2357
|
"fl-row-dir": node.is_dir,
|
|
1808
2358
|
"fl-row-root": node.isRoot,
|
|
1809
|
-
"fl-row-selected": !node.is_dir && selected.value.has(node.path)
|
|
2359
|
+
"fl-row-selected": !node.is_dir && selected.value.has(node.path),
|
|
2360
|
+
"fl-row-locked": node.locked,
|
|
2361
|
+
"fl-row-prompting": node.locked && node.prompting,
|
|
2362
|
+
"fl-row-error": node.locked && node.prompting && !!node.unlockError
|
|
1810
2363
|
}]),
|
|
1811
2364
|
style: normalizeStyle({ "--fl-depth": node.depth })
|
|
1812
2365
|
}, [
|
|
1813
|
-
createElementVNode("label",
|
|
2366
|
+
createElementVNode("label", _hoisted_43, [createElementVNode("input", {
|
|
1814
2367
|
type: "checkbox",
|
|
2368
|
+
disabled: node.locked,
|
|
1815
2369
|
"aria-label": t("selectItem", { name: node.name }),
|
|
1816
2370
|
checked: isChecked(node),
|
|
1817
2371
|
".indeterminate": isIndeterminate(node),
|
|
1818
2372
|
onChange: ($event) => toggleCheck(node, $event)
|
|
1819
|
-
}, null, 40,
|
|
2373
|
+
}, null, 40, _hoisted_44)]),
|
|
1820
2374
|
createElementVNode("span", {
|
|
1821
2375
|
class: "fl-cell fl-cell-name",
|
|
1822
2376
|
title: node.isRoot ? node.path : void 0
|
|
1823
2377
|
}, [
|
|
1824
|
-
_cache[
|
|
2378
|
+
_cache[20] || (_cache[20] = createElementVNode("span", {
|
|
1825
2379
|
class: "fl-indent",
|
|
1826
2380
|
"aria-hidden": "true"
|
|
1827
2381
|
}, null, -1)),
|
|
1828
|
-
node.
|
|
2382
|
+
node.locked ? (openBlock(), createElementBlock("button", {
|
|
1829
2383
|
key: 0,
|
|
2384
|
+
class: "fl-arrow fl-lock",
|
|
2385
|
+
type: "button",
|
|
2386
|
+
"aria-label": t("unlockFolder", { name: node.name }),
|
|
2387
|
+
title: t("unlockFolder", { name: node.name }),
|
|
2388
|
+
onClick: ($event) => toggleExpand(node)
|
|
2389
|
+
}, [..._cache[16] || (_cache[16] = [createElementVNode("svg", {
|
|
2390
|
+
viewBox: "0 0 24 24",
|
|
2391
|
+
width: "14",
|
|
2392
|
+
height: "14",
|
|
2393
|
+
fill: "none",
|
|
2394
|
+
stroke: "currentColor",
|
|
2395
|
+
"stroke-width": "2.2",
|
|
2396
|
+
"stroke-linecap": "round",
|
|
2397
|
+
"stroke-linejoin": "round",
|
|
2398
|
+
"aria-hidden": "true"
|
|
2399
|
+
}, [createElementVNode("rect", {
|
|
2400
|
+
x: "5",
|
|
2401
|
+
y: "11",
|
|
2402
|
+
width: "14",
|
|
2403
|
+
height: "10",
|
|
2404
|
+
rx: "2"
|
|
2405
|
+
}), createElementVNode("path", { d: "M8 11V8a4 4 0 0 1 8 0v3" })], -1)])], 8, _hoisted_46)) : node.is_dir ? (openBlock(), createElementBlock("button", {
|
|
2406
|
+
key: 1,
|
|
1830
2407
|
class: normalizeClass(["fl-arrow", { "fl-arrow-open": node.expanded }]),
|
|
1831
2408
|
type: "button",
|
|
1832
2409
|
"aria-label": t(node.expanded ? "collapse" : "expand", { name: node.name }),
|
|
1833
2410
|
"aria-expanded": node.expanded,
|
|
1834
2411
|
onClick: ($event) => toggleExpand(node)
|
|
1835
|
-
}, [..._cache[
|
|
2412
|
+
}, [..._cache[17] || (_cache[17] = [createElementVNode("svg", {
|
|
1836
2413
|
viewBox: "0 0 24 24",
|
|
1837
2414
|
width: "14",
|
|
1838
2415
|
height: "14",
|
|
@@ -1842,85 +2419,223 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1842
2419
|
"stroke-linecap": "round",
|
|
1843
2420
|
"stroke-linejoin": "round",
|
|
1844
2421
|
"aria-hidden": "true"
|
|
1845
|
-
}, [createElementVNode("path", { d: "m9 6 6 6-6 6" })], -1)])], 10,
|
|
1846
|
-
node.is_dir ? (openBlock(), createElementBlock("svg",
|
|
1847
|
-
key:
|
|
2422
|
+
}, [createElementVNode("path", { d: "m9 6 6 6-6 6" })], -1)])], 10, _hoisted_47)) : (openBlock(), createElementBlock("span", _hoisted_48)),
|
|
2423
|
+
node.is_dir ? (openBlock(), createElementBlock("svg", _hoisted_49, [..._cache[18] || (_cache[18] = [createElementVNode("path", { d: "M3 7a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v8a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z" }, null, -1)])])) : (openBlock(), createElementBlock("span", {
|
|
2424
|
+
key: 4,
|
|
1848
2425
|
class: "fl-type",
|
|
1849
2426
|
"data-kind": unref(fileKind)(node.name),
|
|
1850
2427
|
"aria-hidden": "true"
|
|
1851
|
-
}, toDisplayString(unref(extOf)(node.name) || "FILE"), 9,
|
|
1852
|
-
createElementVNode("span",
|
|
2428
|
+
}, toDisplayString(unref(extOf)(node.name) || "FILE"), 9, _hoisted_50)),
|
|
2429
|
+
createElementVNode("span", _hoisted_51, [createElementVNode("span", {
|
|
1853
2430
|
class: normalizeClass(["fl-name", { "fl-name-dir": node.is_dir }]),
|
|
1854
|
-
onClick: ($event) => node.is_dir ? toggleExpand(node) : download(node)
|
|
1855
|
-
}, toDisplayString(node.name), 11,
|
|
1856
|
-
node.is_dir && node.loaded ? (openBlock(), createElementBlock("span",
|
|
1857
|
-
node.
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
|
|
1877
|
-
|
|
1878
|
-
|
|
2431
|
+
onClick: ($event) => node.locked || node.is_dir ? toggleExpand(node) : download(node)
|
|
2432
|
+
}, toDisplayString(node.name), 11, _hoisted_52), createElementVNode("span", _hoisted_53, [node.is_dir ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [node.loaded ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createTextVNode(toDisplayString(t("folderItems", { count: folderFiles(node).length })) + " · " + toDisplayString(formatTotal(unref(totalSize)(folderFiles(node)))), 1)], 64)) : createCommentVNode("v-if", true)], 64)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [createTextVNode(toDisplayString(unref(formatSize)(node.size)) + " · " + toDisplayString(unref(formatDate)(node.modified)), 1)], 64))])]),
|
|
2433
|
+
node.is_dir && node.loaded ? (openBlock(), createElementBlock("span", _hoisted_54, toDisplayString(t("folderItems", { count: folderFiles(node).length })), 1)) : createCommentVNode("v-if", true),
|
|
2434
|
+
node.locked && node.prompting && node.unlockError ? (openBlock(), createElementBlock("span", {
|
|
2435
|
+
key: 6,
|
|
2436
|
+
id: `fl-unlock-error-${node.path}`,
|
|
2437
|
+
class: "fl-unlock-message",
|
|
2438
|
+
role: "alert"
|
|
2439
|
+
}, toDisplayString(unlockErrorText(node.unlockError)), 9, _hoisted_55)) : createCommentVNode("v-if", true),
|
|
2440
|
+
!node.locked && rememberedPaths.value.has(node.path) ? (openBlock(), createElementBlock("button", {
|
|
2441
|
+
key: 7,
|
|
2442
|
+
class: "fl-remembered",
|
|
2443
|
+
type: "button",
|
|
2444
|
+
"aria-label": `${t("forgetPassword")} ${node.name}`,
|
|
2445
|
+
title: t("forgetPassword"),
|
|
2446
|
+
onClick: ($event) => forgetPassword(node)
|
|
2447
|
+
}, [_cache[19] || (_cache[19] = createElementVNode("svg", {
|
|
2448
|
+
viewBox: "0 0 24 24",
|
|
2449
|
+
width: "11",
|
|
2450
|
+
height: "11",
|
|
2451
|
+
fill: "none",
|
|
2452
|
+
stroke: "currentColor",
|
|
2453
|
+
"stroke-width": "2.2",
|
|
2454
|
+
"stroke-linecap": "round",
|
|
2455
|
+
"stroke-linejoin": "round",
|
|
2456
|
+
"aria-hidden": "true"
|
|
2457
|
+
}, [
|
|
2458
|
+
createElementVNode("circle", {
|
|
2459
|
+
cx: "8",
|
|
2460
|
+
cy: "15",
|
|
2461
|
+
r: "4"
|
|
2462
|
+
}),
|
|
2463
|
+
createElementVNode("path", { d: "m11 12 9-9" }),
|
|
2464
|
+
createElementVNode("path", { d: "m17 6 3 3" })
|
|
2465
|
+
], -1)), createTextVNode(" " + toDisplayString(t("remembered")) + " · " + toDisplayString(t("forgetPassword")), 1)], 8, _hoisted_56)) : createCommentVNode("v-if", true),
|
|
2466
|
+
node.loading ? (openBlock(), createElementBlock("span", _hoisted_57, "…")) : createCommentVNode("v-if", true)
|
|
2467
|
+
], 8, _hoisted_45),
|
|
2468
|
+
node.locked && node.prompting ? (openBlock(), createElementBlock("form", {
|
|
1879
2469
|
key: 0,
|
|
1880
|
-
class: "fl-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
title: t("preview"),
|
|
1884
|
-
onClick: ($event) => preview(node)
|
|
1885
|
-
}, [..._cache[17] || (_cache[17] = [createElementVNode("svg", {
|
|
1886
|
-
viewBox: "0 0 24 24",
|
|
1887
|
-
width: "16",
|
|
1888
|
-
height: "16",
|
|
1889
|
-
fill: "none",
|
|
1890
|
-
stroke: "currentColor",
|
|
1891
|
-
"stroke-width": "2",
|
|
1892
|
-
"stroke-linecap": "round",
|
|
1893
|
-
"stroke-linejoin": "round",
|
|
1894
|
-
"aria-hidden": "true"
|
|
1895
|
-
}, [createElementVNode("path", { d: "M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z" }), createElementVNode("circle", {
|
|
1896
|
-
cx: "12",
|
|
1897
|
-
cy: "12",
|
|
1898
|
-
r: "3"
|
|
1899
|
-
})], -1)])], 8, _hoisted_53)) : createCommentVNode("v-if", true), createElementVNode("button", {
|
|
1900
|
-
class: "fl-action fl-download",
|
|
1901
|
-
type: "button",
|
|
1902
|
-
"aria-label": `${t("download")} ${node.name}`,
|
|
1903
|
-
title: t("download"),
|
|
1904
|
-
onClick: ($event) => download(node)
|
|
1905
|
-
}, [..._cache[18] || (_cache[18] = [createElementVNode("svg", {
|
|
1906
|
-
viewBox: "0 0 24 24",
|
|
1907
|
-
width: "16",
|
|
1908
|
-
height: "16",
|
|
1909
|
-
fill: "none",
|
|
1910
|
-
stroke: "currentColor",
|
|
1911
|
-
"stroke-width": "2",
|
|
1912
|
-
"stroke-linecap": "round",
|
|
1913
|
-
"stroke-linejoin": "round",
|
|
1914
|
-
"aria-hidden": "true"
|
|
2470
|
+
class: "fl-unlock fl-unlock-row",
|
|
2471
|
+
onSubmit: withModifiers(($event) => submitUnlock(node), ["prevent"]),
|
|
2472
|
+
onKeydown: withKeys(withModifiers(($event) => cancelUnlock(node), ["prevent"]), ["esc"])
|
|
1915
2473
|
}, [
|
|
1916
|
-
createElementVNode("
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
2474
|
+
_cache[23] || (_cache[23] = createElementVNode("svg", {
|
|
2475
|
+
class: "fl-unlock-lock",
|
|
2476
|
+
viewBox: "0 0 24 24",
|
|
2477
|
+
width: "18",
|
|
2478
|
+
height: "18",
|
|
2479
|
+
fill: "none",
|
|
2480
|
+
stroke: "currentColor",
|
|
2481
|
+
"stroke-width": "2.2",
|
|
2482
|
+
"stroke-linecap": "round",
|
|
2483
|
+
"stroke-linejoin": "round",
|
|
2484
|
+
"aria-hidden": "true"
|
|
2485
|
+
}, [createElementVNode("rect", {
|
|
2486
|
+
x: "5",
|
|
2487
|
+
y: "11",
|
|
2488
|
+
width: "14",
|
|
2489
|
+
height: "10",
|
|
2490
|
+
rx: "2"
|
|
2491
|
+
}), createElementVNode("path", { d: "M8 11V8a4 4 0 0 1 8 0v3" })], -1)),
|
|
2492
|
+
withDirectives(createElementVNode("input", {
|
|
2493
|
+
"onUpdate:modelValue": ($event) => node.unlockInput = $event,
|
|
2494
|
+
type: "password",
|
|
2495
|
+
autocomplete: "off",
|
|
2496
|
+
"data-unlock": node.path,
|
|
2497
|
+
placeholder: node.unlockError ? unlockErrorText(node.unlockError) : t("passwordPlaceholder"),
|
|
2498
|
+
"aria-label": t("passwordFor", { name: node.name }),
|
|
2499
|
+
"aria-invalid": !!node.unlockError,
|
|
2500
|
+
"aria-describedby": node.unlockError ? `fl-unlock-error-${node.path}` : void 0
|
|
2501
|
+
}, null, 8, _hoisted_59), [[vModelText, node.unlockInput]]),
|
|
2502
|
+
canRemember.value ? (openBlock(), createElementBlock("button", {
|
|
2503
|
+
key: 0,
|
|
2504
|
+
class: "fl-unlock-remember",
|
|
2505
|
+
type: "button",
|
|
2506
|
+
"aria-pressed": !!node.unlockRemember,
|
|
2507
|
+
"aria-label": t("rememberPassword"),
|
|
2508
|
+
title: t("rememberPassword"),
|
|
2509
|
+
onClick: ($event) => node.unlockRemember = !node.unlockRemember
|
|
2510
|
+
}, [..._cache[21] || (_cache[21] = [createElementVNode("svg", {
|
|
2511
|
+
viewBox: "0 0 24 24",
|
|
2512
|
+
width: "16",
|
|
2513
|
+
height: "16",
|
|
2514
|
+
fill: "none",
|
|
2515
|
+
stroke: "currentColor",
|
|
2516
|
+
"stroke-width": "2",
|
|
2517
|
+
"stroke-linecap": "round",
|
|
2518
|
+
"stroke-linejoin": "round",
|
|
2519
|
+
"aria-hidden": "true"
|
|
2520
|
+
}, [
|
|
2521
|
+
createElementVNode("circle", {
|
|
2522
|
+
cx: "8",
|
|
2523
|
+
cy: "15",
|
|
2524
|
+
r: "4"
|
|
2525
|
+
}),
|
|
2526
|
+
createElementVNode("path", { d: "m11 12 9-9" }),
|
|
2527
|
+
createElementVNode("path", { d: "m17 6 3 3" })
|
|
2528
|
+
], -1)])], 8, _hoisted_60)) : createCommentVNode("v-if", true),
|
|
2529
|
+
createElementVNode("button", {
|
|
2530
|
+
class: "fl-unlock-submit",
|
|
2531
|
+
type: "submit",
|
|
2532
|
+
disabled: node.unlockBusy || !node.unlockInput
|
|
2533
|
+
}, toDisplayString(t("open")), 9, _hoisted_61),
|
|
2534
|
+
createElementVNode("button", {
|
|
2535
|
+
class: "fl-unlock-cancel",
|
|
2536
|
+
type: "button",
|
|
2537
|
+
"aria-label": t("cancel"),
|
|
2538
|
+
title: t("cancel"),
|
|
2539
|
+
onClick: ($event) => cancelUnlock(node)
|
|
2540
|
+
}, [..._cache[22] || (_cache[22] = [createElementVNode("svg", {
|
|
2541
|
+
viewBox: "0 0 24 24",
|
|
2542
|
+
width: "14",
|
|
2543
|
+
height: "14",
|
|
2544
|
+
fill: "none",
|
|
2545
|
+
stroke: "currentColor",
|
|
2546
|
+
"stroke-width": "2.2",
|
|
2547
|
+
"stroke-linecap": "round",
|
|
2548
|
+
"aria-hidden": "true"
|
|
2549
|
+
}, [createElementVNode("path", { d: "M6 6l12 12" }), createElementVNode("path", { d: "M18 6 6 18" })], -1)])], 8, _hoisted_62)
|
|
2550
|
+
], 40, _hoisted_58)) : (openBlock(), createElementBlock(Fragment, { key: 1 }, [
|
|
2551
|
+
createElementVNode("span", _hoisted_63, toDisplayString(node.is_dir || node.locked ? "—" : unref(formatSize)(node.size)), 1),
|
|
2552
|
+
createElementVNode("span", _hoisted_64, toDisplayString(unref(formatDate)(node.modified)), 1),
|
|
2553
|
+
createElementVNode("span", _hoisted_65, [node.locked ? (openBlock(), createElementBlock("button", {
|
|
2554
|
+
key: 0,
|
|
2555
|
+
class: "fl-action fl-arrow-end fl-lock",
|
|
2556
|
+
type: "button",
|
|
2557
|
+
"aria-label": t("unlockFolder", { name: node.name }),
|
|
2558
|
+
onClick: ($event) => toggleExpand(node)
|
|
2559
|
+
}, [..._cache[24] || (_cache[24] = [createElementVNode("svg", {
|
|
2560
|
+
viewBox: "0 0 24 24",
|
|
2561
|
+
width: "18",
|
|
2562
|
+
height: "18",
|
|
2563
|
+
fill: "none",
|
|
2564
|
+
stroke: "currentColor",
|
|
2565
|
+
"stroke-width": "2.2",
|
|
2566
|
+
"stroke-linecap": "round",
|
|
2567
|
+
"stroke-linejoin": "round",
|
|
2568
|
+
"aria-hidden": "true"
|
|
2569
|
+
}, [createElementVNode("rect", {
|
|
2570
|
+
x: "5",
|
|
2571
|
+
y: "11",
|
|
2572
|
+
width: "14",
|
|
2573
|
+
height: "10",
|
|
2574
|
+
rx: "2"
|
|
2575
|
+
}), createElementVNode("path", { d: "M8 11V8a4 4 0 0 1 8 0v3" })], -1)])], 8, _hoisted_66)) : node.is_dir ? (openBlock(), createElementBlock("button", {
|
|
2576
|
+
key: 1,
|
|
2577
|
+
class: normalizeClass(["fl-action fl-arrow-end", { "fl-arrow-open": node.expanded }]),
|
|
2578
|
+
type: "button",
|
|
2579
|
+
"aria-label": t(node.expanded ? "collapse" : "expand", { name: node.name }),
|
|
2580
|
+
"aria-expanded": node.expanded,
|
|
2581
|
+
onClick: ($event) => toggleExpand(node)
|
|
2582
|
+
}, [..._cache[25] || (_cache[25] = [createElementVNode("svg", {
|
|
2583
|
+
viewBox: "0 0 24 24",
|
|
2584
|
+
width: "18",
|
|
2585
|
+
height: "18",
|
|
2586
|
+
fill: "none",
|
|
2587
|
+
stroke: "currentColor",
|
|
2588
|
+
"stroke-width": "2.2",
|
|
2589
|
+
"stroke-linecap": "round",
|
|
2590
|
+
"stroke-linejoin": "round",
|
|
2591
|
+
"aria-hidden": "true"
|
|
2592
|
+
}, [createElementVNode("path", { d: "m9 6 6 6-6 6" })], -1)])], 10, _hoisted_67)) : !node.locked ? (openBlock(), createElementBlock(Fragment, { key: 2 }, [canPreview(node) ? (openBlock(), createElementBlock("button", {
|
|
2593
|
+
key: 0,
|
|
2594
|
+
class: "fl-action fl-download",
|
|
2595
|
+
type: "button",
|
|
2596
|
+
"aria-label": `${t("preview")} ${node.name}`,
|
|
2597
|
+
title: t("preview"),
|
|
2598
|
+
onClick: ($event) => preview(node)
|
|
2599
|
+
}, [..._cache[26] || (_cache[26] = [createElementVNode("svg", {
|
|
2600
|
+
viewBox: "0 0 24 24",
|
|
2601
|
+
width: "16",
|
|
2602
|
+
height: "16",
|
|
2603
|
+
fill: "none",
|
|
2604
|
+
stroke: "currentColor",
|
|
2605
|
+
"stroke-width": "2",
|
|
2606
|
+
"stroke-linecap": "round",
|
|
2607
|
+
"stroke-linejoin": "round",
|
|
2608
|
+
"aria-hidden": "true"
|
|
2609
|
+
}, [createElementVNode("path", { d: "M2 12s3.5-7 10-7 10 7 10 7-3.5 7-10 7-10-7-10-7Z" }), createElementVNode("circle", {
|
|
2610
|
+
cx: "12",
|
|
2611
|
+
cy: "12",
|
|
2612
|
+
r: "3"
|
|
2613
|
+
})], -1)])], 8, _hoisted_68)) : createCommentVNode("v-if", true), createElementVNode("button", {
|
|
2614
|
+
class: "fl-action fl-download",
|
|
2615
|
+
type: "button",
|
|
2616
|
+
"aria-label": `${t("download")} ${node.name}`,
|
|
2617
|
+
title: t("download"),
|
|
2618
|
+
onClick: ($event) => download(node)
|
|
2619
|
+
}, [..._cache[27] || (_cache[27] = [createElementVNode("svg", {
|
|
2620
|
+
viewBox: "0 0 24 24",
|
|
2621
|
+
width: "16",
|
|
2622
|
+
height: "16",
|
|
2623
|
+
fill: "none",
|
|
2624
|
+
stroke: "currentColor",
|
|
2625
|
+
"stroke-width": "2",
|
|
2626
|
+
"stroke-linecap": "round",
|
|
2627
|
+
"stroke-linejoin": "round",
|
|
2628
|
+
"aria-hidden": "true"
|
|
2629
|
+
}, [
|
|
2630
|
+
createElementVNode("path", { d: "M12 3v12" }),
|
|
2631
|
+
createElementVNode("path", { d: "m7 10 5 5 5-5" }),
|
|
2632
|
+
createElementVNode("path", { d: "M5 21h14" })
|
|
2633
|
+
], -1)])], 8, _hoisted_69)], 64)) : createCommentVNode("v-if", true)])
|
|
2634
|
+
], 64))
|
|
1920
2635
|
], 6);
|
|
1921
2636
|
}), 128)),
|
|
1922
|
-
createElementVNode("div",
|
|
1923
|
-
toast.value ? (openBlock(), createElementBlock("div",
|
|
2637
|
+
createElementVNode("div", _hoisted_70, [createElementVNode("span", null, toDisplayString(t("loaded", { count: allFiles.value.length })) + " · " + toDisplayString(t("totalSize", { size: formatTotal(loadedBytes.value) })), 1)]),
|
|
2638
|
+
toast.value ? (openBlock(), createElementBlock("div", _hoisted_71, toDisplayString(toast.value), 1)) : createCommentVNode("v-if", true),
|
|
1924
2639
|
createVNode(_sfc_main$1, {
|
|
1925
2640
|
open: !!previewNode.value,
|
|
1926
2641
|
file: previewNode.value,
|
|
@@ -1933,9 +2648,9 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1933
2648
|
position: previewPosition.value,
|
|
1934
2649
|
total: previewPosition.value ? previewList.value.length : 0,
|
|
1935
2650
|
onClose: closePreview,
|
|
1936
|
-
onPrev: _cache[
|
|
1937
|
-
onNext: _cache[
|
|
1938
|
-
onDownload: _cache[
|
|
2651
|
+
onPrev: _cache[7] || (_cache[7] = ($event) => stepPreview(-1)),
|
|
2652
|
+
onNext: _cache[8] || (_cache[8] = ($event) => stepPreview(1)),
|
|
2653
|
+
onDownload: _cache[9] || (_cache[9] = ($event) => previewNode.value && download(previewNode.value))
|
|
1939
2654
|
}, null, 8, [
|
|
1940
2655
|
"open",
|
|
1941
2656
|
"file",
|
|
@@ -1948,7 +2663,7 @@ const _sfc_main = /*@__PURE__*/ defineComponent({
|
|
|
1948
2663
|
"position",
|
|
1949
2664
|
"total"
|
|
1950
2665
|
])
|
|
1951
|
-
],
|
|
2666
|
+
], 14, _hoisted_1);
|
|
1952
2667
|
};
|
|
1953
2668
|
}
|
|
1954
2669
|
});
|