chromium/ash/webui/media_app_ui/resources/js/media_app.d.ts

// Copyright 2023 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

/**
 * @fileoverview
 * Types for go/media-app-externs. Currently this only exists in the chromium
 * repository and is handcrafted. When no media_app JS exists, this file will
 * replace go/media-app-externs, and it can be a regular `.ts` file that both
 * toolchains consume directly. Until then, the internal toolchain builds only
 * off the JS externs and has no knowledge of this file.
 */

type RectF =
    import('//resources/mojo/ui/gfx/geometry/mojom/geometry.mojom-webui.js')
        .RectF;
type MojoUrl = import('//resources/mojo/url/mojom/url.mojom-webui.js').Url;

type PageMetadata =
    import('./media_app_ui_untrusted.mojom-webui.js').PageMetadata;
type OcrUntrustedPageInterface =
    import('./media_app_ui_untrusted.mojom-webui.js').OcrUntrustedPageInterface;
type RequestBitmapResponse = import('./media_app_ui_untrusted.mojom-webui.js')
                                 .OcrUntrustedPage_RequestBitmap_ResponseParams;

type MahiUntrustedPageInterface =
    import('./media_app_ui_untrusted.mojom-webui.js')
        .MahiUntrustedPageInterface;
type GetPdfContentResponse =
    import('./media_app_ui_untrusted.mojom-webui.js')
        .MahiUntrustedPage_GetPdfContent_ResponseParams;

/**
 * Wraps an HTML File object (or a mock, or media loaded through another means).
 */
declare interface AbstractFile {
  /**
   * The native Blob representation.
   */
  blob: Blob;
  /**
   * A name to represent this file in the UI. Usually the filename.
   */
  name: string;
  /**
   * A unique number that represents this file, used to communicate the file in
   * IPC with a parent frame.
   */
  token?: number;
  /**
   * Size of the file, e.g., from the HTML5 File API.
   */
  size: number;
  /**
   * Mime Type of the file, e.g., from the HTML5 File API. Note that the name
   * intentionally does not match the File API version because 'type' is a
   * reserved word in TypeScript.
   */
  mimeType: string;
  /**
   * Whether the file came from the clipboard or a similar in-memory source not
   * backed by a file on disk.
   */
  fromClipboard?: boolean;
  /**
   * An error associated with this file.
   * @type {string|undefined}
   */
  error?: string;
  /**
   * A function that queries the original file's path to see if it is in a
   * filesystem that ARC is able to write to. Returns a promise that resolves
   * once this has been determined.
   */
  isArcWritable?: () => Promise<boolean>;
  /**
   * A function that queries the original file's path to see if it is writable
   * according to Ash. Returns a promise that resolves once this has been
   * determined.
   */
  isBrowserWritable?: () => Promise<boolean>;
  /**
   * A function that attempts to launch the file in Photos in editing mode.
   * Returns a promise that resolves when the launch has initiated.
   */
  editInPhotos?: () => Promise<void>;
  /**
   * A function that will overwrite the original file with the provided Blob.
   * Returns a promise that resolves when the write operations are complete. Or
   * rejects. Upon success, `size` will reflect the new file size.
   * If null, then in-place overwriting is not supported for this file.
   * Note the "overwrite" may be simulated with a download operation.
   */
  overwriteOriginal?: (blob: Blob) => Promise<void>;
  /**
   * A function that will delete the original file. Returns a promise that
   * resolves on success. Errors encountered are thrown from the message pipe
   * and handled by invoking functions in Google3.
   */
  deleteOriginalFile?: () => Promise<void>;
  /**
   * A function that will rename the original file. Returns a promise that
   * resolves to an enum value (see RenameResult in message_types) reflecting
   * the result of the rename. Errors encountered are thrown from the message
   * pipe and handled by invoking functions in Google3.
   */
  renameOriginalFile?: (newName: string) => Promise<number>;
  /**
   * A function that will save the provided blob in the file pointed to by
   * pickedFileToken. Once saved, the new file takes over this.token and becomes
   * currently writable. The original file is given a new token
   * and pushed forward in the navigation order.
   */
  saveAs?: (data: Blob, pickedFileToken: number) => Promise<void>;
  /**
   * A function that will show a file picker using the filename and an
   * appropriate starting folder for `this` file. Returns a writable file picked
   * by the user. The argument configures the dialog with the provided set of
   * predefined file extensions that the user may select from. This also helps
   * populate an extension on the chosen file. Contains an array of strings that
   * are "keys" to preconfigured settings for the file picker `accept` option.
   * E.g. ["PNG", "JPG", "PDF", "WEBP"].
   */
  getExportFile?:
      (filePickerAcceptOptionKeys: string[]) => Promise<AbstractFile>;
  /**
   * If defined, resolves a placeholder `blob` to a DOM File object using IPC
   * with the trusted context. Propagates exceptions. Does not modify `this`,
   * and always performs IPC to handle cases where the previously obtained File
   * is no longer accessible. E.g. if a file changes on disk (i.e. its mtime
   * changes), security checks may invalidate an old `File`, requiring it to be
   * "reopened".
   */
  openFile?: () => Promise<File>;
}

