diff --git a/dist/file-picker.esm.js b/dist/file-picker.esm.js
deleted file mode 100644
index d9f7ac1..0000000
--- a/dist/file-picker.esm.js
+++ /dev/null
@@ -1,1194 +0,0 @@
-// node_modules/fflate/esm/browser.js
-var u8 = Uint8Array;
-var u16 = Uint16Array;
-var i32 = Int32Array;
-var fleb = new u8([
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 1,
- 1,
- 1,
- 1,
- 2,
- 2,
- 2,
- 2,
- 3,
- 3,
- 3,
- 3,
- 4,
- 4,
- 4,
- 4,
- 5,
- 5,
- 5,
- 5,
- 0,
- /* unused */
- 0,
- 0,
- /* impossible */
- 0
-]);
-var fdeb = new u8([
- 0,
- 0,
- 0,
- 0,
- 1,
- 1,
- 2,
- 2,
- 3,
- 3,
- 4,
- 4,
- 5,
- 5,
- 6,
- 6,
- 7,
- 7,
- 8,
- 8,
- 9,
- 9,
- 10,
- 10,
- 11,
- 11,
- 12,
- 12,
- 13,
- 13,
- /* unused */
- 0,
- 0
-]);
-var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
-var freb = function(eb, start) {
- var b = new u16(31);
- for (var i = 0; i < 31; ++i) {
- b[i] = start += 1 << eb[i - 1];
- }
- var r = new i32(b[30]);
- for (var i = 1; i < 30; ++i) {
- for (var j = b[i]; j < b[i + 1]; ++j) {
- r[j] = j - b[i] << 5 | i;
- }
- }
- return { b, r };
-};
-var _a = freb(fleb, 2);
-var fl = _a.b;
-var revfl = _a.r;
-fl[28] = 258, revfl[258] = 28;
-var _b = freb(fdeb, 0);
-var fd = _b.b;
-var revfd = _b.r;
-var rev = new u16(32768);
-for (i = 0; i < 32768; ++i) {
- x = (i & 43690) >> 1 | (i & 21845) << 1;
- x = (x & 52428) >> 2 | (x & 13107) << 2;
- x = (x & 61680) >> 4 | (x & 3855) << 4;
- rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
-}
-var x;
-var i;
-var hMap = (function(cd, mb, r) {
- var s = cd.length;
- var i = 0;
- var l = new u16(mb);
- for (; i < s; ++i) {
- if (cd[i])
- ++l[cd[i] - 1];
- }
- var le = new u16(mb);
- for (i = 1; i < mb; ++i) {
- le[i] = le[i - 1] + l[i - 1] << 1;
- }
- var co;
- if (r) {
- co = new u16(1 << mb);
- var rvb = 15 - mb;
- for (i = 0; i < s; ++i) {
- if (cd[i]) {
- var sv = i << 4 | cd[i];
- var r_1 = mb - cd[i];
- var v = le[cd[i] - 1]++ << r_1;
- for (var m = v | (1 << r_1) - 1; v <= m; ++v) {
- co[rev[v] >> rvb] = sv;
- }
- }
- }
- } else {
- co = new u16(s);
- for (i = 0; i < s; ++i) {
- if (cd[i]) {
- co[i] = rev[le[cd[i] - 1]++] >> 15 - cd[i];
- }
- }
- }
- return co;
-});
-var flt = new u8(288);
-for (i = 0; i < 144; ++i)
- flt[i] = 8;
-var i;
-for (i = 144; i < 256; ++i)
- flt[i] = 9;
-var i;
-for (i = 256; i < 280; ++i)
- flt[i] = 7;
-var i;
-for (i = 280; i < 288; ++i)
- flt[i] = 8;
-var i;
-var fdt = new u8(32);
-for (i = 0; i < 32; ++i)
- fdt[i] = 5;
-var i;
-var flrm = /* @__PURE__ */ hMap(flt, 9, 1);
-var fdrm = /* @__PURE__ */ hMap(fdt, 5, 1);
-var max = function(a) {
- var m = a[0];
- for (var i = 1; i < a.length; ++i) {
- if (a[i] > m)
- m = a[i];
- }
- return m;
-};
-var bits = function(d, p, m) {
- var o = p / 8 | 0;
- return (d[o] | d[o + 1] << 8) >> (p & 7) & m;
-};
-var bits16 = function(d, p) {
- var o = p / 8 | 0;
- return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7);
-};
-var shft = function(p) {
- return (p + 7) / 8 | 0;
-};
-var slc = function(v, s, e) {
- if (s == null || s < 0)
- s = 0;
- if (e == null || e > v.length)
- e = v.length;
- return new u8(v.subarray(s, e));
-};
-var ec = [
- "unexpected EOF",
- "invalid block type",
- "invalid length/literal",
- "invalid distance",
- "stream finished",
- "no stream handler",
- ,
- // determined by compression function
- "no callback",
- "invalid UTF-8 data",
- "extra field too long",
- "date not in range 1980-2099",
- "filename too long",
- "stream finishing",
- "invalid zip data"
- // determined by unknown compression method
-];
-var err = function(ind, msg, nt) {
- var e = new Error(msg || ec[ind]);
- e.code = ind;
- if (Error.captureStackTrace)
- Error.captureStackTrace(e, err);
- if (!nt)
- throw e;
- return e;
-};
-var inflt = function(dat, st, buf, dict) {
- var sl = dat.length, dl = dict ? dict.length : 0;
- if (!sl || st.f && !st.l)
- return buf || new u8(0);
- var noBuf = !buf;
- var resize = noBuf || st.i != 2;
- var noSt = st.i;
- if (noBuf)
- buf = new u8(sl * 3);
- var cbuf = function(l2) {
- var bl = buf.length;
- if (l2 > bl) {
- var nbuf = new u8(Math.max(bl * 2, l2));
- nbuf.set(buf);
- buf = nbuf;
- }
- };
- var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n;
- var tbts = sl * 8;
- do {
- if (!lm) {
- final = bits(dat, pos, 1);
- var type = bits(dat, pos + 1, 3);
- pos += 3;
- if (!type) {
- var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l;
- if (t > sl) {
- if (noSt)
- err(0);
- break;
- }
- if (resize)
- cbuf(bt + l);
- buf.set(dat.subarray(s, t), bt);
- st.b = bt += l, st.p = pos = t * 8, st.f = final;
- continue;
- } else if (type == 1)
- lm = flrm, dm = fdrm, lbt = 9, dbt = 5;
- else if (type == 2) {
- var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;
- var tl = hLit + bits(dat, pos + 5, 31) + 1;
- pos += 14;
- var ldt = new u8(tl);
- var clt = new u8(19);
- for (var i = 0; i < hcLen; ++i) {
- clt[clim[i]] = bits(dat, pos + i * 3, 7);
- }
- pos += hcLen * 3;
- var clb = max(clt), clbmsk = (1 << clb) - 1;
- var clm = hMap(clt, clb, 1);
- for (var i = 0; i < tl; ) {
- var r = clm[bits(dat, pos, clbmsk)];
- pos += r & 15;
- var s = r >> 4;
- if (s < 16) {
- ldt[i++] = s;
- } else {
- var c = 0, n = 0;
- if (s == 16)
- n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1];
- else if (s == 17)
- n = 3 + bits(dat, pos, 7), pos += 3;
- else if (s == 18)
- n = 11 + bits(dat, pos, 127), pos += 7;
- while (n--)
- ldt[i++] = c;
- }
- }
- var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);
- lbt = max(lt);
- dbt = max(dt);
- lm = hMap(lt, lbt, 1);
- dm = hMap(dt, dbt, 1);
- } else
- err(1);
- if (pos > tbts) {
- if (noSt)
- err(0);
- break;
- }
- }
- if (resize)
- cbuf(bt + 131072);
- var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;
- var lpos = pos;
- for (; ; lpos = pos) {
- var c = lm[bits16(dat, pos) & lms], sym = c >> 4;
- pos += c & 15;
- if (pos > tbts) {
- if (noSt)
- err(0);
- break;
- }
- if (!c)
- err(2);
- if (sym < 256)
- buf[bt++] = sym;
- else if (sym == 256) {
- lpos = pos, lm = null;
- break;
- } else {
- var add = sym - 254;
- if (sym > 264) {
- var i = sym - 257, b = fleb[i];
- add = bits(dat, pos, (1 << b) - 1) + fl[i];
- pos += b;
- }
- var d = dm[bits16(dat, pos) & dms], dsym = d >> 4;
- if (!d)
- err(3);
- pos += d & 15;
- var dt = fd[dsym];
- if (dsym > 3) {
- var b = fdeb[dsym];
- dt += bits16(dat, pos) & (1 << b) - 1, pos += b;
- }
- if (pos > tbts) {
- if (noSt)
- err(0);
- break;
- }
- if (resize)
- cbuf(bt + 131072);
- var end = bt + add;
- if (bt < dt) {
- var shift = dl - dt, dend = Math.min(dt, end);
- if (shift + bt < 0)
- err(3);
- for (; bt < dend; ++bt)
- buf[bt] = dict[shift + bt];
- }
- for (; bt < end; ++bt)
- buf[bt] = buf[bt - dt];
- }
- }
- st.l = lm, st.p = lpos, st.b = bt, st.f = final;
- if (lm)
- final = 1, st.m = lbt, st.d = dm, st.n = dbt;
- } while (!final);
- return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);
-};
-var et = /* @__PURE__ */ new u8(0);
-var b2 = function(d, b) {
- return d[b] | d[b + 1] << 8;
-};
-var b4 = function(d, b) {
- return (d[b] | d[b + 1] << 8 | d[b + 2] << 16 | d[b + 3] << 24) >>> 0;
-};
-var b8 = function(d, b) {
- return b4(d, b) + b4(d, b + 4) * 4294967296;
-};
-function inflateSync(data, opts) {
- return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary);
-}
-var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder();
-var tds = 0;
-try {
- td.decode(et, { stream: true });
- tds = 1;
-} catch (e) {
-}
-var dutf8 = function(d) {
- for (var r = "", i = 0; ; ) {
- var c = d[i++];
- var eb = (c > 127) + (c > 223) + (c > 239);
- if (i + eb > d.length)
- return { s: r, r: slc(d, i - 1) };
- if (!eb)
- r += String.fromCharCode(c);
- else if (eb == 3) {
- c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | d[i++] & 63) - 65536, r += String.fromCharCode(55296 | c >> 10, 56320 | c & 1023);
- } else if (eb & 1)
- r += String.fromCharCode((c & 31) << 6 | d[i++] & 63);
- else
- r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | d[i++] & 63);
- }
-};
-function strFromU8(dat, latin1) {
- if (latin1) {
- var r = "";
- for (var i = 0; i < dat.length; i += 16384)
- r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384));
- return r;
- } else if (td) {
- return td.decode(dat);
- } else {
- var _a2 = dutf8(dat), s = _a2.s, r = _a2.r;
- if (r.length)
- err(8);
- return s;
- }
-}
-var slzh = function(d, b) {
- return b + 30 + b2(d, b + 26) + b2(d, b + 28);
-};
-var zh = function(d, b, z) {
- var fnl = b2(d, b + 28), efl = b2(d, b + 30), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl;
- var _a2 = z64hs(d, es, efl, z, b4(d, b + 20), b4(d, b + 24), b4(d, b + 42)), sc = _a2[0], su = _a2[1], off = _a2[2];
- return [b2(d, b + 10), sc, su, fn, es + efl + b2(d, b + 32), off];
-};
-var z64hs = function(d, b, l, z, sc, su, off) {
- var nsc = sc == 4294967295, nsu = su == 4294967295, noff = off == 4294967295, e = b + l;
- var nf = nsc + nsu + noff;
- if (z && nf) {
- for (; b + 4 < e; b += 4 + b2(d, b + 2)) {
- if (b2(d, b) == 1) {
- return [
- nsc ? b8(d, b + 4 + 8 * nsu) : sc,
- nsu ? b8(d, b + 4) : su,
- noff ? b8(d, b + 4 + 8 * (nsu + nsc)) : off,
- 1
- ];
- }
- }
- if (z < 2)
- err(13);
- }
- return [sc, su, off, 0];
-};
-function unzipSync(data, opts) {
- var files = {};
- var e = data.length - 22;
- for (; b4(data, e) != 101010256; --e) {
- if (!e || data.length - e > 65558)
- err(13);
- }
- ;
- var c = b2(data, e + 8);
- if (!c)
- return {};
- var o = b4(data, e + 16);
- var z = b4(data, e - 20) == 117853008;
- if (z) {
- var ze = b4(data, e - 12);
- z = b4(data, ze) == 101075792;
- if (z) {
- c = b4(data, ze + 32);
- o = b4(data, ze + 48);
- }
- }
- var fltr = opts && opts.filter;
- for (var i = 0; i < c; ++i) {
- var _a2 = zh(data, o, z), c_2 = _a2[0], sc = _a2[1], su = _a2[2], fn = _a2[3], no = _a2[4], off = _a2[5], b = slzh(data, off);
- o = no;
- if (!fltr || fltr({
- name: fn,
- size: sc,
- originalSize: su,
- compression: c_2
- })) {
- if (!c_2)
- files[fn] = slc(data, b, b + sc);
- else if (c_2 == 8)
- files[fn] = inflateSync(data.subarray(b, b + sc), { out: new u8(su) });
- else
- err(14, "unknown compression type " + c_2);
- }
- }
- return files;
-}
-
-// upload/frontend/table/rebase_tree.js
-function rebaseTree(root, prefix) {
- root.path = `${prefix}/${root.path}`;
- if (root.file) root.file = new File([root.file], root.file.name, { lastModified: root.file.lastModified });
- root.children.forEach((child) => rebaseTree(child, prefix));
- return root;
-}
-
-// upload/frontend/zip/list_zip_files.js
-var DEFAULT_LIMITS = {
- maxEntries: 1e3,
- maxTotalBytes: 100 * 1024 * 1024,
- maxEntryBytes: 50 * 1024 * 1024,
- maxDepth: 20
-};
-function extensionAllowed(name, allowedExt) {
- const lowerName = name.toLowerCase();
- return allowedExt.some((extension) => lowerName.endsWith(extension.toLowerCase()));
-}
-function makeFile(data, name) {
- return new File([data], name.split("/").at(-1));
-}
-function safeEntryParts(entryName) {
- if (!entryName || entryName.startsWith("/") || entryName.includes("\\")) return null;
- const parts = entryName.split("/");
- if (parts.some((part) => !part || part === "." || part === "..")) return null;
- return parts;
-}
-function node(kind, name, path, children = [], file = null) {
- return { id: crypto.randomUUID(), kind, name, path, children, file, expanded: kind === "file" };
-}
-function addPath(root, parts, fileNode) {
- let current = root;
- parts.forEach((part, index) => {
- const last = index === parts.length - 1;
- let child = current.children.find((item) => item.name === part);
- if (!child) {
- child = last ? fileNode : node("folder", part, `${current.path}/${part}`);
- current.children.push(child);
- }
- current = child;
- });
-}
-async function listEntries(data, zipName, allowedExt, depth, limits, budget) {
- if (depth > limits.maxDepth) throw new Error("\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u0433\u043B\u0443\u0431\u043E\u043A\u0430\u044F \u0432\u043B\u043E\u0436\u0435\u043D\u043D\u043E\u0441\u0442\u044C ZIP");
- const entries = unzipSync(data, {
- filter: (entry) => {
- budget.entries += 1;
- if (budget.entries > limits.maxEntries) throw new Error("\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u043C\u043D\u043E\u0433\u043E ZIP entries");
- const lowerName = entry.name.toLowerCase();
- if (!extensionAllowed(lowerName, allowedExt) && !lowerName.endsWith(".zip")) return false;
- if (entry.originalSize > limits.maxEntryBytes) return false;
- if (budget.totalBytes + entry.originalSize > limits.maxTotalBytes) {
- throw new Error("\u041F\u0440\u0435\u0432\u044B\u0448\u0435\u043D \u0441\u0443\u043C\u043C\u0430\u0440\u043D\u044B\u0439 \u0440\u0430\u0437\u043C\u0435\u0440 \u0440\u0430\u0441\u043F\u0430\u043A\u043E\u0432\u0430\u043D\u043D\u044B\u0445 ZIP entries");
- }
- budget.totalBytes += entry.originalSize;
- return true;
- }
- });
- const root = node("zip", zipName, zipName);
- for (const [entryName, entryData] of Object.entries(entries)) {
- if (entryName.endsWith("/")) continue;
- const parts = safeEntryParts(entryName);
- if (!parts) continue;
- const normalizedName = parts.join("/");
- if (normalizedName.toLowerCase().endsWith(".zip")) {
- const nested = await listEntries(entryData, entryName, allowedExt, depth + 1, limits, budget);
- if (nested) {
- rebaseTree(nested, zipName);
- nested.name = parts.at(-1);
- addPath(root, parts, nested);
- }
- } else if (extensionAllowed(normalizedName, allowedExt)) {
- const path = `${zipName}/${normalizedName}`;
- const file = makeFile(entryData, path);
- addPath(root, parts, node("file", parts.at(-1), path, [], file));
- }
- }
- return root.children.length ? root : null;
-}
-async function listZipFiles(file, allowedExt, customLimits = {}) {
- const data = new Uint8Array(await file.arrayBuffer());
- const limits = { ...DEFAULT_LIMITS, ...customLimits };
- return listEntries(data, file.name, allowedExt, 0, limits, { entries: 0, totalBytes: 0 });
-}
-
-// upload/frontend/table/add_file_with_dedup.js
-function addFileWithDedup(state, fileNode) {
- const accept = (node2) => {
- if (node2.kind === "file") {
- const key = `${node2.path}\0${node2.file.size}`;
- if (state.fileKeys.has(key)) return null;
- state.fileKeys.add(key);
- return node2;
- }
- node2.children = node2.children.map(accept).filter(Boolean);
- return node2.children.length ? node2 : null;
- };
- const accepted = accept(fileNode);
- if (!accepted || accepted.kind !== "file" && !accepted.children.length) return false;
- if (accepted.kind !== "file") {
- const existing = state.nodes.find((node2) => node2.kind !== "file" && node2.path === accepted.path);
- if (existing) {
- mergeChildren(existing, accepted);
- return true;
- }
- }
- state.nodes.push(accepted);
- return true;
-}
-function mergeChildren(target, incoming) {
- incoming.children.forEach((child) => {
- if (child.kind === "file") {
- const duplicate = target.children.some((existing2) => existing2.kind === "file" && existing2.path === child.path && existing2.file.size === child.file.size);
- if (!duplicate) target.children.push(child);
- return;
- }
- const existing = target.children.find((candidate) => candidate.kind !== "file" && candidate.path === child.path);
- if (existing) mergeChildren(existing, child);
- else target.children.push(child);
- });
-}
-
-// upload/frontend/table/esc.js
-function esc(value) {
- return String(value).replace(/[&<>"']/g, (character) => ({
- "&": "&",
- "<": "<",
- ">": ">",
- '"': """,
- "'": "'"
- })[character]);
-}
-
-// upload/frontend/table/fs.js
-function fs(bytes) {
- return bytes < 1024 ? `${bytes} B` : bytes < 1048576 ? `${(bytes / 1024).toFixed(1)} KB` : `${(bytes / 1048576).toFixed(1)} MB`;
-}
-
-// upload/frontend/table/render.js
-var DEFAULT_RENDER_CONFIG = {
- labels: {
- statusReady: "\u0433\u043E\u0442\u043E\u0432",
- remove: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C",
- empty: "\u041D\u0435\u0442 \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0445 \u0444\u0430\u0439\u043B\u043E\u0432",
- columns: { path: "\u041F\u0443\u0442\u044C", size: "\u0420\u0430\u0437\u043C\u0435\u0440", status: "\u0421\u0442\u0430\u0442\u0443\u0441" },
- count: (count, bytes) => `${count} \u0444\u0430\u0439\u043B\u043E\u0432 \xB7 ${fs(bytes)}`
- },
- layout: { columns: ["path", "size", "status"] }
-};
-function renderConfig(cfg = {}) {
- return {
- labels: {
- ...DEFAULT_RENDER_CONFIG.labels,
- ...cfg.labels || {},
- columns: {
- ...DEFAULT_RENDER_CONFIG.labels.columns,
- ...cfg.labels?.columns || {}
- }
- },
- layout: { ...DEFAULT_RENDER_CONFIG.layout, ...cfg.layout || {} }
- };
-}
-function renderNode(node2, depth, cfg) {
- const isGroup = node2.kind !== "file";
- const padding = depth * 4;
- const name = esc(node2.name);
- const action = isGroup ? `` : `${name}`;
- const remove = ``;
- const pathAttribute = node2.kind === "file" ? ` data-path="${esc(node2.path)}"` : "";
- const cells = {
- path: action,
- size: node2.kind === "file" ? fs(node2.file.size) : "",
- status: node2.error ? esc(node2.error) : node2.kind === "file" ? esc(cfg.labels.statusReady) : ""
- };
- const columns = cfg.layout.columns?.length ? cfg.layout.columns : Object.keys(DEFAULT_RENDER_CONFIG.labels.columns);
- const row = `
` + columns.map((column) => `| ${cells[column] || ""} | `).join("") + `${remove} |
`;
- if (!isGroup || !node2.expanded) return row;
- return row + node2.children.map((child) => renderNode(child, depth + 1, cfg)).join("");
-}
-function render(state, elements, cfg) {
- const normalized = renderConfig(cfg);
- const columns = normalized.layout.columns?.length ? normalized.layout.columns : Object.keys(DEFAULT_RENDER_CONFIG.labels.columns);
- elements.tableBodyEl.innerHTML = state.nodes.length ? state.nodes.map((node2) => renderNode(node2, 0, normalized)).join("") : `| ${esc(normalized.labels.empty)} |
`;
- const files = [];
- const visit = (node2) => {
- if (node2.kind === "file") files.push(node2);
- else node2.children.forEach(visit);
- };
- state.nodes.forEach(visit);
- const totalBytes = files.reduce((sum, node2) => sum + node2.file.size, 0);
- elements.countEl.textContent = normalized.labels.count(files.length, totalBytes);
-}
-function findNode(nodes, id) {
- for (const node2 of nodes) {
- if (node2.id === id) return { node: node2, nodes };
- const found = findNode(node2.children || [], id);
- if (found) return found;
- }
- return null;
-}
-function flattenFiles(nodes, result = []) {
- nodes.forEach((node2) => {
- if (node2.kind === "file") result.push({ path: node2.path, name: node2.name, size: node2.file.size, file: node2.file });
- else flattenFiles(node2.children, result);
- });
- return result;
-}
-
-// upload/frontend/table/on_files_change.js
-async function addFiles(state, cfg, files, elements) {
- for (const file of Array.from(files)) {
- if (!file.name.toLowerCase().endsWith(".zip")) {
- if (!cfg.allowedExt.some((extension) => file.name.toLowerCase().endsWith(extension.toLowerCase()))) {
- continue;
- }
- addFileWithDedup(state, {
- id: crypto.randomUUID(),
- kind: "file",
- name: file.name,
- path: file.name,
- file,
- children: [],
- expanded: true
- });
- continue;
- }
- try {
- const zipTree = await listZipFiles(file, cfg.allowedExt, cfg.limits);
- if (zipTree) addFileWithDedup(state, zipTree);
- } catch (error) {
- if (typeof cfg.onError === "function") {
- cfg.onError(error, file);
- } else if (elements.statusEl) {
- elements.statusEl.textContent = `\u041E\u0448\u0438\u0431\u043A\u0430 \u0447\u0442\u0435\u043D\u0438\u044F \u0430\u0440\u0445\u0438\u0432\u0430 ${file.name}: ${error.message}`;
- }
- continue;
- }
- }
- render(state, elements, cfg);
-}
-function onFilesChange(state, cfg, elements) {
- return async () => {
- if (state.busy) return;
- state.busy = true;
- try {
- await addFiles(state, cfg, elements.fileInputEl.files, elements);
- } finally {
- elements.fileInputEl.value = "";
- state.busy = false;
- }
- };
-}
-
-// upload/frontend/table/on_folder_change.js
-function onFolderChange(state, cfg, elements) {
- return async () => {
- if (state.busy) return;
- state.busy = true;
- try {
- const roots = /* @__PURE__ */ new Map();
- for (const file of Array.from(elements.folderInputEl.files)) {
- const parts = (file.webkitRelativePath || file.name).split("/");
- const relativePath = parts.slice(1).join("/") || file.name;
- const lowerPath = relativePath.toLowerCase();
- const rootName = parts[0] || file.name;
- if (!roots.has(rootName)) {
- roots.set(rootName, {
- id: crypto.randomUUID(),
- kind: "folder",
- name: rootName,
- path: rootName,
- children: [],
- expanded: false
- });
- }
- const root = roots.get(rootName);
- const addToFolder = (node2) => {
- let current = root;
- const nodeParts = node2.path.split("/").slice(1);
- nodeParts.forEach((part, index) => {
- const last = index === nodeParts.length - 1;
- let child = current.children.find((item) => item.name === part);
- if (!child) {
- child = last ? node2 : {
- id: crypto.randomUUID(),
- kind: "folder",
- name: part,
- path: `${rootName}/${nodeParts.slice(0, index + 1).join("/")}`,
- children: [],
- expanded: false
- };
- current.children.push(child);
- }
- current = child;
- });
- };
- if (lowerPath.endsWith(".zip")) {
- try {
- const zip = await listZipFiles(file, cfg.allowedExt, cfg.limits);
- if (zip) {
- rebaseTree(zip, rootName);
- addToFolder(zip);
- }
- } catch (error) {
- if (typeof cfg.onError === "function") {
- cfg.onError(error, file);
- } else if (elements.statusEl) {
- elements.statusEl.textContent = `\u041E\u0448\u0438\u0431\u043A\u0430 \u0447\u0442\u0435\u043D\u0438\u044F \u0430\u0440\u0445\u0438\u0432\u0430 ${file.name}: ${error.message}`;
- }
- continue;
- }
- } else if (cfg.allowedExt.some((extension) => lowerPath.endsWith(extension))) {
- addToFolder({
- id: crypto.randomUUID(),
- kind: "file",
- name: parts.at(-1),
- path: `${rootName}/${relativePath}`,
- file,
- children: [],
- expanded: true
- });
- }
- }
- roots.forEach((root) => addFileWithDedup(state, root));
- elements.folderInputEl.value = "";
- render(state, elements, cfg);
- } finally {
- state.busy = false;
- }
- };
-}
-
-// upload/frontend/upload/put_to_vm.js
-function putToVm(file, url, options = {}) {
- return new Promise((resolve, reject) => {
- const xhr = new XMLHttpRequest();
- if (options.onXHR) {
- options.onXHR(xhr);
- }
- const abortHandler = () => {
- xhr.abort();
- reject(new DOMException("Upload aborted", "AbortError"));
- };
- if (options.signal) {
- if (options.signal.aborted) {
- reject(new DOMException("Upload aborted", "AbortError"));
- return;
- }
- options.signal.addEventListener("abort", abortHandler, { once: true });
- }
- xhr.open("PUT", url);
- xhr.timeout = options.timeoutMs || 3e5;
- xhr.upload.onprogress = (e) => {
- if (e.lengthComputable && options.onProgress) {
- const pct = Math.round(e.loaded / e.total * 100);
- options.onProgress(pct, e.loaded, e.total);
- }
- };
- xhr.onload = () => {
- if (options.signal) {
- options.signal.removeEventListener("abort", abortHandler);
- }
- if (xhr.status >= 200 && xhr.status < 300) {
- resolve();
- } else {
- reject(new Error(`\u0411\u0443\u0444\u0435\u0440: HTTP ${xhr.status} ${xhr.statusText}`));
- }
- };
- xhr.onerror = () => {
- if (options.signal) {
- options.signal.removeEventListener("abort", abortHandler);
- }
- reject(new Error("\u0421\u0435\u0442\u0435\u0432\u0430\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0435 \u0432 \u0431\u0443\u0444\u0435\u0440"));
- };
- xhr.ontimeout = () => {
- if (options.signal) {
- options.signal.removeEventListener("abort", abortHandler);
- }
- reject(new Error(`\u0422\u0430\u0439\u043C\u0430\u0443\u0442 \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u044F \u043E\u0442\u0432\u0435\u0442\u0430 \u0431\u0443\u0444\u0435\u0440\u0430 (${Math.round(xhr.timeout / 1e3)}\u0441)`));
- };
- xhr.onabort = () => {
- if (options.signal) {
- options.signal.removeEventListener("abort", abortHandler);
- }
- reject(new DOMException("Upload aborted", "AbortError"));
- };
- xhr.send(file);
- });
-}
-
-// upload/frontend/upload/upload_via_vm.js
-function generateUuid() {
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
- return crypto.randomUUID();
- }
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
- const r = Math.random() * 16 | 0;
- const v = c === "x" ? r : r & 3 | 8;
- return v.toString(16);
- });
-}
-function normalizeFileEntry(item) {
- if (item instanceof File || item instanceof Blob) {
- return { name: item.name || "unnamed", size: item.size, file: item, path: item.name || "" };
- }
- if (item && item.file) {
- return {
- name: item.name || item.file.name || "unnamed",
- size: item.size ?? item.file.size ?? 0,
- file: item.file,
- path: item.path || item.name || ""
- };
- }
- throw new Error("\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043E\u0431\u044A\u0435\u043A\u0442 \u0444\u0430\u0439\u043B\u0430");
-}
-async function uploadViaVM(files, options = {}) {
- if (!options.vmUploadUrl) {
- return { ok: false, error: "\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 options.vmUploadUrl \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u0435\u043D" };
- }
- const normalizedFiles = Array.from(files).map(normalizeFileEntry);
- const total = normalizedFiles.length;
- if (total === 0) {
- return { ok: true, session: options.session || "", count: 0 };
- }
- const backendUrl = options.backendUploadUrl || (options.apiBase || "") + "/api/upload_refs";
- const vmBase = options.vmUploadUrl.endsWith("/") ? options.vmUploadUrl : `${options.vmUploadUrl}/`;
- let currentSession = options.session || "";
- let totalAdded = 0;
- for (let k = 0; k < total; k++) {
- if (options.signal?.aborted) {
- return { ok: false, error: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043E\u0442\u043C\u0435\u043D\u0435\u043D\u0430", aborted: true, session: currentSession };
- }
- const { name, size, file } = normalizedFiles[k];
- const fileKey = `${generateUuid()}_${k}`;
- const fileUrl = `${vmBase}${fileKey}`;
- if (options.onStatus) {
- options.onStatus(`\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u0432 \u0431\u0443\u0444\u0435\u0440 (${k + 1}/${total}): ${name}`);
- }
- if (options.onFileStatus) {
- options.onFileStatus(k, "\u23F3 \u0412 \u0431\u0443\u0444\u0435\u0440...");
- }
- const t0 = performance.now();
- try {
- await putToVm(file, fileUrl, {
- signal: options.signal,
- onXHR: options.onXHR,
- onProgress(pct, loaded, fileTotal) {
- const elapsed = (performance.now() - t0) / 1e3;
- const speed = elapsed > 0 ? loaded / elapsed : 0;
- if (options.onFileStatus) {
- options.onFileStatus(k, `\u23F3 ${pct}% (${fs(speed)}/s)`);
- }
- if (options.onProgress) {
- options.onProgress({ index: k, total, pct, speed, loaded, fileTotal, name });
- }
- }
- });
- } catch (err2) {
- if (options.signal?.aborted) {
- return { ok: false, error: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043E\u0442\u043C\u0435\u043D\u0435\u043D\u0430", aborted: true, session: currentSession };
- }
- if (options.onFileStatus) {
- options.onFileStatus(k, "\u2717 \u041E\u0448\u0438\u0431\u043A\u0430 \u0431\u0443\u0444\u0435\u0440\u0430");
- }
- return {
- ok: false,
- error: `\u041E\u0448\u0438\u0431\u043A\u0430 \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0438 \u0444\u0430\u0439\u043B\u0430 ${name} \u0432 \u0431\u0443\u0444\u0435\u0440: ${err2.message}`,
- failedIndex: k,
- session: currentSession
- };
- }
- if (options.onStatus) {
- options.onStatus(`\u041F\u0440\u0438\u0451\u043C \u0441\u0435\u0440\u0432\u0438\u0441\u043E\u043C (${k + 1}/${total}): ${name}`);
- }
- if (options.onFileStatus) {
- options.onFileStatus(k, "\u26A1 \u0412 \u0441\u0435\u0441\u0441\u0438\u044E...");
- }
- try {
- const resp = await fetch(backendUrl, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({
- session: currentSession,
- files: [{ name, size, url: fileUrl }]
- }),
- signal: options.signal
- });
- if (!resp.ok) {
- throw new Error(`HTTP ${resp.status} ${resp.statusText}`);
- }
- const data = await resp.json();
- if (!data.ok) {
- throw new Error(data.error || "\u0411\u044D\u043A\u0435\u043D\u0434 \u0432\u0435\u0440\u043D\u0443\u043B \u043E\u0448\u0438\u0431\u043A\u0443");
- }
- currentSession = data.session || currentSession;
- totalAdded = data.count ?? totalAdded + 1;
- if (options.onFileStatus) {
- options.onFileStatus(k, "\u2713 \u0414\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D");
- }
- if (options.onFileComplete) {
- options.onFileComplete({
- fileIndex: k,
- name,
- size,
- session: currentSession,
- totalAdded
- });
- }
- } catch (err2) {
- if (options.signal?.aborted) {
- return { ok: false, error: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043E\u0442\u043C\u0435\u043D\u0435\u043D\u0430", aborted: true, session: currentSession };
- }
- if (options.onFileStatus) {
- options.onFileStatus(k, "\u2717 \u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438\u0451\u043C\u0430");
- }
- return {
- ok: false,
- error: `\u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438\u0451\u043C\u0430 \u0444\u0430\u0439\u043B\u0430 ${name} \u0431\u044D\u043A\u0435\u043D\u0434\u043E\u043C: ${err2.message}`,
- failedIndex: k,
- session: currentSession
- };
- }
- }
- if (options.onStatus) {
- options.onStatus(`\u0417\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E. \u0423\u0441\u043F\u0435\u0448\u043D\u043E \u043F\u0435\u0440\u0435\u0434\u0430\u043D\u043E \u0444\u0430\u0439\u043B\u043E\u0432: ${total}`);
- }
- return { ok: true, session: currentSession, count: totalAdded };
-}
-
-// upload/frontend/index.js
-var DEFAULTS = {
- allowedExt: [],
- labels: {
- pickFiles: "\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0444\u0430\u0439\u043B\u044B",
- pickFolder: "\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u043F\u0430\u043F\u043A\u0443",
- clear: "\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C",
- empty: "\u041D\u0435\u0442 \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0445 \u0444\u0430\u0439\u043B\u043E\u0432",
- statusReady: "\u0433\u043E\u0442\u043E\u0432",
- remove: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C",
- columns: { path: "\u041F\u0443\u0442\u044C", size: "\u0420\u0430\u0437\u043C\u0435\u0440", status: "\u0421\u0442\u0430\u0442\u0443\u0441" },
- count: (count, bytes) => `${count} \u0444\u0430\u0439\u043B\u043E\u0432 \xB7 ${bytes} B`
- },
- layout: { columns: ["path", "size", "status"], controls: ["files", "folder", "clear"] },
- limits: {
- maxEntries: 1e3,
- maxTotalBytes: 100 * 1024 * 1024,
- maxEntryBytes: 50 * 1024 * 1024,
- maxDepth: 20
- }
-};
-function resolveMount(mount) {
- const element = typeof mount === "string" ? document.querySelector(mount) : mount;
- if (!element) throw new Error("File picker mount element \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D");
- return element;
-}
-function normalizeConfig(config) {
- return {
- ...config,
- allowedExt: config.allowedExt || DEFAULTS.allowedExt,
- labels: {
- ...DEFAULTS.labels,
- ...config.labels || {},
- columns: { ...DEFAULTS.labels.columns, ...config.labels?.columns || {} }
- },
- layout: { ...DEFAULTS.layout, ...config.layout || {} },
- limits: { ...DEFAULTS.limits, ...config.limits || {} }
- };
-}
-function injectStyles() {
- if (document.querySelector("style[data-file-picker]")) return;
- const style = document.createElement("style");
- style.dataset.filePicker = "";
- style.textContent = `
-.file-picker { color: #17211b; font-family: Georgia, 'Times New Roman', serif; }
-.file-picker .fp-toolbar { display: flex; flex-wrap: wrap; gap: 10px; margin: 16px 0; }
-.file-picker .fp-toolbar button { border: 0; border-radius: 4px; padding: 12px 17px; color: #f7faf4; background: #1f5a3b; font: 700 13px sans-serif; cursor: pointer; }
-.file-picker .fp-toolbar button.secondary { color: #1f5a3b; background: #cbdcc9; }
-.file-picker .fp-toolbar button.quiet { color: #5d6a61; background: transparent; }
-.file-picker .fp-table-wrap { overflow-x: auto; border-top: 1px solid #b9c7ba; }
-.file-picker .fp-table { width: 100%; border-collapse: collapse; font: 14px/1.4 sans-serif; }
-.file-picker .fp-table th, .file-picker .fp-table td { padding: 14px 10px; border-bottom: 1px solid #cbd5cc; text-align: left; }
-.file-picker .fp-table th { color: #56745f; font-size: 11px; text-transform: uppercase; letter-spacing: 1px; }
-.file-picker .fp-status, .file-picker .fp-count { color: #5d6a61; font: 13px sans-serif; }
-.file-picker .fp-count { min-height: 22px; }
-.file-picker .tree-name { display: inline-flex; align-items: center; gap: 8px; min-width: 240px; padding-top: 0; padding-bottom: 0; border: 0; background: transparent; color: #17211b; font: inherit; text-align: left; }
-.file-picker .tree-group { padding-left: 0; cursor: pointer; }
-.file-picker .tree-chevron { display: inline-block; width: 12px; color: #78917d; font-size: 10px; }
-.file-picker .remove-btn { padding: 2px 7px; color: #8c5148; background: transparent; font: 20px/1 sans-serif; }
-.file-picker .tree-row td:first-child { white-space: nowrap; }
-@media (max-width: 600px) { .file-picker .fp-toolbar button { flex: 1 1 42%; } }
-`;
- document.head.append(style);
-}
-function buildMarkup(root, cfg) {
- const controls = cfg.layout.controls || [];
- const control = (name, id, label, className = "") => controls.includes(name) ? `` : "";
- const columns = cfg.layout.columns?.length ? cfg.layout.columns : Object.keys(cfg.labels.columns);
- const headings = columns.map((column) => `${esc(cfg.labels.columns[column] || column)} | `).join("");
- root.innerHTML = `
-
-
-
-
- ${control("files", "fp-files-btn", cfg.labels.pickFiles)}
- ${control("folder", "fp-folder-btn", cfg.labels.pickFolder, "secondary")}
- ${control("clear", "fp-clear-btn", cfg.labels.clear, "quiet")}
-
-
-
-
-
`;
-}
-function notify(cfg, state) {
- if (typeof cfg.onChange === "function") cfg.onChange([...flattenFiles(state.nodes)]);
-}
-function removeMetadata(state, node2) {
- if (node2.kind === "file") {
- state.fileKeys.delete(`${node2.path}\0${node2.file.size}`);
- return;
- }
- node2.children.forEach((child) => removeMetadata(state, child));
-}
-function removeNode(state, id) {
- const found = findNode(state.nodes, id);
- if (!found) return false;
- removeMetadata(state, found.node);
- found.nodes.splice(found.nodes.indexOf(found.node), 1);
- return true;
-}
-function initFilePicker(config) {
- const cfg = normalizeConfig(config);
- const mount = resolveMount(cfg.mount);
- injectStyles();
- buildMarkup(mount, cfg);
- const root = mount.firstElementChild;
- const elements = {
- fileInputEl: root.querySelector(".fp-file-input"),
- folderInputEl: root.querySelector(".fp-folder-input"),
- statusEl: root.querySelector(".fp-status"),
- tableBodyEl: root.querySelector(".fp-table-body"),
- countEl: root.querySelector(".fp-count")
- };
- const state = { nodes: [], fileKeys: /* @__PURE__ */ new Set(), busy: false };
- const listeners = [];
- const listen = (target, event, handler) => {
- target.addEventListener(event, handler);
- listeners.push(() => target.removeEventListener(event, handler));
- };
- const redraw = () => render(state, elements, cfg);
- const filesChange = onFilesChange(state, cfg, elements);
- const folderChange = onFolderChange(state, cfg, elements);
- listen(elements.fileInputEl, "change", async () => {
- await filesChange();
- notify(cfg, state);
- });
- listen(elements.folderInputEl, "change", async () => {
- await folderChange();
- notify(cfg, state);
- });
- listen(elements.tableBodyEl, "click", (event) => {
- const toggle = event.target.closest("[data-toggle]");
- if (toggle) {
- const found = findNode(state.nodes, toggle.dataset.toggle);
- if (found) found.node.expanded = !found.node.expanded;
- redraw();
- return;
- }
- const remove = event.target.closest("[data-remove]");
- if (remove) {
- if (removeNode(state, remove.dataset.remove)) {
- redraw();
- notify(cfg, state);
- }
- }
- });
- if (root.querySelector("#fp-files-btn")) listen(root.querySelector("#fp-files-btn"), "click", () => elements.fileInputEl.click());
- if (root.querySelector("#fp-folder-btn")) listen(root.querySelector("#fp-folder-btn"), "click", () => elements.folderInputEl.click());
- if (root.querySelector("#fp-clear-btn")) listen(root.querySelector("#fp-clear-btn"), "click", () => {
- state.nodes = [];
- state.fileKeys.clear();
- redraw();
- notify(cfg, state);
- });
- redraw();
- return {
- pickFiles: () => elements.fileInputEl.click(),
- pickFolder: () => elements.folderInputEl.click(),
- addFiles: async (files) => {
- await addFiles(state, cfg, files, elements);
- notify(cfg, state);
- },
- getFiles: () => [...flattenFiles(state.nodes)],
- remove: (id) => {
- if (removeNode(state, id)) {
- redraw();
- notify(cfg, state);
- }
- },
- clear: () => {
- state.nodes = [];
- state.fileKeys.clear();
- redraw();
- notify(cfg, state);
- },
- render: redraw,
- destroy: () => {
- listeners.forEach((removeListener) => removeListener());
- state.nodes = [];
- state.fileKeys.clear();
- mount.replaceChildren();
- }
- };
-}
-export {
- DEFAULTS,
- initFilePicker,
- putToVm,
- uploadViaVM
-};
diff --git a/dist/file-picker.iife.js b/dist/file-picker.iife.js
deleted file mode 100644
index 0659d05..0000000
--- a/dist/file-picker.iife.js
+++ /dev/null
@@ -1,1218 +0,0 @@
-var FilePicker = (() => {
- var __defProp = Object.defineProperty;
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
- var __getOwnPropNames = Object.getOwnPropertyNames;
- var __hasOwnProp = Object.prototype.hasOwnProperty;
- var __export = (target, all) => {
- for (var name in all)
- __defProp(target, name, { get: all[name], enumerable: true });
- };
- var __copyProps = (to, from, except, desc) => {
- if (from && typeof from === "object" || typeof from === "function") {
- for (let key of __getOwnPropNames(from))
- if (!__hasOwnProp.call(to, key) && key !== except)
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
- }
- return to;
- };
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
-
- // upload/frontend/index.js
- var index_exports = {};
- __export(index_exports, {
- DEFAULTS: () => DEFAULTS,
- initFilePicker: () => initFilePicker,
- putToVm: () => putToVm,
- uploadViaVM: () => uploadViaVM
- });
-
- // node_modules/fflate/esm/browser.js
- var u8 = Uint8Array;
- var u16 = Uint16Array;
- var i32 = Int32Array;
- var fleb = new u8([
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 1,
- 1,
- 1,
- 1,
- 2,
- 2,
- 2,
- 2,
- 3,
- 3,
- 3,
- 3,
- 4,
- 4,
- 4,
- 4,
- 5,
- 5,
- 5,
- 5,
- 0,
- /* unused */
- 0,
- 0,
- /* impossible */
- 0
- ]);
- var fdeb = new u8([
- 0,
- 0,
- 0,
- 0,
- 1,
- 1,
- 2,
- 2,
- 3,
- 3,
- 4,
- 4,
- 5,
- 5,
- 6,
- 6,
- 7,
- 7,
- 8,
- 8,
- 9,
- 9,
- 10,
- 10,
- 11,
- 11,
- 12,
- 12,
- 13,
- 13,
- /* unused */
- 0,
- 0
- ]);
- var clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
- var freb = function(eb, start) {
- var b = new u16(31);
- for (var i = 0; i < 31; ++i) {
- b[i] = start += 1 << eb[i - 1];
- }
- var r = new i32(b[30]);
- for (var i = 1; i < 30; ++i) {
- for (var j = b[i]; j < b[i + 1]; ++j) {
- r[j] = j - b[i] << 5 | i;
- }
- }
- return { b, r };
- };
- var _a = freb(fleb, 2);
- var fl = _a.b;
- var revfl = _a.r;
- fl[28] = 258, revfl[258] = 28;
- var _b = freb(fdeb, 0);
- var fd = _b.b;
- var revfd = _b.r;
- var rev = new u16(32768);
- for (i = 0; i < 32768; ++i) {
- x = (i & 43690) >> 1 | (i & 21845) << 1;
- x = (x & 52428) >> 2 | (x & 13107) << 2;
- x = (x & 61680) >> 4 | (x & 3855) << 4;
- rev[i] = ((x & 65280) >> 8 | (x & 255) << 8) >> 1;
- }
- var x;
- var i;
- var hMap = (function(cd, mb, r) {
- var s = cd.length;
- var i = 0;
- var l = new u16(mb);
- for (; i < s; ++i) {
- if (cd[i])
- ++l[cd[i] - 1];
- }
- var le = new u16(mb);
- for (i = 1; i < mb; ++i) {
- le[i] = le[i - 1] + l[i - 1] << 1;
- }
- var co;
- if (r) {
- co = new u16(1 << mb);
- var rvb = 15 - mb;
- for (i = 0; i < s; ++i) {
- if (cd[i]) {
- var sv = i << 4 | cd[i];
- var r_1 = mb - cd[i];
- var v = le[cd[i] - 1]++ << r_1;
- for (var m = v | (1 << r_1) - 1; v <= m; ++v) {
- co[rev[v] >> rvb] = sv;
- }
- }
- }
- } else {
- co = new u16(s);
- for (i = 0; i < s; ++i) {
- if (cd[i]) {
- co[i] = rev[le[cd[i] - 1]++] >> 15 - cd[i];
- }
- }
- }
- return co;
- });
- var flt = new u8(288);
- for (i = 0; i < 144; ++i)
- flt[i] = 8;
- var i;
- for (i = 144; i < 256; ++i)
- flt[i] = 9;
- var i;
- for (i = 256; i < 280; ++i)
- flt[i] = 7;
- var i;
- for (i = 280; i < 288; ++i)
- flt[i] = 8;
- var i;
- var fdt = new u8(32);
- for (i = 0; i < 32; ++i)
- fdt[i] = 5;
- var i;
- var flrm = /* @__PURE__ */ hMap(flt, 9, 1);
- var fdrm = /* @__PURE__ */ hMap(fdt, 5, 1);
- var max = function(a) {
- var m = a[0];
- for (var i = 1; i < a.length; ++i) {
- if (a[i] > m)
- m = a[i];
- }
- return m;
- };
- var bits = function(d, p, m) {
- var o = p / 8 | 0;
- return (d[o] | d[o + 1] << 8) >> (p & 7) & m;
- };
- var bits16 = function(d, p) {
- var o = p / 8 | 0;
- return (d[o] | d[o + 1] << 8 | d[o + 2] << 16) >> (p & 7);
- };
- var shft = function(p) {
- return (p + 7) / 8 | 0;
- };
- var slc = function(v, s, e) {
- if (s == null || s < 0)
- s = 0;
- if (e == null || e > v.length)
- e = v.length;
- return new u8(v.subarray(s, e));
- };
- var ec = [
- "unexpected EOF",
- "invalid block type",
- "invalid length/literal",
- "invalid distance",
- "stream finished",
- "no stream handler",
- ,
- // determined by compression function
- "no callback",
- "invalid UTF-8 data",
- "extra field too long",
- "date not in range 1980-2099",
- "filename too long",
- "stream finishing",
- "invalid zip data"
- // determined by unknown compression method
- ];
- var err = function(ind, msg, nt) {
- var e = new Error(msg || ec[ind]);
- e.code = ind;
- if (Error.captureStackTrace)
- Error.captureStackTrace(e, err);
- if (!nt)
- throw e;
- return e;
- };
- var inflt = function(dat, st, buf, dict) {
- var sl = dat.length, dl = dict ? dict.length : 0;
- if (!sl || st.f && !st.l)
- return buf || new u8(0);
- var noBuf = !buf;
- var resize = noBuf || st.i != 2;
- var noSt = st.i;
- if (noBuf)
- buf = new u8(sl * 3);
- var cbuf = function(l2) {
- var bl = buf.length;
- if (l2 > bl) {
- var nbuf = new u8(Math.max(bl * 2, l2));
- nbuf.set(buf);
- buf = nbuf;
- }
- };
- var final = st.f || 0, pos = st.p || 0, bt = st.b || 0, lm = st.l, dm = st.d, lbt = st.m, dbt = st.n;
- var tbts = sl * 8;
- do {
- if (!lm) {
- final = bits(dat, pos, 1);
- var type = bits(dat, pos + 1, 3);
- pos += 3;
- if (!type) {
- var s = shft(pos) + 4, l = dat[s - 4] | dat[s - 3] << 8, t = s + l;
- if (t > sl) {
- if (noSt)
- err(0);
- break;
- }
- if (resize)
- cbuf(bt + l);
- buf.set(dat.subarray(s, t), bt);
- st.b = bt += l, st.p = pos = t * 8, st.f = final;
- continue;
- } else if (type == 1)
- lm = flrm, dm = fdrm, lbt = 9, dbt = 5;
- else if (type == 2) {
- var hLit = bits(dat, pos, 31) + 257, hcLen = bits(dat, pos + 10, 15) + 4;
- var tl = hLit + bits(dat, pos + 5, 31) + 1;
- pos += 14;
- var ldt = new u8(tl);
- var clt = new u8(19);
- for (var i = 0; i < hcLen; ++i) {
- clt[clim[i]] = bits(dat, pos + i * 3, 7);
- }
- pos += hcLen * 3;
- var clb = max(clt), clbmsk = (1 << clb) - 1;
- var clm = hMap(clt, clb, 1);
- for (var i = 0; i < tl; ) {
- var r = clm[bits(dat, pos, clbmsk)];
- pos += r & 15;
- var s = r >> 4;
- if (s < 16) {
- ldt[i++] = s;
- } else {
- var c = 0, n = 0;
- if (s == 16)
- n = 3 + bits(dat, pos, 3), pos += 2, c = ldt[i - 1];
- else if (s == 17)
- n = 3 + bits(dat, pos, 7), pos += 3;
- else if (s == 18)
- n = 11 + bits(dat, pos, 127), pos += 7;
- while (n--)
- ldt[i++] = c;
- }
- }
- var lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);
- lbt = max(lt);
- dbt = max(dt);
- lm = hMap(lt, lbt, 1);
- dm = hMap(dt, dbt, 1);
- } else
- err(1);
- if (pos > tbts) {
- if (noSt)
- err(0);
- break;
- }
- }
- if (resize)
- cbuf(bt + 131072);
- var lms = (1 << lbt) - 1, dms = (1 << dbt) - 1;
- var lpos = pos;
- for (; ; lpos = pos) {
- var c = lm[bits16(dat, pos) & lms], sym = c >> 4;
- pos += c & 15;
- if (pos > tbts) {
- if (noSt)
- err(0);
- break;
- }
- if (!c)
- err(2);
- if (sym < 256)
- buf[bt++] = sym;
- else if (sym == 256) {
- lpos = pos, lm = null;
- break;
- } else {
- var add = sym - 254;
- if (sym > 264) {
- var i = sym - 257, b = fleb[i];
- add = bits(dat, pos, (1 << b) - 1) + fl[i];
- pos += b;
- }
- var d = dm[bits16(dat, pos) & dms], dsym = d >> 4;
- if (!d)
- err(3);
- pos += d & 15;
- var dt = fd[dsym];
- if (dsym > 3) {
- var b = fdeb[dsym];
- dt += bits16(dat, pos) & (1 << b) - 1, pos += b;
- }
- if (pos > tbts) {
- if (noSt)
- err(0);
- break;
- }
- if (resize)
- cbuf(bt + 131072);
- var end = bt + add;
- if (bt < dt) {
- var shift = dl - dt, dend = Math.min(dt, end);
- if (shift + bt < 0)
- err(3);
- for (; bt < dend; ++bt)
- buf[bt] = dict[shift + bt];
- }
- for (; bt < end; ++bt)
- buf[bt] = buf[bt - dt];
- }
- }
- st.l = lm, st.p = lpos, st.b = bt, st.f = final;
- if (lm)
- final = 1, st.m = lbt, st.d = dm, st.n = dbt;
- } while (!final);
- return bt != buf.length && noBuf ? slc(buf, 0, bt) : buf.subarray(0, bt);
- };
- var et = /* @__PURE__ */ new u8(0);
- var b2 = function(d, b) {
- return d[b] | d[b + 1] << 8;
- };
- var b4 = function(d, b) {
- return (d[b] | d[b + 1] << 8 | d[b + 2] << 16 | d[b + 3] << 24) >>> 0;
- };
- var b8 = function(d, b) {
- return b4(d, b) + b4(d, b + 4) * 4294967296;
- };
- function inflateSync(data, opts) {
- return inflt(data, { i: 2 }, opts && opts.out, opts && opts.dictionary);
- }
- var td = typeof TextDecoder != "undefined" && /* @__PURE__ */ new TextDecoder();
- var tds = 0;
- try {
- td.decode(et, { stream: true });
- tds = 1;
- } catch (e) {
- }
- var dutf8 = function(d) {
- for (var r = "", i = 0; ; ) {
- var c = d[i++];
- var eb = (c > 127) + (c > 223) + (c > 239);
- if (i + eb > d.length)
- return { s: r, r: slc(d, i - 1) };
- if (!eb)
- r += String.fromCharCode(c);
- else if (eb == 3) {
- c = ((c & 15) << 18 | (d[i++] & 63) << 12 | (d[i++] & 63) << 6 | d[i++] & 63) - 65536, r += String.fromCharCode(55296 | c >> 10, 56320 | c & 1023);
- } else if (eb & 1)
- r += String.fromCharCode((c & 31) << 6 | d[i++] & 63);
- else
- r += String.fromCharCode((c & 15) << 12 | (d[i++] & 63) << 6 | d[i++] & 63);
- }
- };
- function strFromU8(dat, latin1) {
- if (latin1) {
- var r = "";
- for (var i = 0; i < dat.length; i += 16384)
- r += String.fromCharCode.apply(null, dat.subarray(i, i + 16384));
- return r;
- } else if (td) {
- return td.decode(dat);
- } else {
- var _a2 = dutf8(dat), s = _a2.s, r = _a2.r;
- if (r.length)
- err(8);
- return s;
- }
- }
- var slzh = function(d, b) {
- return b + 30 + b2(d, b + 26) + b2(d, b + 28);
- };
- var zh = function(d, b, z) {
- var fnl = b2(d, b + 28), efl = b2(d, b + 30), fn = strFromU8(d.subarray(b + 46, b + 46 + fnl), !(b2(d, b + 8) & 2048)), es = b + 46 + fnl;
- var _a2 = z64hs(d, es, efl, z, b4(d, b + 20), b4(d, b + 24), b4(d, b + 42)), sc = _a2[0], su = _a2[1], off = _a2[2];
- return [b2(d, b + 10), sc, su, fn, es + efl + b2(d, b + 32), off];
- };
- var z64hs = function(d, b, l, z, sc, su, off) {
- var nsc = sc == 4294967295, nsu = su == 4294967295, noff = off == 4294967295, e = b + l;
- var nf = nsc + nsu + noff;
- if (z && nf) {
- for (; b + 4 < e; b += 4 + b2(d, b + 2)) {
- if (b2(d, b) == 1) {
- return [
- nsc ? b8(d, b + 4 + 8 * nsu) : sc,
- nsu ? b8(d, b + 4) : su,
- noff ? b8(d, b + 4 + 8 * (nsu + nsc)) : off,
- 1
- ];
- }
- }
- if (z < 2)
- err(13);
- }
- return [sc, su, off, 0];
- };
- function unzipSync(data, opts) {
- var files = {};
- var e = data.length - 22;
- for (; b4(data, e) != 101010256; --e) {
- if (!e || data.length - e > 65558)
- err(13);
- }
- ;
- var c = b2(data, e + 8);
- if (!c)
- return {};
- var o = b4(data, e + 16);
- var z = b4(data, e - 20) == 117853008;
- if (z) {
- var ze = b4(data, e - 12);
- z = b4(data, ze) == 101075792;
- if (z) {
- c = b4(data, ze + 32);
- o = b4(data, ze + 48);
- }
- }
- var fltr = opts && opts.filter;
- for (var i = 0; i < c; ++i) {
- var _a2 = zh(data, o, z), c_2 = _a2[0], sc = _a2[1], su = _a2[2], fn = _a2[3], no = _a2[4], off = _a2[5], b = slzh(data, off);
- o = no;
- if (!fltr || fltr({
- name: fn,
- size: sc,
- originalSize: su,
- compression: c_2
- })) {
- if (!c_2)
- files[fn] = slc(data, b, b + sc);
- else if (c_2 == 8)
- files[fn] = inflateSync(data.subarray(b, b + sc), { out: new u8(su) });
- else
- err(14, "unknown compression type " + c_2);
- }
- }
- return files;
- }
-
- // upload/frontend/table/rebase_tree.js
- function rebaseTree(root, prefix) {
- root.path = `${prefix}/${root.path}`;
- if (root.file) root.file = new File([root.file], root.file.name, { lastModified: root.file.lastModified });
- root.children.forEach((child) => rebaseTree(child, prefix));
- return root;
- }
-
- // upload/frontend/zip/list_zip_files.js
- var DEFAULT_LIMITS = {
- maxEntries: 1e3,
- maxTotalBytes: 100 * 1024 * 1024,
- maxEntryBytes: 50 * 1024 * 1024,
- maxDepth: 20
- };
- function extensionAllowed(name, allowedExt) {
- const lowerName = name.toLowerCase();
- return allowedExt.some((extension) => lowerName.endsWith(extension.toLowerCase()));
- }
- function makeFile(data, name) {
- return new File([data], name.split("/").at(-1));
- }
- function safeEntryParts(entryName) {
- if (!entryName || entryName.startsWith("/") || entryName.includes("\\")) return null;
- const parts = entryName.split("/");
- if (parts.some((part) => !part || part === "." || part === "..")) return null;
- return parts;
- }
- function node(kind, name, path, children = [], file = null) {
- return { id: crypto.randomUUID(), kind, name, path, children, file, expanded: kind === "file" };
- }
- function addPath(root, parts, fileNode) {
- let current = root;
- parts.forEach((part, index) => {
- const last = index === parts.length - 1;
- let child = current.children.find((item) => item.name === part);
- if (!child) {
- child = last ? fileNode : node("folder", part, `${current.path}/${part}`);
- current.children.push(child);
- }
- current = child;
- });
- }
- async function listEntries(data, zipName, allowedExt, depth, limits, budget) {
- if (depth > limits.maxDepth) throw new Error("\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u0433\u043B\u0443\u0431\u043E\u043A\u0430\u044F \u0432\u043B\u043E\u0436\u0435\u043D\u043D\u043E\u0441\u0442\u044C ZIP");
- const entries = unzipSync(data, {
- filter: (entry) => {
- budget.entries += 1;
- if (budget.entries > limits.maxEntries) throw new Error("\u0421\u043B\u0438\u0448\u043A\u043E\u043C \u043C\u043D\u043E\u0433\u043E ZIP entries");
- const lowerName = entry.name.toLowerCase();
- if (!extensionAllowed(lowerName, allowedExt) && !lowerName.endsWith(".zip")) return false;
- if (entry.originalSize > limits.maxEntryBytes) return false;
- if (budget.totalBytes + entry.originalSize > limits.maxTotalBytes) {
- throw new Error("\u041F\u0440\u0435\u0432\u044B\u0448\u0435\u043D \u0441\u0443\u043C\u043C\u0430\u0440\u043D\u044B\u0439 \u0440\u0430\u0437\u043C\u0435\u0440 \u0440\u0430\u0441\u043F\u0430\u043A\u043E\u0432\u0430\u043D\u043D\u044B\u0445 ZIP entries");
- }
- budget.totalBytes += entry.originalSize;
- return true;
- }
- });
- const root = node("zip", zipName, zipName);
- for (const [entryName, entryData] of Object.entries(entries)) {
- if (entryName.endsWith("/")) continue;
- const parts = safeEntryParts(entryName);
- if (!parts) continue;
- const normalizedName = parts.join("/");
- if (normalizedName.toLowerCase().endsWith(".zip")) {
- const nested = await listEntries(entryData, entryName, allowedExt, depth + 1, limits, budget);
- if (nested) {
- rebaseTree(nested, zipName);
- nested.name = parts.at(-1);
- addPath(root, parts, nested);
- }
- } else if (extensionAllowed(normalizedName, allowedExt)) {
- const path = `${zipName}/${normalizedName}`;
- const file = makeFile(entryData, path);
- addPath(root, parts, node("file", parts.at(-1), path, [], file));
- }
- }
- return root.children.length ? root : null;
- }
- async function listZipFiles(file, allowedExt, customLimits = {}) {
- const data = new Uint8Array(await file.arrayBuffer());
- const limits = { ...DEFAULT_LIMITS, ...customLimits };
- return listEntries(data, file.name, allowedExt, 0, limits, { entries: 0, totalBytes: 0 });
- }
-
- // upload/frontend/table/add_file_with_dedup.js
- function addFileWithDedup(state, fileNode) {
- const accept = (node2) => {
- if (node2.kind === "file") {
- const key = `${node2.path}\0${node2.file.size}`;
- if (state.fileKeys.has(key)) return null;
- state.fileKeys.add(key);
- return node2;
- }
- node2.children = node2.children.map(accept).filter(Boolean);
- return node2.children.length ? node2 : null;
- };
- const accepted = accept(fileNode);
- if (!accepted || accepted.kind !== "file" && !accepted.children.length) return false;
- if (accepted.kind !== "file") {
- const existing = state.nodes.find((node2) => node2.kind !== "file" && node2.path === accepted.path);
- if (existing) {
- mergeChildren(existing, accepted);
- return true;
- }
- }
- state.nodes.push(accepted);
- return true;
- }
- function mergeChildren(target, incoming) {
- incoming.children.forEach((child) => {
- if (child.kind === "file") {
- const duplicate = target.children.some((existing2) => existing2.kind === "file" && existing2.path === child.path && existing2.file.size === child.file.size);
- if (!duplicate) target.children.push(child);
- return;
- }
- const existing = target.children.find((candidate) => candidate.kind !== "file" && candidate.path === child.path);
- if (existing) mergeChildren(existing, child);
- else target.children.push(child);
- });
- }
-
- // upload/frontend/table/esc.js
- function esc(value) {
- return String(value).replace(/[&<>"']/g, (character) => ({
- "&": "&",
- "<": "<",
- ">": ">",
- '"': """,
- "'": "'"
- })[character]);
- }
-
- // upload/frontend/table/fs.js
- function fs(bytes) {
- return bytes < 1024 ? `${bytes} B` : bytes < 1048576 ? `${(bytes / 1024).toFixed(1)} KB` : `${(bytes / 1048576).toFixed(1)} MB`;
- }
-
- // upload/frontend/table/render.js
- var DEFAULT_RENDER_CONFIG = {
- labels: {
- statusReady: "\u0433\u043E\u0442\u043E\u0432",
- remove: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C",
- empty: "\u041D\u0435\u0442 \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0445 \u0444\u0430\u0439\u043B\u043E\u0432",
- columns: { path: "\u041F\u0443\u0442\u044C", size: "\u0420\u0430\u0437\u043C\u0435\u0440", status: "\u0421\u0442\u0430\u0442\u0443\u0441" },
- count: (count, bytes) => `${count} \u0444\u0430\u0439\u043B\u043E\u0432 \xB7 ${fs(bytes)}`
- },
- layout: { columns: ["path", "size", "status"] }
- };
- function renderConfig(cfg = {}) {
- return {
- labels: {
- ...DEFAULT_RENDER_CONFIG.labels,
- ...cfg.labels || {},
- columns: {
- ...DEFAULT_RENDER_CONFIG.labels.columns,
- ...cfg.labels?.columns || {}
- }
- },
- layout: { ...DEFAULT_RENDER_CONFIG.layout, ...cfg.layout || {} }
- };
- }
- function renderNode(node2, depth, cfg) {
- const isGroup = node2.kind !== "file";
- const padding = depth * 4;
- const name = esc(node2.name);
- const action = isGroup ? `` : `${name}`;
- const remove = ``;
- const pathAttribute = node2.kind === "file" ? ` data-path="${esc(node2.path)}"` : "";
- const cells = {
- path: action,
- size: node2.kind === "file" ? fs(node2.file.size) : "",
- status: node2.error ? esc(node2.error) : node2.kind === "file" ? esc(cfg.labels.statusReady) : ""
- };
- const columns = cfg.layout.columns?.length ? cfg.layout.columns : Object.keys(DEFAULT_RENDER_CONFIG.labels.columns);
- const row = `` + columns.map((column) => `| ${cells[column] || ""} | `).join("") + `${remove} |
`;
- if (!isGroup || !node2.expanded) return row;
- return row + node2.children.map((child) => renderNode(child, depth + 1, cfg)).join("");
- }
- function render(state, elements, cfg) {
- const normalized = renderConfig(cfg);
- const columns = normalized.layout.columns?.length ? normalized.layout.columns : Object.keys(DEFAULT_RENDER_CONFIG.labels.columns);
- elements.tableBodyEl.innerHTML = state.nodes.length ? state.nodes.map((node2) => renderNode(node2, 0, normalized)).join("") : `| ${esc(normalized.labels.empty)} |
`;
- const files = [];
- const visit = (node2) => {
- if (node2.kind === "file") files.push(node2);
- else node2.children.forEach(visit);
- };
- state.nodes.forEach(visit);
- const totalBytes = files.reduce((sum, node2) => sum + node2.file.size, 0);
- elements.countEl.textContent = normalized.labels.count(files.length, totalBytes);
- }
- function findNode(nodes, id) {
- for (const node2 of nodes) {
- if (node2.id === id) return { node: node2, nodes };
- const found = findNode(node2.children || [], id);
- if (found) return found;
- }
- return null;
- }
- function flattenFiles(nodes, result = []) {
- nodes.forEach((node2) => {
- if (node2.kind === "file") result.push({ path: node2.path, name: node2.name, size: node2.file.size, file: node2.file });
- else flattenFiles(node2.children, result);
- });
- return result;
- }
-
- // upload/frontend/table/on_files_change.js
- async function addFiles(state, cfg, files, elements) {
- for (const file of Array.from(files)) {
- if (!file.name.toLowerCase().endsWith(".zip")) {
- if (!cfg.allowedExt.some((extension) => file.name.toLowerCase().endsWith(extension.toLowerCase()))) {
- continue;
- }
- addFileWithDedup(state, {
- id: crypto.randomUUID(),
- kind: "file",
- name: file.name,
- path: file.name,
- file,
- children: [],
- expanded: true
- });
- continue;
- }
- try {
- const zipTree = await listZipFiles(file, cfg.allowedExt, cfg.limits);
- if (zipTree) addFileWithDedup(state, zipTree);
- } catch (error) {
- if (typeof cfg.onError === "function") {
- cfg.onError(error, file);
- } else if (elements.statusEl) {
- elements.statusEl.textContent = `\u041E\u0448\u0438\u0431\u043A\u0430 \u0447\u0442\u0435\u043D\u0438\u044F \u0430\u0440\u0445\u0438\u0432\u0430 ${file.name}: ${error.message}`;
- }
- continue;
- }
- }
- render(state, elements, cfg);
- }
- function onFilesChange(state, cfg, elements) {
- return async () => {
- if (state.busy) return;
- state.busy = true;
- try {
- await addFiles(state, cfg, elements.fileInputEl.files, elements);
- } finally {
- elements.fileInputEl.value = "";
- state.busy = false;
- }
- };
- }
-
- // upload/frontend/table/on_folder_change.js
- function onFolderChange(state, cfg, elements) {
- return async () => {
- if (state.busy) return;
- state.busy = true;
- try {
- const roots = /* @__PURE__ */ new Map();
- for (const file of Array.from(elements.folderInputEl.files)) {
- const parts = (file.webkitRelativePath || file.name).split("/");
- const relativePath = parts.slice(1).join("/") || file.name;
- const lowerPath = relativePath.toLowerCase();
- const rootName = parts[0] || file.name;
- if (!roots.has(rootName)) {
- roots.set(rootName, {
- id: crypto.randomUUID(),
- kind: "folder",
- name: rootName,
- path: rootName,
- children: [],
- expanded: false
- });
- }
- const root = roots.get(rootName);
- const addToFolder = (node2) => {
- let current = root;
- const nodeParts = node2.path.split("/").slice(1);
- nodeParts.forEach((part, index) => {
- const last = index === nodeParts.length - 1;
- let child = current.children.find((item) => item.name === part);
- if (!child) {
- child = last ? node2 : {
- id: crypto.randomUUID(),
- kind: "folder",
- name: part,
- path: `${rootName}/${nodeParts.slice(0, index + 1).join("/")}`,
- children: [],
- expanded: false
- };
- current.children.push(child);
- }
- current = child;
- });
- };
- if (lowerPath.endsWith(".zip")) {
- try {
- const zip = await listZipFiles(file, cfg.allowedExt, cfg.limits);
- if (zip) {
- rebaseTree(zip, rootName);
- addToFolder(zip);
- }
- } catch (error) {
- if (typeof cfg.onError === "function") {
- cfg.onError(error, file);
- } else if (elements.statusEl) {
- elements.statusEl.textContent = `\u041E\u0448\u0438\u0431\u043A\u0430 \u0447\u0442\u0435\u043D\u0438\u044F \u0430\u0440\u0445\u0438\u0432\u0430 ${file.name}: ${error.message}`;
- }
- continue;
- }
- } else if (cfg.allowedExt.some((extension) => lowerPath.endsWith(extension))) {
- addToFolder({
- id: crypto.randomUUID(),
- kind: "file",
- name: parts.at(-1),
- path: `${rootName}/${relativePath}`,
- file,
- children: [],
- expanded: true
- });
- }
- }
- roots.forEach((root) => addFileWithDedup(state, root));
- elements.folderInputEl.value = "";
- render(state, elements, cfg);
- } finally {
- state.busy = false;
- }
- };
- }
-
- // upload/frontend/upload/put_to_vm.js
- function putToVm(file, url, options = {}) {
- return new Promise((resolve, reject) => {
- const xhr = new XMLHttpRequest();
- if (options.onXHR) {
- options.onXHR(xhr);
- }
- const abortHandler = () => {
- xhr.abort();
- reject(new DOMException("Upload aborted", "AbortError"));
- };
- if (options.signal) {
- if (options.signal.aborted) {
- reject(new DOMException("Upload aborted", "AbortError"));
- return;
- }
- options.signal.addEventListener("abort", abortHandler, { once: true });
- }
- xhr.open("PUT", url);
- xhr.timeout = options.timeoutMs || 3e5;
- xhr.upload.onprogress = (e) => {
- if (e.lengthComputable && options.onProgress) {
- const pct = Math.round(e.loaded / e.total * 100);
- options.onProgress(pct, e.loaded, e.total);
- }
- };
- xhr.onload = () => {
- if (options.signal) {
- options.signal.removeEventListener("abort", abortHandler);
- }
- if (xhr.status >= 200 && xhr.status < 300) {
- resolve();
- } else {
- reject(new Error(`\u0411\u0443\u0444\u0435\u0440: HTTP ${xhr.status} ${xhr.statusText}`));
- }
- };
- xhr.onerror = () => {
- if (options.signal) {
- options.signal.removeEventListener("abort", abortHandler);
- }
- reject(new Error("\u0421\u0435\u0442\u0435\u0432\u0430\u044F \u043E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438 \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0435 \u0432 \u0431\u0443\u0444\u0435\u0440"));
- };
- xhr.ontimeout = () => {
- if (options.signal) {
- options.signal.removeEventListener("abort", abortHandler);
- }
- reject(new Error(`\u0422\u0430\u0439\u043C\u0430\u0443\u0442 \u043E\u0436\u0438\u0434\u0430\u043D\u0438\u044F \u043E\u0442\u0432\u0435\u0442\u0430 \u0431\u0443\u0444\u0435\u0440\u0430 (${Math.round(xhr.timeout / 1e3)}\u0441)`));
- };
- xhr.onabort = () => {
- if (options.signal) {
- options.signal.removeEventListener("abort", abortHandler);
- }
- reject(new DOMException("Upload aborted", "AbortError"));
- };
- xhr.send(file);
- });
- }
-
- // upload/frontend/upload/upload_via_vm.js
- function generateUuid() {
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
- return crypto.randomUUID();
- }
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
- const r = Math.random() * 16 | 0;
- const v = c === "x" ? r : r & 3 | 8;
- return v.toString(16);
- });
- }
- function normalizeFileEntry(item) {
- if (item instanceof File || item instanceof Blob) {
- return { name: item.name || "unnamed", size: item.size, file: item, path: item.name || "" };
- }
- if (item && item.file) {
- return {
- name: item.name || item.file.name || "unnamed",
- size: item.size ?? item.file.size ?? 0,
- file: item.file,
- path: item.path || item.name || ""
- };
- }
- throw new Error("\u041D\u0435\u043A\u043E\u0440\u0440\u0435\u043A\u0442\u043D\u044B\u0439 \u043E\u0431\u044A\u0435\u043A\u0442 \u0444\u0430\u0439\u043B\u0430");
- }
- async function uploadViaVM(files, options = {}) {
- if (!options.vmUploadUrl) {
- return { ok: false, error: "\u041F\u0430\u0440\u0430\u043C\u0435\u0442\u0440 options.vmUploadUrl \u043E\u0431\u044F\u0437\u0430\u0442\u0435\u043B\u0435\u043D" };
- }
- const normalizedFiles = Array.from(files).map(normalizeFileEntry);
- const total = normalizedFiles.length;
- if (total === 0) {
- return { ok: true, session: options.session || "", count: 0 };
- }
- const backendUrl = options.backendUploadUrl || (options.apiBase || "") + "/api/upload_refs";
- const vmBase = options.vmUploadUrl.endsWith("/") ? options.vmUploadUrl : `${options.vmUploadUrl}/`;
- let currentSession = options.session || "";
- let totalAdded = 0;
- for (let k = 0; k < total; k++) {
- if (options.signal?.aborted) {
- return { ok: false, error: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043E\u0442\u043C\u0435\u043D\u0435\u043D\u0430", aborted: true, session: currentSession };
- }
- const { name, size, file } = normalizedFiles[k];
- const fileKey = `${generateUuid()}_${k}`;
- const fileUrl = `${vmBase}${fileKey}`;
- if (options.onStatus) {
- options.onStatus(`\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u0432 \u0431\u0443\u0444\u0435\u0440 (${k + 1}/${total}): ${name}`);
- }
- if (options.onFileStatus) {
- options.onFileStatus(k, "\u23F3 \u0412 \u0431\u0443\u0444\u0435\u0440...");
- }
- const t0 = performance.now();
- try {
- await putToVm(file, fileUrl, {
- signal: options.signal,
- onXHR: options.onXHR,
- onProgress(pct, loaded, fileTotal) {
- const elapsed = (performance.now() - t0) / 1e3;
- const speed = elapsed > 0 ? loaded / elapsed : 0;
- if (options.onFileStatus) {
- options.onFileStatus(k, `\u23F3 ${pct}% (${fs(speed)}/s)`);
- }
- if (options.onProgress) {
- options.onProgress({ index: k, total, pct, speed, loaded, fileTotal, name });
- }
- }
- });
- } catch (err2) {
- if (options.signal?.aborted) {
- return { ok: false, error: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043E\u0442\u043C\u0435\u043D\u0435\u043D\u0430", aborted: true, session: currentSession };
- }
- if (options.onFileStatus) {
- options.onFileStatus(k, "\u2717 \u041E\u0448\u0438\u0431\u043A\u0430 \u0431\u0443\u0444\u0435\u0440\u0430");
- }
- return {
- ok: false,
- error: `\u041E\u0448\u0438\u0431\u043A\u0430 \u043E\u0442\u043F\u0440\u0430\u0432\u043A\u0438 \u0444\u0430\u0439\u043B\u0430 ${name} \u0432 \u0431\u0443\u0444\u0435\u0440: ${err2.message}`,
- failedIndex: k,
- session: currentSession
- };
- }
- if (options.onStatus) {
- options.onStatus(`\u041F\u0440\u0438\u0451\u043C \u0441\u0435\u0440\u0432\u0438\u0441\u043E\u043C (${k + 1}/${total}): ${name}`);
- }
- if (options.onFileStatus) {
- options.onFileStatus(k, "\u26A1 \u0412 \u0441\u0435\u0441\u0441\u0438\u044E...");
- }
- try {
- const resp = await fetch(backendUrl, {
- method: "POST",
- headers: { "Content-Type": "application/json" },
- body: JSON.stringify({
- session: currentSession,
- files: [{ name, size, url: fileUrl }]
- }),
- signal: options.signal
- });
- if (!resp.ok) {
- throw new Error(`HTTP ${resp.status} ${resp.statusText}`);
- }
- const data = await resp.json();
- if (!data.ok) {
- throw new Error(data.error || "\u0411\u044D\u043A\u0435\u043D\u0434 \u0432\u0435\u0440\u043D\u0443\u043B \u043E\u0448\u0438\u0431\u043A\u0443");
- }
- currentSession = data.session || currentSession;
- totalAdded = data.count ?? totalAdded + 1;
- if (options.onFileStatus) {
- options.onFileStatus(k, "\u2713 \u0414\u043E\u0441\u0442\u0430\u0432\u043B\u0435\u043D");
- }
- if (options.onFileComplete) {
- options.onFileComplete({
- fileIndex: k,
- name,
- size,
- session: currentSession,
- totalAdded
- });
- }
- } catch (err2) {
- if (options.signal?.aborted) {
- return { ok: false, error: "\u0417\u0430\u0433\u0440\u0443\u0437\u043A\u0430 \u043E\u0442\u043C\u0435\u043D\u0435\u043D\u0430", aborted: true, session: currentSession };
- }
- if (options.onFileStatus) {
- options.onFileStatus(k, "\u2717 \u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438\u0451\u043C\u0430");
- }
- return {
- ok: false,
- error: `\u041E\u0448\u0438\u0431\u043A\u0430 \u043F\u0440\u0438\u0451\u043C\u0430 \u0444\u0430\u0439\u043B\u0430 ${name} \u0431\u044D\u043A\u0435\u043D\u0434\u043E\u043C: ${err2.message}`,
- failedIndex: k,
- session: currentSession
- };
- }
- }
- if (options.onStatus) {
- options.onStatus(`\u0417\u0430\u0432\u0435\u0440\u0448\u0435\u043D\u043E. \u0423\u0441\u043F\u0435\u0448\u043D\u043E \u043F\u0435\u0440\u0435\u0434\u0430\u043D\u043E \u0444\u0430\u0439\u043B\u043E\u0432: ${total}`);
- }
- return { ok: true, session: currentSession, count: totalAdded };
- }
-
- // upload/frontend/index.js
- var DEFAULTS = {
- allowedExt: [],
- labels: {
- pickFiles: "\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u0444\u0430\u0439\u043B\u044B",
- pickFolder: "\u0412\u044B\u0431\u0440\u0430\u0442\u044C \u043F\u0430\u043F\u043A\u0443",
- clear: "\u041E\u0447\u0438\u0441\u0442\u0438\u0442\u044C",
- empty: "\u041D\u0435\u0442 \u0432\u044B\u0431\u0440\u0430\u043D\u043D\u044B\u0445 \u0444\u0430\u0439\u043B\u043E\u0432",
- statusReady: "\u0433\u043E\u0442\u043E\u0432",
- remove: "\u0423\u0434\u0430\u043B\u0438\u0442\u044C",
- columns: { path: "\u041F\u0443\u0442\u044C", size: "\u0420\u0430\u0437\u043C\u0435\u0440", status: "\u0421\u0442\u0430\u0442\u0443\u0441" },
- count: (count, bytes) => `${count} \u0444\u0430\u0439\u043B\u043E\u0432 \xB7 ${bytes} B`
- },
- layout: { columns: ["path", "size", "status"], controls: ["files", "folder", "clear"] },
- limits: {
- maxEntries: 1e3,
- maxTotalBytes: 100 * 1024 * 1024,
- maxEntryBytes: 50 * 1024 * 1024,
- maxDepth: 20
- }
- };
- function resolveMount(mount) {
- const element = typeof mount === "string" ? document.querySelector(mount) : mount;
- if (!element) throw new Error("File picker mount element \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D");
- return element;
- }
- function normalizeConfig(config) {
- return {
- ...config,
- allowedExt: config.allowedExt || DEFAULTS.allowedExt,
- labels: {
- ...DEFAULTS.labels,
- ...config.labels || {},
- columns: { ...DEFAULTS.labels.columns, ...config.labels?.columns || {} }
- },
- layout: { ...DEFAULTS.layout, ...config.layout || {} },
- limits: { ...DEFAULTS.limits, ...config.limits || {} }
- };
- }
- function injectStyles() {
- if (document.querySelector("style[data-file-picker]")) return;
- const style = document.createElement("style");
- style.dataset.filePicker = "";
- style.textContent = `
-.file-picker { color: #17211b; font-family: Georgia, 'Times New Roman', serif; }
-.file-picker .fp-toolbar { display: flex; flex-wrap: wrap; gap: 10px; margin: 16px 0; }
-.file-picker .fp-toolbar button { border: 0; border-radius: 4px; padding: 12px 17px; color: #f7faf4; background: #1f5a3b; font: 700 13px sans-serif; cursor: pointer; }
-.file-picker .fp-toolbar button.secondary { color: #1f5a3b; background: #cbdcc9; }
-.file-picker .fp-toolbar button.quiet { color: #5d6a61; background: transparent; }
-.file-picker .fp-table-wrap { overflow-x: auto; border-top: 1px solid #b9c7ba; }
-.file-picker .fp-table { width: 100%; border-collapse: collapse; font: 14px/1.4 sans-serif; }
-.file-picker .fp-table th, .file-picker .fp-table td { padding: 14px 10px; border-bottom: 1px solid #cbd5cc; text-align: left; }
-.file-picker .fp-table th { color: #56745f; font-size: 11px; text-transform: uppercase; letter-spacing: 1px; }
-.file-picker .fp-status, .file-picker .fp-count { color: #5d6a61; font: 13px sans-serif; }
-.file-picker .fp-count { min-height: 22px; }
-.file-picker .tree-name { display: inline-flex; align-items: center; gap: 8px; min-width: 240px; padding-top: 0; padding-bottom: 0; border: 0; background: transparent; color: #17211b; font: inherit; text-align: left; }
-.file-picker .tree-group { padding-left: 0; cursor: pointer; }
-.file-picker .tree-chevron { display: inline-block; width: 12px; color: #78917d; font-size: 10px; }
-.file-picker .remove-btn { padding: 2px 7px; color: #8c5148; background: transparent; font: 20px/1 sans-serif; }
-.file-picker .tree-row td:first-child { white-space: nowrap; }
-@media (max-width: 600px) { .file-picker .fp-toolbar button { flex: 1 1 42%; } }
-`;
- document.head.append(style);
- }
- function buildMarkup(root, cfg) {
- const controls = cfg.layout.controls || [];
- const control = (name, id, label, className = "") => controls.includes(name) ? `` : "";
- const columns = cfg.layout.columns?.length ? cfg.layout.columns : Object.keys(cfg.labels.columns);
- const headings = columns.map((column) => `${esc(cfg.labels.columns[column] || column)} | `).join("");
- root.innerHTML = `
-
-
-
-
- ${control("files", "fp-files-btn", cfg.labels.pickFiles)}
- ${control("folder", "fp-folder-btn", cfg.labels.pickFolder, "secondary")}
- ${control("clear", "fp-clear-btn", cfg.labels.clear, "quiet")}
-
-
-
-
-
`;
- }
- function notify(cfg, state) {
- if (typeof cfg.onChange === "function") cfg.onChange([...flattenFiles(state.nodes)]);
- }
- function removeMetadata(state, node2) {
- if (node2.kind === "file") {
- state.fileKeys.delete(`${node2.path}\0${node2.file.size}`);
- return;
- }
- node2.children.forEach((child) => removeMetadata(state, child));
- }
- function removeNode(state, id) {
- const found = findNode(state.nodes, id);
- if (!found) return false;
- removeMetadata(state, found.node);
- found.nodes.splice(found.nodes.indexOf(found.node), 1);
- return true;
- }
- function initFilePicker(config) {
- const cfg = normalizeConfig(config);
- const mount = resolveMount(cfg.mount);
- injectStyles();
- buildMarkup(mount, cfg);
- const root = mount.firstElementChild;
- const elements = {
- fileInputEl: root.querySelector(".fp-file-input"),
- folderInputEl: root.querySelector(".fp-folder-input"),
- statusEl: root.querySelector(".fp-status"),
- tableBodyEl: root.querySelector(".fp-table-body"),
- countEl: root.querySelector(".fp-count")
- };
- const state = { nodes: [], fileKeys: /* @__PURE__ */ new Set(), busy: false };
- const listeners = [];
- const listen = (target, event, handler) => {
- target.addEventListener(event, handler);
- listeners.push(() => target.removeEventListener(event, handler));
- };
- const redraw = () => render(state, elements, cfg);
- const filesChange = onFilesChange(state, cfg, elements);
- const folderChange = onFolderChange(state, cfg, elements);
- listen(elements.fileInputEl, "change", async () => {
- await filesChange();
- notify(cfg, state);
- });
- listen(elements.folderInputEl, "change", async () => {
- await folderChange();
- notify(cfg, state);
- });
- listen(elements.tableBodyEl, "click", (event) => {
- const toggle = event.target.closest("[data-toggle]");
- if (toggle) {
- const found = findNode(state.nodes, toggle.dataset.toggle);
- if (found) found.node.expanded = !found.node.expanded;
- redraw();
- return;
- }
- const remove = event.target.closest("[data-remove]");
- if (remove) {
- if (removeNode(state, remove.dataset.remove)) {
- redraw();
- notify(cfg, state);
- }
- }
- });
- if (root.querySelector("#fp-files-btn")) listen(root.querySelector("#fp-files-btn"), "click", () => elements.fileInputEl.click());
- if (root.querySelector("#fp-folder-btn")) listen(root.querySelector("#fp-folder-btn"), "click", () => elements.folderInputEl.click());
- if (root.querySelector("#fp-clear-btn")) listen(root.querySelector("#fp-clear-btn"), "click", () => {
- state.nodes = [];
- state.fileKeys.clear();
- redraw();
- notify(cfg, state);
- });
- redraw();
- return {
- pickFiles: () => elements.fileInputEl.click(),
- pickFolder: () => elements.folderInputEl.click(),
- addFiles: async (files) => {
- await addFiles(state, cfg, files, elements);
- notify(cfg, state);
- },
- getFiles: () => [...flattenFiles(state.nodes)],
- remove: (id) => {
- if (removeNode(state, id)) {
- redraw();
- notify(cfg, state);
- }
- },
- clear: () => {
- state.nodes = [];
- state.fileKeys.clear();
- redraw();
- notify(cfg, state);
- },
- render: redraw,
- destroy: () => {
- listeners.forEach((removeListener) => removeListener());
- state.nodes = [];
- state.fileKeys.clear();
- mount.replaceChildren();
- }
- };
- }
- return __toCommonJS(index_exports);
-})();