barkey/packages/frontend/src/scripts/file-drop.ts
syuilo ffd8cf07e6
update deps (#15311)
* wip

* bump misskey-dev/eslint-plugin

* lint fixes (backend)

* lint fixes (frontend)

* lint fixes (frontend-embed)

* rollback nsfwjs to 4.2.0

ref: infinitered/nsfwjs#904

* rollback openapi-typescript to v6

v7でOpenAPIのバリデーションが入るようになった関係でスコープ外での変更が避けられないため一時的に戻した

* lint fixes (misskey-js)

* temporarily disable errored lint rule (frontend-shared)

* fix lint

* temporarily ignore errored file for lint (frontend-shared)

* rollback simplewebauthn/server to 12.0.0

v13 contains breaking changes that require some decision making

* lint fixes (frontend-shared)

* build misskey-js with types

* fix(backend): migrate simplewebauthn/server to v12

* fix(misskey-js/autogen): ignore indent rules to generate consistent output

* attempt to fix test

changes due to capricorn86/happy-dom#1617 (XMLSerializer now produces valid XML)

* attempt to fix test

changes due to capricorn86/happy-dom#1617 (XMLSerializer now produces valid XML)

* fix test

* fix test

* fix test

* Apply suggestions from code review

Co-authored-by: anatawa12 <anatawa12@icloud.com>

* bump summaly to v5.2.0

* update tabler-icons to v3.30.0-based

---------

Co-authored-by: かっこかり <67428053+kakkokari-gtyih@users.noreply.github.com>
Co-authored-by: anatawa12 <anatawa12@icloud.com>
2025-02-15 10:24:22 +09:00

121 lines
3.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* SPDX-FileCopyrightText: syuilo and other misskey contributors
* SPDX-License-Identifier: AGPL-3.0-only
*/
export type DroppedItem = DroppedFile | DroppedDirectory;
export type DroppedFile = {
isFile: true;
path: string;
file: File;
};
export type DroppedDirectory = {
isFile: false;
path: string;
children: DroppedItem[];
};
export async function extractDroppedItems(ev: DragEvent): Promise<DroppedItem[]> {
const dropItems = ev.dataTransfer?.items;
if (!dropItems || dropItems.length === 0) {
return [];
}
const apiTestItem = dropItems[0];
if ('webkitGetAsEntry' in apiTestItem) {
return readDataTransferItems(dropItems);
} else {
// webkitGetAsEntryに対応していない場合はfilesから取得するディレクトリのサポートは出来ない
const dropFiles = ev.dataTransfer.files;
if (dropFiles.length === 0) {
return [];
}
const droppedFiles = Array.of<DroppedFile>();
for (let i = 0; i < dropFiles.length; i++) {
const file = dropFiles.item(i);
if (file) {
droppedFiles.push({
isFile: true,
path: file.name,
file,
});
}
}
return droppedFiles;
}
}
/**
* ドラッグ&ドロップされたファイルのリストからディレクトリ構造とファイルへの参照({@link File})を取得する。
*/
export async function readDataTransferItems(itemList: DataTransferItemList): Promise<DroppedItem[]> {
async function readEntry(entry: FileSystemEntry): Promise<DroppedItem> {
if (entry.isFile) {
return {
isFile: true,
path: entry.fullPath,
file: await readFile(entry as FileSystemFileEntry),
};
} else {
return {
isFile: false,
path: entry.fullPath,
children: await readDirectory(entry as FileSystemDirectoryEntry),
};
}
}
function readFile(fileSystemFileEntry: FileSystemFileEntry): Promise<File> {
return new Promise((resolve, reject) => {
fileSystemFileEntry.file(resolve, reject);
});
}
function readDirectory(fileSystemDirectoryEntry: FileSystemDirectoryEntry): Promise<DroppedItem[]> {
return new Promise(async (resolve) => {
const allEntries = Array.of<FileSystemEntry>();
const reader = fileSystemDirectoryEntry.createReader();
while (true) {
const entries = await new Promise<FileSystemEntry[]>((res, rej) => reader.readEntries(res, rej));
if (entries.length === 0) {
break;
}
allEntries.push(...entries);
}
resolve(await Promise.all(allEntries.map(readEntry)));
});
}
// 扱いにくいので配列に変換
const items = Array.of<DataTransferItem>();
for (let i = 0; i < itemList.length; i++) {
items.push(itemList[i]);
}
return Promise.all(
items
.map(it => it.webkitGetAsEntry())
.filter(it => it)
.map(it => readEntry(it!)),
);
}
/**
* {@link DroppedItem}のリストからディレクトリを再帰的に検索し、ファイルのリストを取得する。
*/
export function flattenDroppedFiles(items: DroppedItem[]): DroppedFile[] {
const result = Array.of<DroppedFile>();
for (const item of items) {
if (item.isFile) {
result.push(item);
} else {
result.push(...flattenDroppedFiles(item.children));
}
}
return result;
}