chromium/chrome/browser/resources/settings/a11y_page/a11y_page.ts

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

/**
 * @fileoverview
 * 'settings-a11y-page' is the small section of advanced settings with
 * a link to the web store accessibility page on most platforms, and
 * a subpage with lots of other settings on Chrome OS.
 */
import 'chrome://resources/cr_elements/cr_link_row/cr_link_row.js';
import '../controls/settings_toggle_button.js';
import '../settings_page/settings_animated_pages.js';
import '../settings_shared.css.js';
// clang-format off
// <if expr="not is_macosx and not is_chromeos">
import './captions_subpage.js';
import '../settings_page/settings_subpage.js';
// </if>

// <if expr="is_win or is_linux or is_macosx">
import './ax_annotations_section.js';
// </if>

// <if expr="is_win or is_macosx">
import './live_caption_section.js';

import {CaptionsBrowserProxyImpl} from '/shared/settings/a11y_page/captions_browser_proxy.js';
// </if>
// clang-format on
import {PrefsMixin} from '/shared/settings/prefs/prefs_mixin.js';
import {WebUiListenerMixin} from 'chrome://resources/cr_elements/web_ui_listener_mixin.js';
import {PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';

import {BaseMixin} from '../base_mixin.js';
import type {SettingsToggleButtonElement} from '../controls/settings_toggle_button.js';
import {loadTimeData} from '../i18n_setup.js';
import {routes} from '../route.js';
import {Router} from '../router.js';

import type {AccessibilityBrowserProxy} from './a11y_browser_proxy.js';
import {AccessibilityBrowserProxyImpl} from './a11y_browser_proxy.js';
import {getTemplate} from './a11y_page.html.js';

// clang-format off
// <if expr="not is_chromeos">
import type {LanguageHelper, LanguagesModel} from '../languages_page/languages_types.js';

// </if>
// clang-format on

const SettingsA11yPageElementBase =
    PrefsMixin(WebUiListenerMixin(BaseMixin(PolymerElement)));

export class SettingsA11yPageElement extends SettingsA11yPageElementBase {
  static get is() {
    return 'settings-a11y-page' as const;
  }

  static get template() {
    return getTemplate();
  }

  static get properties() {
    return {
      /**
       * The current active route.
       */
      currentRoute: {
        type: Object,
        notify: true,
      },

      /**
       * Preferences state.
       */
      prefs: {
        type: Object,
        notify: true,
      },

      // <if expr="not is_chromeos">
      /**
       * Read-only reference to the languages model provided by the
       * 'settings-languages' instance.
       */
      languages: {
        type: Object,
        notify: true,
      },

      languageHelper: Object,

      enableLiveCaption_: {
        type: Boolean,
        value: function() {
          return loadTimeData.getBoolean('enableLiveCaption');
        },
      },
      // </if>

      /**
       * Indicate whether a screen reader is enabled. Also, determine whether
       * to show accessibility labels settings.
       */
      hasScreenReader_: {
        type: Boolean,
        value: false,
      },

      // <if expr="is_win or is_linux or is_macosx">
      /**
       * Whether to show the AxAnnotations subpage.
       */
      showAxAnnotationsSection_: {
        type: Boolean,
        computed: 'computeShowAxAnnotationsSection_(hasScreenReader_)',
      },
      // </if>

      focusConfig_: {
        type: Object,
        value() {
          const map = new Map();
          if (routes.CAPTIONS) {
            map.set(routes.CAPTIONS.path, '#captions');
          }
          return map;
        },
      },

      /**
       * Whether the caption settings link opens externally.
       */
      captionSettingsOpensExternally_: {
        type: Boolean,
        value() {
          let opensExternally = false;
          // <if expr="is_macosx or is_win">
          opensExternally = true;
          // </if>
          return opensExternally;
        },
      },

      /**
       * Whether to show the overscroll history navigation setting.
       */
      showOverscrollHistoryNavigationToggle_: {
        type: Boolean,
        value: function() {
          let showOverscroll = false;
          // <if expr="is_win or is_linux or is_macosx">
          showOverscroll = true;
          // </if>
          return showOverscroll;
        },
      },
    };
  }

  private browserProxy_: AccessibilityBrowserProxy =
      AccessibilityBrowserProxyImpl.getInstance();

  // <if expr="not is_chromeos">
  languages: LanguagesModel;
  languageHelper: LanguageHelper;

  private enableLiveCaption_: boolean;
  // </if>

  private captionSettingsOpensExternally_: boolean;
  private hasScreenReader_: boolean;
  private showOverscrollHistoryNavigationToggle_: boolean;
  // <if expr="is_win or is_linux or is_macosx">
  private showAxAnnotationsSection_: boolean;
  // </if>

  override connectedCallback() {
    super.connectedCallback();

    const updateScreenReaderState = (hasScreenReader: boolean) => {
      this.hasScreenReader_ = hasScreenReader;
    };
    this.browserProxy_.getScreenReaderState().then(updateScreenReaderState);
    this.addWebUiListener(
        'screen-reader-state-changed', updateScreenReaderState);
  }

  private onA11yCaretBrowsingChange_(event: Event) {
    if ((event.target as SettingsToggleButtonElement).checked) {
      chrome.metricsPrivate.recordUserAction(
          'Accessibility.CaretBrowsing.EnableWithSettings');
    } else {
      chrome.metricsPrivate.recordUserAction(
          'Accessibility.CaretBrowsing.DisableWithSettings');
    }
  }

  private onA11yImageLabelsChange_(event: Event) {
    const a11yImageLabelsOn =
        (event.target as SettingsToggleButtonElement).checked;
    if (a11yImageLabelsOn) {
      chrome.send('confirmA11yImageLabels');
    }
  }

  // <if expr="is_win or is_linux or is_macosx">
  /**
   * Return whether to show the AxAnnotations subpage based on:
   *    1. If any annotation's feature flag is enabled.
   *    2. Whether a screen reader is enabled.
   * Note: on ChromeOS, the AxAnnotations subpage is shown on a different
   * settings page; i.e. Settings > Accessibility > Text-to-Speech.
   */
  private computeShowAxAnnotationsSection_(): boolean {
    const anyAxAnnotationsFeatureEnabled =
        loadTimeData.getBoolean('mainNodeAnnotationsEnabled');
    return anyAxAnnotationsFeatureEnabled && this.hasScreenReader_;
  }
  // </if>

  // <if expr="not is_chromeos">
  private onFocusHighlightChange_(event: Event) {
    chrome.metricsPrivate.recordBoolean(
        'Accessibility.FocusHighlight.ToggleEnabled',
        (event.target as SettingsToggleButtonElement).checked);
  }
  // </if>

  // <if expr="is_chromeos">
  private onManageSystemAccessibilityFeaturesClick_() {
    window.location.href = 'chrome://os-settings/osAccessibility';
  }
  // </if>

  /** private */
  private onMoreFeaturesLinkClick_() {
    window.open(
        'https://chrome.google.com/webstore/category/collection/3p_accessibility_extensions');
  }

  private onCaptionsClick_() {
    if (this.captionSettingsOpensExternally_) {
      // <if expr="is_win or is_macosx">
      CaptionsBrowserProxyImpl.getInstance().openSystemCaptionsDialog();
      // </if>
    } else {
      Router.getInstance().navigateTo(routes.CAPTIONS);
    }
  }

  // <if expr="is_win or is_linux">
  private onOverscrollHistoryNavigationChange_(event: Event) {
    const enabled = (event.target as SettingsToggleButtonElement).checked;
    this.browserProxy_.recordOverscrollHistoryNavigationChanged(enabled);
  }
  // </if>

  // <if expr="is_macosx">
  private onMacTrackpadGesturesLinkClick_() {
    this.browserProxy_.openTrackpadGesturesSettings();
  }
  // </if>
}

declare global {
  interface HTMLElementTagNameMap {
    [SettingsA11yPageElement.is]: SettingsA11yPageElement;
  }
}

customElements.define(SettingsA11yPageElement.is, SettingsA11yPageElement);