summaryrefslogtreecommitdiff
path: root/chromium/chrome/browser/resources/components/components.js
blob: 968f1728abe126bcefb33e4439aec02f3edb2538 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
// Copyright 2013 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import './strings.m.js';

import {addWebUIListener, isChromeOS, sendWithPromise} from 'chrome://resources/js/cr.m.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
import {$} from 'chrome://resources/js/util.m.js';

/**
 * An array of the latest component data including ID, name, status and
 * version. This is populated in returnComponentsData() for the convenience of
 * tests.
 */
let currentComponentsData = null;

/**
 * Takes the |componentsData| input argument which represents data about the
 * currently installed components and populates the html jstemplate with
 * that data. It expects an object structure like the above.
 * @param {Object} componentsData Detailed info about installed components.
 *      Same expected format as returnComponentsData().
 */
function renderTemplate(componentsData) {
  // This is the javascript code that processes the template:
  const input = new JsEvalContext(componentsData);
  const output = $('component-template').cloneNode(true);
  $('component-placeholder').innerHTML = trustedTypes.emptyHTML;
  $('component-placeholder').appendChild(output);
  jstProcess(input, output);
  output.removeAttribute('hidden');

  // <if expr="chromeos_ash or chromeos_lacros">
  const crosUrlRedirectButton = $('os-link-href');
  if (crosUrlRedirectButton) {
    crosUrlRedirectButton.onclick = crosUrlComponentRedirect;
  }
// </if>
}

// <if expr="chromeos_ash or chromeos_lacros">
/**
 * Called when the user clicks on the os-link-href button.
 */
function crosUrlComponentRedirect() {
  chrome.send('crosUrlComponentsRedirect');
}
// </if>

/**
 * Asks the C++ ComponentsDOMHandler to get details about the installed
 * components.
 */
function requestComponentsData() {
  sendWithPromise('requestComponentsData').then(returnComponentsData);
}

/**
 * Called by the WebUI to re-populate the page with data representing the
 * current state of installed components. The componentsData will also be
 * stored in currentComponentsData to be available to JS for testing purposes.
 * @param {{
 *   components: !Array<!{name: string, version: string}>,
 *   showOsLink: Boolean
 * }} componentsData Detailed info about installed components. The template
 * expects each component's format to match the following structure to correctly
 *     populate the page:
 *   {
 *     components: [
 *       {
 *          name: 'Component1',
 *          version: '1.2.3',
 *       },
 *       {
 *          name: 'Component2',
 *          version: '4.5.6',
 *       },
 *     ]
 *   }
 */
function returnComponentsData(componentsData) {
  const bodyContainer = $('body-container');
  const body = document.body;

  bodyContainer.style.visibility = 'hidden';
  body.className = '';

  // Initialize |currentComponentsData|, which can also be updated in
  // onComponentEvent() later.
  currentComponentsData = componentsData.components;

  renderTemplate(componentsData);

  // Add handlers to dynamically created HTML elements.
  const links = document.getElementsByClassName('button-check-update');
  for (let i = 0; i < links.length; i++) {
    links[i].onclick = function(e) {
      handleCheckUpdate(this);
      e.preventDefault();
    };
  }

  // Disable some controls for Guest mode in ChromeOS.
  if (isChromeOS && loadTimeData.getBoolean('isGuest')) {
    document.querySelectorAll('[guest-disabled]').forEach(function(element) {
      element.disabled = true;
    });
  }

  const systemFlagsLinkDiv = $('os-link-container');
  if (systemFlagsLinkDiv) {
    systemFlagsLinkDiv.hidden = !componentsData.showOsLink;
  }

  bodyContainer.style.visibility = 'visible';
  body.className = 'show-tmi-mode-initial';
}

/**
 * Listener called when state of component updater service changes.
 * @param {Object} eventArgs Contains event and component ID. Component ID is
 * optional.
 */
function onComponentEvent(eventArgs) {
  if (!eventArgs['id']) {
    return;
  }

  const id = eventArgs['id'];

  const filteredComponents = currentComponentsData.filter(function(entry) {
    return entry.id === id;
  });

  // A component may be added from another page so the status and version
  // should only be updated if the component is listed on this page.
  if (filteredComponents.length === 0) {
    return;
  }

  const component = filteredComponents[0];

  const status = eventArgs['event'];
  $('status-' + id).textContent = status;
  component['status'] = status;

  if (eventArgs['version']) {
    const version = eventArgs['version'];
    $('version-' + id).textContent = version;
    component['version'] = version;
  }
}

/**
 * Handles an 'enable' or 'disable' button getting clicked.
 * @param {HTMLElement} node The HTML element representing the component
 *     being checked for update.
 */
function handleCheckUpdate(node) {
  $('status-' + String(node.id)).textContent =
      loadTimeData.getString('checkingLabel');

  // Tell the C++ ComponentssDOMHandler to check for update.
  chrome.send('checkUpdate', [String(node.id)]);
}

// Get data and have it displayed upon loading.
document.addEventListener('DOMContentLoaded', function() {
  addWebUIListener('component-event', onComponentEvent);
  requestComponentsData();
});