chromium/chrome/browser/resources/side_panel/bookmarks/bookmarks_api_proxy.ts

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

import type {ChromeEvent} from '/tools/typescript/definitions/chrome_event.js';
import type {ClickModifiers} from 'chrome://resources/mojo/ui/base/mojom/window_open_disposition.mojom-webui.js';

import type {ActionSource, SortOrder, ViewType} from './bookmarks.mojom-webui.js';
import {BookmarksPageHandlerFactory, BookmarksPageHandlerRemote} from './bookmarks.mojom-webui.js';

let instance: BookmarksApiProxy|null = null;

export interface BookmarksApiProxy {
  callbackRouter: {[key: string]: ChromeEvent<Function>};
  bookmarkCurrentTabInFolder(folderId: string): void;
  cutBookmark(id: string): void;
  contextMenuOpenBookmarkInNewTab(ids: string[], source: ActionSource): void;
  contextMenuOpenBookmarkInNewWindow(ids: string[], source: ActionSource): void;
  contextMenuOpenBookmarkInIncognitoWindow(ids: string[], source: ActionSource):
      void;
  contextMenuOpenBookmarkInNewTabGroup(ids: string[], source: ActionSource):
      void;
  contextMenuAddToBookmarksBar(id: string, source: ActionSource): void;
  contextMenuRemoveFromBookmarksBar(id: string, source: ActionSource): void;
  contextMenuDelete(ids: string[], source: ActionSource): void;
  copyBookmark(id: string): Promise<void>;
  createFolder(parentId: string, title: string):
      Promise<chrome.bookmarks.BookmarkTreeNode>;
  editBookmarks(
      ids: string[], newTitle: string|undefined, newUrl: string|undefined,
      newParentId: string|undefined): void;
  deleteBookmarks(ids: string[]): Promise<void>;
  getActiveUrl(): Promise<string|undefined>;
  getFolders(): Promise<chrome.bookmarks.BookmarkTreeNode[]>;
  openBookmark(
      id: string, depth: number, clickModifiers: ClickModifiers,
      source: ActionSource): void;
  pasteToBookmark(parentId: string, destinationId?: string): Promise<void>;
  renameBookmark(id: string, title: string): void;
  setSortOrder(sortOrder: SortOrder): void;
  setViewType(viewType: ViewType): void;
  showContextMenu(id: string, x: number, y: number, source: ActionSource): void;
  showUi(): void;
  undo(): void;
}

export class BookmarksApiProxyImpl implements BookmarksApiProxy {
  callbackRouter: {[key: string]: ChromeEvent<Function>};
  handler: BookmarksPageHandlerRemote;

  constructor() {
    this.callbackRouter = {
      onChanged: chrome.bookmarks.onChanged,
      onChildrenReordered: chrome.bookmarks.onChildrenReordered,
      onCreated: chrome.bookmarks.onCreated,
      onMoved: chrome.bookmarks.onMoved,
      onRemoved: chrome.bookmarks.onRemoved,
      onTabActivated: chrome.tabs.onActivated,
      onTabUpdated: chrome.tabs.onUpdated,
    };

    this.handler = new BookmarksPageHandlerRemote();

    const factory = BookmarksPageHandlerFactory.getRemote();
    factory.createBookmarksPageHandler(
        this.handler.$.bindNewPipeAndPassReceiver());
  }

  bookmarkCurrentTabInFolder(folderId: string) {
    this.handler.bookmarkCurrentTabInFolder(BigInt(folderId));
  }

  cutBookmark(id: string) {
    chrome.bookmarkManagerPrivate.cut([id]);
  }

  contextMenuOpenBookmarkInNewTab(ids: string[], source: ActionSource) {
    this.handler.executeOpenInNewTabCommand(ids.map(id => BigInt(id)), source);
  }

  contextMenuOpenBookmarkInNewWindow(ids: string[], source: ActionSource) {
    this.handler.executeOpenInNewWindowCommand(
        ids.map(id => BigInt(id)), source);
  }

  contextMenuOpenBookmarkInIncognitoWindow(
      ids: string[], source: ActionSource) {
    this.handler.executeOpenInIncognitoWindowCommand(
        ids.map(id => BigInt(id)), source);
  }

  contextMenuOpenBookmarkInNewTabGroup(ids: string[], source: ActionSource) {
    this.handler.executeOpenInNewTabGroupCommand(
        ids.map(id => BigInt(id)), source);
  }

  contextMenuAddToBookmarksBar(id: string, source: ActionSource) {
    this.handler.executeAddToBookmarksBarCommand(BigInt(id), source);
  }

  contextMenuRemoveFromBookmarksBar(id: string, source: ActionSource) {
    this.handler.executeRemoveFromBookmarksBarCommand(BigInt(id), source);
  }

  contextMenuDelete(ids: string[], source: ActionSource) {
    this.handler.executeDeleteCommand(ids.map(id => BigInt(id)), source);
  }

  copyBookmark(id: string) {
    return chrome.bookmarkManagerPrivate.copy([id]);
  }

  createFolder(parentId: string, title: string) {
    return chrome.bookmarks.create(
        {parentId: parentId, title: title, index: 0});
  }

  editBookmarks(
      ids: string[], newTitle: string|undefined, newUrl: string|undefined,
      newParentId: string|undefined) {
    // Current use cases do not expect one of newTitle and newUrl to be
    // provided without the other.
    if (newTitle !== undefined && newUrl !== undefined) {
      ids.forEach(id => {
        chrome.bookmarks.update(id, {title: newTitle, url: newUrl});
      });
    }
    if (newParentId) {
      ids.forEach(id => {
        chrome.bookmarks.move(id, {parentId: newParentId});
      });
    }
  }

  deleteBookmarks(ids: string[]) {
    return chrome.bookmarkManagerPrivate.removeTrees(ids);
  }

  getActiveUrl() {
    return chrome.tabs.query({active: true, currentWindow: true}).then(tabs => {
      if (tabs[0]) {
        return tabs[0].url;
      }
      return undefined;
    });
  }

  getFolders() {
    return chrome.bookmarks.getTree().then(results => {
      if (results[0] && results[0].children) {
        return results[0].children;
      }
      return [];
    });
  }

  openBookmark(
      id: string, depth: number, clickModifiers: ClickModifiers,
      source: ActionSource) {
    this.handler.openBookmark(BigInt(id), depth, clickModifiers, source);
  }

  pasteToBookmark(parentId: string, destinationId?: string) {
    const destination = destinationId ? [destinationId] : [];
    return chrome.bookmarkManagerPrivate.paste(parentId, destination);
  }

  renameBookmark(id: string, title: string) {
    chrome.bookmarks.update(id, {title: title});
  }

  setSortOrder(sortOrder: SortOrder) {
    this.handler.setSortOrder(sortOrder);
  }

  setViewType(viewType: ViewType) {
    this.handler.setViewType(viewType);
  }

  showContextMenu(id: string, x: number, y: number, source: ActionSource) {
    this.handler.showContextMenu(id, {x, y}, source);
  }

  showUi() {
    this.handler.showUI();
  }

  undo() {
    chrome.bookmarkManagerPrivate.undo();
  }

  static getInstance(): BookmarksApiProxy {
    return instance || (instance = new BookmarksApiProxyImpl());
  }

  static setInstance(obj: BookmarksApiProxy) {
    instance = obj;
  }
}