Skip to content

Commit

Permalink
GoogleChromeLabs#129 Draft - support for new fileHierarchy() function…
Browse files Browse the repository at this point in the history
… which adds a handle to the requested directory as well as the content of that directory
  • Loading branch information
reubenfirmin committed Nov 24, 2022
1 parent 9ed9982 commit d30afb0
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 0 deletions.
28 changes: 28 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ const options = {
startIn: 'downloads',
// By specifying an ID, the user agent can remember different directories for different IDs.
id: 'projects',
// Set to 'read' or 'readwrite'; the browser will prompt the user accordingly.
mode: 'read',
// Callback to determine whether a directory should be entered, return `true` to skip.
skipDirectory: (entry) => entry.name[0] === '.',
};
Expand All @@ -176,6 +178,32 @@ const blobs = await directoryOpen(options);

The module also polyfills a [`webkitRelativePath`](https://developer.mozilla.org/en-US/docs/Web/API/File/webkitRelativePath) property on returned files in a consistent way, regardless of the underlying implementation.

### Opening A Directory Hierarchy

A variant of directoryOpen which is not backwards/legacy compatible, but includes
a handle referencing the directory being opened, as well as its contents.

```js
// Options are optional.
const options = {
// Set to `true` to recursively open files in all subdirectories,
// defaults to `false`.
recursive: true,
// Suggested directory in which the file picker opens. A well-known directory, or a file or directory handle.
startIn: 'downloads',
// By specifying an ID, the user agent can remember different directories for different IDs.
id: 'projects',
// Set to 'read' or 'readwrite'; the browser will prompt the user accordingly.
mode: 'read',
// Callback to determine whether a directory should be entered, return `true` to skip.
skipDirectory: (entry) => entry.name[0] === '.',
};

const dirWithContents = fileHierarchy(options);
const dir = dirWithContents.currentDir;
const contents = await dirWithContents.contents;
```

### Saving files:

```js
Expand Down
58 changes: 58 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,64 @@ export function directoryOpen(options?: {
) => (reject?: (reason?: any) => void) => void;
}): Promise<FileWithDirectoryAndFileHandle[]>;

/**
* Opens a directory from disk using the File System Access API. Includes a reference to the directory being listed
* (similar to the "." entry in UNIX file systems.) Not supported in legacy fallback mode.
* @returns Contained files.
*/
export function fileHierarchy(options?: {
/** Whether to recursively get subdirectories. */
recursive: boolean;
/** Suggested directory in which the file picker opens. */
startIn?: WellKnownDirectory | FileSystemHandle;
/** By specifying an ID, the user agent can remember different directories for different IDs. */
id?: string;
/** By specifying a mode of `'readwrite'`, you can open a directory with write access. */
mode?: FileSystemPermissionMode;
/** Callback to determine whether a directory should be entered, return `true` to skip. */
skipDirectory?: (
entry: FileSystemDirectoryEntry | FileSystemDirectoryHandle
) => boolean;
/**
* Configurable setup, cleanup and `Promise` rejector usable with legacy API
* for determining when (and reacting if) a user cancels the operation. The
* method will be passed a reference to the internal `rejectionHandler` that
* can, e.g., be attached to/removed from the window or called after a
* timeout. The method should return a function that will be called when
* either the user chooses to open a file or the `rejectionHandler` is
* called. In the latter case, the returned function will also be passed a
* reference to the `reject` callback for the `Promise` returned by
* `fileOpen`, so that developers may reject the `Promise` when desired at
* that time.
* Example rejector:
*
* const file = await fileHierarchy({
* legacySetup: (rejectionHandler) => {
* const timeoutId = setTimeout(rejectionHandler, 10_000);
* return (reject) => {
* clearTimeout(timeoutId);
* if (reject) {
* reject('My error message here.');
* }
* };
* },
* });
*
* ToDo: Remove this workaround once
* https://github.com/whatwg/html/issues/6376 is specified and supported.
*/
legacySetup?: (
resolve: (value: FileWithDirectoryAndFileHandle) => void,
rejectionHandler: () => void,
input: HTMLInputElement
) => (reject?: (reason?: any) => void) => void;
}): DirectoryHandleWithContents;

export interface DirectoryHandleWithContents {
currentDir: FileSystemDirectoryHandle;
contents: Promise<FileWithDirectoryAndFileHandle[]>;
}

/**
* Whether the File System Access API is supported.
*/
Expand Down
1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
export { fileOpen } from './file-open.mjs';
export { directoryOpen } from './directory-open.mjs';
export { fileSave } from './file-save.mjs';
export { fileHierarchy } from './file-hierarchy.mjs';

export { default as fileOpenModern } from './fs-access/file-open.mjs';
export { default as directoryOpenModern } from './fs-access/directory-open.mjs';
Expand Down

0 comments on commit d30afb0

Please sign in to comment.