// 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 './strings.m.js'; import {assert} from 'chrome://resources/js/assert_ts.js'; import {addWebUiListener, sendWithPromise} from 'chrome://resources/js/cr.js'; import {loadTimeData} from 'chrome://resources/js/load_time_data.js'; import {isChromeOS} from 'chrome://resources/js/platform.js'; import {$, getRequiredElement} from 'chrome://resources/js/util_ts.js'; declare global { class JsEvalContext { constructor(data: any); } function jstProcess(context: JsEvalContext, template: HTMLElement): void; const trustedTypes: {emptyHTML: string}; } interface Component { id: string; name: string; status: string; version: string; } interface ComponentsData { components: Component[]; showOsLink: boolean; } /** * 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: Component[]|null = 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 componentsData Detailed info about installed components. * Same expected format as returnComponentsData(). */ function renderTemplate(componentsData: ComponentsData) { // This is the javascript code that processes the template: const input = new JsEvalContext(componentsData); const output = document.body.querySelector( '#component-template')!.cloneNode(true) as HTMLElement; getRequiredElement('component-placeholder').innerHTML = trustedTypes.emptyHTML; getRequiredElement('component-placeholder').appendChild(output); jstProcess(input, output); output.removeAttribute('hidden'); // const crosUrlRedirectButton = $('os-link-href'); if (crosUrlRedirectButton) { crosUrlRedirectButton.onclick = crosUrlComponentRedirect; } // } // /** * Called when the user clicks on the os-link-href button. */ function crosUrlComponentRedirect() { chrome.send('crosUrlComponentsRedirect'); } // /** * 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 componentsData Detailed info about installed components. */ function returnComponentsData(componentsData: ComponentsData) { const bodyContainer = getRequiredElement('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.body.querySelectorAll('.button-check-update'); for (const link of links) { link.onclick = function(e) { handleCheckUpdate(link); e.preventDefault(); }; } // Disable some controls for Guest mode in ChromeOS. if (isChromeOS && loadTimeData.getBoolean('isGuest')) { document.body.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'; } interface ComponentEvent { event: string; id?: string; version?: string; } /** * Listener called when state of component updater service changes. * @param event Contains event and component ID. Component ID is * optional. */ function onComponentEvent(event: ComponentEvent) { if (!event.id) { return; } const id = event.id; assert(currentComponentsData); 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]; assert(component); const status = event.event; getRequiredElement('status-' + id).textContent = status; component.status = status; if (event.version) { const version = event.version; getRequiredElement('version-' + id).textContent = version; component.version = version; } } /** * Handles an 'enable' or 'disable' button getting clicked. * @param node The HTML element representing the component being checked for * update. */ function handleCheckUpdate(node: HTMLElement) { getRequiredElement('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(); });