chromium/chrome/browser/resources/webapks/about_webapks.ts

// Copyright 2017 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} from 'chrome://resources/js/assert.js';
import {addWebUiListener} from 'chrome://resources/js/cr.js';

interface WebApkInfo {
  name: string;
  shortName: string;
  packageName: string;
  id: string;
  shellApkVersion: number;
  versionCode: number;
  uri: string;
  scope: string;
  manifestUrl: string;
  manifestStartUrl: string;
  manifestId: string;
  displayMode: string;
  orientation: string;
  themeColor: string;
  backgroundColor: string;
  darkThemeColor: string;
  darkBackgroundColor: string;
  lastUpdateCheckTimeMs: number;
  lastUpdateCompletionTimeMs: number;
  relaxUpdates: boolean;
  backingBrowser: string;
  isBackingBrowser: boolean;
  updateStatus: string;
}

/**
 * Creates and returns an element (with |text| as content) assigning it the
 * |className| class.
 *
 * @param text Text to be shown in the span.
 * @param type Type of element to be added such as 'div'.
 * @param className Class to be assigned to the new element.
 * @return The created element.
 */
function createElementWithTextAndClass(
    text: string, type: string, className: string): HTMLElement {
  const element = document.createElement(type);
  element.className = className;
  element.textContent = text;
  return element;
}

/**
 * @param webApkList List of elements which contain WebAPK attributes.
 * @param label Text that identifies the new element.
 * @param value Text to set in the new element.
 */
function addWebApkField(webApkList: HTMLElement, label: string, value: string) {
  const divElement =
      createElementWithTextAndClass(label, 'div', 'app-property-label');
  divElement.appendChild(
      createElementWithTextAndClass(value, 'span', 'app-property-value'));
  webApkList.appendChild(divElement);
}

/**
 * @param webApkList List of elements which contain WebAPK attributes.
 * @param text For the button.
 * @param callback Invoked on click.
 * @return The button that was created.
 */
function addWebApkButton(
    webApkList: HTMLElement, text: string, callback: () => void): HTMLElement {
  const divElement =
      createElementWithTextAndClass(text, 'button', 'update-button');
  divElement.onclick = callback;
  webApkList.appendChild(divElement);
  return divElement;
}

/**
 * Adds a new entry to the page with the information of a WebAPK.
 *
 * @param webApkInfo Information about an installed WebAPK.
 */
function addWebApk(webApkInfo: WebApkInfo) {
  const webApkList = document.body.querySelector<HTMLElement>('#webapk-list');
  assert(webApkList);

  webApkList.appendChild(
      createElementWithTextAndClass(webApkInfo.name, 'span', 'app-name'));

  webApkList.appendChild(createElementWithTextAndClass(
      'Short name: ', 'span', 'app-property-label'));
  webApkList.appendChild(document.createTextNode(webApkInfo.shortName));

  addWebApkField(webApkList, 'Package name: ', webApkInfo.packageName);
  addWebApkField(
      webApkList, 'Shell APK version: ', '' + webApkInfo.shellApkVersion);
  addWebApkField(webApkList, 'Version code: ', '' + webApkInfo.versionCode);
  addWebApkField(webApkList, 'URI: ', webApkInfo.uri);
  addWebApkField(webApkList, 'Scope: ', webApkInfo.scope);
  addWebApkField(webApkList, 'Manifest URL: ', webApkInfo.manifestUrl);
  addWebApkField(
      webApkList, 'Manifest Start URL: ', webApkInfo.manifestStartUrl);
  addWebApkField(webApkList, 'Manifest Id: ', webApkInfo.manifestId);
  addWebApkField(webApkList, 'Display Mode: ', webApkInfo.displayMode);
  addWebApkField(webApkList, 'Orientation: ', webApkInfo.orientation);
  addWebApkField(webApkList, 'Theme color: ', webApkInfo.themeColor);
  addWebApkField(webApkList, 'Background color: ', webApkInfo.backgroundColor);
  addWebApkField(webApkList, 'Dark theme color: ', webApkInfo.darkThemeColor);
  addWebApkField(
      webApkList, 'Dark background color: ', webApkInfo.darkBackgroundColor);
  addWebApkField(
      webApkList, 'Last Update Check Time: ',
      new Date(webApkInfo.lastUpdateCheckTimeMs).toString());
  addWebApkField(
      webApkList, 'Last Update Completion Time: ',
      new Date(webApkInfo.lastUpdateCompletionTimeMs).toString());
  addWebApkField(
      webApkList, 'Check for Updates Less Frequently: ',
      webApkInfo.relaxUpdates.toString());
  addWebApkField(webApkList, 'Owning Browser: ', webApkInfo.backingBrowser);
  addWebApkField(
      webApkList, 'Update Status (Reload page to get new status): ',
      webApkInfo.updateStatus);

  // TODO(ckitagawa): Convert to an enum using mojom handlers.
  if (webApkInfo.updateStatus === 'Not updatable' ||
      !webApkInfo.isBackingBrowser) {
    return;
  }

  addWebApkButton(webApkList, 'Update ' + webApkInfo.name, () => {
    alert(
        'The WebAPK will check for an update the next time it launches. ' +
        'If an update is available, the "Update Status" on this page ' +
        'will switch to "Scheduled". The update will be installed once ' +
        'the WebAPK is closed (this may take a few minutes). Update ' +
        'requests don\'t work if they are requested right after (< 1 ' +
        'minute) the completion of the previous update request.');
    chrome.send('requestWebApkUpdate', [webApkInfo.id]);
    window.location.reload();
  });
}

document.addEventListener('DOMContentLoaded', function() {
  // Add a WebUI listener for the 'web-apk-info' event emitted from the
  // backend. This will be triggered once per WebAPK.
  addWebUiListener('web-apk-info', addWebApk);
  chrome.send('requestWebApksInfo');
});