From 4b1d4e7711dba58c44067a825d37ec883fcf49f2 Mon Sep 17 00:00:00 2001 From: Brandon T Date: Fri, 6 Sep 2024 15:23:03 -0400 Subject: [PATCH] Pack Resources --- ios/app/resources/BUILD.gn | 10 +- ios/browser/components/resources/BUILD.gn | 27 ++ .../resources/components_resources.grd | 14 ++ .../resources/components_ui/BUILD.gn | 18 ++ .../resources/components_ui/components.css | 237 ++++++++++++++++++ .../resources/components_ui/components.grdp | 6 + .../resources/components_ui/components.html | 74 ++++++ .../resources/components_ui/components.js | 123 +++++++++ .../resources/components_ui/components.ts | 191 ++++++++++++++ 9 files changed, 698 insertions(+), 2 deletions(-) create mode 100644 ios/browser/components/resources/BUILD.gn create mode 100644 ios/browser/components/resources/components_resources.grd create mode 100644 ios/browser/components/resources/components_ui/BUILD.gn create mode 100644 ios/browser/components/resources/components_ui/components.css create mode 100644 ios/browser/components/resources/components_ui/components.grdp create mode 100644 ios/browser/components/resources/components_ui/components.html create mode 100644 ios/browser/components/resources/components_ui/components.js create mode 100644 ios/browser/components/resources/components_ui/components.ts diff --git a/ios/app/resources/BUILD.gn b/ios/app/resources/BUILD.gn index 691841633d73..e77fc5493fd0 100644 --- a/ios/app/resources/BUILD.gn +++ b/ios/app/resources/BUILD.gn @@ -12,7 +12,13 @@ group("resources") { repack("repack_unscaled_resources") { visibility = [ ":resources" ] output = "$target_gen_dir/brave_resources.pak" - sources = [ "$root_gen_dir/components/brave_components_resources.pak" ] - deps = [ "//brave/components/resources" ] + sources = [ + "$root_gen_dir/components/brave_components_resources.pak", + "$root_gen_dir/brave/ios/browser/components/brave_ios_components_resources.pak", + ] + deps = [ + "//brave/components/resources", + "//brave/ios/browser/components/resources", + ] copy_data_to_bundle = true } diff --git a/ios/browser/components/resources/BUILD.gn b/ios/browser/components/resources/BUILD.gn new file mode 100644 index 000000000000..093a555403a3 --- /dev/null +++ b/ios/browser/components/resources/BUILD.gn @@ -0,0 +1,27 @@ +import("//build/config/locales.gni") +import("//brave/resources/brave_grit.gni") +import("//tools/grit/repack.gni") + +repack("resources") { + deps = [ + ":static_resources", + ] + sources = [ + "$root_gen_dir/brave/ios/browser/components/brave_ios_components_static.pak", + ] + + output = "$root_gen_dir/brave/ios/browser/components/brave_ios_components_resources.pak" +} + +brave_grit("static_resources") { + source = "components_resources.grd" + + output_name = "brave_ios_components_resources_new" + + outputs = [ + "grit/brave_ios_components_resources.h", + "brave_ios_components_static.pak", + ] + + output_dir = "$root_gen_dir/brave/ios/browser/components" +} \ No newline at end of file diff --git a/ios/browser/components/resources/components_resources.grd b/ios/browser/components/resources/components_resources.grd new file mode 100644 index 000000000000..69efbde03a49 --- /dev/null +++ b/ios/browser/components/resources/components_resources.grd @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ios/browser/components/resources/components_ui/BUILD.gn b/ios/browser/components/resources/components_ui/BUILD.gn new file mode 100644 index 000000000000..a7a96f4a0e5b --- /dev/null +++ b/ios/browser/components/resources/components_ui/BUILD.gn @@ -0,0 +1,18 @@ +# Copyright 2019 The Chromium Authors +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +import("//ui/webui/resources/tools/build_webui.gni") + +build_webui("build") { + grd_prefix = "components" + static_files = [ + "components.html", + "components.css", + ] + non_web_component_files = [ "components.ts" ] + + ts_definitions = [ "//tools/typescript/definitions/chrome_send.d.ts" ] + ts_deps = [ "//ui/webui/resources/js:build_ts" ] + webui_context_type = "trusted" +} \ No newline at end of file diff --git a/ios/browser/components/resources/components_ui/components.css b/ios/browser/components/resources/components_ui/components.css new file mode 100644 index 000000000000..31d0ec29c136 --- /dev/null +++ b/ios/browser/components/resources/components_ui/components.css @@ -0,0 +1,237 @@ +/* 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. */ + +body { + margin: 10px; + min-width: 47em; +} + +a { + color: blue; + font-size: 103%; +} + +#header { + background: url(chrome://resources/images/extension.svg) + left center / 48px no-repeat; + box-sizing: border-box; + margin-bottom: 1.05em; + overflow: hidden; + padding-inline-start: 0; + position: relative; +} + +html[dir=rtl] #header { + background-position-x: right; +} + +#header h1 { + line-height: 48px; + padding-inline-start: 51px; +} + +h1 { + font-size: 156%; + font-weight: bold; + margin: 0; + padding: 0; +} + +#disabled-container { + font-size: 120%; + padding-bottom: 1.5em; +} + +#disabled-header { + color: red; + font-weight: bold; +} + +.content { + margin-top: 5px; +} + +.section-header { + background: rgb(235, 239, 249); + border-top: 1px solid rgb(181, 199, 222); + font-size: 99%; + padding-bottom: 2px; + padding-inline-start: 5px; + padding-top: 3px; + width: 100%; +} + +.section-header > table tr td:first-child { + width: 100%; +} + +.section-header > table tr { + vertical-align: center; +} + +.section-header > table { + width: 100%; + border-collapse:collapse +} + +.section-header-title { + font-weight: bold; +} + +#top { + padding-inline-end: 5px; +} + +.show-in-tmi-mode { + overflow: hidden; +} + +body.hide-tmi-mode-initial .show-in-tmi-mode { + height: 0 !important; + opacity: 0; +} + +body.hide-tmi-mode .show-in-tmi-mode { + height: 0 !important; + opacity: 0; + transition: all 100ms ease-out; +} + +body.show-tmi-mode-initial .show-in-tmi-mode { + opacity: 1; +} + +body.show-tmi-mode .show-in-tmi-mode { + opacity: 1; + transition: all 100ms ease-in; +} + +.tmi-mode-image { + margin-top: 2px; + padding-inline-end: 5px; + padding-inline-start: 5px; +} + +.tmi-mode-link { + margin-inline-end: 3px; + white-space: nowrap; +} + +.tmi-mode-link a { + font-size: 97%; +} + +.tmi-mode { + background: rgb(244, 246, 252); + border-bottom: 1px solid rgb(237, 239, 245); + font-size: 89%; + padding-bottom: 0.8em; + padding-inline-start: 10px; + padding-top: 0.8em; + width: 100%; +} + +.component-disabled { + background-color: #f0f0f0; + color: #a0a0a0; +} + +.component > tr > td { + padding-bottom: 4px; + padding-top: 5px; + vertical-align: top; +} + +.component > table { + width: 100%; + border-collapse:collapse +} + +.plugin-file { + padding-bottom: 5px; + padding-top: 5px; +} + +.component { + border-bottom: 1px solid #cdcdcd; +} + +.critical { + color: red; +} + +/* Indent the text related to each plug-in. */ +.component-text { + padding-inline-start: 5px; +} + +.component-name { + font-weight: bold; +} + +.no-components { + font-size: 1.2em; + margin: 6em 0 0; + text-align: center; +} + +/* Use tables for layout, so eliminate extra spacing. */ +.plugin-details table { + -webkit-border-horizontal-spacing: 0; + -webkit-border-vertical-spacing: 0; +} + +.plugin-details { + padding-inline-start: 1em; +} + +/* Separate the inital line, Description, Location, and MIME Types lines. */ +.plugin-details > div { + padding-top: 0.1em +} + +/* Align rows of tables along the top. */ +.plugin-details tr { + vertical-align: top; +} + +/* Separate columns by 1em for the most part. */ +.plugin-details td+td { + padding-inline-start: 1em; +} + +/* Make the MIME Types tables smaller. */ +.plugin-details .mime-types { + font-size: 95%; +} + +/* Separate the header from the contents in each MIME Types table. */ +.plugin-details .mime-types .header td { + border-bottom: 1px solid black; + padding-bottom: 0.1em; +} + +/* Separate the columns for tables used for horizontal listings only a bit. */ +.hlisting td+td { + padding-inline-start: 0.4em; +} + +/* Match the indentation of .plugin-text. */ +.component-actions { + margin-bottom: 0.2em; + margin-top: 0.2em; + padding-inline-start: 5px; +} + +.always-allow { + margin-inline-start: 30px; +} + +button { + font-size: 104%; +} + +button[disabled] { + color: #999; +} diff --git a/ios/browser/components/resources/components_ui/components.grdp b/ios/browser/components/resources/components_ui/components.grdp new file mode 100644 index 000000000000..ddb7b8e9ab7f --- /dev/null +++ b/ios/browser/components/resources/components_ui/components.grdp @@ -0,0 +1,6 @@ + + + + + + diff --git a/ios/browser/components/resources/components_ui/components.html b/ios/browser/components/resources/components_ui/components.html new file mode 100644 index 000000000000..f5de62b6779b --- /dev/null +++ b/ios/browser/components/resources/components_ui/components.html @@ -0,0 +1,74 @@ + + + + +$i18n{componentsTitle} + + + + + + + + + + + + diff --git a/ios/browser/components/resources/components_ui/components.js b/ios/browser/components/resources/components_ui/components.js new file mode 100644 index 000000000000..716924cef40d --- /dev/null +++ b/ios/browser/components/resources/components_ui/components.js @@ -0,0 +1,123 @@ +// 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.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.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 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 = document.body.querySelector('#component-template').cloneNode(true); + getRequiredElement('component-placeholder').innerHTML = ""; + getRequiredElement('component-placeholder').appendChild(output); + jstProcess(input, output); + output.removeAttribute('hidden'); + // +} +// +/** + * 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) { + 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'; +} +/** + * Listener called when state of component updater service changes. + * @param event Contains event and component ID. Component ID is + * optional. + */ +function onComponentEvent(event) { + 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) { + 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(); +}); diff --git a/ios/browser/components/resources/components_ui/components.ts b/ios/browser/components/resources/components_ui/components.ts new file mode 100644 index 000000000000..a56847907129 --- /dev/null +++ b/ios/browser/components/resources/components_ui/components.ts @@ -0,0 +1,191 @@ +// 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.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.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(); +}); \ No newline at end of file