/**
 * Wraps an HTML FileList object.
 */
declare interface AbstractFileList {
  length: number;
  /**
   * The index of the currently active file which navigation and other file
   * operations are performed relative to. Defaults to -1 if file list is empty.
   */
  currentFileIndex: number;
  item(index: number): AbstractFile|null;
  /**
   * Loads the next file in the navigation order into the media app.
   * @param currentFileToken the token of the file that is currently
   *     loaded into the media app.
   */
  loadNext(currentFileToken?: number): Promise<void>;
  /**
   * Loads the previous file in the navigation order into the media app.
   */
  loadPrev(currentFileToken?: number): Promise<void>;
  /**
   * @param observer invoked when the size or contents of the file list changes.
   */
  addObserver(observer: (fileList: AbstractFileList) => void): void;
  /**
   * Request for the user to be prompted with an open file dialog. Files chosen
   * will be added to the last received file list.
   * TODO(b/230670565): Remove the undefined here once we can ensure all file
   * lists implement a openFilesWithFilePicker function.
   */
  openFilesWithFilePicker?:
      (acceptTypeKeys: string[], startInFolder?: AbstractFile,
       isSingleFile?: boolean) => Promise<void>;
  /**
   * Filters items represented by this file list in place, possibly changing the
   * length. Only items for which the filter returns true are kept.
   */
  filterInPlace?: (filter: (file: AbstractFile) => boolean) => void;
}

/**
 * The delegate which exposes open source privileged WebUi functions to
 * MediaApp.
 */
