chromium/ash/webui/camera_app_ui/resources/js/views/dialog.ts

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

import {assert, assertString} from '../assert.js';
import * as dom from '../dom.js';
import {I18nString} from '../i18n_string.js';
import {getI18nMessage} from '../models/load_time_data.js';
import {ChromeHelper} from '../mojo/chrome_helper.js';
import {ViewName} from '../type.js';

import {DialogEnterOptions, View} from './view.js';

interface ButtonEvent {
  onNegativeButtonClicked?: () => void;
  onPositiveButtonClicked?: () => void;
}

/**
 * Creates the Dialog view controller.
 */
export class Dialog extends View {
  private readonly positiveButton: HTMLButtonElement;

  private readonly negativeButton: HTMLButtonElement|null;

  private readonly messageHolder: HTMLElement;

  private readonly titleHolder: HTMLDivElement|null;

  protected readonly descHolder: HTMLDivElement|null;

  constructor(
      name: ViewName,
      {onPositiveButtonClicked, onNegativeButtonClicked}: ButtonEvent = {}) {
    super(
        name,
        {dismissByEsc: true, defaultFocusSelector: '.dialog-positive-button'});

    this.positiveButton =
        dom.getFrom(this.root, '.dialog-positive-button', HTMLButtonElement);
    this.negativeButton = dom.getFromIfExists(
        this.root, '.dialog-negative-button', HTMLButtonElement);
    this.messageHolder =
        dom.getFrom(this.root, '.dialog-msg-holder', HTMLElement);
    this.titleHolder =
        dom.getFromIfExists(this.root, '.dialog-title', HTMLDivElement);
    this.descHolder =
        dom.getFromIfExists(this.root, '.dialog-description', HTMLDivElement);

    this.positiveButton.addEventListener('click', () => {
      onPositiveButtonClicked?.();
      this.leave({kind: 'CLOSED', val: true});
    });
    this.negativeButton?.addEventListener('click', () => {
      onNegativeButtonClicked?.();
      this.leave();
    });
  }

  override entering(
      {cancellable, description, message, title}: DialogEnterOptions = {}):
      void {
    // Update dialog text
    if (message !== undefined) {
      this.messageHolder.textContent = assertString(message);
    }
    // Update title and description, and update i18n-text for testing purpose.
    if (title !== undefined && this.titleHolder !== null) {
      this.titleHolder.textContent = getI18nMessage(title);
      this.titleHolder.setAttribute('i18n-text', title);
    }
    if (description !== undefined && this.descHolder !== null) {
      this.descHolder.textContent = getI18nMessage(description);
      this.descHolder.setAttribute('i18n-text', description);
    }

    // Only change visibility when explicitly define boolean value.
    if (this.negativeButton !== null && cancellable !== undefined) {
      this.negativeButton.hidden = !cancellable;
    }
  }
}

const HELP_PAGE_URL =
    'https://support.google.com/chromebook/?p=camera_usage_on_chromebook';
export class SuperResIntroDialog extends Dialog {
  constructor() {
    const learnMoreAction = () => {
      ChromeHelper.getInstance().openUrlInBrowser(HELP_PAGE_URL);
      this.leave();
    };
    super(
        ViewName.SUPER_RES_INTRO_DIALOG,
        {onNegativeButtonClicked: learnMoreAction});
  }

  override entering(): void {
    // Replace the description placeholder with PTZ button icon.
    assert(this.descHolder !== null);

    const ptzIconPlaceholder = '<PTZ ICON>';
    const desc = getI18nMessage(
        I18nString.SUPER_RES_INTRO_DIALOG_DESC, ptzIconPlaceholder);
    const replacePosition = desc.indexOf(ptzIconPlaceholder);

    const textNode = document.createTextNode(desc);
    const textAfterIcon = textNode.splitText(replacePosition)
                              .splitText(ptzIconPlaceholder.length);

    const icon = document.createElement('svg-wrapper');
    icon.name = 'camera_button_ptz_panel.svg';

    const iconWrapper = document.createElement('span');
    iconWrapper.classList.add('ptz-icon');
    iconWrapper.setAttribute(
        'aria-label', getI18nMessage(I18nString.OPEN_PTZ_PANEL_BUTTON));
    iconWrapper.appendChild(icon);

    this.descHolder.append(textNode, iconWrapper, textAfterIcon);
  }
}