init
This commit is contained in:
37
src/utils/api.ts
Normal file
37
src/utils/api.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import { CloudreveFile } from "../types";
|
||||
import { list } from "../services/navigate";
|
||||
import { pathJoin } from "../component/Uploader/core/utils";
|
||||
|
||||
export function getPreviewPath(selected: any): string {
|
||||
return encodeURIComponent(
|
||||
selected.path === "/"
|
||||
? selected.path + selected.name
|
||||
: selected.path + "/" + selected.name
|
||||
);
|
||||
}
|
||||
|
||||
export async function walk(
|
||||
file: CloudreveFile[],
|
||||
share: any
|
||||
): Promise<CloudreveFile[]> {
|
||||
let res: CloudreveFile[] = [];
|
||||
for (const f of file) {
|
||||
if (f.type === "file") {
|
||||
res.push(f);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (f.type === "dir") {
|
||||
const response = await list(
|
||||
pathJoin([f.path, f.name]),
|
||||
share,
|
||||
"",
|
||||
""
|
||||
);
|
||||
const subs = await walk(response.data.objects, share);
|
||||
res = [...res, ...subs];
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
53
src/utils/datetime.js
Normal file
53
src/utils/datetime.js
Normal file
@@ -0,0 +1,53 @@
|
||||
import dayjs from "dayjs";
|
||||
import timezone from "dayjs/plugin/timezone";
|
||||
import utc from "dayjs/plugin/utc";
|
||||
import Auth from "../middleware/Auth";
|
||||
import i18next from "../i18n";
|
||||
|
||||
dayjs.extend(utc);
|
||||
dayjs.extend(timezone);
|
||||
|
||||
let userTimezone = "";
|
||||
try {
|
||||
userTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
} catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
if (!userTimezone || userTimezone=="Etc/Unknown") {
|
||||
userTimezone = "Asia/Shanghai";
|
||||
}
|
||||
|
||||
const preferTimeZone = Auth.GetPreference("timeZone");
|
||||
export let timeZone = preferTimeZone ? preferTimeZone : userTimezone;
|
||||
|
||||
export function refreshTimeZone() {
|
||||
timeZone = Auth.GetPreference("timeZone");
|
||||
timeZone = timeZone ? timeZone : userTimezone;
|
||||
}
|
||||
|
||||
export function formatLocalTime(time) {
|
||||
return i18next.t("intlDateTime", {
|
||||
ns: "common",
|
||||
val: dayjs(time).tz(timeZone).toDate(),
|
||||
formatParams: {
|
||||
val: {
|
||||
year: "numeric",
|
||||
month: "numeric",
|
||||
day: "numeric",
|
||||
hour: "numeric",
|
||||
minute: "numeric",
|
||||
second: "numeric",
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function validateTimeZone(name) {
|
||||
try {
|
||||
dayjs().tz(name).format();
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
81
src/utils/filesystem.ts
Normal file
81
src/utils/filesystem.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
// get the paths of files (no directories) in the directory
|
||||
// parent: "" or "/"
|
||||
export const getFileSystemDirectoryPaths = async (
|
||||
handle: FileSystemDirectoryHandle,
|
||||
parent = ""
|
||||
): Promise<string[]> => {
|
||||
const paths: Array<string> = [];
|
||||
|
||||
for await (const [path, fileSystemHandle] of handle.entries()) {
|
||||
if (fileSystemHandle instanceof window.FileSystemFileHandle) {
|
||||
paths.push(`${parent}${path}`);
|
||||
} else {
|
||||
paths.push(
|
||||
...(await getFileSystemDirectoryPaths(
|
||||
fileSystemHandle,
|
||||
`${parent}${path}/`
|
||||
))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return paths;
|
||||
};
|
||||
|
||||
// create the dst directory if it doesn't exist
|
||||
// return the dst directory handle
|
||||
// paths: "/dir1/dir2" => ["dir1","dir2"]
|
||||
export const createFileSystemDirectory = async (
|
||||
handle: FileSystemDirectoryHandle,
|
||||
paths: string[]
|
||||
) => {
|
||||
let cur = handle;
|
||||
while (paths.length > 0) {
|
||||
const path = paths.shift();
|
||||
if (!path) {
|
||||
break;
|
||||
}
|
||||
cur = await cur.getDirectoryHandle(path, { create: true });
|
||||
}
|
||||
return cur;
|
||||
};
|
||||
|
||||
// save file into the dst directory
|
||||
// create the dst file if it doesn't exist by default
|
||||
// path: a/b/c.jpg
|
||||
export const saveFileToFileSystemDirectory = async (
|
||||
handle: FileSystemDirectoryHandle,
|
||||
stream: FileSystemWriteChunkType,
|
||||
path: string,
|
||||
create = true
|
||||
) => {
|
||||
const paths = path.split("/");
|
||||
const fileName = paths.pop();
|
||||
if (!fileName) return;
|
||||
|
||||
const dir = await createFileSystemDirectory(handle, paths);
|
||||
const file = await dir.getFileHandle(fileName, { create });
|
||||
const writable = await file.createWritable();
|
||||
await writable.write(stream);
|
||||
await writable.close();
|
||||
};
|
||||
|
||||
// verify or request the permission of the readwrite permission
|
||||
export async function verifyFileSystemRWPermission(
|
||||
fileHandle: FileSystemDirectoryHandle
|
||||
) {
|
||||
const opts = { mode: "readwrite" as FileSystemPermissionMode };
|
||||
|
||||
// Check if we already have permission, if so, return true.
|
||||
if ((await fileHandle.queryPermission(opts)) === "granted") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Request permission to the file, if the user grants permission, return true.
|
||||
if ((await fileHandle.requestPermission(opts)) === "granted") {
|
||||
return true;
|
||||
}
|
||||
|
||||
// The user did not grant permission, return false.
|
||||
return false;
|
||||
}
|
172
src/utils/index.js
Normal file
172
src/utils/index.js
Normal file
@@ -0,0 +1,172 @@
|
||||
export const sizeToString = (bytes) => {
|
||||
if (bytes === 0 || bytes === "0") return "0 B";
|
||||
const k = 1024;
|
||||
const sizes = ["B", "KB", "MB", "GB", "TB", "PB", "EB", "ZB", "YB"];
|
||||
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
||||
return (bytes / Math.pow(k, i)).toFixed(1) + " " + sizes[i];
|
||||
};
|
||||
|
||||
export const fixUrlHash = (path) => {
|
||||
return path;
|
||||
};
|
||||
|
||||
export const setCookie = (name, value, days) => {
|
||||
if (days) {
|
||||
const date = new Date();
|
||||
date.setTime(date.getTime() + days * 24 * 60 * 60 * 1000);
|
||||
}
|
||||
document.cookie = name + "=" + (value || "") + "; path=/";
|
||||
};
|
||||
|
||||
export const setGetParameter = (paramName, paramValue) => {
|
||||
let url = window.location.href;
|
||||
|
||||
if (url.indexOf(paramName + "=") >= 0) {
|
||||
const prefix = url.substring(0, url.indexOf(paramName));
|
||||
let suffix = url.substring(url.indexOf(paramName));
|
||||
suffix = suffix.substring(suffix.indexOf("=") + 1);
|
||||
suffix =
|
||||
suffix.indexOf("&") >= 0
|
||||
? suffix.substring(suffix.indexOf("&"))
|
||||
: "";
|
||||
url = prefix + paramName + "=" + paramValue + suffix;
|
||||
} else {
|
||||
if (url.indexOf("?") < 0) url += "?" + paramName + "=" + paramValue;
|
||||
else url += "&" + paramName + "=" + paramValue;
|
||||
}
|
||||
if (url === window.location.href) {
|
||||
return;
|
||||
}
|
||||
window.history.pushState(null, null, url);
|
||||
};
|
||||
|
||||
export const checkGetParameters = (field) => {
|
||||
const url = window.location.href;
|
||||
if (url.indexOf("?" + field + "=") !== -1) return true;
|
||||
else if (url.indexOf("&" + field + "=") !== -1) return true;
|
||||
return false;
|
||||
};
|
||||
|
||||
export const changeThemeColor = (color) => {
|
||||
const metaThemeColor = window.document.querySelector(
|
||||
"meta[name=theme-color]"
|
||||
);
|
||||
metaThemeColor.setAttribute("content", color);
|
||||
};
|
||||
|
||||
export function bufferDecode(value) {
|
||||
return Uint8Array.from(atob(value), (c) => c.charCodeAt(0));
|
||||
}
|
||||
|
||||
// ArrayBuffer to URLBase64
|
||||
export function bufferEncode(value) {
|
||||
return btoa(String.fromCharCode.apply(null, new Uint8Array(value)))
|
||||
.replace(/\+/g, "-")
|
||||
.replace(/\//g, "_")
|
||||
.replace(/=/g, "");
|
||||
}
|
||||
|
||||
export function pathBack(path) {
|
||||
const folders =
|
||||
path !== null
|
||||
? path.substr(1).split("/")
|
||||
: this.props.path.substr(1).split("/");
|
||||
return "/" + folders.slice(0, folders.length - 1).join("/");
|
||||
}
|
||||
|
||||
export function filePath(file) {
|
||||
return file.path === "/"
|
||||
? file.path + file.name
|
||||
: file.path + "/" + file.name;
|
||||
}
|
||||
|
||||
export function hex2bin(hex) {
|
||||
return parseInt(hex, 16).toString(2).padStart(8, "0");
|
||||
}
|
||||
|
||||
export function pathJoin(parts, sep) {
|
||||
const separator = sep || "/";
|
||||
parts = parts.map((part, index) => {
|
||||
if (index) {
|
||||
part = part.replace(new RegExp("^" + separator), "");
|
||||
}
|
||||
if (index !== parts.length - 1) {
|
||||
part = part.replace(new RegExp(separator + "$"), "");
|
||||
}
|
||||
return part;
|
||||
});
|
||||
return parts.join(separator);
|
||||
}
|
||||
|
||||
export function basename(path) {
|
||||
if (!path) {
|
||||
return "";
|
||||
}
|
||||
const pathList = path.split("/");
|
||||
pathList.pop();
|
||||
return pathList.join("/") === "" ? "/" : pathList.join("/");
|
||||
}
|
||||
|
||||
export function filename(path) {
|
||||
const pathList = path.split("/");
|
||||
return pathList.pop();
|
||||
}
|
||||
|
||||
export function fileNameNoExt(filename) {
|
||||
return filename.substring(0, filename.lastIndexOf(".")) || filename;
|
||||
}
|
||||
|
||||
export function randomStr(length) {
|
||||
let result = "";
|
||||
const characters =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
|
||||
const charactersLength = characters.length;
|
||||
for (let i = 0; i < length; i++) {
|
||||
result += characters.charAt(
|
||||
Math.floor(Math.random() * charactersLength)
|
||||
);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
export function getNumber(base, conditions) {
|
||||
conditions.forEach((v) => {
|
||||
if (v) {
|
||||
base++;
|
||||
}
|
||||
});
|
||||
return base;
|
||||
}
|
||||
|
||||
export const isMac = () => {
|
||||
return navigator.platform.toUpperCase().indexOf("MAC") >= 0;
|
||||
};
|
||||
|
||||
export const isMobileSafari = () => {
|
||||
const ua = window.navigator.userAgent;
|
||||
const iOS = !!ua.match(/iPad/i) || !!ua.match(/iPhone/i);
|
||||
const webkit = !!ua.match(/WebKit/i);
|
||||
return iOS && webkit && !ua.match(/CriOS/i);
|
||||
};
|
||||
|
||||
export function vhCheck() {
|
||||
const vh = window.innerHeight;
|
||||
document.documentElement.style.setProperty("--vh", `${vh}px`);
|
||||
}
|
||||
|
||||
export const getSelectItemStyles = (name, personName, theme) => {
|
||||
return {
|
||||
fontWeight:
|
||||
personName.indexOf(name) === -1
|
||||
? theme.typography.fontWeightRegular
|
||||
: theme.typography.fontWeightMedium,
|
||||
};
|
||||
};
|
||||
|
||||
export const removeI18nCache = () => {
|
||||
Object.keys(localStorage).forEach(function (key) {
|
||||
if (key && key.startsWith("i18next_res_")) {
|
||||
localStorage.removeItem(key);
|
||||
}
|
||||
});
|
||||
};
|
18
src/utils/page.ts
Normal file
18
src/utils/page.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
const statusHelper = {
|
||||
isHomePage(path: string) {
|
||||
return path === "/home";
|
||||
},
|
||||
isSharePage(path: string) {
|
||||
return path && path.startsWith("/s/");
|
||||
},
|
||||
isAdminPage(path: string) {
|
||||
return path && path.startsWith("/admin");
|
||||
},
|
||||
isLoginPage(path: string) {
|
||||
return path && path.startsWith("/login");
|
||||
},
|
||||
isMobile() {
|
||||
return window.innerWidth < 600;
|
||||
},
|
||||
};
|
||||
export default statusHelper;
|
257
src/utils/zip.js
Normal file
257
src/utils/zip.js
Normal file
@@ -0,0 +1,257 @@
|
||||
/* eslint-disable */
|
||||
class Crc32 {
|
||||
constructor() {
|
||||
this.crc = -1;
|
||||
}
|
||||
|
||||
append(data) {
|
||||
let crc = this.crc | 0;
|
||||
const table = this.table;
|
||||
for (let offset = 0, len = data.length | 0; offset < len; offset++) {
|
||||
crc = (crc >>> 8) ^ table[(crc ^ data[offset]) & 0xff];
|
||||
}
|
||||
this.crc = crc;
|
||||
}
|
||||
|
||||
get() {
|
||||
return ~this.crc;
|
||||
}
|
||||
}
|
||||
Crc32.prototype.table = (() => {
|
||||
let i;
|
||||
let j;
|
||||
let t;
|
||||
const table = [];
|
||||
for (i = 0; i < 256; i++) {
|
||||
t = i;
|
||||
for (j = 0; j < 8; j++) {
|
||||
t = t & 1 ? (t >>> 1) ^ 0xedb88320 : t >>> 1;
|
||||
}
|
||||
table[i] = t;
|
||||
}
|
||||
return table;
|
||||
})();
|
||||
|
||||
const getDataHelper = (byteLength) => {
|
||||
const uint8 = new Uint8Array(byteLength);
|
||||
return {
|
||||
array: uint8,
|
||||
view: new DataView(uint8.buffer),
|
||||
};
|
||||
};
|
||||
|
||||
const pump = (zipObj) =>
|
||||
zipObj.reader.read().then((chunk) => {
|
||||
if (chunk.done) return zipObj.writeFooter();
|
||||
const outputData = chunk.value;
|
||||
zipObj.crc.append(outputData);
|
||||
zipObj.uncompressedLength += outputData.length;
|
||||
zipObj.compressedLength += outputData.length;
|
||||
zipObj.ctrl.enqueue(outputData);
|
||||
});
|
||||
|
||||
/**
|
||||
* [createWriter description]
|
||||
* @param {Object} underlyingSource [description]
|
||||
* @return {Boolean} [description]
|
||||
*/
|
||||
function createWriter(underlyingSource) {
|
||||
const files = Object.create(null);
|
||||
const filenames = [];
|
||||
const encoder = new TextEncoder();
|
||||
let offset = 0;
|
||||
let activeZipIndex = 0;
|
||||
let ctrl;
|
||||
let activeZipObject, closed;
|
||||
|
||||
function next() {
|
||||
activeZipIndex++;
|
||||
activeZipObject = files[filenames[activeZipIndex]];
|
||||
if (activeZipObject) processNextChunk();
|
||||
else if (closed) closeZip();
|
||||
}
|
||||
|
||||
const zipWriter = {
|
||||
enqueue(fileLike) {
|
||||
if (closed)
|
||||
throw new TypeError(
|
||||
"Cannot enqueue a chunk into a readable stream that is closed or has been requested to be closed"
|
||||
);
|
||||
|
||||
let name = fileLike.name.trim();
|
||||
const date = new Date(
|
||||
typeof fileLike.lastModified === "undefined"
|
||||
? Date.now()
|
||||
: fileLike.lastModified
|
||||
);
|
||||
|
||||
if (fileLike.directory && !name.endsWith("/")) name += "/";
|
||||
if (files[name]) throw new Error("File already exists.");
|
||||
|
||||
const nameBuf = encoder.encode(name);
|
||||
filenames.push(name);
|
||||
|
||||
const zipObject = (files[name] = {
|
||||
level: 0,
|
||||
ctrl,
|
||||
directory: !!fileLike.directory,
|
||||
nameBuf,
|
||||
comment: encoder.encode(fileLike.comment || ""),
|
||||
compressedLength: 0,
|
||||
uncompressedLength: 0,
|
||||
writeHeader() {
|
||||
const header = getDataHelper(26);
|
||||
const data = getDataHelper(30 + nameBuf.length);
|
||||
|
||||
zipObject.offset = offset;
|
||||
zipObject.header = header;
|
||||
if (zipObject.level !== 0 && !zipObject.directory) {
|
||||
header.view.setUint16(4, 0x0800);
|
||||
}
|
||||
header.view.setUint32(0, 0x14000808);
|
||||
header.view.setUint16(
|
||||
6,
|
||||
(((date.getHours() << 6) | date.getMinutes()) << 5) |
|
||||
(date.getSeconds() / 2),
|
||||
true
|
||||
);
|
||||
header.view.setUint16(
|
||||
8,
|
||||
((((date.getFullYear() - 1980) << 4) |
|
||||
(date.getMonth() + 1)) <<
|
||||
5) |
|
||||
date.getDate(),
|
||||
true
|
||||
);
|
||||
header.view.setUint16(22, nameBuf.length, true);
|
||||
data.view.setUint32(0, 0x504b0304);
|
||||
data.array.set(header.array, 4);
|
||||
data.array.set(nameBuf, 30);
|
||||
offset += data.array.length;
|
||||
ctrl.enqueue(data.array);
|
||||
},
|
||||
writeFooter() {
|
||||
const footer = getDataHelper(16);
|
||||
footer.view.setUint32(0, 0x504b0708);
|
||||
|
||||
if (zipObject.crc) {
|
||||
zipObject.header.view.setUint32(
|
||||
10,
|
||||
zipObject.crc.get(),
|
||||
true
|
||||
);
|
||||
zipObject.header.view.setUint32(
|
||||
14,
|
||||
zipObject.compressedLength,
|
||||
true
|
||||
);
|
||||
zipObject.header.view.setUint32(
|
||||
18,
|
||||
zipObject.uncompressedLength,
|
||||
true
|
||||
);
|
||||
footer.view.setUint32(4, zipObject.crc.get(), true);
|
||||
footer.view.setUint32(
|
||||
8,
|
||||
zipObject.compressedLength,
|
||||
true
|
||||
);
|
||||
footer.view.setUint32(
|
||||
12,
|
||||
zipObject.uncompressedLength,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
ctrl.enqueue(footer.array);
|
||||
offset += zipObject.compressedLength + 16;
|
||||
next();
|
||||
},
|
||||
fileLike,
|
||||
});
|
||||
|
||||
if (!activeZipObject) {
|
||||
activeZipObject = zipObject;
|
||||
processNextChunk();
|
||||
}
|
||||
},
|
||||
close() {
|
||||
if (closed)
|
||||
throw new TypeError(
|
||||
"Cannot close a readable stream that has already been requested to be closed"
|
||||
);
|
||||
if (!activeZipObject) closeZip();
|
||||
closed = true;
|
||||
},
|
||||
};
|
||||
|
||||
function closeZip() {
|
||||
let length = 0;
|
||||
let index = 0;
|
||||
let indexFilename, file;
|
||||
for (
|
||||
indexFilename = 0;
|
||||
indexFilename < filenames.length;
|
||||
indexFilename++
|
||||
) {
|
||||
file = files[filenames[indexFilename]];
|
||||
length += 46 + file.nameBuf.length + file.comment.length;
|
||||
}
|
||||
const data = getDataHelper(length + 22);
|
||||
for (
|
||||
indexFilename = 0;
|
||||
indexFilename < filenames.length;
|
||||
indexFilename++
|
||||
) {
|
||||
file = files[filenames[indexFilename]];
|
||||
data.view.setUint32(index, 0x504b0102);
|
||||
data.view.setUint16(index + 4, 0x1400);
|
||||
data.array.set(file.header.array, index + 6);
|
||||
data.view.setUint16(index + 32, file.comment.length, true);
|
||||
if (file.directory) {
|
||||
data.view.setUint8(index + 38, 0x10);
|
||||
}
|
||||
data.view.setUint32(index + 42, file.offset, true);
|
||||
data.array.set(file.nameBuf, index + 46);
|
||||
data.array.set(file.comment, index + 46 + file.nameBuf.length);
|
||||
index += 46 + file.nameBuf.length + file.comment.length;
|
||||
}
|
||||
data.view.setUint32(index, 0x504b0506);
|
||||
data.view.setUint16(index + 8, filenames.length, true);
|
||||
data.view.setUint16(index + 10, filenames.length, true);
|
||||
data.view.setUint32(index + 12, length, true);
|
||||
data.view.setUint32(index + 16, offset, true);
|
||||
ctrl.enqueue(data.array);
|
||||
ctrl.close();
|
||||
}
|
||||
|
||||
function processNextChunk() {
|
||||
if (!activeZipObject) return;
|
||||
if (activeZipObject.directory)
|
||||
return activeZipObject.writeFooter(activeZipObject.writeHeader());
|
||||
if (activeZipObject.reader) return pump(activeZipObject);
|
||||
if (activeZipObject.fileLike.stream) {
|
||||
activeZipObject.crc = new Crc32();
|
||||
activeZipObject.reader = activeZipObject.fileLike
|
||||
.stream()
|
||||
.getReader();
|
||||
activeZipObject.writeHeader();
|
||||
} else next();
|
||||
}
|
||||
return new ReadableStream({
|
||||
start: (c) => {
|
||||
ctrl = c;
|
||||
underlyingSource.start &&
|
||||
Promise.resolve(underlyingSource.start(zipWriter));
|
||||
},
|
||||
pull() {
|
||||
return (
|
||||
processNextChunk() ||
|
||||
(underlyingSource.pull &&
|
||||
Promise.resolve(underlyingSource.pull(zipWriter)))
|
||||
);
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
window.ZIP = createWriter;
|
Reference in New Issue
Block a user