declare interface ClientApiDelegate {
  /**
   * Opens up the built-in chrome feedback dialog.
   * @return Promise which resolves when the request has been
   *     acknowledged, if the dialog could not be opened the promise resolves
   *     with an error message, resolves with null otherwise.
   */
  openFeedbackDialog(): Promise<string>;
  /**
   * Toggles browser fullscreen mode.
   */
  toggleBrowserFullscreenMode?: () => Promise<void>;
  /**
   * Request for the user to be prompted with a save file dialog. Once the user
   * selects a location a new file handle is created and a new AbstractFile
   * representing that file will be returned. This can be then used in a save as
   * operation.
   * @param suggestedName The name to suggest in the file picker.
   * @param mimeType Fallback MIME type (deprecated).
   * @param acceptTypeKeys File filter configuration for the file
   * picker dialog. See getExportFile.
   */
  requestSaveFile(
      suggestedName: string, mimeType: string,
      acceptTypeKeys: string[]): Promise<AbstractFile>;
  /**
   * Notify MediaApp that the current file has been updated.
   */
  notifyCurrentFile(name?: string, type?: string): void;
  /**
   * Notify MediaApp that a file has been opened.
   */
  notifyFileOpened(name?: string, type?: string): void;
  /**
   * Notify the app that the current file's name has been changed by "Rename"
   * or "Saved as".
   */
  notifyFilenameChanged(name: string): void;
  /**
   * Attempts to extract a JPEG "preview" from a RAW image file. Throws on any
   * failure. Note this is typically a full-sized preview, not a thumbnail.
   * @return A Blob-backed File with type: image/jpeg.
   */
  extractPreview(file: Blob): Promise<File>;
  /**
   * Passes the provided `blobUuid` to a sandboxed viewer in a popup window.
   * This enables the trusted context to open the popup so that it does not
   * appear with UI suggesting to the user that it is insecure. Only the UUID of
   * the blob should be passed (hex digits and hyphens), which will reconstruct
   * the blob URL in the sandbox. The provided `title` will be used to set the
   * document title (e.g., to include the filename), which will appear in the
   * popup title bar and shelf context menu.
   */
  openInSandboxedViewer?: (title: string, blobUuid: string) => void;
  /**
   * Opens the provided `url` in a browser tab.
   */
  openUrlInBrowserTab?: (url: string) => void;
  /**
   * Reloads the main frame, reloading launch files.
   */
  reloadMainFrame?: () => void;
  /**
   * Indicates to the WebUI Controller that a trigger for displaying the PDF
   * HaTS survey has occurred.
   */
  maybeTriggerPdfHats?: () => void;
  /**
   * Called when the media app finishes loading a PDF file, to notify Mahi about
   * the refresh availability.
   */
  onPdfLoaded(): void;
  /**
   * Called when the media app shows a context menu on PDF surface, to notify
   * Mahi to show its widget card accordingly.
   * @param anchor The coordinate and size of the context menu to help Mahi
   *     align the widget.
   */
  onPdfContextMenuShow(anchor: RectF): void;
  /**
   * Called when the media app hides its context menu from PDF surface, to
   * notify Mahi to hide its widget card accordingly.
   */
  onPdfContextMenuHide(): void;
  /**
   * Alert the OCR service that the PDF's page metadata has changed.
   */
  pageMetadataUpdated(pageMetadata: PageMetadata[]): void;
  /**
   * Alert the OCR service that a specific page's contents has changed and
   * should have OCR applied again.
   */
  pageContentsUpdated(dirtyPageId: string): void;
  /**
   * Submit a form to a URL - required since plain form submit doesn't have ideal behavior in LaCrOS.
   * @param url URL to submit the form to (must have host == lens.google.com).
   * @param payload Bytes corresponding to formdata which is the payload.
   * @param header The content-type header including the form boundary specifier.
   */
  submitForm(url: MojoUrl, payload: number[], header: string): void;
  /**
   * Called whenever the viewport changes, e.g. due to scrolling, zooming,
   * resizing the window, or opening and closing toolbars/panels.
   * @param viewportBox The new bounding box of the viewport.
   * @param scaleFactor The ratio between CSS pixels (i.e. ignoring browser
   *     and pinch zoom) and ink units. Larger numbers indicate the document
   *     is more zoomed in.
   */
  viewportUpdated(viewportBox: RectF, scaleFactor: number): void;

}

/**
 * The client Api for interacting with the media app instance.
 */
declare interface ClientApi extends OcrUntrustedPageInterface,
                                    MahiUntrustedPageInterface {
  /**
   * Looks up handler(s) and loads media via FileList.
   */
  loadFiles(files: AbstractFileList): Promise<void>;
  /**
   * Sets the delegate through which MediaApp can access open-source privileged
   * WebUI methods.
   */
  setDelegate(delegate: ClientApiDelegate|null): void;
  /**
   * Gets the bitmap for the page with `requestedPageId`.
   */
  requestBitmap(requestedPageId: string): Promise<RequestBitmapResponse>;
  /**
   * If a document is currently loaded, scrolls and zooms to the given viewport.
   */
  setViewport(viewport: RectF): Promise<void>;
  /**
   * Gets the text content from the PDF file, truncated if the byte size exceeds
   * `byteSizeLimit`.
   */
  getPdfContent(byteSizeLimit: number): Promise<GetPdfContentResponse>;
  /**
   * Hides the context menu from the PDF surface, if currently shown.
   */
  hidePdfContextMenu(): Promise<void>;
}

/**
 * Launch data that can be read by the app when it first loads.
 */
declare interface CustomLaunchData {
  delegate?: ClientApiDelegate;
  files: AbstractFileList;
}

interface Window {
  customLaunchData: CustomLaunchData;
}