diff options
Diffstat (limited to 'chromium/ui/webui/resources')
259 files changed, 4961 insertions, 4477 deletions
diff --git a/chromium/ui/webui/resources/BUILD.gn b/chromium/ui/webui/resources/BUILD.gn index 988878976b1..6bb3412c605 100644 --- a/chromium/ui/webui/resources/BUILD.gn +++ b/chromium/ui/webui/resources/BUILD.gn @@ -2,6 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/chromeos/ui_mode.gni") import("//third_party/closure_compiler/compile_js.gni") import("//ui/webui/resources/tools/generate_grd.gni") @@ -14,16 +15,30 @@ generate_grd("build_grd") { deps = [ "css:build_grdp", "html:build_grdp", + "images:build_grdp", "js:build_grdp", "js/cr/ui:build_grdp", ] grdp_files = [ "$target_gen_dir/css/resources.grdp", "$target_gen_dir/html/resources.grdp", + "$target_gen_dir/images/resources.grdp", "$target_gen_dir/js/cr/ui/resources.grdp", "$target_gen_dir/js/resources.grdp", ] + if (!is_chromeos_ash && !is_android) { + # Roboto Font. Roboto-Regular and Roboto-Light is already available on + # Android, and Roboto-Medium is not used on Android. All 6 weights of + # Roboto are available on Chrome OS. + input_files_base_dir = rebase_path(".", "//") + input_files = [ + "roboto/roboto-bold.woff2", + "roboto/roboto-medium.woff2", + "roboto/roboto-regular.woff2", + ] + } + if (include_polymer) { deps += [ "cr_components:build_grdp", @@ -39,7 +54,7 @@ generate_grd("build_grd") { ] } - if (is_chromeos) { + if (is_chromeos_ash) { deps += [ "//third_party/web-animations-js:build_grdp" ] grdp_files += [ "$root_gen_dir/third_party/web-animations-js/web_animations_resources.grdp" ] } diff --git a/chromium/ui/webui/resources/cr_components/BUILD.gn b/chromium/ui/webui/resources/cr_components/BUILD.gn index 5d11cb92984..c58c0846275 100644 --- a/chromium/ui/webui/resources/cr_components/BUILD.gn +++ b/chromium/ui/webui/resources/cr_components/BUILD.gn @@ -2,14 +2,16 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/chromeos/ui_mode.gni") import("//third_party/closure_compiler/compile_js.gni") -import("//tools/grit/preprocess_grit.gni") +import("//tools/grit/preprocess_if_expr.gni") import("//ui/webui/resources/tools/generate_grd.gni") import("//ui/webui/webui_features.gni") preprocess_folder = "$root_gen_dir/ui/webui/resources/preprocessed/cr_components" preprocess_gen_manifest = "preprocessed_gen_manifest.json" +preprocess_mojom_manifest = "preprocessed_mojom_manifest.json" preprocess_polymer2_manifest = "preprocessed_polymer2_manifest.json" preprocess_src_manifest = "preprocessed_src_manifest.json" @@ -17,8 +19,52 @@ generate_grd("build_grdp") { grd_prefix = "cr_components" out_grd = "$target_gen_dir/${grd_prefix}_resources.grdp" deps = [ ":preprocess" ] + input_files_base_dir = rebase_path(".", "//") + input_files = [ + "customize_themes/colorize.svg", + "customize_themes/brush.svg", + ] + if (is_chromeos_ash) { + input_files += [ + "chromeos/multidevice_setup/all_set_1x.svg", + "chromeos/multidevice_setup/all_set_2x.svg", + "chromeos/multidevice_setup/start_setup_icon_1x.png", + "chromeos/multidevice_setup/start_setup_icon_2x.png", + "chromeos/cellular_setup/error_1x.png", + "chromeos/cellular_setup/error_2x.png", + "chromeos/cellular_setup/final_page_success_1x.png", + "chromeos/cellular_setup/final_page_success_2x.png", + "chromeos/cellular_setup/psim_1x.png", + "chromeos/cellular_setup/psim_2x.png", + "chromeos/cellular_setup/esim_1x.png", + "chromeos/cellular_setup/esim_2x.png", + "chromeos/cellular_setup/default_esim_profile.svg", + "chromeos/network/cellular_0_with_x.svg", + "chromeos/network/cellular_0.svg", + "chromeos/network/cellular_1.svg", + "chromeos/network/cellular_2.svg", + "chromeos/network/cellular_3.svg", + "chromeos/network/cellular_4.svg", + "chromeos/network/cellular_off.svg", + "chromeos/network/ethernet.svg", + "chromeos/network/vpn.svg", + "chromeos/network/wifi_0_with_x.svg", + "chromeos/network/wifi_0.svg", + "chromeos/network/wifi_1.svg", + "chromeos/network/wifi_2.svg", + "chromeos/network/wifi_3.svg", + "chromeos/network/wifi_4.svg", + "chromeos/network/wifi_off.svg", + "chromeos/network_health/test_canceled.png", + "chromeos/network_health/test_failed.png", + "chromeos/network_health/test_not_run.png", + "chromeos/network_health/test_passed.png", + "chromeos/network_health/test_warning.png", + ] + } manifest_files = [ "$target_gen_dir/$preprocess_gen_manifest", + "$target_gen_dir/$preprocess_mojom_manifest", "$target_gen_dir/$preprocess_polymer2_manifest", "$target_gen_dir/$preprocess_src_manifest", ] @@ -28,12 +74,13 @@ generate_grd("build_grdp") { group("preprocess") { public_deps = [ ":preprocess_generated", + ":preprocess_mojom", ":preprocess_polymer2", ":preprocess_src", ] } -preprocess_grit("preprocess_src") { +preprocess_if_expr("preprocess_src") { in_folder = "./" out_folder = "$preprocess_folder" out_manifest = "$target_gen_dir/$preprocess_src_manifest" @@ -48,14 +95,22 @@ preprocess_grit("preprocess_src") { } } -preprocess_grit("preprocess_generated") { +preprocess_if_expr("preprocess_mojom") { + deps = + [ "//ui/webui/resources/cr_components/customize_themes:mojom_webui_js" ] + in_folder = "$root_gen_dir/mojom-webui/ui/webui/resources/cr_components" + out_folder = "$preprocess_folder" + out_manifest = "$target_gen_dir/$preprocess_mojom_manifest" + in_files = [ "customize_themes/customize_themes.mojom-webui.js" ] +} + +preprocess_if_expr("preprocess_generated") { deps = [ ":polymer3_elements" ] in_folder = target_gen_dir out_folder = "$preprocess_folder" out_manifest = "$target_gen_dir/$preprocess_gen_manifest" in_files = [ "customize_themes/customize_themes.js", - "customize_themes/customize_themes.mojom-lite.js", "customize_themes/theme_icon.js", "managed_footnote/managed_footnote.m.js", "omnibox/cr_autocomplete_match_list.js", @@ -79,28 +134,51 @@ preprocess_grit("preprocess_generated") { ] } - if (is_chromeos) { + if (is_chromeos_ash) { in_files += [ "chromeos/bluetooth/bluetooth_dialog.m.js", "chromeos/cellular_setup/activation_code_page.m.js", "chromeos/cellular_setup/base_page.m.js", "chromeos/cellular_setup/button_bar.m.js", "chromeos/cellular_setup/cellular_setup_delegate.m.js", + "chromeos/cellular_setup/cellular_setup_icons.m.js", "chromeos/cellular_setup/cellular_setup.m.js", "chromeos/cellular_setup/cellular_types.m.js", + "chromeos/cellular_setup/confirmation_code_page.m.js", "chromeos/cellular_setup/esim_flow_ui.m.js", "chromeos/cellular_setup/final_page.m.js", "chromeos/cellular_setup/mojo_interface_provider.m.js", + "chromeos/cellular_setup/esim_manager_listener_behavior.m.js", + "chromeos/cellular_setup/esim_manager_utils.m.js", "chromeos/cellular_setup/profile_discovery_list_item.m.js", "chromeos/cellular_setup/profile_discovery_list_page.m.js", "chromeos/cellular_setup/provisioning_page.m.js", "chromeos/cellular_setup/psim_flow_ui.m.js", "chromeos/cellular_setup/setup_selection_flow.m.js", - "chromeos/cellular_setup/sim_detect_page.m.js", + "chromeos/cellular_setup/cellular_eid_popup.m.js", + "chromeos/cellular_setup/setup_loading_page.m.js", "chromeos/cellular_setup/subflow_behavior.m.js", "chromeos/cellular_setup/webview_post_util.m.js", + "chromeos/multidevice_setup/mojo_api.m.js", + "chromeos/multidevice_setup/fake_mojo_service.m.js", + "chromeos/multidevice_setup/button_bar.m.js", + "chromeos/multidevice_setup/multidevice_setup.m.js", + "chromeos/multidevice_setup/multidevice_setup_browser_proxy.m.js", + "chromeos/multidevice_setup/multidevice_setup_delegate.m.js", + "chromeos/multidevice_setup/password_page.m.js", + "chromeos/multidevice_setup/setup_succeeded_page.m.js", + "chromeos/multidevice_setup/start_setup_page.m.js", + "chromeos/multidevice_setup/ui_page_container_behavior.m.js", + "chromeos/multidevice_setup/multidevice_setup_shared_css.m.js", + "chromeos/multidevice_setup/ui_page.m.js", + "chromeos/multidevice_setup/icons.m.js", + "chromeos/network_health/network_health_container.m.js", + "chromeos/network_health/network_health_summary.m.js", + "chromeos/network_health/network_health_mojo.m.js", "chromeos/network_health/network_diagnostics.m.js", "chromeos/network_health/network_diagnostics_mojo.m.js", + "chromeos/network_health/network_diagnostics_types.m.js", + "chromeos/network_health/routine_group.m.js", "chromeos/network/cr_policy_network_behavior_mojo.m.js", "chromeos/network/cr_policy_network_indicator_mojo.m.js", "chromeos/network/mojo_interface_provider.m.js", @@ -109,6 +187,7 @@ preprocess_grit("preprocess_generated") { "chromeos/network/network_config_element_behavior.m.js", "chromeos/network/network_config_input.m.js", "chromeos/network/network_config.m.js", + "chromeos/network/cellular_utils.m.js", "chromeos/network/network_config_select.m.js", "chromeos/network/network_config_toggle.m.js", "chromeos/network/network_icon.m.js", @@ -138,7 +217,7 @@ preprocess_grit("preprocess_generated") { } } -preprocess_grit("preprocess_polymer2") { +preprocess_if_expr("preprocess_polymer2") { in_folder = "./" out_folder = "$preprocess_folder" out_manifest = "$target_gen_dir/$preprocess_polymer2_manifest" @@ -146,7 +225,7 @@ preprocess_grit("preprocess_polymer2") { "managed_footnote/managed_footnote.html", "managed_footnote/managed_footnote.js", ] - if (is_chromeos) { + if (is_chromeos_ash) { if (!optimize_webui) { in_files += [ "chromeos/bluetooth/bluetooth_dialog.html", @@ -193,16 +272,23 @@ preprocess_grit("preprocess_polymer2") { "chromeos/cellular_setup/button_bar.js", "chromeos/cellular_setup/cellular_setup_delegate.html", "chromeos/cellular_setup/cellular_setup_delegate.js", + "chromeos/cellular_setup/cellular_setup_icons.html", "chromeos/cellular_setup/cellular_setup.html", "chromeos/cellular_setup/cellular_setup.js", "chromeos/cellular_setup/cellular_types.html", "chromeos/cellular_setup/cellular_types.js", + "chromeos/cellular_setup/confirmation_code_page.html", + "chromeos/cellular_setup/confirmation_code_page.js", "chromeos/cellular_setup/esim_flow_ui.html", "chromeos/cellular_setup/esim_flow_ui.js", "chromeos/cellular_setup/final_page.html", "chromeos/cellular_setup/final_page.js", "chromeos/cellular_setup/mojo_interface_provider.html", "chromeos/cellular_setup/mojo_interface_provider.js", + "chromeos/cellular_setup/esim_manager_listener_behavior.html", + "chromeos/cellular_setup/esim_manager_listener_behavior.js", + "chromeos/cellular_setup/esim_manager_utils.html", + "chromeos/cellular_setup/esim_manager_utils.js", "chromeos/cellular_setup/profile_discovery_list_item.html", "chromeos/cellular_setup/profile_discovery_list_item.js", "chromeos/cellular_setup/profile_discovery_list_page.html", @@ -213,8 +299,10 @@ preprocess_grit("preprocess_polymer2") { "chromeos/cellular_setup/psim_flow_ui.js", "chromeos/cellular_setup/setup_selection_flow.html", "chromeos/cellular_setup/setup_selection_flow.js", - "chromeos/cellular_setup/sim_detect_page.html", - "chromeos/cellular_setup/sim_detect_page.js", + "chromeos/cellular_setup/cellular_eid_popup.html", + "chromeos/cellular_setup/cellular_eid_popup.js", + "chromeos/cellular_setup/setup_loading_page.html", + "chromeos/cellular_setup/setup_loading_page.js", "chromeos/cellular_setup/subflow_behavior.html", "chromeos/cellular_setup/subflow_behavior.js", "chromeos/cellular_setup/webview_post_util.html", @@ -251,8 +339,16 @@ preprocess_grit("preprocess_polymer2") { "chromeos/network_health/network_diagnostics.js", "chromeos/network_health/network_diagnostics_mojo.html", "chromeos/network_health/network_diagnostics_mojo.js", + "chromeos/network_health/network_diagnostics_types.html", + "chromeos/network_health/network_diagnostics_types.js", + "chromeos/network_health/network_health_container.html", + "chromeos/network_health/network_health_container.js", "chromeos/network_health/network_health_summary.html", "chromeos/network_health/network_health_summary.js", + "chromeos/network_health/network_health_mojo.html", + "chromeos/network_health/network_health_mojo.js", + "chromeos/network_health/routine_group.html", + "chromeos/network_health/routine_group.js", "chromeos/network/mojo_interface_provider.html", "chromeos/network/mojo_interface_provider.js", "chromeos/network/network_icon.html", @@ -260,6 +356,8 @@ preprocess_grit("preprocess_polymer2") { "chromeos/network/network_icons.html", "chromeos/network/network_listener_behavior.html", "chromeos/network/network_listener_behavior.js", + "chromeos/network/cellular_utils.html", + "chromeos/network/cellular_utils.js", "chromeos/network/network_list.html", "chromeos/network/network_list_item.html", "chromeos/network/network_list_item.js", @@ -294,7 +392,7 @@ group("closure_compile") { "omnibox:closure_compile", ] - if (is_chromeos) { + if (is_chromeos_ash) { deps += [ "chromeos:closure_compile" ] } } @@ -306,7 +404,7 @@ group("polymer3_elements") { "managed_footnote:managed_footnote_module", "omnibox:web_components", ] - if (is_chromeos) { + if (is_chromeos_ash) { public_deps += [ "chromeos:polymer3_elements" ] } } diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_entry.html b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_entry.html index b3fa0b940eb..629b5723708 100644 --- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_entry.html +++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_entry.html @@ -12,7 +12,7 @@ <cr-policy-indicator indicator-type="[[getPolicyIndicatorType_(model)]]"> </cr-policy-indicator> <cr-expand-button expanded="{{expanded_}}" - alt="[[i18n('certificateManagerExpandA11yLabel')]]"> + aria-label="[[i18n('certificateManagerExpandA11yLabel')]]"> </cr-expand-button> </div> <template is="dom-if" if="[[expanded_]]"> diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_browser_proxy.js b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_browser_proxy.js index 57e3428ec13..f4ca727001b 100644 --- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_browser_proxy.js +++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_browser_proxy.js @@ -17,6 +17,7 @@ import {addSingletonGetter} from 'chrome://resources/js/cr.m.js'; * * @typedef {{ * certProfileId: string, + * certProfileName: string, * isDeviceWide: boolean, * status: string, * stateId: number, diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_details_dialog.html b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_details_dialog.html index fba5360e091..6aae708405c 100644 --- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_details_dialog.html +++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_details_dialog.html @@ -29,21 +29,41 @@ </div> <div slot="body"> <div class="two-line"> - <div class="label">[[i18n('certificateProvisioningProfile')]]</div> - <div class="value">[[model.certProfileId]]</div> + <div class="label" aria-describedby="certProfileName"> + [[i18n('certificateProvisioningProfileName')]] + </div> + <div class="value" id="certProfileName" aria-hidden="true"> + [[model.certProfileName]] + </div> + </div> + <div class="two-line"> + <div class="label" aria-describedby="certProfileId"> + [[i18n('certificateProvisioningProfileId')]] + </div> + <div class="value" id="certProfileId" aria-hidden="true"> + [[model.certProfileId]] + </div> </div> <div class="button-box"> <div class="two-line flex"> - <div class="label">[[i18n('certificateProvisioningStatus')]]</div> - <span class="value">[[model.status]]</span> + <div class="label" aria-describedby="status"> + [[i18n('certificateProvisioningStatus')]] + </div> + <span class="value" id="status" aria-hidden="true"> + [[model.status]] + </span> </div> <cr-button id="refresh" role="button" on-click="onRefresh_"> [[i18n('certificateProvisioningRefresh')]] </cr-button> </div> <div class="two-line"> - <div class="label">[[i18n('certificateProvisioningLastUpdate')]]</div> - <div class="value">[[model.timeSinceLastUpdate]]</div> + <div class="label" aria-describedby="timeSinceLastUpdate"> + [[i18n('certificateProvisioningLastUpdate')]] + </div> + <div class="value" id="timeSinceLastUpdate" aria-hidden="true"> + [[model.timeSinceLastUpdate]] + </div> </div> <hr></hr> <cr-expand-button expanded="{{advancedExpanded_}}" @@ -52,12 +72,20 @@ </cr-expand-button> <iron-collapse id="advancedInfo" opened="[[advancedExpanded_]]"> <div class="two-line"> - <div class="label">[[i18n('certificateProvisioningStatusId')]]</div> - <div class="value">[[model.stateId]]</div> + <div class="label" aria-describedby="stateId"> + [[i18n('certificateProvisioningStatusId')]] + </div> + <div class="value" id="stateId" aria-hidden="true"> + [[model.stateId]] + </div> </div> <div class="two-line"> - <div class="label">[[i18n('certificateProvisioningPublicKey')]]</div> - <div class="value">[[model.publicKey]]</div> + <div class="label" aria-describedby="publicKey"> + [[i18n('certificateProvisioningPublicKey')]] + </div> + <div class="value" id="publicKey" aria-hidden="true"> + [[model.publicKey]] + </div> </div> </iron-collapse> </div> diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_details_dialog.js b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_details_dialog.js index c04422d3534..a601972e4b0 100644 --- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_details_dialog.js +++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_details_dialog.js @@ -36,6 +36,10 @@ Polymer({ advancedExpanded_: Boolean, }, + close() { + /** @type {!CrDialogElement} */ (this.$.dialog).close(); + }, + /** @private */ onRefresh_() { CertificateProvisioningBrowserProxyImpl.getInstance() diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_entry.html b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_entry.html index c2efcda5f2f..70f3a5623af 100644 --- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_entry.html +++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_entry.html @@ -8,7 +8,7 @@ } </style> <div class="cert-box"> - <div class="flex" tabindex="0">[[model.certProfileId]]</div> + <div class="flex" tabindex="0">[[model.certProfileName]]</div> <cr-icon-button class="icon-more-vert" id="dots" title="[[i18n('moreActions')]]" on-click="onDotsClick_"> </cr-icon-button> diff --git a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_list.js b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_list.js index 3e7d02518c5..26c5ae7f916 100644 --- a/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_list.js +++ b/chromium/ui/webui/resources/cr_components/certificate_manager/certificate_provisioning_list.js @@ -83,6 +83,10 @@ Polymer({ }); if (newDialogModel) { this.provisioningDetailsDialogModel_ = newDialogModel; + } else { + // Close cert provisioning process details dialog if the process is no + // longer in the list eg. when process completed successfully. + this.$$('certificate-provisioning-details-dialog').close(); } }, diff --git a/chromium/ui/webui/resources/cr_components/chromeos/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/BUILD.gn index 125836958c8..4f185562fc1 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/BUILD.gn +++ b/chromium/ui/webui/resources/cr_components/chromeos/BUILD.gn @@ -8,18 +8,15 @@ assert(is_chromeos, "Only ChromeOS components belong here.") group("closure_compile") { deps = [ - "bluetooth:closure_compile", "bluetooth:closure_compile_module", - "cellular_setup:closure_compile", "cellular_setup:closure_compile_module", "multidevice_setup:closure_compile", + "multidevice_setup:closure_compile_module", "network:closure_compile", "network:closure_compile_module", - "network_health:closure_compile", "network_health:closure_compile_module", "quick_unlock:closure_compile", "quick_unlock:closure_compile_module", - "smb_shares:closure_compile", "smb_shares:closure_compile_module", ] } @@ -28,6 +25,7 @@ group("polymer3_elements") { public_deps = [ "bluetooth:polymer3_elements", "cellular_setup:polymer3_elements", + "multidevice_setup:polymer3_elements", "network:polymer3_elements", "network_health:polymer3_elements", "quick_unlock:polymer3_elements", diff --git a/chromium/ui/webui/resources/cr_components/chromeos/bluetooth/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/bluetooth/BUILD.gn index 16484cc89e9..784546d7be5 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/bluetooth/BUILD.gn +++ b/chromium/ui/webui/resources/cr_components/chromeos/bluetooth/BUILD.gn @@ -8,29 +8,6 @@ import("//ui/webui/resources/tools/js_modulizer.gni") assert(is_chromeos, "Bluetooth dialog is Chrome OS only.") -js_type_check("closure_compile") { - deps = [ ":bluetooth_dialog" ] -} - -js_library("bluetooth_dialog") { - deps = [ - "//third_party/polymer/v1_0/components-chromium/iron-resizable-behavior:iron-resizable-behavior-extracted", - "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog", - "//ui/webui/resources/cr_elements/cr_input:cr_input", - "//ui/webui/resources/js:assert", - "//ui/webui/resources/js:cr", - "//ui/webui/resources/js:i18n_behavior", - ] - externs_list = chrome_extension_public_externs + [ - "$externs_path/bluetooth.js", - "$externs_path/bluetooth_private.js", - ] - extra_sources = [ - "$interfaces_path/bluetooth_interface.js", - "$interfaces_path/bluetooth_private_interface.js", - ] -} - js_type_check("closure_compile_module") { is_polymer3 = true deps = [ ":bluetooth_dialog.m" ] diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn index 0c87689c71c..49b33d3a8e5 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/BUILD.gn @@ -9,175 +9,28 @@ import("../os_cr_components.gni") assert(is_chromeos, "CellularSetup UI is Chrome OS only.") -js_type_check("closure_compile") { - deps = [ - ":activation_code_page", - ":base_page", - ":button_bar", - ":cellular_setup", - ":cellular_setup_delegate", - ":cellular_types", - ":final_page", - ":mojo_interface_provider", - ":profile_discovery_list_item", - ":profile_discovery_list_page", - ":provisioning_page", - ":psim_flow_ui", - ":setup_selection_flow", - ":sim_detect_page", - ":webview_post_util", - ] -} - -js_library("button_bar") { - deps = [ - ":cellular_types", - "//ui/webui/resources/js:i18n_behavior", - ] -} - -js_library("base_page") { - deps = [ "//ui/webui/resources/js:i18n_behavior" ] -} - -js_library("sim_detect_page") { - deps = [ - ":base_page", - ":cellular_setup_delegate", - ] -} - -js_library("webview_post_util") { - deps = [ "//ui/webui/resources/js:cr" ] - externs_list = [ - "$externs_path/chrome_extensions.js", - "$externs_path/webview_tag.js", - ] -} - -js_library("provisioning_page") { - deps = [ - ":base_page", - ":cellular_setup_delegate", - ":webview_post_util", - ] - externs_list = [ - "$externs_path/chrome_extensions.js", - "$externs_path/webview_tag.js", - ] -} - -js_library("final_page") { - deps = [ ":base_page" ] -} - -js_library("activation_code_page") { - deps = [ - ":cellular_setup_delegate", - ":subflow_behavior", - "//ui/webui/resources/js:i18n_behavior", - ] -} - -js_library("profile_discovery_list_page") { - deps = [ - "//third_party/polymer/v1_0/components-chromium/iron-list:iron-list-extracted", - "//ui/webui/resources/js:i18n_behavior", - ] -} - -js_library("profile_discovery_list_item") { - deps = [ "//ui/webui/resources/js:i18n_behavior" ] -} - -js_library("psim_flow_ui") { - deps = [ - ":cellular_setup_delegate", - ":cellular_types", - ":final_page", - ":mojo_interface_provider", - ":provisioning_page", - ":sim_detect_page", - ":subflow_behavior", - "//chromeos/services/cellular_setup/public/mojom:mojom_js_library_for_compile", - "//ui/webui/resources/js:assert.m", - "//ui/webui/resources/js:i18n_behavior", - ] -} - -js_library("esim_flow_ui") { - deps = [ - ":activation_code_page", - ":cellular_setup_delegate", - ":profile_discovery_list_item", - ":profile_discovery_list_page", - ":subflow_behavior", - "//ui/webui/resources/js:i18n_behavior", - ] -} - -js_library("setup_selection_flow") { - deps = [ - ":cellular_types", - ":subflow_behavior", - "//ui/webui/resources/js:i18n_behavior", - ] -} - -js_library("subflow_behavior") { - deps = [ - ":cellular_types", - "//ui/webui/resources/js:cr", - ] -} - -js_library("cellular_types") { - deps = [ "//ui/webui/resources/js:cr" ] -} - -js_library("cellular_setup_delegate") { - deps = [ "//ui/webui/resources/js:cr" ] -} - -js_library("cellular_setup") { - deps = [ - ":button_bar", - ":cellular_setup_delegate", - ":cellular_types", - ":esim_flow_ui", - ":psim_flow_ui", - ":setup_selection_flow", - "//ui/webui/resources/js:i18n_behavior", - ] -} - -js_library("mojo_interface_provider") { - deps = [ - "//chromeos/services/cellular_setup/public/mojom:mojom_js_library_for_compile", - "//ui/webui/resources/js:cr", - ] -} - -# Polymer3 files - js_type_check("closure_compile_module") { is_polymer3 = true deps = [ ":activation_code_page.m", ":base_page.m", ":button_bar.m", + ":cellular_eid_popup.m", ":cellular_setup.m", ":cellular_setup_delegate.m", ":cellular_types.m", + ":confirmation_code_page.m", ":esim_flow_ui.m", + ":esim_manager_listener_behavior.m", + ":esim_manager_utils.m", ":final_page.m", ":mojo_interface_provider.m", ":profile_discovery_list_item.m", ":profile_discovery_list_page.m", ":provisioning_page.m", ":psim_flow_ui.m", + ":setup_loading_page.m", ":setup_selection_flow.m", - ":sim_detect_page.m", ":subflow_behavior.m", ":webview_post_util.m", ] @@ -207,15 +60,28 @@ js_library("activation_code_page.m") { deps = [ ":cellular_setup_delegate.m", ":subflow_behavior.m", + "//third_party/polymer/v3_0/components-chromium/paper-spinner:paper-spinner-lite", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", "//ui/webui/resources/js:i18n_behavior.m", ] extra_deps = [ ":activation_code_page_module" ] } +js_library("confirmation_code_page.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/confirmation_code_page.m.js" ] + deps = [ + "//third_party/polymer/v3_0/components-chromium/paper-spinner:paper-spinner-lite", + "//ui/webui/resources/js:i18n_behavior.m", + ] + extra_deps = [ ":confirmation_code_page_module" ] +} + js_library("profile_discovery_list_item.m") { sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.m.js" ] - deps = [ "//ui/webui/resources/js:i18n_behavior.m" ] + deps = [ + "//third_party/polymer/v3_0/components-chromium/paper-spinner:paper-spinner-lite", + "//ui/webui/resources/js:i18n_behavior.m", + ] extra_deps = [ ":profile_discovery_list_item_module" ] } @@ -237,6 +103,18 @@ js_library("mojo_interface_provider.m") { extra_deps = [ ":modulize" ] } +js_library("esim_manager_utils.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_utils.m.js" ] + deps = [ ":mojo_interface_provider.m" ] + extra_deps = [ ":modulize" ] +} + +js_library("esim_manager_listener_behavior.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_listener_behavior.m.js" ] + deps = [ ":mojo_interface_provider.m" ] + extra_deps = [ ":modulize" ] +} + js_library("webview_post_util.m") { sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/webview_post_util.m.js" ] deps = [] @@ -247,13 +125,14 @@ js_library("webview_post_util.m") { extra_deps = [ ":modulize" ] } -js_library("sim_detect_page.m") { - sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.m.js" ] +js_library("setup_loading_page.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.m.js" ] deps = [ ":base_page.m", ":cellular_setup_delegate.m", + "//ui/webui/resources/js:assert.m", ] - extra_deps = [ ":sim_detect_page_module" ] + extra_deps = [ ":setup_loading_page_module" ] } js_library("provisioning_page.m") { @@ -279,6 +158,7 @@ js_library("button_bar.m") { ":cellular_types.m", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", "//ui/webui/resources/js:i18n_behavior.m", + "//ui/webui/resources/js/cr/ui:focus_without_ink.m", ] extra_deps = [ ":button_bar_module" ] } @@ -307,7 +187,7 @@ js_library("psim_flow_ui.m") { ":final_page.m", ":mojo_interface_provider.m", ":provisioning_page.m", - ":sim_detect_page.m", + ":setup_loading_page.m", ":subflow_behavior.m", "//chromeos/services/cellular_setup/public/mojom:mojom_js_library_for_compile", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", @@ -323,11 +203,17 @@ js_library("esim_flow_ui.m") { ":activation_code_page.m", ":cellular_setup_delegate.m", ":cellular_types.m", + ":confirmation_code_page.m", + ":esim_manager_utils.m", ":final_page.m", + ":mojo_interface_provider.m", ":profile_discovery_list_item.m", ":profile_discovery_list_page.m", ":subflow_behavior.m", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/cr_components/chromeos/network:cellular_utils.m", + "//ui/webui/resources/cr_components/chromeos/network:network_listener_behavior.m", + "//ui/webui/resources/js:assert.m", "//ui/webui/resources/js:i18n_behavior.m", ] extra_deps = [ ":esim_flow_ui_module" ] @@ -343,6 +229,12 @@ js_library("setup_selection_flow.m") { extra_deps = [ ":setup_selection_flow_module" ] } +js_library("cellular_eid_popup.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_popup.m.js" ] + deps = [ "//ui/webui/resources/js:i18n_behavior.m" ] + extra_deps = [ ":cellular_eid_popup_module" ] +} + js_library("cellular_setup.m") { sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.m.js" ] deps = [ @@ -352,6 +244,8 @@ js_library("cellular_setup.m") { ":esim_flow_ui.m", ":psim_flow_ui.m", ":setup_selection_flow.m", + "//ui/webui/resources/cr_components/chromeos/network:cellular_utils.m", + "//ui/webui/resources/cr_components/chromeos/network:mojo_interface_provider.m", "//ui/webui/resources/js:i18n_behavior.m", ] extra_deps = [ ":cellular_setup_module" ] @@ -362,7 +256,10 @@ group("polymer3_elements") { ":activation_code_page_module", ":base_page_module", ":button_bar_module", + ":cellular_eid_popup_module", + ":cellular_setup_icons_module", ":cellular_setup_module", + ":confirmation_code_page_module", ":esim_flow_ui_module", ":final_page_module", ":modulize", @@ -370,8 +267,8 @@ group("polymer3_elements") { ":profile_discovery_list_page_module", ":provisioning_page_module", ":psim_flow_ui_module", + ":setup_loading_page_module", ":setup_selection_flow_module", - ":sim_detect_page_module", ] } @@ -407,9 +304,17 @@ polymer_modulizer("button_bar") { auto_imports = cr_components_chromeos_auto_imports } -polymer_modulizer("sim_detect_page") { - js_file = "sim_detect_page.js" - html_file = "sim_detect_page.html" +polymer_modulizer("confirmation_code_page") { + js_file = "confirmation_code_page.js" + html_file = "confirmation_code_page.html" + html_type = "dom-module" + namespace_rewrites = cr_components_chromeos_namespace_rewrites + auto_imports = cr_components_chromeos_auto_imports +} + +polymer_modulizer("setup_loading_page") { + js_file = "setup_loading_page.js" + html_file = "setup_loading_page.html" html_type = "dom-module" namespace_rewrites = cr_components_chromeos_namespace_rewrites auto_imports = cr_components_chromeos_auto_imports @@ -463,6 +368,14 @@ polymer_modulizer("setup_selection_flow") { auto_imports = cr_components_chromeos_auto_imports } +polymer_modulizer("cellular_eid_popup") { + js_file = "cellular_eid_popup.js" + html_file = "cellular_eid_popup.html" + html_type = "dom-module" + namespace_rewrites = cr_components_chromeos_namespace_rewrites + auto_imports = cr_components_chromeos_auto_imports +} + polymer_modulizer("cellular_setup") { js_file = "cellular_setup.js" html_file = "cellular_setup.html" @@ -471,11 +384,19 @@ polymer_modulizer("cellular_setup") { auto_imports = cr_components_chromeos_auto_imports } +polymer_modulizer("cellular_setup_icons") { + js_file = "cellular_setup_icons.m.js" + html_file = "cellular_setup_icons.html" + html_type = "iron-iconset" +} + js_modulizer("modulize") { input_files = [ "cellular_types.js", "cellular_setup_delegate.js", "mojo_interface_provider.js", + "esim_manager_utils.js", + "esim_manager_listener_behavior.js", "subflow_behavior.js", "webview_post_util.js", ] diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.html index 8e9086e9818..8a6243f857c 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.html @@ -1,13 +1,17 @@ <link rel="import" href="../../../html/polymer.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html"> <link rel="import" href="../../../html/i18n_behavior.html"> <link rel="import" href="../../../cr_elements/cr_input/cr_input.html"> <link rel="import" href="base_page.html"> <link rel="import" href="cellular_setup_delegate.html"> +<link rel="import" href="cellular_setup_icons.html"> <dom-module id="activation-code-page"> <template> - <style> + <style include="iron-positioning"> [slot='page-body'] { height: 300px; margin-top: -20px; @@ -35,13 +39,8 @@ background-color: transparent; } - #scanSuccessMessage { - color: green; - font-size: medium; - } - - #scanSuccessMessage:hover { - cursor: default; + cr-button[disabled] { + background-color: transparent; } .center { @@ -51,34 +50,65 @@ transform: translateY(-50%) translateX(-50%); } + .width-92 { + width: 92%; + } + .label { font-weight: 500; } .button-image { - height: 20px; margin-inline-end: 8px; - width: 20px; } - #useCameraAgainButton { - font-weight: 500; - left: 50%; - margin-top: 16px; - transform: translateX(-50%); - } - - #scanSuccessImage { - height: 20px; + .scan-finish-image { position: absolute; - width: 20px; } - #scanSuccessMessage { + .scan-finish-message { padding-inline-end: 0; padding-inline-start: 30px; } + .scan-finish-message:hover { + cursor: default; + } + + .blue-icon { + --iron-icon-fill-color: #1A73E8; + } + + #scanSucessHeader { + --iron-icon-fill-color: #1E8E3E; + margin-bottom: 8px; + } + + #scanSuccessMessage { + color: green; + font-size: medium; + } + + #scanFailureHeader { + --iron-icon-fill-color: #D93025; + margin-bottom: 4px; + } + + #scanFailureMessage { + color: var(--google-red-600); + } + + #useCameraAgainButton { + display: block; + font-weight: 500; + text-align: center; + } + + #tryAgainButton { + display: block; + text-align: center; + } + #switchCameraButton { background-color: rgba(0, 0, 0, 0.04); border-radius: 4px; @@ -90,60 +120,107 @@ z-index: 2; } - #switchCameraButton img { + #switchCameraButton iron-icon { filter: brightness(2.1); + --iron-icon-fill-color: #5F6368; + } + + paper-spinner-lite { + height: 20px; + position: absolute; + right: 16px; + top: 24px; + width: 20px; + } + + #loadingMessage { + bottom: 0; + color: var(--google-grey-refresh-500); + font-size: var(--cr-form-field-label-font-size); + letter-spacing: .4px; + line-height: var(--cr-form-field-label-line-height); + position: absolute; } </style> <base-page> <div slot="page-body"> <span id="scanQrCodeDescription"> - [[i18n('scanQRCode')]] + [[getDescription_(showNoProfilesMessage, cameraCount_ )]] </span> - <div id="esimQrCodeDetection"> - <cr-button id="switchCameraButton" - on-click="onSwitchCameraButtonPressed_" - hidden$="[[isUiElementHidden_(UiElement.SWITCH_CAMERA, state_, hasMultipleCameras_)]]" - disabled="[[isUiElementDisabled_(UiElement.SWITCH_CAMERA, state_)]]"> - <img class="button-image" - src="activation_code_page_switch_camera.svg" - aria-hidden="true"> - [[i18n('switchCamera')]] - </cr-button> - <video id="video" - hidden$="[[isUiElementHidden_(UiElement.VIDEO, state_)]]"> - </video> - <div class="center" id="startScanningContainer" - hidden$="[[isUiElementHidden_(UiElement.START_SCANNING, state_)]]"> - <cr-button class="label" - id="startScanningButton" - on-click="startScanning_" - aria-describedby="scanQrCodeDescription"> - <img class="button-image" - src="activation_code_page_camera.svg" - aria-hidden="true"> - [[i18n('useCamera')]] + <template is="dom-if" + if="[[isScanningAvailable_(cameraCount_, qrCodeDetector_.*)]]" restamp> + <div id="esimQrCodeDetection"> + <cr-button id="switchCameraButton" + on-click="onSwitchCameraButtonPressed_" + hidden$="[[isUiElementHidden_(UiElement.SWITCH_CAMERA, state_, cameraCount_)]]" + disabled="[[isUiElementDisabled_(UiElement.SWITCH_CAMERA, state_, showBusy)]]"> + <iron-icon class="button-image" icon="cellular-setup:switch-camera"></iron-icon> + [[i18n('switchCamera')]] </cr-button> - </div> - <div class="center" id="scanSuccessContainer" - hidden$="[[isUiElementHidden_(UiElement.SCAN_SUCCESS, state_)]]"> - <div> - <img id="scanSuccessImage" - src="activation_code_page_checked.svg" - aria-hidden="true"> - <span class="label" id="scanSuccessMessage"> - [[i18n('scanQRCodeSuccess')]] - </span> + <video id="video" + hidden$="[[isUiElementHidden_(UiElement.VIDEO, state_)]]"> + </video> + <div class="center" id="startScanningContainer" class="blue-icon" + hidden$="[[isUiElementHidden_(UiElement.START_SCANNING, state_)]]"> + <cr-button class="label" + id="startScanningButton" + on-click="startScanning_" + aria-describedby="scanQrCodeDescription" + disabled="[[isUiElementDisabled_(UiElement.START_SCANNING, state_, showBusy)]]"> + <iron-icon class="button-image" icon="cellular-setup:camera"></iron-icon> + [[i18n('useCamera')]] + </cr-button> + </div> + <div class="center" id="scanFinishContainer" + hidden$="[[isUiElementHidden_(UiElement.SCAN_FINISH, state_)]]"> + <div> + <div id="scanSuccessContainer" + hidden$="[[isUiElementHidden_(UiElement.SCAN_SUCCESS, state_)]]"> + <div id=scanSucessHeader> + <iron-icon class="scan-finish-image" icon="cellular-setup:checked"></iron-icon> + <span class="label scan-finish-message" id="scanSuccessMessage"> + [[i18n('scanQRCodeSuccess')]] + </span> + </div> + <cr-button id="useCameraAgainButton" class="blue-icon" + on-click="startScanning_" + disabled="[[isUiElementDisabled_(UiElement.SCAN_SUCCESS, state_, showBusy)]]"> + <iron-icon class="button-image" icon="cellular-setup:camera"></iron-icon> + [[i18n('qrCodeUseCameraAgain')]] + </cr-button> + </div> + <div id="scanFailureContainer" + hidden$="[[isUiElementHidden_(UiElement.SCAN_FAILURE, state_)]]"> + <div id="scanFailureHeader" class="blue-icon"> + <iron-icon class="scan-finish-image" icon="cellular-setup:error"></iron-icon> + <span class="label scan-finish-message" id="scanFailureMessage"> + [[i18n('scanQrCodeError')]] + </span> + </div> + <cr-button id="tryAgainButton" class="blue-icon" + on-click="startScanning_" + disabled="[[isUiElementDisabled_(UiElement.SCAN_FAILURE, state_, showBusy)]]"> + <iron-icon class="button-image" icon="cellular-setup:try-again"></iron-icon> + [[i18n('qrCodeRetry')]] + </cr-button> + </div> + </div> </div> - <cr-button id="useCameraAgainButton" - on-click="startScanning_"> - [[i18n('qrCodeRetry')]] - </cr-button> </div> - </div> - <cr-input id="activationCode" + </template> + <div id="activationCodeContainer" class$="[[computeActivationCodeClass_(cameraCount_)]]"> + <cr-input id="activationCode" label="[[i18n('activationCode')]]" - value="{{activationCode_}}"> - </cr-input> + value="{{activationCode}}" + disabled="[[showBusy]]"> + </cr-input> + <paper-spinner-lite active + hidden$="[[!showBusy]]"> + </paper-spinner-lite> + <div id="loadingMessage" hidden$="[[!showBusy]]"> + [[i18n('scanQrCodeLoading')]] + </div> + </div> </div> </base-page> </template> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.js index eb391054d34..23a6bf848ad 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page.js @@ -16,17 +16,26 @@ const PageState = { SWITCHING_CAM_USER_TO_ENVIRONMENT: 4, SWITCHING_CAM_ENVIRONMENT_TO_USER: 5, SUCCESS: 6, + FAILURE: 7, }; /** @enum {number} */ const UiElement = { START_SCANNING: 1, VIDEO: 2, - SCAN_SUCCESS: 3, - SWITCH_CAMERA: 4, + SWITCH_CAMERA: 3, + SCAN_FINISH: 4, + SCAN_SUCCESS: 5, + SCAN_FAILURE: 6, }; /** + * barcode format used by |BarcodeDetector| + * @private {string} + */ +const QR_CODE_FORMAT = 'qr_code'; + +/** * Page in eSIM Setup flow that accepts activation code. User has option for * manual entry or scan a QR code. */ @@ -36,13 +45,26 @@ Polymer({ behaviors: [I18nBehavior], properties: { - /** @private */ - activationCode_: { + activationCode: { type: String, - value: '', + notify: true, observer: 'onActivationCodeChanged_', }, + showError: { + type: Boolean, + notify: true, + observer: 'onShowErrorChanged_', + }, + + /** + * Indicates the UI is busy with an operation and cannot be interacted with. + */ + showBusy: { + type: Boolean, + value: false, + }, + /** * @type {!PageState} * @private @@ -50,13 +72,14 @@ Polymer({ state_: { type: Object, value: PageState, + observer: 'onStateChanged_', }, /** @private */ - hasMultipleCameras_: { - type: Boolean, - value: false, - observer: 'onHasMultipleCamerasChanged_', + cameraCount_: { + type: Number, + value: 0, + observer: 'onHasCameraCountChanged_', }, /** @@ -70,6 +93,11 @@ Polymer({ type: Object, value: UiElement, }, + + /** @private */ + showNoProfilesMessage: { + type: Boolean, + } }, /** @@ -90,9 +118,25 @@ Polymer({ */ qrCodeDetectorTimer_: null, + /** + * TODO(crbug.com/1093185): add type |BarcodeDetector| when externs + * becomes available + * @private + */ + qrCodeDetector_: null, + + /** + * TODO(crbug.com/1093185): add type |BarcodeDetector| when externs + * becomes available + * @suppress {undefinedVars|missingProperties} + * @private + */ + barcodeDetectorClass_: BarcodeDetector, + /** @override */ ready() { this.setMediaDevices(navigator.mediaDevices); + this.initBarcodeDetector(); this.state_ = PageState.INITIAL; }, @@ -105,7 +149,36 @@ Polymer({ clearTimeout(this.qrCodeDetectorTimer_); } this.mediaDevices_.removeEventListener( - 'devicechange', this.updateHasMultipleCameras_.bind(this)); + 'devicechange', this.updateCameraCount_.bind(this)); + }, + + /** + * @return {boolean} + * @private + */ + isScanningAvailable_() { + return this.cameraCount_ > 0 && !!this.qrCodeDetector_; + }, + + /** + * TODO(crbug.com/1093185): Remove suppression when shape_detection extern + * definitions become available. + * @suppress {undefinedVars|missingProperties} + * @private + */ + async initBarcodeDetector() { + const formats = await this.barcodeDetectorClass_.getSupportedFormats(); + + if (!formats || formats.length === 0) { + this.qrCodeDetector_ = null; + return; + } + + const qrCodeFormat = formats.find(format => format === QR_CODE_FORMAT); + if (qrCodeFormat) { + this.qrCodeDetector_ = + new this.barcodeDetectorClass_({formats: [QR_CODE_FORMAT]}); + } }, /** @@ -113,25 +186,42 @@ Polymer({ */ setMediaDevices(mediaDevices) { this.mediaDevices_ = mediaDevices; + this.updateCameraCount_(); this.mediaDevices_.addEventListener( - 'devicechange', this.updateHasMultipleCameras_.bind(this)); + 'devicechange', this.updateCameraCount_.bind(this)); + }, + + /** + * @return {string} + * @private + */ + computeActivationCodeClass_() { + return this.isScanningAvailable_() ? 'relative' : 'center width-92'; }, /** @private */ - updateHasMultipleCameras_() { - this.mediaDevices_.enumerateDevices().then(devices => { - const numVideoInputDevices = - devices.filter(device => device.kind === 'videoinput').length; - this.hasMultipleCameras_ = numVideoInputDevices > 1; - }); + updateCameraCount_() { + if (!this.mediaDevices_ || !this.mediaDevices_.enumerateDevices) { + this.cameraCount_ = 0; + return; + } + + this.mediaDevices_.enumerateDevices() + .then(devices => { + this.cameraCount_ = + devices.filter(device => device.kind === 'videoinput').length; + }) + .catch(e => { + this.cameraCount_ = 0; + }); }, /** @private */ - onHasMultipleCamerasChanged_() { + onHasCameraCountChanged_() { // If the user was using an environment-facing camera and it was removed, // restart scanning with the user-facing camera. if ((this.state_ === PageState.SCANNING_ENVIRONMENT_FACING) && - !this.hasMultipleCameras_) { + this.cameraCount_ === 1) { this.state_ = PageState.SWITCHING_CAM_ENVIRONMENT_TO_USER; this.startScanning_(); } @@ -157,8 +247,8 @@ Polymer({ }) .then(stream => { this.stream_ = stream; - if (stream) { - const video = this.$.video; + if (this.stream_) { + const video = this.$$('#video'); video.srcObject = stream; video.play(); } @@ -166,38 +256,41 @@ Polymer({ oldStream.getTracks()[0].stop(); } - this.activationCode_ = ''; + this.activationCode = ''; this.state_ = useUserFacingCamera ? PageState.SCANNING_USER_FACING : PageState.SCANNING_ENVIRONMENT_FACING; - this.detectQrCode_(stream); + if (this.stream_) { + this.detectQrCode_(); + } + }) + .catch(e => { + this.state_ = PageState.FAILURE; }); }, /** * Continuously checks stream if it contains a QR code. If a QR code is - * detected, activationCode_ is set to the QR code's value and the detection + * detected, activationCode is set to the QR code's value and the detection * stops. - * @param {MediaStream} stream * @private */ - async detectQrCode_(stream) { + async detectQrCode_() { try { this.qrCodeDetectorTimer_ = setInterval( (async function() { - const capturer = new ImageCapture(stream.getVideoTracks()[0]); + const capturer = new ImageCapture(this.stream_.getVideoTracks()[0]); const frame = await capturer.grabFrame(); const activationCode = await this.detectActivationCode_(frame); if (activationCode) { clearTimeout(this.qrCodeDetectorTimer_); - this.activationCode_ = activationCode; + this.activationCode = activationCode; } }).bind(this), QR_CODE_DETECTION_INTERVAL_MS); } catch (error) { - // TODO(crbug.com/1093185): Update the UI in response to the error. - console.log(error); + this.state_ = PageState.FAILURE; } }, @@ -210,12 +303,11 @@ Polymer({ * @private */ async detectActivationCode_(frame) { - const qrCodeDetector = new BarcodeDetector({ - formats: [ - 'qr_code', - ] - }); - const qrCodes = await qrCodeDetector.detect(frame); + if (!this.qrCodeDetector_) { + return null; + } + + const qrCodes = await this.qrCodeDetector_.detect(frame); if (qrCodes.length > 0) { return qrCodes[0].rawValue; } @@ -224,14 +316,15 @@ Polymer({ /** @private */ onActivationCodeChanged_() { - const activationCode = this.validateActivationCode_(this.activationCode_); + const activationCode = this.validateActivationCode_(this.activationCode); this.fire('activation-code-updated', {activationCode: activationCode}); - // TODO(crbug.com/1093185): Handle if activation code is invalid. if (activationCode) { if (this.stream_) { this.stream_.getTracks()[0].stop(); } this.state_ = PageState.SUCCESS; + } else { + this.state_ = PageState.FAILURE; } }, @@ -261,34 +354,56 @@ Polymer({ this.startScanning_(); }, + /** @private */ + onShowErrorChanged_() { + if (this.showError) { + this.state_ = PageState.FAILURE; + } + }, + + /** @private */ + onStateChanged_() { + if (this.state_ !== PageState.FAILURE) { + this.showError = false; + } + }, + /** * @param {UiElement} uiElement * @param {PageState} state - * @param {boolean} hasMultipleCameras + * @param {number} cameraCount * @private */ - isUiElementHidden_(uiElement, state, hasMultipleCameras) { + isUiElementHidden_(uiElement, state, cameraCount) { switch (uiElement) { case UiElement.START_SCANNING: return state !== PageState.INITIAL; case UiElement.VIDEO: return state !== PageState.SCANNING_USER_FACING && state !== PageState.SCANNING_ENVIRONMENT_FACING; - case UiElement.SCAN_SUCCESS: - return state !== PageState.SUCCESS; case UiElement.SWITCH_CAMERA: const isScanning = state === PageState.SCANNING_USER_FACING || state === PageState.SCANNING_ENVIRONMENT_FACING; - return !(isScanning && hasMultipleCameras); + return !(isScanning && this.cameraCount_ > 1); + case UiElement.SCAN_FINISH: + return state !== PageState.SUCCESS && state !== PageState.FAILURE; + case UiElement.SCAN_SUCCESS: + return state !== PageState.SUCCESS; + case UiElement.SCAN_FAILURE: + return state !== PageState.FAILURE; } }, /** * @param {UiElement} uiElement * @param {PageState} state + * @param {boolean} showBusy * @private */ - isUiElementDisabled_(uiElement, state) { + isUiElementDisabled_(uiElement, state, showBusy) { + if (showBusy) { + return true; + } switch (uiElement) { case UiElement.SWITCH_CAMERA: return state === PageState.SWITCHING_CAM_USER_TO_ENVIRONMENT || @@ -297,4 +412,16 @@ Polymer({ return false; } }, + + /** + * @return {string} + * @private + */ + getDescription_() { + if (!this.isScanningAvailable_()) { + return this.i18n('scanQRCodeEnterActivationCode'); + } + return this.showNoProfilesMessage ? this.i18n('scanQRCodeNoProfiles') : + this.i18n('scanQRCode'); + }, }); diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_camera.svg b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_camera.svg deleted file mode 100644 index 9e8e0fe771c..00000000000 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_camera.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><mask id="a" maskUnits="userSpaceOnUse" x="1" y="2" width="18" height="16"><path fill-rule="evenodd" clip-rule="evenodd" d="M16.667 4.167h-2.642L12.5 2.5h-5L5.975 4.167H3.334c-.917 0-1.667.75-1.667 1.666v10c0 .917.75 1.667 1.667 1.667h13.333c.917 0 1.667-.75 1.667-1.667v-10c0-.916-.75-1.666-1.667-1.666zm0 11.666H3.334v-10h13.333v10zm-10-5A3.332 3.332 0 1 1 10 14.166a3.332 3.332 0 0 1-3.333-3.333z" fill="#fff"/></mask><g mask="url(#a)"><path fill="#1A73E8" d="M0 0h20v20H0z"/></g></svg>
\ No newline at end of file diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_checked.svg b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_checked.svg deleted file mode 100644 index adf445fe700..00000000000 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_checked.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M13.707 7.293a1 1 0 0 0-1.414 0L9 10.586 7.707 9.293a1 1 0 0 0-1.414 1.414l2 2a1 1 0 0 0 1.414 0l4-4a1 1 0 0 0 0-1.414z" fill="#1E8E3E"/><path fill-rule="evenodd" clip-rule="evenodd" d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm0-2a6 6 0 1 0 0-12 6 6 0 0 0 0 12z" fill="#1E8E3E"/></svg>
\ No newline at end of file diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_switch_camera.svg b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_switch_camera.svg deleted file mode 100644 index ba6127d7e39..00000000000 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/activation_code_page_switch_camera.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M7 9V7H4.802A5.996 5.996 0 0 1 10 4a6 6 0 0 1 5.917 5h2.021c-.491-3.945-3.853-7-7.93-7a7.992 7.992 0 0 0-6.009 2.712L4 3H2v6h5zm5.938 2v2h2.198a5.996 5.996 0 0 1-5.198 3 6 6 0 0 1-5.917-5H2c.492 3.945 3.853 7 7.93 7a7.992 7.992 0 0 0 6.009-2.712V17h2v-6h-5zM10 12a2 2 0 1 0 0-4 2 2 0 0 0 0 4z" fill="#5F6368"/></svg>
\ No newline at end of file diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/base_page.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/base_page.html index 0a0e2fe045e..2f8fc2a6930 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/base_page.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/base_page.html @@ -2,10 +2,12 @@ <link rel="import" href="../../../cr_elements/shared_vars_css.html"> <link rel="import" href="../../../html/i18n_behavior.html"> +<link rel="import" href="chrome://resources/cr_components/chromeos/cellular_setup/cellular_setup_icons.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> <dom-module id="base-page"> <template> - <style> + <style include="iron-positioning"> #title { color: var(--google-grey-900); font-weight: normal; @@ -21,11 +23,21 @@ height: 256px; width: 100%; } + + #message iron-icon { + padding-inline-end: 4px; + } </style> <template is="dom-if" if="[[isTitleShown_(title)]]" restamp> <h3 id="title">[[getTitle_(title)]]</h3> </template> - <div id="message">[[message]]</div> + <div id="message"> + <iron-icon + icon$="cellular-setup:[[messageIcon]]" + hidden$="[[!isMessageIconShown_(messageIcon)]]"> + </iron-icon> + [[message]] + </div> <slot name="page-body"></slot> </template> <script src="base_page.js"></script> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/base_page.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/base_page.js index edaac70c770..3efd9ecd352 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/base_page.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/base_page.js @@ -22,6 +22,16 @@ Polymer({ * @type {string} */ message: String, + + /** + * Name for the cellular-setup iconset iron-icon displayed beside message. + * + * @type {string} + */ + messageIcon: { + type: String, + value: '', + } }, /** @@ -38,5 +48,13 @@ Polymer({ */ isTitleShown_() { return !!this.title; + }, + + /** + * @returns {boolean} + * @private + */ + isMessageIconShown_() { + return !!this.messageIcon; } }); diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.html index a3908c637a4..54b88a776fb 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.html @@ -6,6 +6,7 @@ <link rel="import" href="../../../cr_elements/shared_style_css.html"> <link rel="import" href="../../../cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/html/assert.html"> +<link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout.html"> <dom-module id="button-bar"> @@ -44,26 +45,12 @@ hidden$="[[isButtonHidden_(Button.TRY_AGAIN, buttonState.*)]]"> [[i18n('tryAgain')]] </cr-button> - <cr-button id="done" + <cr-button id="forward" class="action-button" - on-click="onDoneButtonClicked_" - disabled="[[isButtonDisabled_(Button.DONE, buttonState.*)]]" - hidden$="[[isButtonHidden_(Button.DONE, buttonState.*)]]"> - [[i18n('done')]] - </cr-button> - <cr-button id="skipDiscovery" - class="action-button" - on-click="onNextButtonClicked_" - disabled="[[isButtonDisabled_(Button.SKIP_DISCOVERY, buttonState.*)]]" - hidden$="[[isButtonHidden_(Button.SKIP_DISCOVERY, buttonState.*)]]"> - [[i18n('skipDiscovery')]] - </cr-button> - <cr-button id="next" - class="action-button" - on-click="onNextButtonClicked_" - disabled="[[isButtonDisabled_(Button.NEXT, buttonState.*)]]" - hidden$="[[isButtonHidden_(Button.NEXT, buttonState.*)]]"> - [[i18n('next')]] + on-click="onForwardButtonClicked_" + disabled="[[isButtonDisabled_(Button.FORWARD, buttonState.*)]]" + hidden$="[[isButtonHidden_(Button.FORWARD, buttonState.*)]]"> + [[forwardButtonLabel]] </cr-button> </template> <script src="button_bar.js"></script> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.js index 05b648c5b6f..21dd2c9de8c 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/button_bar.js @@ -15,7 +15,10 @@ Polymer({ * Sets the states of all buttons * @type {!cellularSetup.ButtonBarState} */ - buttonState: {type: Object, value: {}}, + buttonState: { + type: Object, + value: {}, + }, /** * @type {!cellularSetup.Button} @@ -24,6 +27,11 @@ Polymer({ type: Object, value: cellularSetup.Button, }, + + forwardButtonLabel: { + type: String, + value: '', + } }, /** @@ -32,8 +40,7 @@ Polymer({ * @private */ isButtonHidden_(buttonName) { - const state = this.getButtonBarState_(buttonName); - return state === cellularSetup.ButtonState.HIDDEN; + return !this.getButtonBarState_(buttonName); }, /** @@ -43,7 +50,19 @@ Polymer({ */ isButtonDisabled_(buttonName) { const state = this.getButtonBarState_(buttonName); - return state === cellularSetup.ButtonState.SHOWN_BUT_DISABLED; + return state === cellularSetup.ButtonState.DISABLED; + }, + + focusDefaultButton() { + const buttons = this.shadowRoot.querySelectorAll('cr-button'); + // Focus the first non-disabled, non-hidden button from the end. + for (let i = buttons.length - 1; i >= 0; i--) { + const button = buttons.item(i); + if (!button.disabled && !button.hidden) { + cr.ui.focusWithoutInk(button); + return; + } + } }, /** @private */ @@ -62,12 +81,7 @@ Polymer({ }, /** @private */ - onDoneButtonClicked_() { - this.fire('complete-flow-requested'); - }, - - /** @private */ - onNextButtonClicked_() { + onForwardButtonClicked_() { this.fire('forward-nav-requested'); }, @@ -83,17 +97,13 @@ Polymer({ return this.buttonState.backward; case cellularSetup.Button.CANCEL: return this.buttonState.cancel; - case cellularSetup.Button.DONE: - return this.buttonState.done; - case cellularSetup.Button.NEXT: - return this.buttonState.next; + case cellularSetup.Button.FORWARD: + return this.buttonState.forward; case cellularSetup.Button.TRY_AGAIN: return this.buttonState.tryAgain; - case cellularSetup.Button.SKIP_DISCOVERY: - return this.buttonState.skipDiscovery; default: assertNotReached(); - return cellularSetup.ButtonState.SHOWN_AND_ENABLED; + return cellularSetup.ButtonState.ENABLED; } } }); diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_popup.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_popup.html new file mode 100644 index 00000000000..b045ae54b57 --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_popup.html @@ -0,0 +1,96 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> + +<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> +<link rel="import" href="chrome://resources/html/i18n_behavior.html"> +<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html"> +<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> + +<dom-module id="cellular-eid-popup"> + <template> + <style include="cr-shared-style iron-flex"> + :host { + background-color: white; + border-radius: 4px; + box-shadow: 0 2px 5px rgba(0,0,0,0.18); + margin: 34px 0 0 12px; + position: absolute; + width: 275px; + z-index: 1; + } + + .cellular-network-list-header { + border-top: var(--cr-separator-line); + padding: 16px 0 8px 0; + } + + .body { + margin-top: 6px; + } + + .cellular-network-content { + margin: 8px 0 8px 32px; + } + + .cellular-not-setup { + color: var(--google-grey-700); + font-size: smaller; + margin-bottom: 16px; + } + + .header { + display: flex; + justify-content: space-between; + } + + .title { + align-self: center; + } + + #container { + padding: 8px 16px; + } + + #closeBtn { + align-self: center; + cursor: pointer; + } + + #qrCodeCanvas { + width: 100%; + } + + #eid { + margin-top: 15px; + } + </style> + <div id="container" + class="dialog" + tabindex="1" + aria-labelledby="eidTitle" + aria-describedby="eidDescription"> + <div class="header"> + <div id="eidTitle" class="title" arian-hidden="true"> + [[i18n('eidPopupTitle')]] + </div> + <cr-icon-button + id="eidPopupCloseIcon" + iron-icon="cr:close" + title="[[i18n('closeEidPopupButtonLabel')]]" + aria-label="[[i18n('closeEidPopupButtonLabel')]]" + on-click="onCloseTap_"> + </cr-icon-button> + </div> + <div class="body"> + <div id="eidDescription" arian-hidden="true"> + [[i18n('eidPopupDescription')]] + </div> + <div id="eid">[[eid_]]</div> + <canvas id="qrCodeCanvas" + width="[[canvasSize_]]" + height="[[canvasSize_]]"> + </canvas> + </div> + </div> + </template> + <script src="cellular_eid_popup.js"></script> +</dom-module>
\ No newline at end of file diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_popup.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_popup.js new file mode 100644 index 00000000000..983d4bbe040 --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_eid_popup.js @@ -0,0 +1,117 @@ +// Copyright 2020 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. + +/** + * @fileoverview Polymer element for displaying cellular EID and QR code + */ + +// The size of each tile in pixels. +const QR_CODE_TILE_SIZE = 5; +// Amount of padding around the QR code in pixels. +const QR_CODE_PADDING = 4 * QR_CODE_TILE_SIZE; +// Styling for filled tiles in the QR code. +const QR_CODE_FILL_STYLE = '#000000'; + +Polymer({ + is: 'cellular-eid-popup', + + behaviors: [ + I18nBehavior, + ], + + properties: { + /** + * The euicc object whose EID and QRCode should be shown in the popup. + */ + euicc: Object, + + /** @private */ + canvasSize_: Number, + + /** @private */ + eid_: String, + }, + + /** + * @private {?CanvasRenderingContext2D} + */ + canvasContext_: null, + + /** @override */ + attached() { + if (!this.euicc) { + return; + } + this.euicc.getEidQRCode().then(this.updateQRCode_.bind(this)); + this.euicc.getProperties().then(this.updateEid_.bind(this)); + }, + + /** @override */ + focus() { + this.$$('.dialog').focus(); + }, + + /**@private */ + onCloseTap_() { + this.fire('close-eid-popup'); + }, + + /** + * @private + * @param {{qrCode: chromeos.cellularSetup.mojom.QRCode} | null} response + */ + updateQRCode_(response) { + if (!response || !response.qrCode) { + return; + } + this.canvasSize_ = + response.qrCode.size * QR_CODE_TILE_SIZE + 2 * QR_CODE_PADDING; + Polymer.dom.flush(); + const context = this.getCanvasContext_(); + context.clearRect(0, 0, this.canvasSize_, this.canvasSize_); + context.fillStyle = QR_CODE_FILL_STYLE; + let index = 0; + for (let x = 0; x < response.qrCode.size; x++) { + for (let y = 0; y < response.qrCode.size; y++) { + if (response.qrCode.data[index]) { + context.fillRect( + x * QR_CODE_TILE_SIZE + QR_CODE_PADDING, + y * QR_CODE_TILE_SIZE + QR_CODE_PADDING, QR_CODE_TILE_SIZE, + QR_CODE_TILE_SIZE); + } + index++; + } + } + }, + + /** + * @private + * @param {{properties: chromeos.cellularSetup.mojom.EuiccProperties}} + * response + */ + updateEid_(response) { + if (!response || !response.properties) { + return; + } + this.eid_ = response.properties.eid; + }, + + /** + * @private + * @return {CanvasRenderingContext2D} + */ + getCanvasContext_() { + if (this.canvasContext_) { + return this.canvasContext_; + } + return this.$.qrCodeCanvas.getContext('2d'); + }, + + /** + * @param {CanvasRenderingContext2D} canvasContext + */ + setCanvasContextForTest(canvasContext) { + this.canvasContext_ = canvasContext; + } +}); diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html index dd55d49c420..6b5e07912ff 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.html @@ -7,6 +7,8 @@ <link rel="import" href="cellular_setup_delegate.html"> <link rel="import" href="setup_selection_flow.html"> <link rel="import" href="../../../html/i18n_behavior.html"> +<link rel="import" href="chrome://resources/cr_components/chromeos/network/cellular_utils.html"> +<link rel="import" href="chrome://resources/cr_components/chromeos/network/mojo_interface_provider.html"> <dom-module id="cellular-setup"> <template> @@ -17,7 +19,8 @@ <setup-selection-flow selected-page="{{selectedFlow_}}" button-state="{{buttonState_}}" - id="setup-selection-flow"> + id="setup-selection-flow" + forward-button-label="{{forwardButtonLabel_}}"> </setup-selection-flow> <template is="dom-if" if="[[isPSimSelected_(currentPageName)]]" restamp> @@ -25,7 +28,8 @@ button-state="{{buttonState_}}" name-of-carrier-pending-setup="{{flowTitle}}" delegate="[[delegate]]" - id="psim-flow-ui"> + id="psim-flow-ui" + forward-button-label="{{forwardButtonLabel_}}"> </psim-flow-ui> </template> <template is="dom-if" @@ -33,11 +37,15 @@ <esim-flow-ui button-state="{{buttonState_}}" delegate="[[delegate]]" - id="esim-flow-ui"> + id="esim-flow-ui" + forward-button-label="{{forwardButtonLabel_}}"> </esim-flow-ui> </template> </iron-pages> - <button-bar button-state="[[buttonState_]]"> + <button-bar + id="buttonBar" + button-state="[[buttonState_]]" + forward-button-label="[[forwardButtonLabel_]]"> </button-bar> </template> <script src="cellular_setup.js"></script> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.js index d716ce4538a..677186b6508 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup.js @@ -24,10 +24,7 @@ Polymer({ * Name of the currently displayed sub-page. * @private {!cellularSetup.CellularSetupPageName|null} */ - currentPageName: { - type: String, - value: cellularSetup.CellularSetupPageName.SETUP_FLOW_SELECTION, - }, + currentPageName: String, /** * Current user selected setup flow page name. @@ -57,14 +54,65 @@ Polymer({ type: Object, observer: 'onPageChange_', }, + + /** + * Text for the button_bar's 'Forward' button. + * @private {string} + */ + forwardButtonLabel_: { + type: String, + } }, listeners: { 'backward-nav-requested': 'onBackwardNavRequested_', 'retry-requested': 'onRetryRequested_', - 'complete-flow-requested': 'onCompleteFlowRequested_', 'forward-nav-requested': 'onForwardNavRequested_', 'cancel-requested': 'onCancelRequested_', + 'focus-default-button': 'onFocusDefaultButton_', + }, + + + /** @override */ + attached() { + if (!this.currentPageName) { + this.setCurrentPage_(); + } + }, + + /** + * Sets current cellular setup flow, one of eSIM flow, pSIM flow or + * selection flow, depending on available pSIM and eSIM slots. + * @private + */ + setCurrentPage_() { + const networkConfig = network_config.MojoInterfaceProviderImpl.getInstance() + .getMojoServiceRemote(); + networkConfig.getDeviceStateList().then(response => { + const deviceStateList = response.result; + + const deviceState = deviceStateList.find( + (device) => device.type === + chromeos.networkConfig.mojom.NetworkType.kCellular); + + if (!deviceState) { + this.currentPageName = + cellularSetup.CellularSetupPageName.SETUP_FLOW_SELECTION; + return; + } + + const {pSimSlots, eSimSlots} = getSimSlotCount(deviceState); + + if (pSimSlots > 0 && eSimSlots === 0) { + this.currentPageName = cellularSetup.CellularSetupPageName.PSIM_FLOW_UI; + return; + } else if (pSimSlots === 0 && eSimSlots > 0) { + this.currentPageName = cellularSetup.CellularSetupPageName.ESIM_FLOW_UI; + return; + } + this.currentPageName = + cellularSetup.CellularSetupPageName.SETUP_FLOW_SELECTION; + }); }, /** @private */ @@ -83,7 +131,7 @@ Polymer({ // navigation any more. Switch back to the selection flow in this case so // that the user can select a flow again. if (!isNavHandled) { - this.currentPageName_ = + this.currentPageName = cellularSetup.CellularSetupPageName.SETUP_FLOW_SELECTION; } }, @@ -98,22 +146,22 @@ Polymer({ }, /** @private */ - onCompleteFlowRequested_() { - // TODO(crbug.com/1093185): Add completion logic. - }, - - /** @private */ onForwardNavRequested_() { // Switch current page to user selected flow when navigating forward from // setup selection. - if (this.currentPageName_ === + if (this.currentPageName === cellularSetup.CellularSetupPageName.SETUP_FLOW_SELECTION) { - this.currentPageName_ = this.selectedFlow_; + this.currentPageName = this.selectedFlow_; return; } this.currentPage_.navigateForward(); }, + /** @private */ + onFocusDefaultButton_() { + this.$.buttonBar.focusDefaultButton(); + }, + /** * @param {string} currentPage * @private diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup_icons.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup_icons.html new file mode 100644 index 00000000000..c68f68cdbb1 --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup_icons.html @@ -0,0 +1,18 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> + +<link rel="import" href="chrome://resources/polymer/v1_0/iron-iconset-svg/iron-iconset-svg.html"> + +<!-- These icons were converted from source .svg files. --> + +<iron-iconset-svg name="cellular-setup" size="20"> + <svg> + <defs> + <g id="camera" viewBox="0 0 20 20"><mask id="a" maskUnits="userSpaceOnUse" x="1" y="2" width="18" height="16"><path fill-rule="evenodd" clip-rule="evenodd" d="M16.667 4.167h-2.642L12.5 2.5h-5L5.975 4.167H3.334c-.917 0-1.667.75-1.667 1.666v10c0 .917.75 1.667 1.667 1.667h13.333c.917 0 1.667-.75 1.667-1.667v-10c0-.916-.75-1.666-1.667-1.666zm0 11.666H3.334v-10h13.333v10zm-10-5A3.332 3.332 0 1 1 10 14.166a3.332 3.332 0 0 1-3.333-3.333z" fill="#fff"></mask><g mask="url(#a)"><path d="M0 0h20v20H0z"></g></g> + <g id="checked" viewBox="0 0 20 20"><path d="M13.707 7.293a1 1 0 0 0-1.414 0L9 10.586 7.707 9.293a1 1 0 0 0-1.414 1.414l2 2a1 1 0 0 0 1.414 0l4-4a1 1 0 0 0 0-1.414z"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M10 18a8 8 0 1 0 0-16 8 8 0 0 0 0 16zm0-2a6 6 0 1 0 0-12 6 6 0 0 0 0 12z"></path></g> + <g id="error" viewBox="0 0 20 20"><path fill-rule="evenodd" clip-rule="evenodd" d="M9 10h2V6H9v4zm1-8c-4.416 0-8 3.584-8 8s3.584 8 8 8 8-3.584 8-8-3.584-8-8-8zm0 14c-3.308 0-6-2.693-6-6 0-3.308 2.692-6 6-6 3.307 0 6 2.692 6 6 0 3.307-2.693 6-6 6zm-1-2h2v-2H9v2z"></g> + <g id="switch-camera" viewBox="0 0 20 20"><path fill-rule="evenodd" clip-rule="evenodd" d="M7 9V7H4.802A5.996 5.996 0 0 1 10 4a6 6 0 0 1 5.917 5h2.021c-.491-3.945-3.853-7-7.93-7a7.992 7.992 0 0 0-6.009 2.712L4 3H2v6h5zm5.938 2v2h2.198a5.996 5.996 0 0 1-5.198 3 6 6 0 0 1-5.917-5H2c.492 3.945 3.853 7 7.93 7a7.992 7.992 0 0 0 6.009-2.712V17h2v-6h-5zM10 12a2 2 0 1 0 0-4 2 2 0 0 0 0 4z"></g> + <g id="try-again" viewBox="0 0 20 20"><path path fill-rule="evenodd" clip-rule="evenodd" d="M10 3C6.136 3 3 6.136 3 10C3 13.864 6.136 17 10 17C12.1865 17 14.1399 15.9959 15.4239 14.4239L13.9984 12.9984C13.0852 14.2129 11.6325 15 10 15C7.24375 15 5 12.7563 5 10C5 7.24375 7.24375 5 10 5C11.6318 5 13.0839 5.78641 13.9972 7H11V9H17V3H15V5.10253C13.7292 3.80529 11.9581 3 10 3Z"></g> + <g id="warning" viewBox="0 0 20 20"><path d="M9 12H11V8H9V12Z"></path><path d="M11 15H9V13H11V15Z"></path><path fill-rule="evenodd" clip-rule="evenodd" d="M9.13177 2.50386C9.51566 1.83205 10.4844 1.83205 10.8683 2.50386L18.8683 16.5039C19.2492 17.1705 18.7678 18 18 18H2.00001C1.23219 18 0.750823 17.1705 1.13177 16.5039L9.13177 2.50386ZM10 5.01556L3.72321 16H16.2768L10 5.01556Z"></g> + </defs> + </svg> +</iron-iconset-svg>
\ No newline at end of file diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_types.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_types.js index ec12f757a6b..338e9ccd40b 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_types.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_types.js @@ -15,29 +15,24 @@ cr.define('cellularSetup', function() { /** @enum {number} */ /* #export */ const ButtonState = { - HIDDEN: 1, - SHOWN_AND_ENABLED: 2, - SHOWN_BUT_DISABLED: 3, + ENABLED: 1, + DISABLED: 2, }; /** @enum {number} */ /* #export */ const Button = { BACKWARD: 1, CANCEL: 2, - DONE: 3, - NEXT: 4, - TRY_AGAIN: 5, - SKIP_DISCOVERY: 6, + FORWARD: 3, + TRY_AGAIN: 4, }; /** * @typedef {{ * backward: (!cellularSetup.ButtonState|undefined), * cancel: (!cellularSetup.ButtonState|undefined), - * done: (!cellularSetup.ButtonState|undefined), - * next: (!cellularSetup.ButtonState|undefined), + * forward: (!cellularSetup.ButtonState|undefined), * tryAgain: (!cellularSetup.ButtonState|undefined), - * skipDiscovery: (!cellularSetup.ButtonState|undefined), * }} */ /* #export */ let ButtonBarState; diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/confirmation_code_page.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/confirmation_code_page.html new file mode 100644 index 00000000000..e055c141766 --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/confirmation_code_page.html @@ -0,0 +1,89 @@ +<link rel="import" href="../../../html/polymer.html"> + +<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html"> +<link rel="import" href="../../../html/i18n_behavior.html"> +<link rel="import" href="base_page.html"> + +<dom-module id="confirmation-code-page"> + <template> + <style include="iron-flex iron-positioning"> + [slot='page-body'] { + margin-top: -20px; + } + + #outerDiv { + height: 236px; + } + + .container { + width: 472px; + } + + #details { + align-items: center; + color: var(--cr-primary-text-color); + display: flex; + margin-bottom: 40px; + } + + #profileImage { + margin-inline-end: 16px; + } + + #confirmationCodeContainer { + margin-inline-end: 16px; + } + + paper-spinner-lite { + height: 20px; + position: absolute; + right: 16px; + top: 24px; + width: 20px; + } + + #loadingMessage { + bottom: 0; + color: var(--google-grey-refresh-500); + font-size: var(--cr-form-field-label-font-size); + letter-spacing: .4px; + line-height: var(--cr-form-field-label-line-height); + position: absolute; + } + </style> + <base-page> + <div slot="page-body"> + <div id="description">[[i18n('confirmationCodeMessage')]]</div> + <div id="outerDiv" class="layout horizontal center"> + <div class="container"> + <div id="details" hidden$="[[!shouldShowProfileDetails_(profile)]]"> + <!-- TODO(crbug.com/1093185): Update with real profile image. --> + <img id="profileImage" src="chrome://resources/cr_components/chromeos/cellular_setup/default_esim_profile.svg"> + <div> + [[getProfileName_(profileProperties_)]] + </div> + </div> + <div id="confirmationCodeContainer" class="relative"> + <cr-input id="confirmationCode" + label="[[i18n('confirmationCodeInput')]]" + value="{{confirmationCode}}" + aria-describedby="description" + error-message="[[i18n('confirmationCodeError')]]" + invalid="[[showError]]" + disabled="[[showBusy]]"> + </cr-input> + <paper-spinner-lite active + hidden$="[[!showBusy]]"> + </paper-spinner-lite> + <div id="loadingMessage" hidden$="[[!showBusy]]"> + [[i18n('confirmationCodeLoading')]] + </div> + </div> + </div> + </div> + </div> + </base-page> + </template> + <script src="confirmation_code_page.js"></script> +</dom-module> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/confirmation_code_page.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/confirmation_code_page.js new file mode 100644 index 00000000000..374a5e9f606 --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/confirmation_code_page.js @@ -0,0 +1,80 @@ +// Copyright 2020 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. + +/** + * Page in eSIM Cellular Setup flow shown if an eSIM profile requires a + * confirmation code to install. This element contains an input for the user to + * enter the confirmation code. + */ +Polymer({ + is: 'confirmation-code-page', + + behaviors: [I18nBehavior], + + properties: { + /** + * @type {?chromeos.cellularSetup.mojom.ESimProfileRemote} + */ + profile: { + type: Object, + observer: 'onProfileChanged_', + }, + + confirmationCode: { + type: String, + notify: true, + }, + + showError: { + type: Boolean, + }, + + /** + * Indicates the UI is busy with an operation and cannot be interacted with. + */ + showBusy: { + type: Boolean, + value: false, + }, + + /** + * @type {?chromeos.cellularSetup.mojom.ESimProfileProperties} + * @private + */ + profileProperties_: { + type: Object, + value: null, + }, + }, + + /** @private */ + onProfileChanged_() { + if (!this.profile) { + this.profileProperties_ = null; + return; + } + this.profile.getProperties().then(response => { + this.profileProperties_ = response.properties; + }); + }, + + /** + * @return {boolean} + * @private + */ + shouldShowProfileDetails_() { + return !!this.profile; + }, + + /** + * @return {string} + * @private + */ + getProfileName_() { + if (!this.profileProperties_) { + return ''; + } + return String.fromCharCode(...this.profileProperties_.name.data); + }, +});
\ No newline at end of file diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/default_esim_profile.svg b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/default_esim_profile.svg new file mode 100644 index 00000000000..058d7e0ce38 --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/default_esim_profile.svg @@ -0,0 +1 @@ +<svg width="31" height="20" viewBox="0 0 31 20" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill-rule="evenodd" clip-rule="evenodd" d="M4 2a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h23a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2H4zm7.704 10.915h-3.55V6.18h-1.36V14h4.91v-1.085zm4.254-5.64h2.438V6.18h-6.203v1.095h2.417V14h1.348V7.275zm4.823 3.234h3.212V9.435h-3.212v-2.16h3.717V6.18h-5.076V14h5.114v-1.085H20.78v-2.406z" fill="#5F6368"/></svg>
\ No newline at end of file diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.html index 4657fa02d5c..36651ea37bc 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.html @@ -1,12 +1,19 @@ +<link rel="import" href="chrome://resources/cr_components/chromeos/network/cellular_utils.html"> +<link rel="import" href="chrome://resources/cr_components/chromeos/network/network_listener_behavior.html"> +<link rel="import" href="chrome://resources/html/assert.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html"> <link rel="import" href="../../../html/polymer.html"> <link rel="import" href="../../../html/i18n_behavior.html"> +<link rel="import" href="mojo_interface_provider.html"> +<link rel="import" href="esim_manager_utils.html"> <link rel="import" href="subflow_behavior.html"> <link rel="import" href="cellular_types.html"> <link rel="import" href="cellular_setup_delegate.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html"> +<link rel="import" href="setup_loading_page.html"> <link rel="import" href="activation_code_page.html"> <link rel="import" href="final_page.html"> <link rel="import" href="profile_discovery_list_page.html"> +<link rel="import" href="confirmation_code_page.html"> <dom-module id="esim-flow-ui"> <template> @@ -20,14 +27,34 @@ </style> <iron-pages attr-for-selected="id" selected="[[selectedESimPageName_]]"> + <setup-loading-page id="profileLoadingPage" + delegate="[[delegate]]" + loading-message="[[i18n('eSimProfileDetectMessage')]]" + state="[[getLoadingPageState_(hasActivePSimNetwork_)]]"> + </setup-loading-page> <profile-discovery-list-page id="profileDiscoveryPage" - selected-profiles="{{selectedProfiles_}}"> + pending-profiles="[[pendingProfiles_]]" + selected-profile="{{selectedProfile_}}" + show-busy="[[shouldShowSubpageBusy_(state_)]]"> </profile-discovery-list-page> - <activation-code-page id="activationCodePage"></activation-code-page> + <activation-code-page id="activationCodePage" + activation-code="{{activationCode_}}" + show-no-profiles-message="[[getShowNoProfilesMessage_(pendingProfiles_)]]" + show-error="{{showError_}}" + show-busy="[[shouldShowSubpageBusy_(state_)]]"> + </activation-code-page> + <confirmation-code-page id="confirmationCodePage" + confirmation-code="{{confirmationCode_}}" + profile="[[selectedProfile_]]" + show-error="{{showError_}}" + show-busy="[[shouldShowSubpageBusy_(state_)]]"> + </confirmation-code-page> <final-page id="finalPage" delegate="[[delegate]]" - show-error="[[showError_]]"> + show-error="[[showError_]]" + message="[[i18n('eSimFinalPageMessage')]]" + error-message="[[i18n('eSimFinalPageErrorMessage')]]"> </final-page> </iron-pages> </template> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js index 745f808b82c..1ebf329afe7 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_flow_ui.js @@ -5,10 +5,27 @@ cr.define('cellular_setup', function() { /** @enum{string} */ /* #export */ const ESimPageName = { + PROFILE_LOADING: 'profileLoadingPage', PROFILE_DISCOVERY: 'profileDiscoveryPage', - ESIM: 'activationCodePage', + ACTIVATION_CODE: 'activationCodePage', + CONFIRMATION_CODE: 'confirmationCodePage', FINAL: 'finalPage', }; + + /** @enum{string} */ + /* #export */ const ESimUiState = { + PROFILE_SEARCH: 'profile-search', + ACTIVATION_CODE_ENTRY: 'activation-code-entry', + ACTIVATION_CODE_ENTRY_READY: 'activation-code-entry-ready', + ACTIVATION_CODE_ENTRY_INSTALLING: 'activation-code-entry-installing', + CONFIRMATION_CODE_ENTRY: 'confirmation-code-entry', + CONFIRMATION_CODE_ENTRY_READY: 'confirmation-code-entry-ready', + CONFIRMATION_CODE_ENTRY_INSTALLING: 'confirmation-code-entry-installing', + PROFILE_SELECTION: 'profile-selection', + PROFILE_SELECTION_INSTALLING: 'profile-selection-installing', + SETUP_FINISH: 'setup-finish', + }; + /** * Root element for the eSIM cellular setup flow. This element interacts with * the CellularSetup service to carry out the esim activation flow. @@ -18,6 +35,7 @@ cr.define('cellular_setup', function() { behaviors: [ I18nBehavior, + NetworkListenerBehavior, SubflowBehavior, ], @@ -25,17 +43,30 @@ cr.define('cellular_setup', function() { /** @type {!cellular_setup.CellularSetupDelegate} */ delegate: Object, + forwardButtonLabel: { + type: String, + notify: true, + }, + /** - * Element name of the current selected sub-page. - * @type {!cellular_setup.ESimPageName} + * @type {!cellular_setup.ESimUiState} * @private */ - selectedESimPageName_: { + state_: { type: String, - value: ESimPageName.PROFILE_DISCOVERY, + value: ESimUiState.PROFILE_SEARCH, + observer: 'onStateChanged_', }, /** + * Element name of the current selected sub-page. + * This is set in updateSelectedPage_ on initialization. + * @type {?cellular_setup.ESimPageName} + * @private + */ + selectedESimPageName_: String, + + /** * Whether error state should be shown for the current page. * @private {boolean} */ @@ -45,72 +76,408 @@ cr.define('cellular_setup', function() { }, /** - * @type {Array<!Object>} + * Profiles fetched that have status kPending. + * @type {!Array<!chromeos.cellularSetup.mojom.ESimProfileRemote>} + * @private + */ + pendingProfiles_: { + type: Array, + }, + + /** + * Profile selected to be installed. + * @type {?chromeos.cellularSetup.mojom.ESimProfileRemote} * @private */ - selectedProfiles_: { + selectedProfile_: { type: Object, }, + + /** @private */ + activationCode_: { + type: String, + value: '', + }, + + /** @private */ + confirmationCode_: { + type: String, + value: '', + observer: 'onConfirmationCodeUpdated_', + }, + + /** @private */ + hasActivePSimNetwork_: { + type: Boolean, + value: false, + }, }, + /** + * Provides an interface to the ESimManager Mojo service. + * @private {?chromeos.cellularSetup.mojom.ESimManagerRemote} + */ + eSimManagerRemote_: null, + + /** @private {?chromeos.cellularSetup.mojom.EuiccRemote} */ + euicc_: null, + listeners: { 'activation-code-updated': 'onActivationCodeUpdated_', }, - observers: ['onSelectedProfilesChanged_(selectedProfiles_.splices)'], + observers: ['onSelectedProfileChanged_(selectedProfile_)'], + + /** @override */ + created() { + this.eSimManagerRemote_ = cellular_setup.getESimManagerRemote(); + }, initSubflow() { - this.buttonState = { - backward: cellularSetup.ButtonState.HIDDEN, - cancel: this.delegate.shouldShowCancelButton() ? - cellularSetup.ButtonState.SHOWN_AND_ENABLED : - cellularSetup.ButtonState.HIDDEN, - done: cellularSetup.ButtonState.HIDDEN, - next: cellularSetup.ButtonState.HIDDEN, - tryAgain: cellularSetup.ButtonState.HIDDEN, - skipDiscovery: cellularSetup.ButtonState.SHOWN_AND_ENABLED, - }; + this.fetchProfiles_(); + this.onNetworkStateListChanged(); + }, + + /** @private */ + async fetchProfiles_() { + const euicc = await cellular_setup.getEuicc(); + if (!euicc) { + // TODO(crbug.com/1093185) User should have at least 1 EUICC or + // we shouldn't have gotten to this flow. Add check for this in + // cellular_setup. + console.error('No Euiccs found'); + return; + } + this.euicc_ = euicc; + const requestPendingProfilesResponse = + await euicc.requestPendingProfiles(); + if (requestPendingProfilesResponse.result === + chromeos.cellularSetup.mojom.ESimOperationResult.kFailure) { + console.error( + 'Error requesting pending profiles: ', + requestPendingProfilesResponse); + } + this.pendingProfiles_ = + await cellular_setup.getPendingESimProfiles(euicc); + switch (this.pendingProfiles_.length) { + case 0: + this.state_ = ESimUiState.ACTIVATION_CODE_ENTRY; + break; + case 1: + this.selectedProfile_ = this.pendingProfiles_[0]; + // Assume installing the profile doesn't require a confirmation + // code, send an empty string. + this.selectedProfile_.installProfile('').then( + this.handleProfileInstallResponse_.bind(this)); + break; + default: + this.state_ = ESimUiState.PROFILE_SELECTION; + break; + } + }, + + /** + * @private + * @param {{result: chromeos.cellularSetup.mojom.ProfileInstallResult}} + * response + */ + handleProfileInstallResponse_(response) { + if (response.result === + chromeos.cellularSetup.mojom.ProfileInstallResult + .kErrorNeedsConfirmationCode) { + this.state_ = ESimUiState.CONFIRMATION_CODE_ENTRY; + return; + } + this.showError_ = response.result !== + chromeos.cellularSetup.mojom.ProfileInstallResult.kSuccess; + if (response.result === + chromeos.cellularSetup.mojom.ProfileInstallResult.kFailure && + this.state_ === ESimUiState.CONFIRMATION_CODE_ENTRY_INSTALLING) { + this.state_ = ESimUiState.CONFIRMATION_CODE_ENTRY_READY; + return; + } + if (response.result === + chromeos.cellularSetup.mojom.ProfileInstallResult + .kErrorInvalidActivationCode) { + this.state_ = ESimUiState.ACTIVATION_CODE_ENTRY_READY; + return; + } + if (response.result === + chromeos.cellularSetup.mojom.ProfileInstallResult.kSuccess || + response.result === + chromeos.cellularSetup.mojom.ProfileInstallResult.kFailure) { + this.state_ = ESimUiState.SETUP_FINISH; + } + }, + + /** @private */ + onStateChanged_(newState, oldState) { + this.updateButtonBarState_(); + this.updateSelectedPage_(); + this.initializePageState_(newState, oldState); + }, + + /** @private */ + updateSelectedPage_() { + const oldSelectedESimPageName = this.selectedESimPageName_; + switch (this.state_) { + case ESimUiState.PROFILE_SEARCH: + this.selectedESimPageName_ = ESimPageName.PROFILE_LOADING; + break; + case ESimUiState.ACTIVATION_CODE_ENTRY: + case ESimUiState.ACTIVATION_CODE_ENTRY_READY: + case ESimUiState.ACTIVATION_CODE_ENTRY_INSTALLING: + this.selectedESimPageName_ = ESimPageName.ACTIVATION_CODE; + break; + case ESimUiState.CONFIRMATION_CODE_ENTRY: + case ESimUiState.CONFIRMATION_CODE_ENTRY_READY: + case ESimUiState.CONFIRMATION_CODE_ENTRY_INSTALLING: + this.selectedESimPageName_ = ESimPageName.CONFIRMATION_CODE; + break; + case ESimUiState.PROFILE_SELECTION: + case ESimUiState.PROFILE_SELECTION_INSTALLING: + this.selectedESimPageName_ = ESimPageName.PROFILE_DISCOVERY; + break; + case ESimUiState.SETUP_FINISH: + this.selectedESimPageName_ = ESimPageName.FINAL; + break; + default: + assertNotReached(); + break; + } + // If there is a page change, fire focus event. + if (oldSelectedESimPageName !== this.selectedESimPageName_) { + this.fire('focus-default-button'); + } + }, + + /** @private */ + updateButtonBarState_() { + let buttonState; + const cancelButtonStateIfEnabled = + this.delegate.shouldShowCancelButton() ? + cellularSetup.ButtonState.ENABLED : + undefined; + switch (this.state_) { + case ESimUiState.PROFILE_SEARCH: + case ESimUiState.ACTIVATION_CODE_ENTRY: + this.forwardButtonLabel = this.i18n('next'); + buttonState = { + backward: cellularSetup.ButtonState.ENABLED, + cancel: cancelButtonStateIfEnabled, + forward: cellularSetup.ButtonState.DISABLED, + }; + break; + case ESimUiState.ACTIVATION_CODE_ENTRY_READY: + this.forwardButtonLabel = this.i18n('next'); + buttonState = { + backward: cellularSetup.ButtonState.ENABLED, + cancel: cancelButtonStateIfEnabled, + forward: cellularSetup.ButtonState.ENABLED, + }; + break; + case ESimUiState.CONFIRMATION_CODE_ENTRY: + this.forwardButtonLabel = this.i18n('confirm'); + buttonState = { + backward: cellularSetup.ButtonState.ENABLED, + cancel: cancelButtonStateIfEnabled, + forward: cellularSetup.ButtonState.DISABLED, + }; + break; + case ESimUiState.CONFIRMATION_CODE_ENTRY_READY: + this.forwardButtonLabel = this.i18n('confirm'); + buttonState = { + backward: cellularSetup.ButtonState.ENABLED, + cancel: cancelButtonStateIfEnabled, + forward: cellularSetup.ButtonState.ENABLED, + }; + break; + case ESimUiState.PROFILE_SELECTION: + this.forwardButtonLabel = this.selectedProfile_ ? + this.i18n('next') : + this.i18n('skipDiscovery'); + buttonState = { + backward: cellularSetup.ButtonState.ENABLED, + cancel: cancelButtonStateIfEnabled, + forward: cellularSetup.ButtonState.ENABLED, + }; + break; + case ESimUiState.ACTIVATION_CODE_ENTRY_INSTALLING: + case ESimUiState.PROFILE_SELECTION_INSTALLING: + case ESimUiState.CONFIRMATION_CODE_ENTRY_INSTALLING: + buttonState = { + backward: cellularSetup.ButtonState.DISABLED, + cancel: cancelButtonStateIfEnabled, + forward: cellularSetup.ButtonState.DISABLED, + }; + break; + case ESimUiState.SETUP_FINISH: + this.forwardButtonLabel = this.i18n('done'); + buttonState = { + forward: cellularSetup.ButtonState.ENABLED, + }; + break; + default: + assertNotReached(); + break; + } + this.set('buttonState', buttonState); + }, + + /** @private */ + initializePageState_(newState, oldState) { + if (newState === ESimUiState.CONFIRMATION_CODE_ENTRY && + oldState !== ESimUiState.CONFIRMATION_CODE_ENTRY_READY) { + this.confirmationCode_ = ''; + } + if (newState === ESimUiState.ACTIVATION_CODE_ENTRY && + oldState !== ESimUiState.ACTIVATION_CODE_ENTRY_READY) { + this.activationCode_ = ''; + } }, /** @private */ onActivationCodeUpdated_(event) { - if (event.detail.activationCode) { - this.set( - 'buttonState.next', cellularSetup.ButtonState.SHOWN_AND_ENABLED); - } else { - this.set( - 'buttonState.next', cellularSetup.ButtonState.SHOWN_BUT_DISABLED); + // initializePageState_() may cause this observer to fire and update the + // buttonState when we're not on the activation code page. Check we're on + // the activation code page before proceeding. + if (this.state_ !== ESimUiState.ACTIVATION_CODE_ENTRY && + this.state_ !== ESimUiState.ACTIVATION_CODE_ENTRY_READY) { + return; + } + this.state_ = event.detail.activationCode ? + ESimUiState.ACTIVATION_CODE_ENTRY_READY : + ESimUiState.ACTIVATION_CODE_ENTRY; + }, + + /** @private */ + onSelectedProfileChanged_() { + // initializePageState_() may cause this observer to fire and update the + // buttonState when we're not on the profile selection page. Check we're + // on the profile selection page before proceeding. + if (this.state_ !== ESimUiState.PROFILE_SELECTION) { + return; } + this.forwardButtonLabel = this.selectedProfile_ ? + this.i18n('next') : + this.i18n('skipDiscovery'); }, /** @private */ - onSelectedProfilesChanged_() { - // TODO(crbug.com/1093185): Add navigation logic. - if (this.selectedProfiles_.length > 0) { - this.set('buttonState.skipDiscovery', cellularSetup.ButtonState.HIDDEN); - this.set( - 'buttonState.done', cellularSetup.ButtonState.SHOWN_AND_ENABLED); - } else { - this.set( - 'buttonState.skipDiscovery', - cellularSetup.ButtonState.SHOWN_AND_ENABLED); - this.set('buttonState.done', cellularSetup.ButtonState.HIDDEN); + onConfirmationCodeUpdated_() { + // initializePageState_() may cause this observer to fire and update the + // buttonState when we're not on the confirmation code page. Check we're + // on the confirmation code page before proceeding. + if (this.state_ !== ESimUiState.CONFIRMATION_CODE_ENTRY && + this.state_ !== ESimUiState.CONFIRMATION_CODE_ENTRY_READY) { + return; } + this.state_ = this.confirmationCode_ ? + ESimUiState.CONFIRMATION_CODE_ENTRY_READY : + ESimUiState.CONFIRMATION_CODE_ENTRY; }, + /** SubflowBehavior override */ navigateForward() { - this.selectedESimPageName_ = ESimPageName.FINAL; + this.showError_ = false; + + switch (this.state_) { + case ESimUiState.ACTIVATION_CODE_ENTRY_READY: + // Assume installing the profile doesn't require a confirmation + // code, send an empty string. + this.state_ = ESimUiState.ACTIVATION_CODE_ENTRY_INSTALLING; + this.euicc_ + .installProfileFromActivationCode( + this.activationCode_, /*confirmationCode=*/ '') + .then(this.handleProfileInstallResponse_.bind(this)); + break; + case ESimUiState.PROFILE_SELECTION: + if (this.selectedProfile_) { + this.state_ = ESimUiState.PROFILE_SELECTION_INSTALLING; + // Assume installing the profile doesn't require a confirmation + // code, send an empty string. + this.selectedProfile_.installProfile('').then( + this.handleProfileInstallResponse_.bind(this)); + } else { + this.state_ = ESimUiState.ACTIVATION_CODE_ENTRY; + } + break; + case ESimUiState.CONFIRMATION_CODE_ENTRY_READY: + this.state_ = ESimUiState.CONFIRMATION_CODE_ENTRY_INSTALLING; + if (this.selectedProfile_) { + this.selectedProfile_.installProfile(this.confirmationCode_) + .then(this.handleProfileInstallResponse_.bind(this)); + } else { + this.euicc_ + .installProfileFromActivationCode( + this.activationCode_, this.confirmationCode_) + .then(this.handleProfileInstallResponse_.bind(this)); + } + break; + case ESimUiState.SETUP_FINISH: + this.fire('exit-cellular-setup'); + break; + default: + assertNotReached(); + break; + } }, /** * @returns {boolean} true if backward navigation was handled + * SubflowBehavior override */ attemptBackwardNavigation() { - // TODO(crbug.com/1093185): Handle state when camera is used + if ((this.state_ === ESimUiState.ACTIVATION_CODE_ENTRY || + this.state_ === ESimUiState.ACTIVATION_CODE_ENTRY_READY) && + this.pendingProfiles_.length > 1) { + this.state_ = ESimUiState.PROFILE_SELECTION; + return true; + } else if ( + this.state_ === ESimUiState.CONFIRMATION_CODE_ENTRY || + this.state_ === ESimUiState.CONFIRMATION_CODE_ENTRY_READY) { + if (this.activationCode_) { + this.state_ = ESimUiState.ACTIVATION_CODE_ENTRY_READY; + } else if (this.pendingProfiles_.length > 1) { + this.state_ = ESimUiState.PROFILE_SELECTION; + } else { + return false; + } + return true; + } return false; }, + + /** @private */ + getShowNoProfilesMessage_() { + return !(this.pendingProfiles_ && this.pendingProfiles_.length > 0); + }, + + /** NetworkListenerBehavior override */ + onNetworkStateListChanged() { + hasActivePSimNetwork().then((hasActive) => { + this.hasActivePSimNetwork_ = hasActive; + }); + }, + + /** @private */ + shouldShowSubpageBusy_() { + return this.state_ === ESimUiState.ACTIVATION_CODE_ENTRY_INSTALLING || + this.state_ === ESimUiState.CONFIRMATION_CODE_ENTRY_INSTALLING || + this.state_ === ESimUiState.PROFILE_SELECTION_INSTALLING; + }, + + /** + * @param {boolean} hasActivePSimNetwork + * @private + */ + getLoadingPageState_(hasActivePSimNetwork) { + return hasActivePSimNetwork ? + LoadingPageState.CELLULAR_DISCONNECT_WARNING : + LoadingPageState.LOADING; + }, }); // #cr_define_end - return {ESimPageName: ESimPageName}; + return {ESimPageName: ESimPageName, ESimUiState: ESimUiState}; });
\ No newline at end of file diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_listener_behavior.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_listener_behavior.html new file mode 100644 index 00000000000..dff799113c8 --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_listener_behavior.html @@ -0,0 +1,2 @@ +<link rel="import" href="mojo_interface_provider.html"> +<script src="esim_manager_listener_behavior.js"></script> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_listener_behavior.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_listener_behavior.js new file mode 100644 index 00000000000..339c8153a79 --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_listener_behavior.js @@ -0,0 +1,40 @@ +// Copyright 2020 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 {observeESimManager} from './mojo_interface_provider.m.js'; + +/** + * @fileoverview Polymer behavior for observing ESimManagerObserver + * events. + */ + +/** @polymerBehavior */ +/* #export */ const ESimManagerListenerBehavior = { + /** @private {?chromeos.cellularSetup.mojom.ESimManagerObserver} */ + observer_: null, + + /** @override */ + attached() { + cellular_setup.observeESimManager(this); + }, + + // ESimManagerObserver methods. Override these in the implementation. + + onAvailableEuiccListChanged() {}, + + /** + * @param {!chromeos.cellularSetup.mojom.EuiccRemote} euicc + */ + onProfileListChanged(euicc) {}, + + /** + * @param {!chromeos.cellularSetup.mojom.EuiccRemote} euicc + */ + onEuiccChanged(euicc) {}, + + /** + * @param {!chromeos.cellularSetup.mojom.ESimProfileRemote} profile + */ + onProfileChanged(profile) {}, +};
\ No newline at end of file diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_utils.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_utils.html new file mode 100644 index 00000000000..8ae13b6392a --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_utils.html @@ -0,0 +1,2 @@ +<link rel="import" href="mojo_interface_provider.html"> +<script src="esim_manager_utils.js"></script>
\ No newline at end of file diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_utils.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_utils.js new file mode 100644 index 00000000000..4f5613aedad --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_utils.js @@ -0,0 +1,98 @@ +// Copyright 2020 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. + +// clang-format off +// #import {getESimManagerRemote} from 'chrome://resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.m.js'; +// #import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js'; +// clang-format on + +cr.define('cellular_setup', function() { + /** + * Fetches the EUICC's eSIM profiles with status 'Pending'. + * @param {!chromeos.cellularSetup.mojom.EuiccRemote} euicc + * @return {!Promise<!Array<!chromeos.cellularSetup.mojom.ESimProfileRemote>>} + */ + /* #export */ function getPendingESimProfiles(euicc) { + return euicc.getProfileList().then(response => { + return filterForPendingProfiles_(response.profiles); + }); + } + + /** + * @private + * @param {!Array<!chromeos.cellularSetup.mojom.ESimProfileRemote>} profiles + * @return {!Promise<Array<!chromeos.cellularSetup.mojom.ESimProfileRemote>>} + */ + function filterForPendingProfiles_(profiles) { + const profilePromises = profiles.map(profile => { + return profile.getProperties().then(response => { + if (response.properties.state !== + chromeos.cellularSetup.mojom.ProfileState.kPending) { + return null; + } + return profile; + }); + }); + return Promise.all(profilePromises).then(profiles => { + return profiles.filter(profile => { + return profile !== null; + }); + }); + } + + /** + * Returns the Euicc that should be used for eSim operations or null + * if there is none available. + * @return {!Promise<?chromeos.cellularSetup.mojom.EuiccRemote>} + */ + /* #export */ async function getEuicc() { + const eSimManagerRemote = cellular_setup.getESimManagerRemote(); + const response = await eSimManagerRemote.getAvailableEuiccs(); + if (!response || !response.euiccs) { + return null; + } + // Onboard Euicc always appears at index 0. If useExternalEuicc flag + // is set, use the next available Euicc. + const euiccIndex = loadTimeData.getBoolean('useExternalEuicc') ? 1 : 0; + if (euiccIndex >= response.euiccs.length) { + return null; + } + return response.euiccs[euiccIndex]; + } + + /** + * Returns the eSIM profile with iccid in the first EUICC and null if none + * found. + * @param {string} iccid + * @return {!Promise<?chromeos.cellularSetup.mojom.ESimProfileRemote>} + */ + /* #export */ async function getESimProfile(iccid) { + if (!iccid) { + return null; + } + const euicc = await cellular_setup.getEuicc(); + + if (!euicc) { + console.error('No Euiccs found'); + return null; + } + const esimProfilesRemotes = await euicc.getProfileList(); + + for (const profileRemote of esimProfilesRemotes.profiles) { + const profileProperties = await profileRemote.getProperties(); + + if (profileProperties.properties.iccid === iccid) { + return profileRemote; + } + } + return null; + } + + // #cr_define_end + return { + getEuicc, + getESimProfile, + getPendingESimProfiles, + }; +}); diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/final_page.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/final_page.html index dae2b94d6ee..262113316ef 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/final_page.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/final_page.html @@ -9,16 +9,18 @@ <style> [slot='page-body'] { background-image: -webkit-image-set( - url(final_page_success_1x.png) 1x, - url(final_page_success_2x.png) 2x); + url(chrome://resources/cr_components/chromeos/cellular_setup/final_page_success_1x.png) 1x, + url(chrome://resources/cr_components/chromeos/cellular_setup/final_page_success_2x.png) 2x); background-position: center center; background-repeat: no-repeat; + background-size: contain; } .error[slot='page-body'] { background-image: -webkit-image-set( - url(error_1x.png) 1x, - url(error_2x.png) 2x); + url(chrome://resources/cr_components/chromeos/cellular_setup/error_1x.png) 1x, + url(chrome://resources/cr_components/chromeos/cellular_setup/error_2x.png) 2x); + background-size: contain; } </style> <base-page title="[[getTitle_(showError)]]" diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/final_page.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/final_page.js index d35c9b99f50..41f4c15eea6 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/final_page.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/final_page.js @@ -21,6 +21,12 @@ Polymer({ * @type {boolean} */ showError: Boolean, + + /** @type {string} */ + message: String, + + /** @type {string} */ + errorMessage: String, }, /** @@ -42,8 +48,7 @@ Polymer({ * @private */ getMessage_(showError) { - return showError ? this.i18n('finalPageErrorMessage') : - this.i18n('finalPageMessage'); + return showError ? this.errorMessage : this.message; }, /** diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.html index b7096a0baf6..b465a3a18d7 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.html @@ -1,4 +1,7 @@ <link rel="import" href="../../../html/cr.html"> <link rel="import" href="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.html"> +<link rel="import" href="chrome://resources/mojo/mojo/public/mojom/base/big_buffer.mojom.html"> +<link rel="import" href="chrome://resources/mojo/mojo/public/mojom/base/string16.mojom.html"> <link rel="import" href="chrome://resources/mojo/chromeos/services/cellular_setup/public/mojom/cellular_setup.mojom.html"> +<link rel="import" href="chrome://resources/mojo/chromeos/services/cellular_setup/public/mojom/esim_manager.mojom.html"> <script src="mojo_interface_provider.js"></script> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.js index 01e24f158c6..5b79070c145 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.js @@ -5,11 +5,16 @@ // clang-format off // #import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js'; // #import 'chrome://resources/mojo/url/mojom/url.mojom-lite.js'; +// #import 'chrome://resources/mojo/mojo/public/mojom/base/big_buffer.mojom-lite.js'; +// #import 'chrome://resources/mojo/mojo/public/mojom/base/string16.mojom-lite.js'; // #import 'chrome://resources/mojo/chromeos/services/cellular_setup/public/mojom/cellular_setup.mojom-lite.js'; +// #import 'chrome://resources/mojo/chromeos/services/cellular_setup/public/mojom/esim_manager.mojom-lite.js'; // clang-format on cr.define('cellular_setup', function() { let cellularRemote = null; + let eSimManagerRemote = null; + let isTesting = false; /** * @param {?chromeos.cellularSetup.mojom.CellularSetupRemote} @@ -17,6 +22,7 @@ cr.define('cellular_setup', function() { */ /* #export */ function setCellularSetupRemoteForTesting(testCellularRemote) { cellularRemote = testCellularRemote; + isTesting = true; } /** @@ -32,6 +38,53 @@ cr.define('cellular_setup', function() { return cellularRemote; } + /** + * @param {?chromeos.cellularSetup.mojom.ESimManagerRemote} + * testESimManagerRemote A test eSimManager remote + */ + /* #export */ function setESimManagerRemoteForTesting(testESimManagerRemote) { + eSimManagerRemote = testESimManagerRemote; + isTesting = true; + } + + /** + * @returns {!chromeos.cellularSetup.mojom.ESimManagerRemote} + */ + /* #export */ function getESimManagerRemote() { + if (eSimManagerRemote) { + return eSimManagerRemote; + } + + eSimManagerRemote = chromeos.cellularSetup.mojom.ESimManager.getRemote(); + + return eSimManagerRemote; + } + + /** + * @param {!chromeos.cellularSetup.mojom.ESimManagerObserverInterface} + * observer + * @returns {?chromeos.cellularSetup.mojom.ESimManagerObserverReceiver} + */ + /* #export */ function observeESimManager(observer) { + if (isTesting) { + getESimManagerRemote().addObserver( + /** @type {!chromeos.cellularSetup.mojom.ESimManagerObserverRemote} */ + (observer)); + return null; + } + + const receiver = + new chromeos.cellularSetup.mojom.ESimManagerObserverReceiver(observer); + getESimManagerRemote().addObserver(receiver.$.bindNewPipeAndPassRemote()); + return receiver; + } + // #cr_define_end - return {setCellularSetupRemoteForTesting, getCellularSetupRemote}; + return { + setCellularSetupRemoteForTesting, + getCellularSetupRemote, + setESimManagerRemoteForTesting, + getESimManagerRemote, + observeESimManager + }; }); diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.html index f6069727917..10eadd33d7f 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.html @@ -3,10 +3,13 @@ <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html"> +<link rel="import" href="cellular_setup_icons.html"> <dom-module id="profile-discovery-list-item"> <template> - <style include="iron-flex"> + <style include="iron-flex iron-positioning"> #details { align-items: center; display: flex; @@ -22,32 +25,48 @@ color: var(--cr-primary-text-color); } - #checkmark { - -webkit-mask: url(activation_code_page_checked.svg) no-repeat center; - background-color: var(--google-blue-600); - height: 20px; + .icon { margin-inline-end: 8px; - mask: url(activation_code_page_checked.svg) no-repeat center; padding-inline-end: var(--cr-section-padding); - width: 20px; + } + + #checkmark { + --iron-icon-fill-color: var(--google-blue-600); + } + + paper-spinner-lite { + height: 16px; + vertical-align: middle; + width: 16px; } </style> <div class="two-line no-padding" selectable> <div class="flex layout horizontal center link-wrapper"> - <div id="details" no-flex$="false"> + <!-- TODO(crbug.com/1093185): Update UI to new spec. --> + <div id="details"> <!-- TODO(crbug.com/1093185): Update with real profile image. --> - <img id="profileImage" src="../../../images/200-logo_googleg.png"> + <img id="profileImage" src="chrome://resources/cr_components/chromeos/cellular_setup/default_esim_profile.svg"> + <!-- The item's aria properties are set in profile_discovery_list_page. --> <div class="flex settings-box-text"> <div id="profileTitleLabel"> - [[profile.name]] + [[getProfileName_(profileProperties_)]] </div> <div id="profileProviderLabel"> - [[profile.provider]] + [[getProfileProvider_(profileProperties_)]] </div> </div> </div> - <span id="checkmark" hidden$="[[!selected]]" - tabindex="-1"> + <div class="icon" + hidden$="[[!selected]]"> + <iron-icon id="checkmark" + icon="cellular-setup:checked" + tabindex="-1" + hidden$="[[showLoadingIndicator]]"> + </iron-icon> + <paper-spinner-lite active + hidden$="[[!showLoadingIndicator]]"> + </paper-spinner-lite> + </div> </div> </div> </template> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.js index a2705ddff12..088344d980c 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_item.js @@ -14,16 +14,57 @@ Polymer({ behaviors: [I18nBehavior], properties: { - // TODO(crbug.com/1093185) Add type annotation when the real Profile struct - // is available. + /** @type {?chromeos.cellularSetup.mojom.ESimProfileRemote} */ profile: { type: Object, value: null, + observer: 'onProfileChanged_', }, selected: { type: Boolean, reflectToAttribute: true, }, + + showLoadingIndicator: { + type: Boolean, + }, + + /** + * @type {?chromeos.cellularSetup.mojom.ESimProfileProperties} + * @private + */ + profileProperties_: { + type: Object, + value: null, + notify: true, + }, + }, + + /** @private */ + onProfileChanged_() { + if (!this.profile) { + this.profileProperties_ = null; + return; + } + this.profile.getProperties().then(response => { + this.profileProperties_ = response.properties; + }); + }, + + /** @private */ + getProfileName_() { + if (!this.profileProperties_) { + return ''; + } + return String.fromCharCode(...this.profileProperties_.name.data); + }, + + /** @private */ + getProfileProvider_() { + if (!this.profileProperties_) { + return ''; + } + return String.fromCharCode(...this.profileProperties_.serviceProvider.data); }, }); diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_page.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_page.html index a6cad8e1d48..7fa907286c6 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_page.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_page.html @@ -33,18 +33,19 @@ <div slot="page-body"> <div>[[i18n('profileListPageMessage')]]</div> <div id="container" class="layout vertical flex" scrollable> - <iron-list id="profileList" items="[[profiles_]]" - scroll-target="container" selection-enabled - preserve-focus multi-selection - selected-items="{{selectedProfiles}}" - role="listbox" - aria-multiselectable="true"> + <iron-list id="profileList" items="[[pendingProfiles]]" + scroll-target="container" + selection-enabled="[[!showBusy]]" + preserve-focus + selected-item="{{selectedProfile}}" + role="listbox"> <template> <profile-discovery-list-item profile="[[item]]" - selected="[[isProfileSelected_(item, selectedProfiles.length)]]" + selected="[[isProfileSelected_(item, selectedProfile)]]" tabindex="0" role="option" - aria-selected="[[isProfileSelected_(item, selectedProfiles.length)]]"> + aria-selected="[[isProfileSelected_(item, selectedProfile)]]" + show-loading-indicator="[[showBusy]]"> </profile-discovery-list-item> </template> </iron-list> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_page.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_page.js index 7ac95a631b0..f8ff38ab3e8 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_page.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/profile_discovery_list_page.js @@ -14,45 +14,36 @@ Polymer({ properties: { /** - * TODO(crbug.com/1093185) Fetch real profiles. - * @type {Array<!Object>} + * @type {Array<!chromeos.cellularSetup.mojom.ESimProfileRemote>} * @private */ - profiles_: { + pendingProfiles: { type: Array, - value() { - return [ - { - name: 'Profile 1', - provider: 'Google Fi', - }, - { - name: 'Profile 2', - provider: 'Verizon', - }, - { - name: 'Profile 3', - provider: 'Google Fi', - }, - ]; - }, }, /** - * @type {Array<!Object>} + * @type {?chromeos.cellularSetup.mojom.ESimProfileRemote} * @private */ - selectedProfiles: { + selectedProfile: { type: Object, notify: true, }, + + /** + * Indicates the UI is busy with an operation and cannot be interacted with. + */ + showBusy: { + type: Boolean, + value: false, + }, }, /** - * @param {Object} profile + * @param {chromeos.cellularSetup.mojom.ESimProfileRemote} profile * @private */ isProfileSelected_(profile) { - return this.selectedProfiles.some(p => p === profile); + return this.selectedProfile === profile; } }); diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/provisioning_page.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/provisioning_page.html index e0d9e9cee3d..ba6ac6e1c4b 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/provisioning_page.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/provisioning_page.html @@ -14,8 +14,8 @@ <template> <style include="iron-flex cr-hidden-style"> paper-spinner-lite { - height: 200px; - width: 200px; + height: 32px; + width: 32px; } #portalContainer { @@ -25,8 +25,8 @@ #error-icon-container { background-image: -webkit-image-set( - url(error_1x.png) 1x, - url(error_2x.png) 2x); + url(chrome://resources/cr_components/chromeos/cellular_setup/error_1x.png) 1x, + url(chrome://resources/cr_components/chromeos/cellular_setup/error_2x.png) 2x); background-position: center center; background-repeat: no-repeat; background-size: contain; diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.html index 3df8674d08f..a500531b5a6 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.html @@ -2,7 +2,7 @@ <link rel="import" href="../../../html/i18n_behavior.html"> <link rel="import" href="mojo_interface_provider.html"> -<link rel="import" href="sim_detect_page.html"> +<link rel="import" href="setup_loading_page.html"> <link rel="import" href="provisioning_page.html"> <link rel="import" href="final_page.html"> <link rel="import" href="subflow_behavior.html"> @@ -23,16 +23,25 @@ flex-direction: column; } </style> - <iron-pages attr-for-selected="is" + <iron-pages attr-for-selected="id" selected="[[selectedPSimPageName_]]" selected-item="{{selectedPage_}}"> - <sim-detect-page delegate="[[delegate]]" show-error="[[showError_]]"></sim-detect-page> - <provisioning-page delegate="[[delegate]]" show-error="{{showError_}}" + <setup-loading-page id="simDetectPage" + delegate="[[delegate]]" state="[[getLoadingPageState_(showError)]]" + loading-message="[[i18n('establishNetworkConnectionMessage')]]"> + </setup-loading-page> + <provisioning-page id="provisioningPage" + delegate="[[delegate]]" show-error="{{showError_}}" cellular-metadata="[[cellularMetadata_]]" on-carrier-portal-loaded="onCarrierPortalLoaded_" on-carrier-portal-result="onCarrierPortalResult_"> </provisioning-page> - <final-page delegate="[[delegate]]" show-error="[[showError_]]"></final-page> + <final-page id="finalPage" + delegate="[[delegate]]" + show-error="[[showError_]]" + message="[[i18n('finalPageMessage')]]" + error-message="[[i18n('finalPageErrorMessage')]]"> + </final-page> </iron-pages> </template> <script src="psim_flow_ui.js"></script> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.js index 3da72094f86..75b34bc3e12 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/psim_flow_ui.js @@ -5,9 +5,9 @@ cr.define('cellularSetup', function() { /** @enum{string} */ /* #export */ const PSimPageName = { - SIM_DETECT: 'sim-detect-page', - PROVISIONING: 'provisioning-page', - FINAL: 'final-page', + SIM_DETECT: 'simDetectPage', + PROVISIONING: 'provisioningPage', + FINAL: 'finalPage', }; /** @enum{string} */ @@ -82,6 +82,11 @@ cr.define('cellularSetup', function() { 'selectedPSimPageName_, cellularMetadata_.*)', }, + forwardButtonLabel: { + type: String, + notify: true, + }, + /** * @type {!cellularSetup.PSimUIState} * @private @@ -104,7 +109,7 @@ cr.define('cellularSetup', function() { /** * DOM Element for the current selected sub-page. - * @private {!SimDetectPageElement|!ProvisioningPageElement| + * @private {!SetupLoadingPageElement|!ProvisioningPageElement| * !FinalPageElement} */ selectedPage_: Object, @@ -181,10 +186,21 @@ cr.define('cellularSetup', function() { }, navigateForward() { - // Navigate forward is only called by clicking next button - // from the provisioning page. - assert(this.selectedPSimPageName_ === PSimPageName.PROVISIONING); - this.state_ = PSimUIState.WAITING_FOR_ACTIVATION_TO_FINISH; + switch (this.state_) { + case PSimUIState.WAITING_FOR_PORTAL_TO_LOAD: + case PSimUIState.TIMEOUT_PORTAL_LOAD: + case PSimUIState.WAITING_FOR_USER_PAYMENT: + case PSimUIState.ACTIVATION_SUCCESS: + this.state_ = PSimUIState.WAITING_FOR_ACTIVATION_TO_FINISH; + break; + case PSimUIState.WAITING_FOR_ACTIVATION_TO_FINISH: + case PSimUIState.TIMEOUT_FINISH_ACTIVATION: + this.fire('exit-cellular-setup'); + break; + default: + assertNotReached(); + break; + } }, /** @@ -207,35 +223,25 @@ cr.define('cellularSetup', function() { case PSimUIState.TIMEOUT_PORTAL_LOAD: case PSimUIState.WAITING_FOR_USER_PAYMENT: buttonState = { - backward: cellularSetup.ButtonState.SHOWN_AND_ENABLED, - cancel: cellularSetup.ButtonState.SHOWN_AND_ENABLED, - done: cellularSetup.ButtonState.HIDDEN, - next: cellularSetup.ButtonState.SHOWN_BUT_DISABLED, - tryAgain: cellularSetup.ButtonState.HIDDEN, - skipDiscovery: cellularSetup.ButtonState.HIDDEN, + backward: cellularSetup.ButtonState.ENABLED, + cancel: cellularSetup.ButtonState.ENABLED, + forward: cellularSetup.ButtonState.DISABLED, }; break; case PSimUIState.ACTIVATION_SUCCESS: case PSimUIState.ALREADY_ACTIVATED: case PSimUIState.ACTIVATION_FAILURE: buttonState = { - backward: cellularSetup.ButtonState.SHOWN_AND_ENABLED, - cancel: cellularSetup.ButtonState.SHOWN_AND_ENABLED, - done: cellularSetup.ButtonState.HIDDEN, - next: cellularSetup.ButtonState.SHOWN_AND_ENABLED, - tryAgain: cellularSetup.ButtonState.HIDDEN, - skipDiscovery: cellularSetup.ButtonState.HIDDEN, + backward: cellularSetup.ButtonState.ENABLED, + cancel: cellularSetup.ButtonState.ENABLED, + forward: cellularSetup.ButtonState.ENABLED, }; break; case PSimUIState.WAITING_FOR_ACTIVATION_TO_FINISH: case PSimUIState.TIMEOUT_FINISH_ACTIVATION: + this.forwardButtonLabel = this.i18n('done'); buttonState = { - backward: cellularSetup.ButtonState.HIDDEN, - cancel: cellularSetup.ButtonState.HIDDEN, - done: cellularSetup.ButtonState.SHOWN_AND_ENABLED, - next: cellularSetup.ButtonState.HIDDEN, - tryAgain: cellularSetup.ButtonState.HIDDEN, - skipDiscovery: cellularSetup.ButtonState.HIDDEN, + forward: cellularSetup.ButtonState.ENABLED, }; break; default: @@ -416,6 +422,15 @@ cr.define('cellularSetup', function() { this.state_ = success ? PSimUIState.ACTIVATION_SUCCESS : PSimUIState.ACTIVATION_FAILURE; }, + + /** + * @param {boolean} showError + * @private + */ + getLoadingPageState_(showError) { + return showError ? LoadingPageState.SIM_DETECT_ERROR : + LoadingPageState.LOADING; + }, }); // #cr_define_end diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.html new file mode 100644 index 00000000000..9e77036fb7b --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.html @@ -0,0 +1,49 @@ +<link rel="import" href="../../../html/polymer.html"> + +<link rel="import" href="../../../html/i18n_behavior.html"> +<link rel="import" href="base_page.html"> +<link rel="import" href="cellular_setup_delegate.html"> +<link rel="import" href="../../../cr_elements/hidden_style_css.html"> +<link rel="import" href="chrome://resources/html/assert.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html"> + +<dom-module id="setup-loading-page"> + <template> + <style include="iron-flex cr-hidden-style"> + paper-spinner-lite { + height: 32px; + margin-bottom: 8px; + width: 32px; + } + + #simDetectError { + background-image: -webkit-image-set( + url(chrome://resources/cr_components/chromeos/cellular_setup/error_1x.png) 1x, + url(chrome://resources/cr_components/chromeos/cellular_setup/error_2x.png) 2x); + background-position: center center; + background-repeat: no-repeat; + background-size: contain; + height: 100%; + width: 100%; + } + + #networkConnectionMessage { + text-align: center; + } + </style> + <base-page title="[[getTitle_(state)]]" + message="[[getMessage_(state)]]" + message-icon="[[getMessageIcon_(state)]]"> + <div slot="page-body" class="layout vertical center-center"> + <paper-spinner-lite active hidden$="[[shouldShowSimDetectError_(state)]]"> + </paper-spinner-lite> + <div id="networkConnectionMessage" hidden$="[[shouldShowSimDetectError_(state)]]"> + [[loadingMessage]] + </div> + <div id="simDetectError" hidden$="[[!shouldShowSimDetectError_(state)]]"></div> + </div> + </base-page> + </template> + <script src="setup_loading_page.js"></script> +</dom-module> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.js new file mode 100644 index 00000000000..284e9cecf5f --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.js @@ -0,0 +1,91 @@ +// Copyright 2019 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. + +/** @enum {number} */ +/* #export */ const LoadingPageState = { + LOADING: 1, + SIM_DETECT_ERROR: 2, + CELLULAR_DISCONNECT_WARNING: 3, +}; + +/** + * Loading subpage in Cellular Setup flow. This element contains image + * asset and description to indicate that a SIM detection or eSIM profiles + * loading is in progress. It can show a 'detecting sim' error or a 'cellular + * disconnection' warning depending on its state. + */ +Polymer({ + is: 'setup-loading-page', + + behaviors: [I18nBehavior], + + properties: { + /** @type {!cellular_setup.CellularSetupDelegate} */ + delegate: Object, + + /** @type {!LoadingPageState} */ + state: { + type: Object, + value: LoadingPageState.LOADING, + }, + + /** + * Message displayed with spinner when in LOADING state. + */ + loadingMessage: { + type: String, + value: '', + }, + }, + + /** + * @param {LoadingPageState} state + * @return {?string} + * @private + */ + getTitle_(state) { + if (this.delegate.shouldShowPageTitle() && + state === LoadingPageState.SIM_DETECT_ERROR) { + return this.i18n('simDetectPageErrorTitle'); + } + return null; + }, + + /** + * @param {LoadingPageState} state + * @return {string} + * @private + */ + getMessage_(state) { + switch (state) { + case LoadingPageState.SIM_DETECT_ERROR: + return this.i18n('simDetectPageErrorMessage'); + case LoadingPageState.CELLULAR_DISCONNECT_WARNING: + return this.i18n('eSimConnectionWarning'); + case LoadingPageState.LOADING: + return ''; + default: + assertNotReached(); + } + }, + + /** + * @param {LoadingPageState} state + * @return {string} + * @private + */ + getMessageIcon_(state) { + return state === LoadingPageState.CELLULAR_DISCONNECT_WARNING ? 'warning' : + ''; + }, + + /** + * @param {LoadingPageState} state + * @return {boolean} + * @private + */ + shouldShowSimDetectError_(state) { + return state === LoadingPageState.SIM_DETECT_ERROR; + }, +}); diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_selection_flow.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_selection_flow.html index 1e663c6e725..9a52fbdbbd3 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_selection_flow.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_selection_flow.html @@ -75,14 +75,14 @@ #psimIconContainer { background-image: -webkit-image-set( - url(psim_1x.png) 1x, - url(psim_2x.png) 2x); + url(chrome://resources/cr_components/chromeos/cellular_setup/psim_1x.png) 1x, + url(chrome://resources/cr_components/chromeos/cellular_setup/psim_2x.png) 2x); } #esimIconContainer { background-image: -webkit-image-set( - url(esim_1x.png) 1x, - url(esim_2x.png) 2x); + url(chrome://resources/cr_components/chromeos/cellular_setup/esim_1x.png) 1x, + url(chrome://resources/cr_components/chromeos/cellular_setup/esim_2x.png) 2x); } .sim-btn-text { diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_selection_flow.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_selection_flow.js index 16339d8e58e..474073bd9e7 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_selection_flow.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/setup_selection_flow.js @@ -17,11 +17,16 @@ Polymer({ properties: { /** * Element name of the current selected sub-page. - * @private {!cellularSetup.CellularSetupPageName} + * @type {!cellularSetup.CellularSetupPageName} */ selectedPage: { type: String, notify: true, + }, + + forwardButtonLabel: { + type: String, + notify: true, } }, @@ -43,18 +48,15 @@ Polymer({ * @private */ updateButtonState_(selectedPage) { + this.forwardButtonLabel = this.i18n('next'); this.buttonState = { - backward: cellularSetup.ButtonState.HIDDEN, - cancel: cellularSetup.ButtonState.SHOWN_AND_ENABLED, - done: cellularSetup.ButtonState.HIDDEN, - tryAgain: cellularSetup.ButtonState.HIDDEN, - skipDiscovery: cellularSetup.ButtonState.HIDDEN, + cancel: cellularSetup.ButtonState.ENABLED, }; if (selectedPage === cellularSetup.CellularSetupPageName.PSIM_FLOW_UI || selectedPage === cellularSetup.CellularSetupPageName.ESIM_FLOW_UI) { - this.buttonState.next = cellularSetup.ButtonState.SHOWN_AND_ENABLED; + this.set('buttonState.forward', cellularSetup.ButtonState.ENABLED); } else { - this.buttonState.next = cellularSetup.ButtonState.SHOWN_BUT_DISABLED; + this.set('buttonState.forward', cellularSetup.ButtonState.DISABLED); } } });
\ No newline at end of file diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.html b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.html deleted file mode 100644 index b5e6b9148f6..00000000000 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.html +++ /dev/null @@ -1,40 +0,0 @@ -<link rel="import" href="../../../html/polymer.html"> - -<link rel="import" href="../../../html/i18n_behavior.html"> -<link rel="import" href="base_page.html"> -<link rel="import" href="cellular_setup_delegate.html"> -<link rel="import" href="../../../cr_elements/hidden_style_css.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html"> - -<dom-module id="sim-detect-page"> - <template> - <style include="iron-flex cr-hidden-style"> - #error-icon-container { - background-image: -webkit-image-set( - url(error_1x.png) 1x, - url(error_2x.png) 2x); - background-position: center center; - background-repeat: no-repeat; - background-size: contain; - height: 100%; - width: 100%; - } - - #network-connection-message { - text-align: center; - } - </style> - <base-page title="[[getTitle_(showError)]]" - message="[[getMessage_(showError)]]"> - <div slot="page-body" class="layout horizontal center-center"> - <!-- TODO(crbug.com/1093185): Conditionally show spinner when setup is added in OOBE --> - <div id="network-connection-message" hidden$="[[showError]]"> - [[i18n('establishNetworkConnectionMessage')]] - </div> - <div id="error-icon-container" hidden$="[[!showError]]"></div> - </div> - </base-page> - </template> - <script src="sim_detect_page.js"></script> -</dom-module> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.js deleted file mode 100644 index 61a68987c46..00000000000 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/sim_detect_page.js +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright 2019 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. - -/** - * SIM Detection subpage in Cellular Setup flow. This element contains image - * asset and description to indicate that the SIM detection is in progress. - * It also has an error state that displays a message for errors that may - * happen during this step. - */ -Polymer({ - is: 'sim-detect-page', - - behaviors: [I18nBehavior], - - properties: { - /** @type {!cellular_setup.CellularSetupDelegate} */ - delegate: Object, - - /** - * Whether error state should be shown. - * @type {boolean} - */ - showError: Boolean, - }, - - /** - * @param {boolean} showError - * @return {?string} - * @private - */ - getTitle_(showError) { - if (this.delegate.shouldShowPageTitle() && showError) { - return this.i18n('simDetectPageErrorTitle'); - } - return null; - }, - - /** - * @param {boolean} showError - * @return {string} - * @private - */ - getMessage_(showError) { - return showError ? this.i18n('simDetectPageErrorMessage') : ''; - }, -}); diff --git a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/webview_post_util.js b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/webview_post_util.js index 5ee36ed4016..0ec5e8c3796 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/webview_post_util.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/cellular_setup/webview_post_util.js @@ -4,8 +4,8 @@ /** * @fileoverview Provides utility methods used by the cellular activation flow. - * Current: chrome://mobilesetup (mobile_setup.html/mobile_setup_portal.html) - * New UI: chrome://cellular-setup (cellular_setup_dialog.html) + * Current: chrome://mobilesetup (mobile_setup.html/mobile_setup_portal.html) + * New UI: cr_components/chromeos/cellular_setup/cellular_setup.html */ cr.define('webviewPost.util', function() { /** diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/BUILD.gn index 63fd8b30f9d..fc7414712d3 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/BUILD.gn +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/BUILD.gn @@ -3,10 +3,14 @@ # found in the LICENSE file. import("//third_party/closure_compiler/compile_js.gni") +import("//tools/polymer/polymer.gni") +import("//ui/webui/resources/tools/js_modulizer.gni") +import("../os_cr_components.gni") assert(is_chromeos, "MultiDevice UI is Chrome OS only.") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":button_bar", ":fake_mojo_service", @@ -82,6 +86,7 @@ js_library("setup_succeeded_page") { js_library("start_setup_page") { deps = [ ":ui_page_container_behavior", + "//ui/webui/resources/cr_elements/cr_lottie:cr_lottie", "//ui/webui/resources/js:web_ui_listener_behavior", ] } @@ -92,3 +97,219 @@ js_library("ui_page_container_behavior") { "//ui/webui/resources/js:i18n_behavior", ] } + +# Polymer 3 files + +js_type_check("closure_compile_module") { + is_polymer3 = true + deps = [ + ":button_bar.m", + ":fake_mojo_service.m", + ":mojo_api.m", + ":multidevice_setup.m", + ":multidevice_setup_browser_proxy.m", + ":multidevice_setup_delegate.m", + ":multidevice_setup_shared_css.m", + ":setup_succeeded_page.m", + ":start_setup_page.m", + ":ui_page.m", + ":ui_page_container_behavior.m", + "//ui/webui/resources/js:web_ui_listener_behavior.m", + ] +} + +js_library("button_bar.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.m.js" ] + deps = [ + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + ] + extra_deps = [ ":button_bar_module" ] +} + +js_library("fake_mojo_service.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.m.js" ] + deps = [ + "//chromeos/services/multidevice_setup/public/mojom:mojom_js_library_for_compile", + "//ui/webui/resources/js:cr.m", + ] + extra_deps = [ ":modulize" ] +} + +js_library("mojo_api.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.m.js" ] + deps = [ + "//chromeos/services/multidevice_setup/public/mojom:mojom_js_library_for_compile", + "//ui/webui/resources/js:cr.m", + ] + extra_deps = [ ":modulize" ] +} + +js_library("multidevice_setup.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.m.js" ] + deps = [ + ":button_bar.m", + ":fake_mojo_service.m", + ":mojo_api.m", + ":multidevice_setup_delegate.m", + ":multidevice_setup_shared_css.m", + ":password_page.m", + ":setup_succeeded_page.m", + ":start_setup_page.m", + "//ui/webui/resources/js:cr.m", + "//ui/webui/resources/js:web_ui_listener_behavior.m", + ] + extra_deps = [ ":multidevice_setup_module" ] +} + +js_library("multidevice_setup_browser_proxy.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.m.js" ] + deps = [ "//ui/webui/resources/js:cr.m" ] + extra_deps = [ ":modulize" ] +} + +js_library("multidevice_setup_delegate.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.m.js" ] + deps = [ "//ui/webui/resources/js:cr.m" ] + extra_deps = [ ":modulize" ] +} + +js_library("password_page.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.m.js" ] + deps = [ + ":multidevice_setup_browser_proxy.m", + ":multidevice_setup_shared_css.m", + ] + extra_deps = [ ":password_page_module" ] + externs_list = chrome_extension_public_externs + + [ "$externs_path/quick_unlock_private.js" ] + extra_sources = [ "$interfaces_path/quick_unlock_private_interface.js" ] +} + +js_library("setup_succeeded_page.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.m.js" ] + deps = [ + ":multidevice_setup_browser_proxy.m", + ":multidevice_setup_shared_css.m", + ":ui_page_container_behavior.m", + ] + extra_deps = [ ":setup_succeeded_page_module" ] +} + +js_library("start_setup_page.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.m.js" ] + deps = [ + ":mojo_api.m", + ":multidevice_setup_delegate.m", + ":multidevice_setup_shared_css.m", + ":ui_page_container_behavior.m", + "//ui/webui/resources/cr_elements/cr_lottie:cr_lottie.m", + "//ui/webui/resources/js:web_ui_listener_behavior.m", + ] + extra_deps = [ ":start_setup_page_module" ] +} + +js_library("ui_page_container_behavior.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.m.js" ] + deps = [ + "//ui/webui/resources/js:cr.m", + "//ui/webui/resources/js:i18n_behavior.m", + ] + extra_deps = [ ":modulize" ] +} + +js_library("multidevice_setup_shared_css.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_shared_css.m.js" ] + deps = [] + extra_deps = [ ":multidevice_setup_shared_css_module" ] +} + +js_library("ui_page.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page.m.js" ] + deps = [ ":multidevice_setup_shared_css.m" ] + extra_deps = [ ":ui_page_module" ] +} + +group("polymer3_elements") { + public_deps = [ + ":button_bar_module", + ":icons_module", + ":modulize", + ":multidevice_setup_module", + ":multidevice_setup_shared_css_module", + ":password_page_module", + ":setup_succeeded_page_module", + ":start_setup_page_module", + ":ui_page_module", + ] +} + +polymer_modulizer("button_bar") { + js_file = "button_bar.js" + html_file = "button_bar.html" + html_type = "dom-module" + namespace_rewrites = cr_components_chromeos_namespace_rewrites + auto_imports = cr_components_chromeos_auto_imports +} + +polymer_modulizer("multidevice_setup") { + js_file = "multidevice_setup.js" + html_file = "multidevice_setup.html" + html_type = "dom-module" + namespace_rewrites = cr_components_chromeos_namespace_rewrites + auto_imports = cr_components_chromeos_auto_imports +} + +polymer_modulizer("password_page") { + js_file = "password_page.js" + html_file = "password_page.html" + html_type = "dom-module" + namespace_rewrites = cr_components_chromeos_namespace_rewrites + auto_imports = cr_components_chromeos_auto_imports +} + +polymer_modulizer("setup_succeeded_page") { + js_file = "setup_succeeded_page.js" + html_file = "setup_succeeded_page.html" + html_type = "dom-module" + namespace_rewrites = cr_components_chromeos_namespace_rewrites + auto_imports = cr_components_chromeos_auto_imports +} + +polymer_modulizer("start_setup_page") { + js_file = "start_setup_page.js" + html_file = "start_setup_page.html" + html_type = "dom-module" + namespace_rewrites = cr_components_chromeos_namespace_rewrites + auto_imports = cr_components_chromeos_auto_imports +} + +polymer_modulizer("multidevice_setup_shared_css") { + js_file = "multidevice_setup_shared_css.m.js" + html_file = "multidevice_setup_shared_css.html" + html_type = "style-module" +} + +polymer_modulizer("ui_page") { + js_file = "ui_page.js" + html_file = "ui_page.html" + html_type = "dom-module" + namespace_rewrites = cr_components_chromeos_namespace_rewrites + auto_imports = cr_components_chromeos_auto_imports +} + +polymer_modulizer("icons") { + js_file = "icons.m.js" + html_file = "icons.html" + html_type = "iron-iconset" +} + +js_modulizer("modulize") { + input_files = [ + "fake_mojo_service.js", + "mojo_api.js", + "multidevice_setup_browser_proxy.js", + "multidevice_setup_delegate.js", + "ui_page_container_behavior.js", + ] + namespace_rewrites = cr_components_chromeos_namespace_rewrites +} diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/all_set_1x.svg b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/all_set_1x.svg new file mode 100644 index 00000000000..bbaed9067ff --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/all_set_1x.svg @@ -0,0 +1 @@ +<svg width="520" height="320" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" d="M0 0h520v320H0z"/><path d="M436.519 96.534h-49.22c-3.716 0-6.728 3.13-6.728 6.991v116.686c0 3.861 3.012 6.992 6.728 6.992h49.22c3.716 0 6.728-3.131 6.728-6.992V103.525c0-3.861-3.012-6.991-6.728-6.991z" fill="#D2E3FC"/><path d="M436.519 96.534h-49.22c-3.716 0-6.728 3.13-6.728 6.991v116.686c0 3.861 3.012 6.992 6.728 6.992h49.22c3.716 0 6.728-3.131 6.728-6.992V103.525c0-3.861-3.012-6.991-6.728-6.991z" fill="#D2E3FC"/><path d="M284.416 114.222c3.759 0 6.806-3.166 6.806-7.073 0-3.907-3.047-7.073-6.806-7.073s-6.807 3.166-6.807 7.073c0 3.907 3.048 7.073 6.807 7.073z" fill="#34A853"/><path d="M193.845 126.414l-49.152 13.901c-.353.1-.675.294-.932.564a2.177 2.177 0 0 0-.536.972c-.092.368-.09.755.006 1.121.097.367.285.7.546.967l36.15 37.281c.261.268.586.459.942.554.356.095.729.09 1.083-.014.353-.104.673-.304.929-.578.255-.275.435-.615.523-.985l12.992-51.183a2.243 2.243 0 0 0-.021-1.104 2.177 2.177 0 0 0-.543-.95 2.065 2.065 0 0 0-.924-.546 1.998 1.998 0 0 0-1.063 0z" fill="#FFBA00"/><path d="M380.571 146.488c-5.209.224-10.298-1.663-14.194-5.262l-5.092-4.708-2.315-1.935a16.471 16.471 0 0 0-8.236-2.974 16.36 16.36 0 0 0-6.574.844 16.806 16.806 0 0 0-5.762 3.397 17.537 17.537 0 0 0-4.071 5.431 18.253 18.253 0 0 0-.936 13.468 17.791 17.791 0 0 0 3.277 5.983 17.08 17.08 0 0 0 5.232 4.223c.639.327 1.297.614 1.97.859h.049s2.768.758 2.847.768l6.678 1.433c5.222 1.129 9.801 4.36 12.736 8.988l3.31 5.231a25.023 25.023 0 0 0 3.083 4.862 24.214 24.214 0 0 0 8.008 6.469" fill="#D2E3FC"/><path d="M380.571 193.596a23.405 23.405 0 0 0 12.022 2.444 23.544 23.544 0 0 0 9.972-2.957 24.527 24.527 0 0 0 7.869-7.019 25.66 25.66 0 0 0 4.325-9.795 26.16 26.16 0 0 0-.012-10.777 25.637 25.637 0 0 0-4.346-9.785 24.497 24.497 0 0 0-7.884-7.001 23.549 23.549 0 0 0-9.978-2.935 23.27 23.27 0 0 0-5.595.338l-6.018.369h-.345" fill="#4285F4"/><path d="M333.714 163.02c12.561 0 22.744-10.582 22.744-23.636 0-13.054-10.183-23.636-22.744-23.636s-22.743 10.582-22.743 23.636c0 13.054 10.182 23.636 22.743 23.636zm76.682-58.778h11.85" stroke="#4285F4" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/><path d="M403.857 105.839c.849 0 1.536-.715 1.536-1.597s-.687-1.597-1.536-1.597-1.537.715-1.537 1.597.688 1.597 1.537 1.597z" fill="#4285F4"/><mask id="a" maskUnits="userSpaceOnUse" x="332" y="131" width="49" height="63"><path d="M380.571 146.488c-5.209.224-10.298-1.663-14.194-5.262l-5.092-4.709-2.315-1.934a17.18 17.18 0 0 0-1.852-1.137 16.487 16.487 0 0 0-6.384-1.837 16.36 16.36 0 0 0-6.574.844 16.806 16.806 0 0 0-5.762 3.397 17.525 17.525 0 0 0-4.071 5.431 18.253 18.253 0 0 0-.936 13.468 17.791 17.791 0 0 0 3.277 5.983 17.062 17.062 0 0 0 5.232 4.222c.639.328 1.297.615 1.97.86h.049s2.768.758 2.847.768l6.678 1.433c5.222 1.129 9.801 4.36 12.736 8.988l3.31 5.231a25.023 25.023 0 0 0 3.083 4.862 24.226 24.226 0 0 0 8.008 6.469" fill="#D2E3FC"/></mask><g mask="url(#a)"><path d="M333.714 163.02c12.561 0 22.744-10.582 22.744-23.636 0-13.054-10.183-23.636-22.744-23.636s-22.743 10.582-22.743 23.636c0 13.054 10.182 23.636 22.743 23.636z" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></g><path d="M99.748 162.416a24.382 24.382 0 0 1 9.84-1.028 24.595 24.595 0 0 1 9.467 2.971 25.54 25.54 0 0 1 7.647 6.517 26.638 26.638 0 0 1 4.659 9.066 27.275 27.275 0 0 1 .957 10.229 27.036 27.036 0 0 1-2.889 9.829 26.104 26.104 0 0 1-6.296 7.926 24.985 24.985 0 0 1-8.738 4.812" fill="#F882FF"/><path d="M85.14 118.03l30.899 109.531 107.001-1.31" stroke="#4285F4" stroke-width="6" stroke-linejoin="round"/><path d="M178.045 129.966a17.323 17.323 0 0 1 .283-6.508 16.966 16.966 0 0 1 2.661-5.898 16.303 16.303 0 0 1 4.633-4.387 15.668 15.668 0 0 1 5.898-2.206l37.105-5.957a15.45 15.45 0 0 1 6.255.292 15.788 15.788 0 0 1 5.671 2.759 16.453 16.453 0 0 1 4.223 4.804 17.097 17.097 0 0 1 2.133 6.117v0a17.321 17.321 0 0 1-.278 6.5 16.985 16.985 0 0 1-2.651 5.893 16.284 16.284 0 0 1-4.621 4.39 15.668 15.668 0 0 1-5.886 2.216l-37.105 5.948a15.463 15.463 0 0 1-6.265-.276 15.777 15.777 0 0 1-5.685-2.752 16.446 16.446 0 0 1-4.234-4.807 17.113 17.113 0 0 1-2.137-6.128v0z" stroke="#FE2C25" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/><mask id="b" maskUnits="userSpaceOnUse" x="143" y="126" width="54" height="56"><path d="M193.845 126.414l-49.152 13.901a2.062 2.062 0 0 0-.932.563c-.258.27-.443.606-.536.973-.092.368-.09.755.006 1.121.097.367.285.7.546.967l36.15 37.281c.261.268.586.459.942.554.356.095.729.09 1.083-.014.353-.104.673-.304.929-.578.255-.275.435-.615.523-.985l12.992-51.183a2.247 2.247 0 0 0-.021-1.105 2.18 2.18 0 0 0-.543-.949 2.056 2.056 0 0 0-.924-.546 1.998 1.998 0 0 0-1.063 0z" fill="#FFBA00"/></mask><g mask="url(#b)"><path d="M178.045 129.966a17.323 17.323 0 0 1 .283-6.508 16.966 16.966 0 0 1 2.661-5.898 16.303 16.303 0 0 1 4.633-4.387 15.668 15.668 0 0 1 5.898-2.206l37.105-5.957a15.45 15.45 0 0 1 6.255.292 15.788 15.788 0 0 1 5.671 2.759 16.453 16.453 0 0 1 4.223 4.804 17.097 17.097 0 0 1 2.133 6.117v0a17.321 17.321 0 0 1-.278 6.5 16.985 16.985 0 0 1-2.651 5.893 16.284 16.284 0 0 1-4.621 4.39 15.668 15.668 0 0 1-5.886 2.216l-37.105 5.948a15.463 15.463 0 0 1-6.265-.276 15.777 15.777 0 0 1-5.685-2.752 16.446 16.446 0 0 1-4.234-4.807 17.113 17.113 0 0 1-2.137-6.128v0z" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"/></g></svg>
\ No newline at end of file diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/all_set_2x.svg b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/all_set_2x.svg new file mode 100644 index 00000000000..0ea7ffbff02 --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/all_set_2x.svg @@ -0,0 +1 @@ +<svg width="1040" height="640" fill="none" xmlns="http://www.w3.org/2000/svg"><path fill="#fff" d="M0 0h1040v640H0z"/><path d="M873.039 193.068h-98.441c-7.431 0-13.455 6.26-13.455 13.983v233.371c0 7.723 6.024 13.983 13.455 13.983h98.441c7.431 0 13.455-6.26 13.455-13.983V207.051c0-7.723-6.024-13.983-13.455-13.983z" fill="#D2E3FC"/><path d="M873.039 193.068h-98.441c-7.431 0-13.455 6.26-13.455 13.983v233.371c0 7.723 6.024 13.983 13.455 13.983h98.441c7.431 0 13.455-6.26 13.455-13.983V207.051c0-7.723-6.024-13.983-13.455-13.983z" fill="#D2E3FC"/><path d="M568.831 228.445c7.519 0 13.613-6.334 13.613-14.147 0-7.813-6.094-14.147-13.613-14.147-7.518 0-13.612 6.334-13.612 14.147 0 7.813 6.094 14.147 13.612 14.147z" fill="#34A853"/><path d="M387.689 252.828l-98.303 27.803a4.128 4.128 0 0 0-1.865 1.126 4.372 4.372 0 0 0-1.07 1.946 4.48 4.48 0 0 0 .012 2.242c.194.733.57 1.4 1.091 1.933l72.299 74.563a4.13 4.13 0 0 0 1.885 1.107 4.01 4.01 0 0 0 2.165-.028 4.122 4.122 0 0 0 1.858-1.157 4.364 4.364 0 0 0 1.046-1.97l25.984-102.365a4.49 4.49 0 0 0-.04-2.209 4.364 4.364 0 0 0-1.087-1.899 4.115 4.115 0 0 0-1.849-1.092 4.006 4.006 0 0 0-2.126 0z" fill="#FFBA00"/><path d="M761.142 292.976c-10.417.448-20.595-3.325-28.388-10.523l-10.185-9.418-4.629-3.869a34.255 34.255 0 0 0-3.704-2.273 32.946 32.946 0 0 0-12.768-3.675 32.732 32.732 0 0 0-13.149 1.688 33.644 33.644 0 0 0-11.524 6.793 35.106 35.106 0 0 0-8.141 10.863 36.309 36.309 0 0 0-3.517 13.275 36.552 36.552 0 0 0 1.644 13.662 35.654 35.654 0 0 0 6.554 11.966 34.13 34.13 0 0 0 10.465 8.444 34.818 34.818 0 0 0 3.94 1.72h.098s5.536 1.515 5.693 1.535l13.357 2.866c10.443 2.257 19.602 8.72 25.472 17.976l6.619 10.461a50.166 50.166 0 0 0 6.166 9.725c4.394 5.446 9.854 9.857 16.017 12.939" fill="#D2E3FC"/><path d="M761.143 387.192a52.023 52.023 0 0 0 3.546 1.597 46.793 46.793 0 0 0 20.497 3.292 47.103 47.103 0 0 0 19.944-5.915c6.159-3.445 11.528-8.234 15.738-14.038 4.21-5.805 7.16-12.488 8.649-19.591a52.284 52.284 0 0 0-.023-21.554c-1.504-7.098-4.469-13.775-8.691-19.57s-9.602-10.572-15.768-14.002a47.09 47.09 0 0 0-19.957-5.869 46.49 46.49 0 0 0-11.19.676l-12.036.737h-.69" fill="#4285F4"/><path d="M667.429 326.04c25.122 0 45.487-21.165 45.487-47.273 0-26.107-20.365-47.272-45.487-47.272-25.122 0-45.488 21.165-45.488 47.272 0 26.108 20.366 47.273 45.488 47.273zm153.364-117.556h23.699" stroke="#4285F4" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/><path d="M807.714 211.678c1.697 0 3.073-1.43 3.073-3.194s-1.376-3.194-3.073-3.194-3.073 1.43-3.073 3.194 1.376 3.194 3.073 3.194z" fill="#4285F4"/><mask id="a" maskUnits="userSpaceOnUse" x="665" y="263" width="97" height="125"><path d="M761.142 292.976c-10.417.447-20.595-3.325-28.388-10.524l-10.185-9.417-4.629-3.87a34.405 34.405 0 0 0-3.704-2.272 32.946 32.946 0 0 0-12.768-3.675 32.732 32.732 0 0 0-13.149 1.688 33.628 33.628 0 0 0-11.524 6.793 35.106 35.106 0 0 0-8.141 10.863 36.304 36.304 0 0 0-3.517 13.274 36.557 36.557 0 0 0 1.644 13.663 35.64 35.64 0 0 0 6.554 11.965 34.119 34.119 0 0 0 10.465 8.445 34.818 34.818 0 0 0 3.94 1.72h.098s5.536 1.515 5.693 1.535l13.357 2.866c10.443 2.257 19.602 8.72 25.472 17.975l6.619 10.462a50.197 50.197 0 0 0 6.166 9.725c4.394 5.446 9.854 9.857 16.017 12.939" fill="#D2E3FC"/></mask><g mask="url(#a)"><path d="M667.429 326.04c25.122 0 45.487-21.165 45.487-47.273 0-26.107-20.365-47.272-45.487-47.272-25.122 0-45.488 21.165-45.488 47.272 0 26.108 20.366 47.273 45.488 47.273z" stroke="#fff" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/></g><path d="M199.496 324.832a48.765 48.765 0 0 1 19.68-2.056 49.19 49.19 0 0 1 18.934 5.943c5.873 3.256 11.071 7.685 15.294 13.033a53.257 53.257 0 0 1 9.317 18.132 54.55 54.55 0 0 1 1.915 20.458A54.092 54.092 0 0 1 258.857 400c-3.152 6.093-7.431 11.481-12.59 15.852-5.16 4.372-11.099 7.643-17.477 9.625" fill="#F882FF"/><path d="M170.279 236.061l61.799 219.061 214.001-2.621" stroke="#4285F4" stroke-width="12" stroke-linejoin="round"/><path d="M356.091 259.932a34.598 34.598 0 0 1 .564-13.015 33.917 33.917 0 0 1 5.323-11.796 32.527 32.527 0 0 1 9.267-8.774 31.303 31.303 0 0 1 11.795-4.413l74.21-11.915a30.918 30.918 0 0 1 12.51.586 31.566 31.566 0 0 1 11.342 5.517 32.914 32.914 0 0 1 8.446 9.607 34.203 34.203 0 0 1 4.266 12.236v0a34.616 34.616 0 0 1-.556 12.999 33.93 33.93 0 0 1-5.303 11.787 32.561 32.561 0 0 1-9.241 8.779 31.31 31.31 0 0 1-11.771 4.433l-74.21 11.894c-4.171.675-8.43.488-12.531-.551a31.546 31.546 0 0 1-11.37-5.504 32.897 32.897 0 0 1-8.468-9.615 34.155 34.155 0 0 1-4.273-12.255v0z" stroke="#FE2C25" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/><mask id="b" maskUnits="userSpaceOnUse" x="286" y="252" width="107" height="112"><path d="M387.689 252.828l-98.303 27.802a4.13 4.13 0 0 0-1.865 1.127 4.367 4.367 0 0 0-1.07 1.946 4.477 4.477 0 0 0 .012 2.241c.194.733.57 1.4 1.091 1.934l72.299 74.562a4.123 4.123 0 0 0 1.885 1.108 4.01 4.01 0 0 0 2.165-.029 4.129 4.129 0 0 0 1.858-1.156 4.37 4.37 0 0 0 1.046-1.97l25.984-102.365a4.49 4.49 0 0 0-.04-2.209 4.364 4.364 0 0 0-1.087-1.899 4.126 4.126 0 0 0-1.849-1.093 4.006 4.006 0 0 0-2.126.001z" fill="#FFBA00"/></mask><g mask="url(#b)"><path d="M356.091 259.932a34.598 34.598 0 0 1 .564-13.015 33.917 33.917 0 0 1 5.323-11.796 32.527 32.527 0 0 1 9.267-8.774 31.303 31.303 0 0 1 11.795-4.413l74.21-11.915a30.918 30.918 0 0 1 12.51.586 31.566 31.566 0 0 1 11.342 5.517 32.914 32.914 0 0 1 8.446 9.607 34.203 34.203 0 0 1 4.266 12.236v0a34.616 34.616 0 0 1-.556 12.999 33.93 33.93 0 0 1-5.303 11.787 32.561 32.561 0 0 1-9.241 8.779 31.31 31.31 0 0 1-11.771 4.433l-74.21 11.894c-4.171.675-8.43.488-12.531-.551a31.546 31.546 0 0 1-11.37-5.504 32.897 32.897 0 0 1-8.468-9.615 34.155 34.155 0 0 1-4.273-12.255v0z" stroke="#fff" stroke-width="6" stroke-linecap="round" stroke-linejoin="round"/></g></svg>
\ No newline at end of file diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.html index b448b290e00..cd25990692e 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.html @@ -27,7 +27,7 @@ } } </style> - <div id="shadow" hidden></div> + <div id="shadow" hidden$="[[!shouldShowShadow]]"></div> <div id="button-container"> <div id="backward" on-click="onBackwardButtonClicked_" @@ -47,6 +47,5 @@ </div> </div> </template> - <script src="button_bar.js"> - </script> + <script src="button_bar.js"></script> </dom-module> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.js index d3176fc6f14..c635763ead5 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/button_bar.js @@ -32,7 +32,6 @@ Polymer({ shouldShowShadow: { type: Boolean, value: false, - observer: 'onShouldShowShadowChange_', } }, @@ -50,9 +49,4 @@ Polymer({ onBackwardButtonClicked_() { this.fire('backward-navigation-requested'); }, - - /** @private */ - onShouldShowShadowChange_() { - this.$.shadow.hidden = !!this.shouldShowShadow; - }, }); diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.html index a2c17b6179d..55f5b15b2ab 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.html @@ -1,4 +1,3 @@ <link rel="import" href="../../../html/cr.html"> -<script src="fake_mojo_service.js"> -</script> +<script src="fake_mojo_service.js"></script> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.js index 965b3fb3a28..8c7af90e813 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/fake_mojo_service.js @@ -2,10 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// clang-format off +// #import {assertNotReached} from 'chrome://resources/js/assert.m.js'; +// clang-format on + /** * @implements {chromeos.multideviceSetup.mojom.MultiDeviceSetupInterface} */ -class FakeMojoService { +/* #export */ class FakeMojoService { constructor() { /** * The number of devices to return in a getEligibleHostDevices() call. diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/icons.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/icons.html index 10b457d3e43..c8544a0de02 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/icons.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/icons.html @@ -23,20 +23,20 @@ <svg> <defs> <g id="messages" fill="none" fill-rule="evenodd"> - <path d="M16.3107503,3 L3.66666667,3 C2.75,3 2,3.75 2,4.66666667 L2,18.3161621 L5.33333333,15 L16.3107503,15 C17.227417,15 17.977417,14.2328288 17.977417,13.3161621 L17.977417,4.66666667 C17.977417,3.75 17.227417,3 16.3107503,3 Z M16,13 L4,13 L4,5 L16,5 L16,13 Z M6,8 L8,8 L8,10 L6,10 L6,8 Z M9,8 L11,8 L11,10 L9,10 L9,8 Z M12,8 L14,8 L14,10 L12,10 L12,8 Z" fill="#9AA0A6"></path> + <path d="M16.3107503,3 L3.66666667,3 C2.75,3 2,3.75 2,4.66666667 L2,18.3161621 L5.33333333,15 L16.3107503,15 C17.227417,15 17.977417,14.2328288 17.977417,13.3161621 L17.977417,4.66666667 C17.977417,3.75 17.227417,3 16.3107503,3 Z M16,13 L4,13 L4,5 L16,5 L16,13 Z M6,8 L8,8 L8,10 L6,10 L6,8 Z M9,8 L11,8 L11,10 L9,10 L9,8 Z M12,8 L14,8 L14,10 L12,10 L12,8 Z" fill="#1E88E5"></path> </g> <g id="notifications" fill="none" fill-rule="evenodd"> - <path d="M11,3.10001812 C13.2822403,3.56328845 15,5.58104209 15,8 C15,10.7614237 15,13 15,13 L17,13 L17,15 L3,15 L3,13 L5,13 C5,13 5,9.9021552 5,8 C5,5.58104209 6.71775968,3.56328845 9,3.10001812 L9,2.5 C9,1.94771525 9.44771525,1.5 10,1.5 C10.5522847,1.5 11,1.94771525 11,2.5 L11,3.10001812 Z M7,8 L7,13 L13,13 L13,8 C13,6.34314575 11.6568542,5 10,5 C8.34314575,5 7,6.34314575 7,8 Z M10,18 C8.8954305,18 8,17.1045695 8,16 L12,16 C12,17.1045695 11.1045695,18 10,18 Z" fill="#9AA0A6"></path> + <path d="M11,3.10001812 C13.2822403,3.56328845 15,5.58104209 15,8 C15,10.7614237 15,13 15,13 L17,13 L17,15 L3,15 L3,13 L5,13 C5,13 5,9.9021552 5,8 C5,5.58104209 6.71775968,3.56328845 9,3.10001812 L9,2.5 C9,1.94771525 9.44771525,1.5 10,1.5 C10.5522847,1.5 11,1.94771525 11,2.5 L11,3.10001812 Z M7,8 L7,13 L13,13 L13,8 C13,6.34314575 11.6568542,5 10,5 C8.34314575,5 7,6.34314575 7,8 Z M10,18 C8.8954305,18 8,17.1045695 8,16 L12,16 C12,17.1045695 11.1045695,18 10,18 Z" fill="#1E88E5"></path> </g> <g id="wifi" fill="none" fill-rule="evenodd"> - <path d="M10.01 17.99L20 5.46C19.613 5.164 15.765 2 10 2 4.227 2 .387 5.165 0 5.46l9.99 12.53.01.01.01-.01z" fill="#9AA0A6" fill-opacity=".3"></path> - <path d="M2.942 9.143l7.05 8.85L10 18l.008-.008 7.05-8.85C16.7 8.867 14.008 6.668 10 6.668s-6.7 2.2-7.058 2.476z" fill="#9AA0A6"></path> + <path d="M10.01 17.99L20 5.46C19.613 5.164 15.765 2 10 2 4.227 2 .387 5.165 0 5.46l9.99 12.53.01.01.01-.01z" fill="#1E88E5" fill-opacity=".3"></path> + <path d="M2.942 9.143l7.05 8.85L10 18l.008-.008 7.05-8.85C16.7 8.867 14.008 6.668 10 6.668s-6.7 2.2-7.058 2.476z" fill="#1E88E5"></path> </g> <g id="downloads" fill="none" fill-rule="evenodd"> - <path d="M2,13 L4,13 L4,16 L16,16 L16,13 L18,13 L18,16 C18,17.1 17.1,18 16,18 L4,18 C2.9,18 2,17.1 2,16 L2,13 Z M13.59,7.59 L11,10.17 L11,2 L9,2 L9,10.17 L6.41,7.59 L5,9 L10,14 L15,9 L13.59,7.59 Z" fill="#9AA0A6"></path> + <path d="M2,13 L4,13 L4,16 L16,16 L16,13 L18,13 L18,16 C18,17.1 17.1,18 16,18 L4,18 C2.9,18 2,17.1 2,16 L2,13 Z M13.59,7.59 L11,10.17 L11,2 L9,2 L9,10.17 L6.41,7.59 L5,9 L10,14 L15,9 L13.59,7.59 Z" fill="#1E88E5"></path> </g> <g id="features" fill="none" fill-rule="evenodd"> - <path d="M5,5 L18,5 L18,3.5 L5.16080729,3.5 C4.24414063,3.5 3.49414062,4.23125 3.49414062,5.125 L3.49414062,14 L1,14 L1,17 L11,17 L11,14 L5,14 L5,5 Z M18.1666667,6.49829102 L13.3713582,6.49829102 C12.9130249,6.49829102 12.5,6.86391602 12.5,7.31079102 L12.5,16.171875 C12.5,16.61875 12.9130249,17 13.3713582,17 L18.1666667,17 C18.625,17 19,16.61875 19,16.171875 L19,7.31079102 C19,6.86391602 18.625,6.49829102 18.1666667,6.49829102 Z M17.5,14 L14,14 L14,8.5 L17.5,8.5 L17.5,14 Z" fill="#9AA0A6"></path> + <path d="M5,5 L18,5 L18,3.5 L5.16080729,3.5 C4.24414063,3.5 3.49414062,4.23125 3.49414062,5.125 L3.49414062,14 L1,14 L1,17 L11,17 L11,14 L5,14 L5,5 Z M18.1666667,6.49829102 L13.3713582,6.49829102 C12.9130249,6.49829102 12.5,6.86391602 12.5,7.31079102 L12.5,16.171875 C12.5,16.61875 12.9130249,17 13.3713582,17 L18.1666667,17 C18.625,17 19,16.61875 19,16.171875 L19,7.31079102 C19,6.86391602 18.625,6.49829102 18.1666667,6.49829102 Z M17.5,14 L14,14 L14,8.5 L17.5,8.5 L17.5,14 Z" fill="#1E88E5"></path> </g> </defs> </svg> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.js index c34499265b6..6d5ba3ad4ee 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.js @@ -2,9 +2,18 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// clang-format off +// #import {addSingletonGetter} from 'chrome://resources/js/cr.m.js'; +// #import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js'; +// #import 'chrome://resources/mojo/mojo/public/mojom/base/time.mojom-lite.js'; +// #import 'chrome://resources/mojo/chromeos/components/multidevice/mojom/multidevice_types.mojom-lite.js'; +// #import 'chrome://resources/mojo/chromeos/services/device_sync/public/mojom/device_sync.mojom-lite.js'; +// #import 'chrome://resources/mojo/chromeos/services/multidevice_setup/public/mojom/multidevice_setup.mojom-lite.js'; +// clang-format on + cr.define('multidevice_setup', function() { /** @interface */ - class MojoInterfaceProvider { + /* #export */ class MojoInterfaceProvider { /** * @return {!chromeos.multideviceSetup.mojom.MultiDeviceSetupRemote} */ @@ -12,7 +21,7 @@ cr.define('multidevice_setup', function() { } /** @implements {multidevice_setup.MojoInterfaceProvider} */ - class MojoInterfaceProviderImpl { + /* #export */ class MojoInterfaceProviderImpl { constructor() { /** @private {?chromeos.multideviceSetup.mojom.MultiDeviceSetupRemote} */ this.remote_ = null; @@ -31,6 +40,7 @@ cr.define('multidevice_setup', function() { cr.addSingletonGetter(MojoInterfaceProviderImpl); + // #cr_define_end return { MojoInterfaceProvider: MojoInterfaceProvider, MojoInterfaceProviderImpl: MojoInterfaceProviderImpl, diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html index 6e61d099146..5ee7f92a284 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.html @@ -10,6 +10,7 @@ <link rel="import" href="start_setup_page.html"> <link rel="import" href="../../../html/cr.html"> <link rel="import" href="../../../html/web_ui_listener_behavior.html"> +<link rel="import" href="chrome://resources/html/assert.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html"> <dom-module id="multidevice-setup"> @@ -31,8 +32,6 @@ height: 100%; line-height: 16px; margin: auto; - max-width: var(--multidevice-setup-width, var(--default-ui-width)); - padding: 32px; } iron-pages { @@ -40,26 +39,49 @@ padding: 0 32px; } + :host-context([new-layout]) iron-pages { + height: 100%; + padding: 0; + } + + :host-context([new-layout]) button-bar { + padding: 24px; + } + + @media screen and (orientation: portrait) { + :host-context([new-layout][screen=oobe]) button-bar, + :host-context([new-layout][screen=gaia-signin]) button-bar { + align-items: center; + } + } + + :host-context(html:not([new-layout])) #container { + max-width: var(--multidevice-setup-width, var(--default-ui-width)); + padding: 32px; + } + @media screen and (max-width: 767px) { /* On narrow screens, decrease width/padding. */ - #container { + :host-context(html:not([new-layout])) #container { height: auto; - /* Add height of buttons plus padding on top and bottom of buttons. */ + /* + * Add height of buttons plus padding on top and bottom of buttons. + */ margin-bottom: calc(var(--narrow-button-bar-height) + calc(2 * var(--narrow-button-bar-spacing))); padding: 32px 32px 0 32px; } - iron-pages { + :host-context(html:not([new-layout])) iron-pages { padding: 0; } /* - * Fix the button bar to the bottom of the window. Some content may be - * beneath the button bar, so make the background slightly transparent - * so that the content can be seen. - */ - button-bar { + * Fix the button bar to the bottom of the window. Some content may be + * beneath the button bar, so make the background slightly transparent + * so that the content can be seen. + */ + :host-context(html:not([new-layout])) button-bar { background: rgba(255, 255, 255, 0.9); bottom: 0; height: var(--narrow-button-bar-height); @@ -105,6 +127,5 @@ </button-bar> </div> </template> - <script src="multidevice_setup.js"> - </script> + <script src="multidevice_setup.js"></script> </dom-module> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js index a565031984e..241167e28dc 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup.js @@ -4,7 +4,7 @@ cr.define('multidevice_setup', function() { /** @enum {string} */ - const PageName = { + /* #export */ const PageName = { PASSWORD: 'password-page', SUCCESS: 'setup-succeeded-page', START: 'start-setup-page', @@ -176,6 +176,7 @@ cr.define('multidevice_setup', function() { }, initializeSetupFlow() { + this.$$('start-setup-page').setPlayAnimation(true); this.mojoInterfaceProvider_.getMojoServiceRemote() .getEligibleActiveHostDevices() .then((responseParams) => { @@ -364,10 +365,12 @@ cr.define('multidevice_setup', function() { * @private */ exitSetupFlow_(didUserCompleteSetup) { + this.$$('start-setup-page').setPlayAnimation(false); this.fire('setup-exited', {didUserCompleteSetup: didUserCompleteSetup}); }, }); + // #cr_define_end return { MultiDeviceSetup: MultiDeviceSetup, PageName: PageName, diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.html index 38c23fdedf0..29e0582cae9 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.html @@ -1,3 +1,2 @@ <link rel="import" href="../../../html/cr.html"> -<script src="multidevice_setup_browser_proxy.js"> -</script> +<script src="multidevice_setup_browser_proxy.js"></script> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.js index be88d746277..841f851c376 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.js @@ -2,9 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// clang-format off +// #import {addSingletonGetter, sendWithPromise} from 'chrome://resources/js/cr.m.js'; +// clang-format on + cr.define('multidevice_setup', function() { /** @interface */ - class BrowserProxy { + /* #export */ class BrowserProxy { /** * Requests profile information; namely, a dictionary containing the user's * e-mail address and profile photo. @@ -20,7 +24,7 @@ cr.define('multidevice_setup', function() { } /** @implements {multidevice_setup.BrowserProxy} */ - class BrowserProxyImpl { + /* #export */ class BrowserProxyImpl { /** @override */ getProfileInfo() { return cr.sendWithPromise('getProfileInfo'); @@ -34,6 +38,7 @@ cr.define('multidevice_setup', function() { cr.addSingletonGetter(BrowserProxyImpl); + // #cr_define_end return { BrowserProxy: BrowserProxy, BrowserProxyImpl: BrowserProxyImpl, diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.html index 22e3eb30088..6995ddafd40 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.html @@ -1,4 +1,3 @@ <link rel="import" href="../../../html/cr.html"> -<script src="multidevice_setup_delegate.js"> -</script> +<script src="multidevice_setup_delegate.js"></script> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.js index 448de24c41d..60f52a81c8e 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.js @@ -8,7 +8,7 @@ cr.define('multidevice_setup', function() { * related logic. * @interface */ - class MultiDeviceSetupDelegate { + /* #export */ class MultiDeviceSetupDelegate { /** @return {boolean} */ isPasswordRequiredToSetHost() {} @@ -29,6 +29,7 @@ cr.define('multidevice_setup', function() { getStartSetupCancelButtonTextId() {} } + // #cr_define_end return { MultiDeviceSetupDelegate: MultiDeviceSetupDelegate, }; diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.html index 1d1b634c8f8..e9d6365feb3 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/password_page.html @@ -1,5 +1,6 @@ <link rel="import" href="../../../html/polymer.html"> +<link rel="import" href="multidevice_setup_browser_proxy.html"> <link rel="import" href="multidevice_setup_shared_css.html"> <link rel="import" href="ui_page.html"> <link rel="import" href="ui_page_container_behavior.html"> @@ -13,6 +14,7 @@ align-items: center; color: var(--paper-grey-600); display: flex; + padding-top: 32px; } #profile-photo { @@ -24,13 +26,33 @@ #passwordInput { height: 32px; - margin-top: 64px; + margin-top: 48px; width: 100%; } + + :host-context([new-layout][orientation=horizontal]) #passwordInput { + width: min(calc(var(--multidevice-setup-dialog-width) - + 2 * var(--multidevice-setup-dialog-content-padding)), 640px); + } + + :host-context([new-layout][orientation=vertical]) #passwordInput { + width: min(calc(var(--multidevice-setup-dialog-width) - + 2 * var(--multidevice-setup-dialog-content-padding)), 480px); + } + + :host-context([new-layout][orientation=vertical]) #content-container { + align-items: center; + display: flex; + flex-direction: column; + } + + :host-context([new-layout][orientation=horizontal]) #user-info-container { + padding-top: 0; + } </style> <ui-page header-text="[[i18nDynamic(locale, 'passwordPageHeader')]]" icon-name="google-g"> - <div id="content-container" slot="additional-content"> + <div id="content-container" slot="message"> <div id="user-info-container"> <img id="profile-photo" src="[[profilePhotoUrl_]]"></img> <span id="email">[[email_]]</span> @@ -46,6 +68,5 @@ </div> </ui-page> </template> - <script src="password_page.js"> - </script> + <script src="password_page.js"></script> </dom-module> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_icon_1x.png b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_icon_1x.png Binary files differdeleted file mode 100644 index 03074bd5735..00000000000 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_icon_1x.png +++ /dev/null diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_icon_2x.png b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_icon_2x.png Binary files differdeleted file mode 100644 index 271b0484e3e..00000000000 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_icon_2x.png +++ /dev/null diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.html index fefc1dc6e55..e23c207471d 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/setup_succeeded_page.html @@ -10,27 +10,28 @@ <template> <style include="multidevice-setup-shared"> #page-icon-container { + align-items: center; display: flex; + flex: 1; + flex-direction: column; justify-content: center; } - #page-icon { - background-image: -webkit-image-set( - url(setup_succeeded_icon_1x.png) 1x, - url(setup_succeeded_icon_2x.png) 2x); - height: 156px; - margin-top: 64px; - width: 416px; + img { + max-height: 100%; + max-width: 100%; + object-fit: contain; } </style> <ui-page header-text="[[i18nDynamic(locale, 'setupSucceededPageHeader')]]" icon-name="google-g"> <span slot="message" inner-h-t-m-l="[[getMessageHtml_()]]"></span> <div id="page-icon-container" slot="additional-content"> - <div id="page-icon"></div> + <img id="success-img" aria-hidden="true" + srcset="chrome://resources/cr_components/chromeos/multidevice_setup/all_set_1x.svg 1x, + chrome://resources/cr_components/chromeos/multidevice_setup/all_set_2x.svg 2x"> </div> </ui-page> </template> - <script src="setup_succeeded_page.js"> - </script> + <script src="setup_succeeded_page.js"></script> </dom-module> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.html index 6ed75f58049..4af72ffac47 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.html @@ -1,108 +1,146 @@ <link rel="import" href="../../../html/polymer.html"> <link rel="import" href="icons.html"> +<link rel="import" href="mojo_api.html"> +<link rel="import" href="multidevice_setup_delegate.html"> <link rel="import" href="multidevice_setup_shared_css.html"> <link rel="import" href="ui_page.html"> <link rel="import" href="ui_page_container_behavior.html"> <link rel="import" href="../../../html/cr.html"> <link rel="import" href="../../../html/web_ui_listener_behavior.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_lottie/cr_lottie.html"> +<link rel="import" href="chrome://resources/html/load_time_data.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <dom-module id="start-setup-page"> <template> <style include="multidevice-setup-shared"> - #selector-and-details-container { - display: flex; - margin-top: 20px; - min-height: 246px; + #multidevice-summary-message a { + display: inline-block; + } + + .feature-detail iron-icon { + --iron-icon-height: 20px; + --iron-icon-width: 20px; + min-width: 20px; } #singleDeviceName { color: var(--google-grey-900); - margin-top: 16px; + } + + .offline-device-name { + color: var(--google-grey-700); + } + + #animation-container { + padding-inline-end: 8px; + padding-top: 16px; + } + + .footnote { + padding-top: 16px; + } + + #deviceSelectionContainer { + display: flex; + flex-direction: column; } #deviceDropdown { - margin-top: 16px; + margin-top: 8px; } - .offline-device-name { - color: var(--google-grey-600); + #singleDeviceName { + margin-top: 8px; } - #page-icon-container { + .feature-detail { + align-items: center; + box-sizing: border-box; display: flex; - justify-content: center; + min-height: 48px; + padding: 12px 0; + } + + #image-container { + display: flex; + flex: 1; + flex-direction: column; } #page-icon { - background-image: -webkit-image-set(url(start_setup_icon_1x.png) 1x, - url(start_setup_icon_2x.png) 2x); + background-image: -webkit-image-set(url(chrome://resources/cr_components/chromeos/multidevice_setup/start_setup_icon_1x.png) 1x, + url(chrome://resources/cr_components/chromeos/multidevice_setup/start_setup_icon_2x.png) 2x); height: 116px; margin-top: 10px; width: 320px; } - #deviceSelectionContainer { - color: var(--paper-grey-600); + #page-icon-container { display: flex; - flex-direction: column; + justify-content: center; } - #feature-details-container { - border-inline-start: 1px solid rgb(218, 220, 224); + #feature-details-container-header { + margin-bottom: 16px; + } + + :host-context([new-layout][orientation=horizontal]) + #additional-content-container { display: flex; flex-direction: column; justify-content: center; - padding-inline-start: 24px; } - #feature-details-container-header { - margin-bottom: 18px; + :host-context([new-layout]) #feature-details-container { + color: var(--google-grey-900); + padding-top: 40px; } - .feature-detail { - align-items: center; - box-sizing: border-box; - display: flex; - padding: 10px 0; + :host-context([new-layout]) .feature-detail:not(:last-child) { + border-bottom: 1px solid rgba(0, 0, 0, 0.08); } - .feature-detail iron-icon { - --iron-icon-height: 20px; - --iron-icon-width: 20px; - min-width: 20px; + :host-context([new-layout]) .feature-detail iron-icon { + padding: 0 20px; } - .feature-detail span { - margin-inline-start: 8px; + :host-context(html:not([new-layout])) #selector-and-details-container { + display: flex; + margin-top: 20px; + min-height: 246px; } - #footnote { - color: var(--paper-grey-600); - padding-top: 12px; + :host-context(html:not([new-layout])) #feature-details-container { + border-inline-start: 1px solid rgb(218, 220, 224); + padding-inline-start: 24px; } - #multidevice-summary-message a { - display: inline-block; + :host-context(html:not([new-layout])) .feature-detail span { + margin-inline-start: 8px; } /* On devices with small screens, use a single-column layout. */ @media screen and (max-width: 767px) { - #selector-and-details-container { + :host-context(html:not([new-layout])) #selector-and-details-container { display: flex; flex-direction: column; margin-top: 32px; } - #feature-details-container { + :host-context(html:not([new-layout])) #feature-details-container { border-inline-start: none; margin-top: 32px; padding-inline-start: inherit; } + } - .feature-detail { - min-height: 45px; + @media screen and (max-height: 736px) { + :host-context([screen=oobe]) #animation-container, + :host-context([screen=gaia-signin]) #animation-container { + height: 143px; + padding-top: 0; } } </style> @@ -112,7 +150,15 @@ <span slot="message" id="multidevice-summary-message" inner-h-t-m-l= "[[i18nAdvancedDynamic_(locale, 'startSetupPageMessage')]]"> </span> - <div slot="additional-content"> + <span slot="message" hidden$="[[!newLayoutEnabled_]]"> + <div id="animation-container"> + <cr-lottie id="multideviceSetupAnimation" + animation-url="multidevice_setup.json"> + </cr-lottie> + </div> + </span> + <div id="additional-content-container" slot="additional-content" + class="flex"> <div id="selector-and-details-container"> <div id="deviceSelectionContainer" class="flex"> [[getDeviceSelectionHeader_(devices)]] @@ -133,35 +179,21 @@ </template> </select> </div> - <div class="flex"></div> - <div id="page-icon-container"> - <div id="page-icon"></div> - </div> - <div class="flex"></div> - <div id="footnote"> - [[i18nAdvancedDynamic_(locale, 'startSetupPageFootnote')]] + <div id="image-container" hidden$="[[newLayoutEnabled_]]"> + <div class="flex"></div> + <div id="page-icon-container"> + <div id="page-icon"></div> + </div> + <div class="flex"></div> + <div class="footnote"> + [[i18nAdvancedDynamic_(locale, 'startSetupPageFootnote')]] + </div> </div> </div> <div id="feature-details-container" class="flex"> <div id="feature-details-container-header"> [[i18nDynamic(locale, 'startSetupPageFeatureListHeader')]] </div> - <div class="feature-detail"> - <iron-icon icon="multidevice-setup-icons-20:messages"></iron-icon> - <span id="awm-summary-message" inner-h-t-m-l=" - [[i18nAdvancedDynamic_( - locale, 'startSetupPageFeatureListAwm')]]"> - </span> - </div> - <template is="dom-if" if="[[phoneHubEnabled_]]"> - <div class="feature-detail"> - <iron-icon icon="multidevice-setup-icons-20:notifications"> - </iron-icon> - <span> - [[i18nDynamic(locale, 'startSetupPageFeatureMirrorPhoneNotifications')]] - </span> - </div> - </template> <template is="dom-if" if="[[wifiSyncEnabled_]]"> <div class="feature-detail"> <iron-icon icon="multidevice-setup-icons-20:wifi"> @@ -172,23 +204,18 @@ </div> </template> <div class="feature-detail"> - <iron-icon icon="multidevice-setup-icons-20:downloads"> - </iron-icon> - <span> - [[i18nDynamic(locale, 'startSetupPageFeatureListInstallApps')]] - </span> - </div> - <div class="feature-detail"> <iron-icon icon="multidevice-setup-icons-20:features"></iron-icon> <span> [[i18nDynamic(locale, 'startSetupPageFeatureListAddFeatures')]] </span> </div> </div> + <div class="footnote" hidden$="[[!newLayoutEnabled_]]"> + [[i18nAdvancedDynamic_(locale, 'startSetupPageFootnote')]] + </div> </div> </div> </ui-page> </template> - <script src="start_setup_page.js"> - </script> + <script src="start_setup_page.js"></script> </dom-module> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.js index 234c722d45d..a5a7b033c9a 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/start_setup_page.js @@ -53,21 +53,25 @@ Polymer({ delegate: Object, /** @private */ - phoneHubEnabled_: { + wifiSyncEnabled_: { type: Boolean, value() { - return loadTimeData.valueExists('phoneHubEnabled') && - loadTimeData.getBoolean('phoneHubEnabled'); + return loadTimeData.valueExists('wifiSyncEnabled') && + loadTimeData.getBoolean('wifiSyncEnabled'); }, }, - /** @private */ - wifiSyncEnabled_: { + /** + * Whether new OOBE layout is enabled. + * + * @type {boolean} + */ + newLayoutEnabled_: { type: Boolean, value() { - return loadTimeData.valueExists('wifiSyncEnabled') && - loadTimeData.getBoolean('wifiSyncEnabled'); - }, + return loadTimeData.valueExists('newLayoutEnabled') && + loadTimeData.getBoolean('newLayoutEnabled'); + } }, }, @@ -83,6 +87,15 @@ Polymer({ this.initializeSetupFlow_.bind(this)); }, + /** + * This will play or stop the screen's lottie animation. + * @param {boolean} enabled Whether the animation should play or not. + */ + setPlayAnimation(enabled) { + /** @type {!CrLottieElement} */ (this.$.multideviceSetupAnimation) + .setPlay(enabled); + }, + /** @private */ initializeSetupFlow_() { // The "Learn More" links are inside a grdp string, so we cannot actually @@ -90,7 +103,6 @@ Polymer({ // manaully add onclick handlers. const helpArticleLinks = [ this.$$('#multidevice-summary-message a'), - this.$$('#awm-summary-message a') ]; for (let i = 0; i < helpArticleLinks.length; i++) { helpArticleLinks[i].onclick = this.fire.bind( diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page.html index 1bdfe7b6e32..c6b77e6bcdb 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page.html @@ -1,5 +1,5 @@ <link rel="import" href="../../../html/polymer.html"> - +<link rel="import" href="chrome://resources/html/load_time_data.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <link rel="import" href="icons.html"> <link rel="import" href="multidevice_setup_shared_css.html"> @@ -7,6 +7,39 @@ <dom-module id="ui-page"> <template> <style include="multidevice-setup-shared"> + :host { + --multidevice-setup-dialog-height: var(--oobe-oobe-dialog-height-base); + --multidevice-setup-dialog-width: var(--oobe-oobe-dialog-width-base); + --multidevice-setup-dialog-content-padding: 40px; + } + + :host-context([orientation=horizontal]) { + --multidevice-setup-dialog-content-direction: row; + --multidevice-setup-dialog-item-alignment: unset; + --multidevice-setup-text-alignment: start; + --multidevice-setup-dialog-content-width: calc( + var(--multidevice-setup-dialog-width) - + 4 * var(--multidevice-setup-dialog-content-padding) - + var(--multidevice-setup-dialog-header-width)); + /* Header takes 40% of the width remaining after applying padding */ + --multidevice-setup-dialog-header-width: clamp(302px, + calc(0.4 * (var(--multidevice-setup-dialog-width) - + 4 * var(--multidevice-setup-dialog-content-padding))) , 346px); + } + + :host-context([orientation=vertical]) { + --multidevice-setup-dialog-content-direction: column; + --multidevice-setup-dialog-item-alignment: center; + --multidevice-setup-text-alignment: center; + --multidevice-setup-dialog-content-width: calc( + var(--multidevice-setup-dialog-width) - + 2 * var(--multidevice-setup-dialog-content-padding)); + /* Header takes 60% of the width remaining after applying padding */ + --multidevice-setup-dialog-header-width: clamp(346px, + calc(0.6 * (var(--multidevice-setup-dialog-width) - + 2 * var(--multidevice-setup-dialog-content-padding))) , 520px); + } + iron-icon { --iron-icon-width: 32px; --iron-icon-height: 32px; @@ -14,29 +47,96 @@ h1 { color: var(--google-grey-900); - font-family: 'Google Sans'; + font-family: 'Google Sans', Roboto, sans-serif; font-size: 28px; font-weight: normal; line-height: 28px; margin: 0; - padding-top: 36px; + padding-top: 40px; } #message-container { - box-sizing: border-box; min-height: 32px; padding-top: 16px; } + + :host-context([new-layout]) #message-container { + color: var(--google-grey-700); + line-height: 18px; + overflow-wrap: break-word; + text-align: var(--multidevice-setup-text-alignment); + } + + :host-context([new-layout]) #main-container { + align-items: var(--multidevice-setup-dialog-item-alignment); + display: flex; + flex-direction: var(--multidevice-setup-dialog-content-direction); + height: 100%; + } + + :host-context([new-layout]) #header-container { + align-items: var(--multidevice-setup-dialog-item-alignment); + display: flex; + flex-direction: column; + padding-bottom: 0; + padding-inline-end: var(--multidevice-setup-dialog-content-padding); + padding-inline-start: var(--multidevice-setup-dialog-content-padding); + padding-top: var(--multidevice-setup-dialog-content-padding); + width: var(--multidevice-setup-dialog-header-width); + } + + :host-context([new-layout][screen=oobe]) #header-container, + :host-context([new-layout][screen=gaia-signin]) #header-container { + padding-top: calc(var(--multidevice-setup-dialog-content-padding) + + 2 * min(40px, max(24px, calc(var(--multidevice-setup-dialog-height) + * 0.025))) + 32px); + } + + :host-context([new-layout]) #additional-content-container { + border: transparent; + display: flex; + flex: 1; + padding-bottom: 0; + padding-inline-end: var(--multidevice-setup-dialog-content-padding); + padding-inline-start: var(--multidevice-setup-dialog-content-padding); + padding-top: 0; + width: var(--multidevice-setup-dialog-content-width); + } + + :host-context([new-layout][orientation=vertical]) + #additional-content-container { + margin-top: 40px; + } + + :host-context([new-layout][orientation=horizontal][screen=oobe]) + #additional-content-container, + :host-context([new-layout][orientation=horizontal][screen=gaia-signin]) + #additional-content-container { + margin-top: 80px; + } + + :host-context([new-layout][screen=oobe]) #additional-content-container, + :host-context([new-layout][screen=gaia-signin]) + #additional-content-container { + overflow-y: auto; + } + + :host-context([new-layout]) h1 { + text-align: var(--multidevice-setup-text-alignment); + } </style> - <iron-icon icon="[[computeIconIdentifier_(iconName)]]"></iron-icon> - <h1>[[headerText]]</h1> - <div id="message-container"> - <slot name="message"></slot> - </div> - <div id="additional-content-container"> - <slot name="additional-content"></slot> + <div id="main-container"> + <div id="header-container"> + <iron-icon icon="[[computeIconIdentifier_(iconName)]]"></iron-icon> + <h1>[[headerText]]</h1> + <div id="message-container"> + <slot name="message"></slot> + </div> + </div> + <div id="additional-content-container"> + <slot name="additional-content"></slot> + </div> </div> </template> - <script src="ui_page.js"> - </script> + <script src="ui_page.js"></script> </dom-module> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.html b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.html index 3485a99540e..020f05077ed 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.html @@ -1,5 +1,4 @@ <link rel="import" href="../../../html/cr.html"> <link rel="import" href="../../../html/i18n_behavior.html"> -<script src="ui_page_container_behavior.js"> -</script> +<script src="ui_page_container_behavior.js"></script> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.js b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.js index 785a3e7a893..06603d543bb 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.js @@ -2,6 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// clang-format off +// #import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js'; +// clang-format on + /** @polymerBehavior */ const UiPageContainerBehaviorImpl = { properties: { @@ -45,7 +49,7 @@ const UiPageContainerBehaviorImpl = { }; /** @polymerBehavior */ -const UiPageContainerBehavior = [ +/* #export */ const UiPageContainerBehavior = [ I18nBehavior, UiPageContainerBehaviorImpl, ]; diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/network/BUILD.gn index 1a9096bdc1b..636bafc181c 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/BUILD.gn +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/BUILD.gn @@ -8,7 +8,9 @@ import("../os_cr_components.gni") assert(is_chromeos, "Only ChromeOS components belong here.") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ + ":cellular_utils", ":cr_policy_network_behavior_mojo", ":cr_policy_network_indicator_mojo", ":mojo_interface_provider", @@ -212,6 +214,7 @@ js_library("network_list") { js_library("network_list_item") { deps = [ ":cr_policy_network_behavior_mojo", + ":mojo_interface_provider", ":network_list_types", "//ui/webui/resources/js:assert", "//ui/webui/resources/js:i18n_behavior", @@ -249,9 +252,17 @@ js_library("onc_mojo") { ] } +js_library("cellular_utils") { + deps = [ + ":mojo_interface_provider", + ":onc_mojo", + ] +} + js_type_check("closure_compile_module") { is_polymer3 = true deps = [ + ":cellular_utils.m", ":cr_policy_network_behavior_mojo.m", ":cr_policy_network_indicator_mojo.m", ":mojo_interface_provider.m", @@ -440,6 +451,7 @@ js_library("network_list.m") { deps = [ ":network_list_item.m", ":network_list_types.m", + ":onc_mojo.m", "//third_party/polymer/v3_0/components-chromium/iron-list:iron-list", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", "//ui/webui/resources/cr_elements:cr_scrollable_behavior.m", @@ -451,7 +463,11 @@ js_library("network_list.m") { js_library("network_list_item.m") { sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network/network_list_item.m.js" ] deps = [ + ":cr_policy_network_behavior_mojo.m", + ":mojo_interface_provider.m", ":network_list_types.m", + ":onc_mojo.m", + "//third_party/polymer/v3_0/components-chromium/paper-spinner:paper-spinner-lite", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", "//ui/webui/resources/js/cr/ui:focus_row_behavior.m", ] @@ -460,6 +476,7 @@ js_library("network_list_item.m") { js_library("network_list_types.m") { sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network/network_list_types.m.js" ] + deps = [ ":onc_mojo.m" ] extra_deps = [ ":modulize" ] } @@ -610,6 +627,15 @@ js_library("onc_mojo.m") { extra_deps = [ ":modulize" ] } +js_library("cellular_utils.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network/cellular_utils.m.js" ] + deps = [ + ":mojo_interface_provider.m", + ":onc_mojo.m", + ] + extra_deps = [ ":modulize" ] +} + import("//tools/polymer/polymer.gni") group("polymer3_elements") { @@ -729,6 +755,7 @@ polymer_modulizer("network_list_item") { html_file = "network_list_item.html" html_type = "dom-module" auto_imports = cr_components_chromeos_auto_imports + namespace_rewrites = cr_components_chromeos_namespace_rewrites } polymer_modulizer("network_nameservers") { @@ -805,6 +832,7 @@ js_modulizer("modulize") { "cr_policy_network_behavior_mojo.js", "mojo_interface_provider.js", "network_config_element_behavior.js", + "cellular_utils.js", "network_listener_behavior.js", "network_list_types.js", "onc_mojo.js", diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/cellular_utils.html b/chromium/ui/webui/resources/cr_components/chromeos/network/cellular_utils.html new file mode 100644 index 00000000000..20e09fecf39 --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/cellular_utils.html @@ -0,0 +1,2 @@ +<link rel="import" href="mojo_interface_provider.html"> +<script src="cellular_utils.js"></script>
\ No newline at end of file diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/cellular_utils.js b/chromium/ui/webui/resources/cr_components/chromeos/network/cellular_utils.js new file mode 100644 index 00000000000..74363e9ef09 --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/cellular_utils.js @@ -0,0 +1,76 @@ +// Copyright 2021 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. + +// clang-format off +// #import {MojoInterfaceProviderImpl} from 'chrome://resources/cr_components/chromeos/network/mojo_interface_provider.m.js'; +// #import {OncMojo} from 'chrome://resources/cr_components/chromeos/network/onc_mojo.m.js'; +// clang-format on + +/** + * Checks if the device has a currently active pSIM network. + * @return {!Promise<boolean>} + */ +/* #export */ function hasActivePSimNetwork() { + const mojom = chromeos.networkConfig.mojom; + const networkConfig = network_config.MojoInterfaceProviderImpl.getInstance() + .getMojoServiceRemote(); + return networkConfig + .getNetworkStateList({ + filter: mojom.FilterType.kActive, + networkType: mojom.NetworkType.kCellular, + limit: mojom.NO_LIMIT, + }) + .then((response) => { + // Filter out non-connected networks and check the remaining if they are + // pSIM. + return Promise.all(response.result + .filter(network => { + return network.connectionState !== + mojom.ConnectionStateType.kNotConnected; + }) + .map(networkIsPSim_)); + }) + .then((networkIsPSimResults) => { + return networkIsPSimResults.some((isPSimNetwork) => isPSimNetwork); + }); +} + +/** + * Returns whether a network is a pSIM network or not. + * @private + * @param {!chromeos.networkConfig.mojom.NetworkStateProperties} network + * @return {!Promise<boolean>} + */ +function networkIsPSim_(network) { + const networkConfig = network_config.MojoInterfaceProviderImpl.getInstance() + .getMojoServiceRemote(); + return networkConfig.getManagedProperties(network.guid).then((response) => { + return !response.result.typeProperties.cellular.eid; + }); +} + +/** + * Returns number of phyical SIM and eSIM slots on the current device + * @param {!chromeos.networkConfig.mojom.DeviceStateProperties} + * deviceState + * @return {!{pSimSlots: number, eSimSlots: number}} + */ +/* #export */ function getSimSlotCount(deviceState) { + let pSimSlots = 0; + let eSimSlots = 0; + + if (!deviceState || !deviceState.simInfos) { + return {pSimSlots, eSimSlots}; + } + + for (const simInfo of deviceState.simInfos) { + if (simInfo.eid) { + eSimSlots++; + continue; + } + pSimSlots++; + } + + return {pSimSlots, eSimSlots}; +} diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_apnlist.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_apnlist.js index 4f4aa91b86a..b4a2a16eecd 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_apnlist.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_apnlist.js @@ -183,15 +183,11 @@ Polymer({ * @private */ setApnSelectList_(activeApn) { - assert(!activeApn || activeApn.accessPointName); - // The generated APN list ensures nonempty accessPointName and name - // properties. const apnList = this.generateApnList_(); - if (apnList === undefined) { - // No APNList property indicates that the network is not in a - // connectable state. Disable the UI. - this.apnSelectList_ = []; - this.set('selectedApn_', ''); + if (apnList === undefined || apnList.length === 0) { + // Show other APN when no APN list property is available. + this.apnSelectList_ = [this.otherApn_]; + this.set('selectedApn_', kOtherAccessPointName); return; } // Get the list entry for activeApn if it exists. It will have 'name' set. diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.html index 45faa6f1825..d2d74437302 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.html @@ -9,6 +9,7 @@ <link rel="import" href="../../../cr_elements/policy/cr_policy_indicator.html"> <link rel="import" href="../../../html/action_link.html"> <link rel="import" href="../../../html/i18n_behavior.html"> +<link rel="import" href="chrome://resources/html/assert.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html"> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.js index 9a9fe325cf0..c7bd8953fcb 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_config.js @@ -1179,10 +1179,11 @@ Polymer({ this.selectedServerCaHash_ = DEFAULT_HASH; } else if (!this.guid && this.serverCaCerts_[0]) { // For unconfigured networks, default to the first available - // certificate, or DO_NOT_CHECK (i.e. skip DEFAULT_HASH). See - /// onNetworkCertificatesChanged() for how certificates are added. + // certificate and fallback to DEFAULT_HASH. See + // onNetworkCertificatesChanged() for how certificates are added. let cert = this.serverCaCerts_[0]; - if (cert.hash === DEFAULT_HASH && this.serverCaCerts_[1]) { + if (cert.hash === DEFAULT_HASH && + this.isRealCertUsableForNetworkAuth_(this.serverCaCerts_[1])) { cert = this.serverCaCerts_[1]; } this.selectedServerCaHash_ = cert.hash; @@ -1207,7 +1208,17 @@ Polymer({ } } }, - + /** + * Checks that the hash of the certificate is set and not one of the default + * special strings. + * @param {chromeos.networkConfig.mojom.NetworkCertificate|undefined} cert + * @return {boolean} + * @private + */ + isRealCertUsableForNetworkAuth_(cert) { + return !!cert && cert.hash !== DO_NOT_CHECK_HASH && + cert.hash !== DEFAULT_HASH; + }, /** * @return {boolean} * @private diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_icon.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_icon.html index 84065f5c3bf..e25a5c4001d 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_icon.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_icon.html @@ -44,41 +44,41 @@ /* Images */ #icon.ethernet { - background: url(ethernet.svg); + background: url(chrome://resources/cr_components/chromeos/network/ethernet.svg); } #icon.vpn { - background: url(vpn.svg); + background: url(chrome://resources/cr_components/chromeos/network/vpn.svg); } /* Wi-Fi images */ #icon.wifi-not-connected { - background: url(wifi_0_with_x.svg); + background: url(chrome://resources/cr_components/chromeos/network/wifi_0_with_x.svg); } #icon.wifi-no-network, #icon.wifi-0 { - background: url(wifi_0.svg); + background: url(chrome://resources/cr_components/chromeos/network/wifi_0.svg); } #icon.wifi-1 { - background: url(wifi_1.svg); + background: url(chrome://resources/cr_components/chromeos/network/wifi_1.svg); } #icon.wifi-2 { - background: url(wifi_2.svg); + background: url(chrome://resources/cr_components/chromeos/network/wifi_2.svg); } #icon.wifi-3 { - background: url(wifi_3.svg); + background: url(chrome://resources/cr_components/chromeos/network/wifi_3.svg); } #icon.wifi-4 { - background: url(wifi_4.svg); + background: url(chrome://resources/cr_components/chromeos/network/wifi_4.svg); } #icon.wifi-off { - background: url(wifi_off.svg); + background: url(chrome://resources/cr_components/chromeos/network/wifi_off.svg); } #icon.wifi-connecting { @@ -88,41 +88,51 @@ } @keyframes wifi-levels { - 0% { background: url(wifi_0.svg); } - 25% { background: url(wifi_1.svg); } - 50% { background: url(wifi_2.svg); } - 75% { background: url(wifi_3.svg); } - 100% { background: url(wifi_4.svg); } + 0% { + background: url(chrome://resources/cr_components/chromeos/network/wifi_0.svg); + } + 25% { + background: url(chrome://resources/cr_components/chromeos/network/wifi_1.svg); + } + 50% { + background: url(chrome://resources/cr_components/chromeos/network/wifi_2.svg); + } + 75% { + background: url(chrome://resources/cr_components/chromeos/network/wifi_3.svg); + } + 100% { + background: url(chrome://resources/cr_components/chromeos/network/wifi_4.svg); + } } /* Cellular images */ #icon.cellular-not-connected { - background: url(cellular_0_with_x.svg); + background: url(chrome://resources/cr_components/chromeos/network/cellular_0_with_x.svg); } #icon.cellular-no-network, #icon.cellular-0 { - background: url(cellular_0.svg); + background: url(chrome://resources/cr_components/chromeos/network/cellular_0.svg); } #icon.cellular-1 { - background: url(cellular_1.svg); + background: url(chrome://resources/cr_components/chromeos/network/cellular_1.svg); } #icon.cellular-2 { - background: url(cellular_2.svg); + background: url(chrome://resources/cr_components/chromeos/network/cellular_2.svg); } #icon.cellular-3 { - background: url(cellular_3.svg); + background: url(chrome://resources/cr_components/chromeos/network/cellular_3.svg); } #icon.cellular-4 { - background: url(cellular_4.svg); + background: url(chrome://resources/cr_components/chromeos/network/cellular_4.svg); } #icon.cellular-off { - background: url(cellular_off.svg); + background: url(chrome://resources/cr_components/chromeos/network/cellular_off.svg); } #icon.cellular-connecting { @@ -132,11 +142,21 @@ } @keyframes cellular-levels { - 0% { background: url(cellular_0.svg); } - 25% { background: url(cellular_1.svg); } - 50% { background: url(cellular_2.svg); } - 75% { background: url(cellular_3.svg); } - 100% { background: url(cellular_4.svg); } + 0% { + background: url(chrome://resources/cr_components/chromeos/network/cellular_0.svg); + } + 25% { + background: url(chrome://resources/cr_components/chromeos/network/cellular_1.svg); + } + 50% { + background: url(chrome://resources/cr_components/chromeos/network/cellular_2.svg); + } + 75% { + background: url(chrome://resources/cr_components/chromeos/network/cellular_3.svg); + } + 100% { + background: url(chrome://resources/cr_components/chromeos/network/cellular_4.svg); + } } </style> <div id="icon" diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_icons.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_icons.html index fd5018a72ae..e1e85634a72 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_icons.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_icons.html @@ -18,6 +18,14 @@ <g id="badge-hspa-plus"><path d="M5.22527 7H6.26374V1H5.22527V3.49725H2.54258V1H1.5V7H2.54258V4.33379H5.22527V7ZM11.2788 3.69918H9.71291V2.03022H8.74038V3.69918H7.16621V4.61401H8.74038V6.39835H9.71291V4.61401H11.2788V3.69918Z"></path></g> <g id="badge-lte"><path d="M2 1H3V5H5V6H2V1ZM10 1H13V2H11V3H12.5V4H11V5H13V6H10V1ZM5 1H9V2H7.5V6H6.5V2H5V1Z"></path></g> <g id="badge-lte-advanced"><path d="M2 1H3V5H5V6H2V1ZM10 1H13V2H11V3H12.5V4H11V5H13V6H10V1ZM5 1H9V2H7.5V6H6.5V2H5V1ZM14 2H15V1H16V2H17V3H16V4H15V3H14V2Z"></path></g> + + <!-- Icons --> + <!-- TODO(crbug.com/1157123) Update network_icon to use iron_icon + and migrate the rest of the icons used by network_icon + into this iconset. --> + <g id="cellular-0"><path fill-rule="evenodd" clip-rule="evenodd" d="M15.002 15.002V7.41622L7.41622 15.002H15.002ZM16.002 17.002C16.5543 17.002 17.002 16.5543 17.002 16.002V5.002C17.002 4.1111 15.9249 3.66493 15.2949 4.2949L4.2949 15.2949C3.66493 15.9249 4.1111 17.002 5.002 17.002H16.002Z" ></g> + + <g id="download" viewBox="0 0 20 20"><path d="M11 9.2L13.5 6.5L15 8L10 13L5 8L6.5 6.5L9 9.2V3H11V9.2Z"></path><path d="M6 15V13H4V15.375C4 16.2688 4.73125 17 5.625 17H14.375C15.2688 17 16 16.2688 16 15.375V13H14V15H6Z"></path></g> </defs> </svg> </iron-iconset-svg> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_list.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_list.html index 67c933d9669..17c8ff3c919 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_list.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_list.html @@ -2,6 +2,7 @@ <link rel="import" href="network_list_item.html"> <link rel="import" href="network_list_types.html"> +<link rel="import" href="onc_mojo.html"> <link rel="import" href="../../../cr_elements/cr_scrollable_behavior.html"> <link rel="import" href="../../../cr_elements/shared_style_css.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> @@ -14,7 +15,6 @@ network-list-item { align-items: center; - height: 48px; } #container { @@ -22,6 +22,10 @@ overflow-y: auto; } + #networkList { + height: 100%; + } + /* Override scrollable border-bottom-color */ #container[no-bottom-scroll-border] { border-bottom-color: transparent; diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_item.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_item.html index a2347543db2..5c57a802174 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_item.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_item.html @@ -1,6 +1,9 @@ <link rel="import" href="../../../html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html"> +<link rel="import" href="chrome://resources/html/load_time_data.html"> +<link rel="import" href="chrome://resources/html/assert.html"> <link rel="import" href="../../../cr_elements/cr_icon_button/cr_icon_button.html"> <link rel="import" href="../../../cr_elements/icons.html"> <link rel="import" href="../../../cr_elements/policy/cr_policy_indicator.html"> @@ -11,6 +14,7 @@ <link rel="import" href="cr_policy_network_behavior_mojo.html"> <link rel="import" href="network_icon.html"> <link rel="import" href="network_list_types.html"> +<link rel="import" href="mojo_interface_provider.html"> <link rel="import" href="onc_mojo.html"> <dom-module id="network-list-item"> @@ -22,8 +26,26 @@ } #divOuter { - height: 100%; + height: var(--cr-network-row-height, 48px); + overflow: auto; + padding-bottom: var(--cr-network-row-padding-bottom, 0); padding-inline-end: var(--cr-icon-ripple-padding); + padding-top: var(--cr-network-row-padding-bottom, 0); + } + + :host([is-e-sim-pending-profile_]) #divText { + opacity: 0.4; + } + + :host(:not([is-e-sim-pending-profile_])) #divIcon { + height: 24px; + width: 24px; + } + + :host([is-e-sim-pending-profile_]) #divIcon { + height: 20px; + opacity: 0.4; + width: 20px; } #divDetail { @@ -48,11 +70,6 @@ color: var(--google-green-500); } - iron-icon { - height: 24px; - width: 24px; - } - cr-policy-indicator { padding: 0 var(--cr-controlled-by-spacing); } @@ -60,6 +77,17 @@ #wrapper { height: 100%; } + + cr-button iron-icon { + --iron-icon-fill-color: #1A73E8; + margin-inline-end: 8px; + } + + paper-spinner-lite { + height: 20px; + margin-inline-end: 16px; + width: 20px; + } </style> <div id="wrapper" focus-row-container class="layout horizontal center flex"> @@ -81,10 +109,17 @@ </network-icon> </template> <template is="dom-if" if="[[item.polymerIcon]]"> - <iron-icon icon="[[item.polymerIcon]]"></iron-icon> + <iron-icon id="divIcon" icon="[[item.polymerIcon]]"></iron-icon> </template> <div id="divText" class="layout horizontal flex"> - <div aria-hidden="true">[[getItemName_(item)]]</div> + <div id="networkName" aria-hidden="true"> + [[getItemName_(item)]] + </div> + <div id="subtitle" + hidden$="[[!isSubtitleVisible_(subtitle_)]]" + aria-hidden="true"> + [[getSubtitle(subtitle_)]] + </div> <div id="networkStateText" class="cr-secondary-text" hidden$="[[!isStateTextVisible_(networkState)]]" @@ -110,6 +145,18 @@ </cr-icon-button> </div> </template> + <template is="dom-if" if="[[isESimPendingProfile_]]" restamp> + <cr-button id="installButton" + aria-label$="[[getItemName_(item)]], [[i18n('networkListItemDownload')]]" + on-click="onInstallButtonClick_"> + <iron-icon icon="network:download"></iron-icon> + [[i18n('networkListItemDownload')]] + </cr-button> + </template> + <template is="dom-if" if="[[isESimInstallingProfile_(item, item.customItemType)]]" restamp> + <paper-spinner-lite active></paper-spinner-lite> + [[i18n('networkListItemAddingProfile')]] + </template> </div> </div> </template> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_item.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_item.js index 91d70ebcdc2..faeb93d4f75 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_item.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_item.js @@ -56,7 +56,7 @@ Polymer({ rowLabel: { type: String, notify: true, - computed: 'getRowLabel_(item, networkState)', + computed: 'getRowLabel_(item, networkState, subtitle_)', }, buttonLabel: { @@ -72,6 +72,17 @@ Polymer({ }, /** + * Whether the network item is a cellular one and is of an esim + * pending profile. + */ + isESimPendingProfile_: { + type: Boolean, + reflectToAttribute: true, + value: false, + computed: 'computeIsESimPendingProfile_(item, item.customItemType)', + }, + + /** * The cached ConnectionState for the network. * @type {!chromeos.networkConfig.mojom.ConnectionStateType|undefined} */ @@ -95,6 +106,32 @@ Polymer({ * @private {!OncMojo.DeviceStateProperties|undefined} deviceState */ deviceState: Object, + + /** + * Subtitle for item. + * @private {string} + */ + subtitle_: { + type: String, + value: '', + }, + + /** @private */ + isUpdatedCellularUiEnabled_: { + type: Boolean, + value() { + return loadTimeData.getBoolean('updatedCellularActivationUi'); + } + }, + }, + + /** @private {?chromeos.networkConfig.mojom.CrosNetworkConfigRemote} */ + networkConfig_: null, + + /** @override */ + created() { + this.networkConfig_ = network_config.MojoInterfaceProviderImpl.getInstance() + .getMojoServiceRemote(); }, /** @override */ @@ -109,12 +146,49 @@ Polymer({ /** @private */ itemChanged_() { - if (this.item && !this.item.hasOwnProperty('customItemName')) { + if (this.item && !this.item.hasOwnProperty('customItemType')) { this.networkState = /** @type {!OncMojo.NetworkStateProperties} */ (this.item); - } else if (this.networkState) { + } else { this.networkState = undefined; } + this.setSubtitle_(); + }, + + /** @private */ + setSubtitle_() { + const mojom = chromeos.networkConfig.mojom; + + if (this.item.hasOwnProperty('customItemSubtitle') && + this.item.customItemSubtitle) { + // Item is a custom OOBE network or pending eSIM profile. + const item = /** @type {!NetworkList.CustomItemState} */ (this.item); + this.subtitle_ = item.customItemSubtitle; + return; + } + + if (!this.networkState) { + return; + } + + if (this.networkState.type !== mojom.NetworkType.kCellular || + !this.isUpdatedCellularUiEnabled_) { + return; + } + + this.networkConfig_.getManagedProperties(this.networkState.guid) + .then(response => { + if (!response || !response.result || + !response.result.typeProperties.cellular.eid) { + return; + } + const managedProperty = response.result; + + if (managedProperty.typeProperties.cellular.homeProvider) { + this.subtitle_ = + managedProperty.typeProperties.cellular.homeProvider.name; + } + }); }, /** @private */ @@ -138,10 +212,9 @@ Polymer({ getItemName_() { if (this.item.hasOwnProperty('customItemName')) { const item = /** @type {!NetworkList.CustomItemState} */ (this.item); - const name = item.customItemName || ''; - const customName = this.i18n(item.customItemName); - - return customName ? customName : name; + return this.i18nExists(item.customItemName) ? + this.i18n(item.customItemName) : + item.customItemName; } return OncMojo.getNetworkStateDisplayName( /** @type {!OncMojo.NetworkStateProperties} */ (this.item)); @@ -162,6 +235,10 @@ Polymer({ * @private */ getRowLabel_() { + if (!this.item) { + return ''; + } + const NetworkType = chromeos.networkConfig.mojom.NetworkType; const OncSource = chromeos.networkConfig.mojom.OncSource; const SecurityType = chromeos.networkConfig.mojom.SecurityType; @@ -187,21 +264,46 @@ Polymer({ case NetworkType.kCellular: if (isManaged) { if (status) { + if (this.subtitle_) { + return this.i18n( + 'networkListItemLabelCellularManagedWithConnectionStatusAndProviderName', + index, total, this.getItemName_(), this.subtitle_, status, + this.item.typeState.cellular.signalStrength); + } return this.i18n( 'networkListItemLabelCellularManagedWithConnectionStatus', index, total, this.getItemName_(), status, this.item.typeState.cellular.signalStrength); } + if (this.subtitle_) { + return this.i18n( + 'networkListItemLabelCellularManagedWithProviderName', index, + total, this.getItemName_(), this.subtitle_, + this.item.typeState.cellular.signalStrength); + } return this.i18n( 'networkListItemLabelCellularManaged', index, total, this.getItemName_(), this.item.typeState.cellular.signalStrength); } if (status) { + if (this.subtitle_) { + return this.i18n( + 'networkListItemLabelCellularWithConnectionStatusAndProviderName', + index, total, this.getItemName_(), this.subtitle_, status, + this.item.typeState.cellular.signalStrength); + } return this.i18n( 'networkListItemLabelCellularWithConnectionStatus', index, total, this.getItemName_(), status, this.item.typeState.cellular.signalStrength); } + + if (this.subtitle_) { + return this.i18n( + 'networkListItemLabelCellularWithProviderName', index, total, + this.getItemName_(), this.subtitle_, + this.item.typeState.cellular.signalStrength); + } return this.i18n( 'networkListItemLabelCellular', index, total, this.getItemName_(), this.item.typeState.cellular.signalStrength); @@ -226,12 +328,26 @@ Polymer({ case NetworkType.kTether: // Tether networks will never be controlled by policy (only disabled). if (status) { + if (this.subtitle_) { + return this.i18n( + 'networkListItemLabelTetherWithConnectionStatusAndProviderName', + index, total, this.getItemName_(), this.subtitle_, status, + this.item.typeState.tether.signalStrength, + this.item.typeState.tether.batteryPercentage); + } return this.i18n( 'networkListItemLabelTetherWithConnectionStatus', index, total, this.getItemName_(), status, this.item.typeState.tether.signalStrength, this.item.typeState.tether.batteryPercentage); } + if (this.subtitle_) { + return this.i18n( + 'networkListItemLabelTetherWithProviderName', index, total, + this.getItemName_(), this.subtitle_, + this.item.typeState.tether.signalStrength, + this.item.typeState.tether.batteryPercentage); + } return this.i18n( 'networkListItemLabelTether', index, total, this.getItemName_(), this.item.typeState.tether.signalStrength, @@ -263,6 +379,25 @@ Polymer({ 'networkListItemLabelWifi', index, total, this.getItemName_(), secured, this.item.typeState.wifi.signalStrength); default: + if (this.isESimPendingProfile_) { + if (this.subtitle_) { + return this.i18n( + 'networkListItemLabelESimPendingProfileWithProviderName', index, + total, this.getItemName_(), this.subtitle_); + } + return this.i18n( + 'networkListItemLabelESimPendingProfile', index, total, + this.getItemName_()); + } else if (this.isESimInstallingProfile_()) { + if (this.subtitle_) { + return this.i18n( + 'networkListItemLabelESimPendingProfileWithProviderNameInstalling', + index, total, this.getItemName_(), this.subtitle_); + } + return this.i18n( + 'networkListItemLabelESimPendingProfileInstalling', index, total, + this.getItemName_()); + } return this.i18n( 'networkListItemLabel', index, total, this.getItemName_()); } @@ -312,6 +447,22 @@ Polymer({ }, /** + * @return {string} + * @private + */ + getSubtitle() { + return this.subtitle_ ? this.subtitle_ : ''; + }, + + /** + * @return {boolean} + * @private + */ + isSubtitleVisible_() { + return !!this.subtitle_; + }, + + /** * @param {!OncMojo.NetworkStateProperties|undefined} networkState * @param {boolean} showButtons * @return {boolean} @@ -364,6 +515,8 @@ Polymer({ if (this.isSubpageButtonVisible_(this.networkState, this.showButtons) && this.$$('#subpage-button') === this.shadowRoot.activeElement) { this.fireShowDetails_(event); + } else if (this.isESimPendingProfile_) { + this.onInstallButtonClick_(); } else if (this.item.hasOwnProperty('customItemName')) { this.fire('custom-item-selected', this.item); } else { @@ -420,4 +573,29 @@ Polymer({ // isFocused is supplied by FocusRowBehavior. return this.isFocused ? 'polite' : 'off'; }, + + /** @private */ + onInstallButtonClick_() { + this.fire('install-profile', {iccid: this.item.customData.iccid}); + }, + + /** + * @return {boolean} + * @private + */ + computeIsESimPendingProfile_() { + return !!this.item && this.item.hasOwnProperty('customItemType') && + this.item.customItemType === + NetworkList.CustomItemType.ESIM_PENDING_PROFILE; + }, + + /** + * @return {boolean} + * @private + */ + isESimInstallingProfile_() { + return !!this.item && this.item.hasOwnProperty('customItemType') && + this.item.customItemType === + NetworkList.CustomItemType.ESIM_INSTALLING_PROFILE; + }, }); diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_types.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_types.js index e8efab5ccfd..82e395130f0 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_types.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_list_types.js @@ -2,6 +2,10 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +// clang-format off +// #import {OncMojo} from './onc_mojo.m.js'; +// clang-format on + /** * @fileoverview * This file contains typedefs properties for NetworkList, shared by @@ -10,10 +14,19 @@ /* #export */ const NetworkList = {}; +/** @enum {number} */ +NetworkList.CustomItemType = { + OOBE: 1, + ESIM_PENDING_PROFILE: 2, + ESIM_INSTALLING_PROFILE: 3, +}; + /** * Custom data for implementation specific network list items. * @typedef {{ + * customItemType: NetworkList.CustomItemType, * customItemName: string, + * customItemSubtitle: string, * polymerIcon: (string|undefined), * customData: (!Object|undefined), * showBeforeNetworksList: boolean, diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_select.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_select.html index d2abd388d3d..4b066ea8bed 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_select.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_select.html @@ -1,6 +1,7 @@ <link rel="import" href="../../../html/polymer.html"> <link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html"> +<link rel="import" href="chrome://resources/html/assert.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-progress/paper-progress.html"> <link rel="import" href="mojo_interface_provider.html"> <link rel="import" href="network_list.html"> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_select.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_select.js index 5c385f28b65..1e6757de278 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_select.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_select.js @@ -39,13 +39,30 @@ Polymer({ }, /** Whether to show technology badges on mobile network icons. */ - showTechnologyBadge: {type: Boolean, value: true}, + showTechnologyBadge: { + type: Boolean, + value: true, + }, + + /** + * Whether this element should trigger periodic Wi-Fi scans to update the + * list of networks. If true, a background scan is performed every 10 + * seconds. + */ + enableWifiScans: { + type: Boolean, + value: true, + observer: 'onEnableWifiScansChanged_', + }, /** * Whether to show a progress indicator at the top of the network list while * a scan (e.g., for nearby Wi-Fi networks) is in progress. */ - showScanProgress: {type: Boolean, value: false}, + showScanProgress: { + type: Boolean, + value: false, + }, /** Whether cellular activation is unavailable in the current context. */ activationUnavailable: Boolean, @@ -65,7 +82,10 @@ Polymer({ * Whether a network scan is currently in progress. * @private */ - isScanOngoing_: {type: Boolean, value: false}, + isScanOngoing_: { + type: Boolean, + value: false, + }, /** * The cellular DeviceState, or undefined if there is no Cellular device. @@ -93,23 +113,12 @@ Polymer({ /** @override */ attached() { this.refreshNetworks(); - - const INTERVAL_MS = 10 * 1000; - // Request only WiFi network scans. Tether and Cellular scans are not useful - // here. Cellular scans are disruptive and should only be triggered by - // explicit user action. - const kWiFi = chromeos.networkConfig.mojom.NetworkType.kWiFi; - this.networkConfig_.requestNetworkScan(kWiFi); - this.scanIntervalId_ = window.setInterval(function() { - this.networkConfig_.requestNetworkScan(kWiFi); - }.bind(this), INTERVAL_MS); + this.onEnableWifiScansChanged_(); }, /** @override */ detached() { - if (this.scanIntervalId_ !== null) { - window.clearInterval(this.scanIntervalId_); - } + this.clearScheduledScans_(); }, /** @@ -194,6 +203,42 @@ Polymer({ }, /** + * Handler for changes to |enableWifiScans| which either schedules upcoming + * scans or clears already-scheduled scans. + * @private + */ + onEnableWifiScansChanged_() { + // Clear any scans which are already scheduled. + this.clearScheduledScans_(); + + // If Scans are disabled, return early. + if (!this.enableWifiScans) { + return; + } + + const INTERVAL_MS = 10 * 1000; + // Request only WiFi network scans. Tether and Cellular scans are not useful + // here. Cellular scans are disruptive and should only be triggered by + // explicit user action. + const kWiFi = chromeos.networkConfig.mojom.NetworkType.kWiFi; + this.networkConfig_.requestNetworkScan(kWiFi); + this.scanIntervalId_ = window.setInterval(function() { + this.networkConfig_.requestNetworkScan(kWiFi); + }.bind(this), INTERVAL_MS); + }, + + /** + * Clears any scheduled Wi-FI scans; no-op if there were no scans scheduled. + * @private + */ + clearScheduledScans_() { + if (this.scanIntervalId_ !== null) { + window.clearInterval(this.scanIntervalId_); + this.scanIntervalId_ = null; + } + }, + + /** * @param {!Array<!OncMojo.DeviceStateProperties>} deviceStates * @private */ diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html b/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html index 528d7296677..bdc1a973e86 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.html @@ -29,7 +29,7 @@ color: red; font-size: 125%; font-weight: 500; - margin-top: 10px; + margin-bottom: 10px; } .error { @@ -60,7 +60,7 @@ </div> <!-- SIM locked --> - <div class="property-box two-line" + <div id="simLocked" class="property-box two-line" hidden$="[[!showSimLocked_(deviceState)]]"> <div class="start layout horizontal center"> <iron-icon icon="cr:sim-lock"></iron-icon> @@ -181,6 +181,9 @@ label="[[i18n('networkSimEnterPuk')]]" disabled="[[inProgress_]]"> </network-password-input> + <div class="dialog-error"> + [[getErrorMsg_(error_, deviceState)]] + </div> <network-password-input id="unlockPin1" value="{{pin_new1_}}" label="[[i18n('networkSimEnterNewPin')]]" disabled="[[inProgress_]]"> @@ -192,9 +195,6 @@ <div class="dialog-error"> [[i18n('networkSimLockedWarning')]] </div> - <div class="dialog-error"> - [[getErrorMsg_(error_, deviceState)]] - </div> </div> <div slot="button-container"> <cr-button class="cancel-button" on-click="closeDialogs_"> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.js b/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.js index db23a954686..e47a727d5f0 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/network_siminfo.js @@ -112,9 +112,6 @@ Polymer({ /** @private {boolean|undefined} */ setLockEnabled_: undefined, - /** @private {boolean} */ - simUnlockSent_: false, - /** @private {?chromeos.networkConfig.mojom.CrosNetworkConfigRemote} */ networkConfig_: null, @@ -125,11 +122,6 @@ Polymer({ }, /** @override */ - attached() { - this.simUnlockSent_ = false; - }, - - /** @override */ detached() { this.closeDialogs_(); }, @@ -294,7 +286,6 @@ Polymer({ setInProgress_() { this.error_ = ErrorType.NONE; this.inProgress_ = true; - this.simUnlockSent_ = true; }, /** @@ -508,29 +499,35 @@ Polymer({ getErrorMsg_() { if (this.error_ === ErrorType.NONE) { return ''; + } else if (this.error_ === ErrorType.MISMATCHED_PIN) { + return this.i18n('networkSimErrorPinMismatch'); } - const retriesLeft = (this.simUnlockSent_ && this.deviceState && - this.deviceState.simLockStatus) ? + + let errorStringId = ''; + switch (this.error_) { + case ErrorType.INCORRECT_PIN: + errorStringId = 'networkSimErrorIncorrectPin'; + break; + case ErrorType.INCORRECT_PUK: + errorStringId = 'networkSimErrorIncorrectPuk'; + break; + case ErrorType.INVALID_PIN: + errorStringId = 'networkSimErrorInvalidPin'; + break; + case ErrorType.INVALID_PUK: + errorStringId = 'networkSimErrorInvalidPuk'; + break; + default: + assertNotReached(); + } + + const retriesLeft = (this.deviceState && this.deviceState.simLockStatus) ? this.deviceState.simLockStatus.retriesLeft : 0; - - if (this.error_ === ErrorType.INCORRECT_PIN) { - return this.i18n('networkSimErrorIncorrectPin', retriesLeft); - } - if (this.error_ === ErrorType.INCORRECT_PUK) { - return this.i18n('networkSimErrorIncorrectPuk', retriesLeft); - } - if (this.error_ === ErrorType.MISMATCHED_PIN) { - return this.i18n('networkSimErrorPinMismatch'); - } - if (this.error_ === ErrorType.INVALID_PIN) { - return this.i18n('networkSimErrorInvalidPin', retriesLeft); - } - if (this.error_ === ErrorType.INVALID_PUK) { - return this.i18n('networkSimErrorInvalidPuk', retriesLeft); + if (retriesLeft !== 1) { + errorStringId += 'Plural'; } - assertNotReached(); - return ''; + return this.i18n(errorStringId, retriesLeft); }, /** diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network/onc_mojo.js b/chromium/ui/webui/resources/cr_components/chromeos/network/onc_mojo.js index 932940e4306..97f830ea95f 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network/onc_mojo.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/network/onc_mojo.js @@ -192,6 +192,8 @@ return 'Prohibited'; case DeviceStateType.kUnavailable: return 'Unavailable'; + case DeviceStateType.kInhibited: + return 'Inhibited'; } assertNotReached('Unexpected enum value: ' + OncMojo.getEnumString(value)); return ''; @@ -208,6 +210,7 @@ case DeviceStateType.kDisabling: case DeviceStateType.kEnabling: case DeviceStateType.kUnavailable: + case DeviceStateType.kInhibited: return true; case DeviceStateType.kDisabled: case DeviceStateType.kEnabled: @@ -269,6 +272,16 @@ } /** + * @param {!chromeos.networkConfig.mojom.NetworkType} value + * @return {boolean} + */ + static networkTypeHasConfigurationFlow(value) { + // Cellular networks are considered "configured" by their SIM, and Instant + // Tethering networks do not have a configuration flow. + return !OncMojo.networkTypeIsMobile(value); + } + + /** * @param {string} value * @return {!chromeos.networkConfig.mojom.NetworkType} */ @@ -542,6 +555,25 @@ } /** + * Determines whether a connection to |network| can be attempted. Note that + * this function does not consider policies which may block a connection from + * succeeding. + * @param {!chromeos.networkConfig.mojom.NetworkStateProperties| + * !chromeos.networkConfig.mojom.ManagedProperties} network + * @return {boolean} Whether the network can currently be connected; if the + * network is not connectable, it must first be configured. + */ + static isNetworkConnectable(network) { + // Networks without a configuration flow are always connectable since no + // additional configuration can be performed to attempt a connection. + if (!OncMojo.networkTypeHasConfigurationFlow(network.type)) { + return true; + } + + return network.connectable; + } + + /** * @param {string} key * @return {boolean} */ @@ -590,6 +622,8 @@ switch (type) { case mojom.NetworkType.kCellular: result.typeState.cellular = { + iccid: '', + eid: '', activationState: mojom.ActivationStateType.kUnknown, networkTechnology: '', roaming: false, @@ -622,6 +656,7 @@ bssid: '', frequency: 0, hexSsid: opt_name || '', + hiddenSsid: false, security: mojom.SecurityType.kNone, signalStrength: 0, ssid: '', @@ -728,6 +763,7 @@ activationState: mojom.ActivationStateType.kUnknown, allowRoaming: false, signalStrength: 0, + simLocked: false, supportNetworkScan: false, } }; @@ -794,7 +830,14 @@ case mojom.NetworkType.kWiFi: // Note: wifi.security can not be changed, so |security| will be ignored // for existing configurations. - return {typeConfig: {wifi: {security: mojom.SecurityType.kNone}}}; + return { + typeConfig: { + wifi: { + security: mojom.SecurityType.kNone, + hiddenSsid: mojom.HiddenSsidMode.kAutomatic + } + } + }; break; } assertNotReached('Unexpected type: ' + type.toString()); diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/network_health/BUILD.gn index a326dc50a52..359a0e05c0d 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network_health/BUILD.gn +++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/BUILD.gn @@ -8,52 +8,23 @@ import("//ui/webui/resources/tools/js_modulizer.gni") assert(is_chromeos, "Only ChromeOS components belong here.") -# JS type check for Polymer 2 and 3 - -js_type_check("closure_compile") { - deps = [ - ":network_diagnostics", - ":network_health_summary", - ] -} - js_type_check("closure_compile_module") { is_polymer3 = true deps = [ ":network_diagnostics.m", ":network_diagnostics_mojo.m", + ":network_diagnostics_types.m", + ":network_health_container.m", + ":network_health_mojo.m", ":network_health_summary.m", - ] -} - -# Sources with Polymer 3 generated modules - -js_library("network_health_summary") { - deps = [ - "//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile", - "//ui/webui/resources/cr_components/chromeos/network:onc_mojo", - "//ui/webui/resources/js:i18n_behavior", - ] -} - -js_library("network_diagnostics") { - deps = [ - "//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile", - "//ui/webui/resources/js:i18n_behavior", - ] -} - -js_library("network_diagnostics_mojo") { - deps = [ - "//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile", - "//ui/webui/resources/js:cr", + ":routine_group.m", ] } js_library("network_health_summary.m") { sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.m.js" ] deps = [ - "//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile", + ":network_health_mojo.m", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", "//ui/webui/resources/cr_components/chromeos/network:onc_mojo", "//ui/webui/resources/js:i18n_behavior.m", @@ -61,10 +32,25 @@ js_library("network_health_summary.m") { extra_deps = [ ":network_health_summary_module" ] } +js_library("network_health_mojo.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.m.js" ] + deps = [ "//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile" ] + extra_deps = [ ":modulize" ] +} + +js_library("network_health_container.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/network_health_container.m.js" ] + deps = + [ "//third_party/polymer/v3_0/components-chromium/iron-icon:iron-icon" ] + extra_deps = [ ":network_health_container_module" ] +} + js_library("network_diagnostics.m") { sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.m.js" ] deps = [ ":network_diagnostics_mojo.m", + ":network_diagnostics_types.m", + ":routine_group.m", "//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", "//ui/webui/resources/js:i18n_behavior.m", @@ -74,32 +60,73 @@ js_library("network_diagnostics.m") { js_library("network_diagnostics_mojo.m") { sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_mojo.m.js" ] - deps = [ "//chrome/browser/ui/webui/settings/chromeos/search:mojo_bindings_js_library_for_compile" ] + deps = [ "//chromeos/services/network_health/public/mojom:mojom_js_library_for_compile" ] + extra_deps = [ ":modulize" ] +} + +js_library("network_diagnostics_types.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.m.js" ] + deps = [ ":network_diagnostics_mojo.m" ] extra_deps = [ ":modulize" ] } +js_library("routine_group.m") { + sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/network_health/routine_group.m.js" ] + deps = [ + ":network_diagnostics_mojo.m", + ":network_diagnostics_types.m", + ":network_health_container.m", + "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", + "//ui/webui/resources/js:i18n_behavior.m", + ] + extra_deps = [ ":routine_group_module" ] +} + # polymer_modulizer for converting Polymer2 to Polymer3 polymer_modulizer("network_health_summary") { js_file = "network_health_summary.js" html_file = "network_health_summary.html" html_type = "dom-module" + auto_imports = [ + "ui/webui/resources/cr_components/chromeos/network/onc_mojo.html|OncMojo", + ] +} + +polymer_modulizer("network_health_container") { + js_file = "network_health_container.js" + html_file = "network_health_container.html" + html_type = "dom-module" } polymer_modulizer("network_diagnostics") { js_file = "network_diagnostics.js" html_file = "network_diagnostics.html" html_type = "dom-module" + auto_imports = [ "ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.html|Routine,RoutineResponse,RoutineGroup,RoutineType" ] +} + +polymer_modulizer("routine_group") { + js_file = "routine_group.js" + html_file = "routine_group.html" + html_type = "dom-module" + auto_imports = [ "ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.html|Icons,Routine,RoutineResponse" ] } js_modulizer("modulize") { - input_files = [ "network_diagnostics_mojo.js" ] + input_files = [ + "network_health_mojo.js", + "network_diagnostics_mojo.js", + "network_diagnostics_types.js", + ] } group("polymer3_elements") { public_deps = [ ":modulize", ":network_diagnostics_module", + ":network_health_container_module", ":network_health_summary_module", + ":routine_group_module", ] } diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.html b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.html index 4e0997eba8d..9acf444ba16 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.html @@ -1,50 +1,35 @@ <link rel="import" href="../../../html/polymer.html"> -<link rel="import" href="chrome://resources/cr_components/chromeos/network_health/network_diagnostics_mojo.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html"> <link rel="import" href="../../../cr_elements/cr_button/cr_button.html"> <link rel="import" href="../../../html/i18n_behavior.html"> +<link rel="import" href="network_diagnostics_mojo.html"> +<link rel="import" href="network_diagnostics_types.html"> +<link rel="import" href="routine_group.html"> <dom-module id="network-diagnostics"> <template> - <style> - .routine-container { - align-items: center; - border: 2px solid rgb(175, 175, 175); - display: flex; - height: 30px; - margin: 10px; - padding: 5px; - } - - .routine-icon { - height: 25px; - padding-inline-end: 10px; - width: auto; - } - - .routine-name { - flex: 1; - font-size: 1rem; - } - </style> - <template is="dom-repeat" items="[[routines_]]" as="routine"> - <div class="routine-container" aria-label="[[i18n(routine.name)]]" - aria-description="[[routine.ariaDescription]]"> - <img class="routine-icon" src="[[getRoutineIcon_(routine.result)]]"> - <div aria-hidden="true" class="routine-name"> - [[i18n(routine.name)]] - </div> - <div aria-hidden="true" class="routine-result" - hidden="[[!routine.resultMsg]]"> - [[routine.resultMsg]] - </div> - - <template is="dom-if" if="[[routine.running]]"> - <paper-spinner-lite active></paper-spinner-lite> - </template> - </div> - </template> + <routine-group name="[[i18n('NetworkDiagnosticsConnectionGroup')]]" + routines="[[getRoutineGroup_(routines_.*, RoutineGroup_.CONNECTION)]]"> + </routine-group> + <routine-group name="[[i18n('NetworkDiagnosticsWifiGroup')]]" + routines="[[getRoutineGroup_(routines_.*, RoutineGroup_.WIFI)]]"> + </routine-group> + <routine-group name="[[i18n('NetworkDiagnosticsCaptivePortal')]]" + routines="[[getRoutineGroup_(routines_.*, RoutineGroup_.PORTAL)]]"> + </routine-group> + <routine-group name="[[i18n('NetworkDiagnosticsGatewayGroup')]]" + routines="[[getRoutineGroup_(routines_.*, RoutineGroup_.GATEWAY)]]"> + </routine-group> + <routine-group name="[[i18n('NetworkDiagnosticsFirewallGroup')]]" + routines="[[getRoutineGroup_(routines_.*, RoutineGroup_.FIREWALL)]]"> + </routine-group> + <routine-group name="[[i18n('NetworkDiagnosticsDnsGroup')]]" + routines="[[getRoutineGroup_(routines_.*, RoutineGroup_.DNS)]]"> + </routine-group> + <routine-group name="[[i18n('NetworkDiagnosticsGoogleServicesGroup')]]" + routines= + "[[getRoutineGroup_(routines_.*, RoutineGroup_.GOOGLE_SERVICES)]]"> + </routine-group> </template> <script src="network_diagnostics.js"></script> </dom-module> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.js b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.js index 1bc363c0810..a721ccb8cbf 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics.js @@ -1,4 +1,3 @@ - // Copyright 2020 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. @@ -11,57 +10,19 @@ const diagnosticsMojom = chromeos.networkDiagnostics.mojom; /** - * A routine response from the Network Diagnostics mojo service. - * @typedef {{ - * verdict: chromeos.networkDiagnostics.mojom.RoutineVerdict, - * }} - * RoutineResponse can optionally have a `problems` field, which is an array of - * enums relevant to the routine run. Unfortunately the closure compiler cannot - * handle optional object fields. - */ -let RoutineResponse; - -/** - * A network diagnostics routine. Holds descriptive information about the - * routine, and it's transient state. - * @typedef {{ - * name: string, - * type: !RoutineType, - * running: boolean, - * resultMsg: string, - * result: ?RoutineResponse, - * }} - */ -let Routine; - -/** - * Definition for all Network diagnostic routine types. This enum is intended - * to be used as an index in an array of routines. - * @enum {number} - */ -const RoutineType = { - LAN_CONNECTIVITY: 0, - SIGNAL_STRENGTH: 1, - GATEWAY_PING: 2, - SECURE_WIFI: 3, - DNS_RESOLVER: 4, - DNS_LATENCY: 5, - DNS_RESOLUTION: 6, - HTTP_FIREWALL: 7, - HTTPS_FIREWALL: 8, - HTTPS_LATENCY: 9, -}; - -/** * Helper function to create a routine object. * @param {string} name * @param {!RoutineType} type + * @param {!RoutineGroup} group + * @param {!function()} func * @return {!Routine} Routine object */ -function createRoutine(name, type) { +function createRoutine(name, type, group, func) { return { name: name, type: type, + group: group, + func: func, running: false, resultMsg: '', result: null, @@ -84,30 +45,125 @@ Polymer({ routines_: { type: Array, value: function() { + const routineGroups = [ + { + group: RoutineGroup.CONNECTION, + routines: [ + { + name: 'NetworkDiagnosticsLanConnectivity', + type: RoutineType.LAN_CONNECTIVITY, + func: () => this.networkDiagnostics_.lanConnectivity(), + }, + ] + }, + { + group: RoutineGroup.WIFI, + routines: [ + { + name: 'NetworkDiagnosticsSignalStrength', + type: RoutineType.SIGNAL_STRENGTH, + func: () => this.networkDiagnostics_.signalStrength(), + }, + { + name: 'NetworkDiagnosticsHasSecureWiFiConnection', + type: RoutineType.SECURE_WIFI, + func: () => this.networkDiagnostics_.hasSecureWiFiConnection(), + }, + ] + }, + { + group: RoutineGroup.PORTAL, + routines: [ + { + name: 'NetworkDiagnosticsCaptivePortal', + type: RoutineType.CAPTIVE_PORTAL, + func: () => this.networkDiagnostics_.captivePortal(), + }, + ] + }, + { + group: RoutineGroup.GATEWAY, + routines: [ + { + name: 'NetworkDiagnosticsGatewayCanBePinged', + type: RoutineType.GATEWAY_PING, + func: () => this.networkDiagnostics_.gatewayCanBePinged(), + }, + ] + }, + { + group: RoutineGroup.FIREWALL, + routines: [ + { + name: 'NetworkDiagnosticsHttpFirewall', + type: RoutineType.HTTP_FIREWALL, + func: () => this.networkDiagnostics_.httpFirewall(), + }, + { + name: 'NetworkDiagnosticsHttpsFirewall', + type: RoutineType.HTTPS_FIREWALL, + func: () => this.networkDiagnostics_.httpsFirewall(), + }, + { + name: 'NetworkDiagnosticsHttpsLatency', + type: RoutineType.HTTPS_LATENCY, + func: () => this.networkDiagnostics_.httpsLatency(), + }, + ] + }, + { + group: RoutineGroup.DNS, + routines: [ + { + name: 'NetworkDiagnosticsDnsResolverPresent', + type: RoutineType.DNS_RESOLVER, + func: () => this.networkDiagnostics_.dnsResolverPresent(), + }, + { + name: 'NetworkDiagnosticsDnsLatency', + type: RoutineType.DNS_LATENCY, + func: () => this.networkDiagnostics_.dnsLatency(), + }, + { + name: 'NetworkDiagnosticsDnsResolution', + type: RoutineType.DNS_RESOLUTION, + func: () => this.networkDiagnostics_.dnsResolution(), + }, + ] + }, + { + group: RoutineGroup.GOOGLE_SERVICES, + routines: [ + { + name: 'NetworkDiagnosticsVideoConferencing', + type: RoutineType.VIDEO_CONFERENCING, + // A null stun_server_hostname will use the routine default. + func: () => this.networkDiagnostics_.videoConferencing( + /*stun_server_hostname=*/ null), + }, + ] + }, + ]; const routines = []; - routines[RoutineType.LAN_CONNECTIVITY] = createRoutine( - 'NetworkDiagnosticsLanConnectivity', RoutineType.LAN_CONNECTIVITY); - routines[RoutineType.SIGNAL_STRENGTH] = createRoutine( - 'NetworkDiagnosticsSignalStrength', RoutineType.SIGNAL_STRENGTH); - routines[RoutineType.GATEWAY_PING] = createRoutine( - 'NetworkDiagnosticsGatewayCanBePinged', RoutineType.GATEWAY_PING); - routines[RoutineType.SECURE_WIFI] = createRoutine( - 'NetworkDiagnosticsHasSecureWiFiConnection', - RoutineType.SECURE_WIFI); - routines[RoutineType.DNS_RESOLVER] = createRoutine( - 'NetworkDiagnosticsDnsResolverPresent', RoutineType.DNS_RESOLVER); - routines[RoutineType.DNS_LATENCY] = createRoutine( - 'NetworkDiagnosticsDnsLatency', RoutineType.DNS_LATENCY); - routines[RoutineType.DNS_RESOLUTION] = createRoutine( - 'NetworkDiagnosticsDnsResolution', RoutineType.DNS_RESOLUTION); - routines[RoutineType.HTTP_FIREWALL] = createRoutine( - 'NetworkDiagnosticsHttpFirewall', RoutineType.HTTP_FIREWALL); - routines[RoutineType.HTTPS_FIREWALL] = createRoutine( - 'NetworkDiagnosticsHttpsFirewall', RoutineType.HTTPS_FIREWALL); - routines[RoutineType.HTTPS_LATENCY] = createRoutine( - 'NetworkDiagnosticsHttpsLatency', RoutineType.HTTPS_LATENCY); + + for (const group of routineGroups) { + for (const routine of group.routines) { + routines[routine.type] = createRoutine( + routine.name, routine.type, group.group, routine.func); + } + } + return routines; } + }, + + /** + * Enum of Routine Groups + * @private {Object} + */ + RoutineGroup_: { + type: Object, + value: RoutineGroup, } }, @@ -160,6 +216,17 @@ Polymer({ }, /** + * Runs all supported network diagnostics routines. + * @param {!PolymerDeepPropertyChange} routines + * @param {Number} group + * @return {!Array<!Routine>} + * @private + */ + getRoutineGroup_(routines, group) { + return routines.base.filter(r => r.group === group); + }, + + /** * @param {!Event} event * @private */ @@ -179,48 +246,8 @@ Polymer({ `routines_.${type}.ariaDescription`, this.i18n('NetworkDiagnosticsRunning')); - switch (type) { - case RoutineType.LAN_CONNECTIVITY: - this.networkDiagnostics_.lanConnectivity().then( - result => this.evaluateRoutine_(type, result)); - break; - case RoutineType.SIGNAL_STRENGTH: - this.networkDiagnostics_.signalStrength().then( - result => this.evaluateRoutine_(type, result)); - break; - case RoutineType.GATEWAY_PING: - this.networkDiagnostics_.gatewayCanBePinged().then( - result => this.evaluateRoutine_(type, result)); - break; - case RoutineType.SECURE_WIFI: - this.networkDiagnostics_.hasSecureWiFiConnection().then( - result => this.evaluateRoutine_(type, result)); - break; - case RoutineType.DNS_RESOLVER: - this.networkDiagnostics_.dnsResolverPresent().then( - result => this.evaluateRoutine_(type, result)); - break; - case RoutineType.DNS_LATENCY: - this.networkDiagnostics_.dnsLatency().then( - result => this.evaluateRoutine_(type, result)); - break; - case RoutineType.DNS_RESOLUTION: - this.networkDiagnostics_.dnsResolution().then( - result => this.evaluateRoutine_(type, result)); - break; - case RoutineType.HTTP_FIREWALL: - this.networkDiagnostics_.httpFirewall().then( - result => this.evaluateRoutine_(type, result)); - break; - case RoutineType.HTTPS_FIREWALL: - this.networkDiagnostics_.httpsFirewall().then( - result => this.evaluateRoutine_(type, result)); - break; - case RoutineType.HTTPS_LATENCY: - this.networkDiagnostics_.httpsLatency().then( - result => this.evaluateRoutine_(type, result)); - break; - } + this.routines_[type].func().then( + result => this.evaluateRoutine_(type, result)); }, /** @@ -239,29 +266,6 @@ Polymer({ }, /** - * Helper function to get the icon for a routine based on the result. - * @param {RoutineResponse} result - * @return {string} - * @private - */ - getRoutineIcon_(result) { - if (!result) { - return 'test_not_run.png'; - } - - switch (result.verdict) { - case diagnosticsMojom.RoutineVerdict.kNoProblem: - return 'test_passed.png'; - case diagnosticsMojom.RoutineVerdict.kProblem: - return 'test_failed.png'; - case diagnosticsMojom.RoutineVerdict.kNotRun: - return 'test_canceled.png'; - } - - return ''; - }, - - /** * Helper function to generate the routine result string. * @param {Routine} routine * @return {string} @@ -310,9 +314,6 @@ Polymer({ switch (type) { case RoutineType.SIGNAL_STRENGTH: switch (problem) { - case diagnosticsMojom.SignalStrengthProblem.kSignalNotFound: - problemStrings.push(getString('SignalStrengthProblem_NotFound')); - break; case diagnosticsMojom.SignalStrengthProblem.kWeakSignal: problemStrings.push(getString('SignalStrengthProblem_Weak')); break; @@ -452,6 +453,48 @@ Polymer({ getString('HttpsLatencyProblem_VeryHighLatency')); break; } + + case RoutineType.CAPTIVE_PORTAL: + switch (problem) { + case diagnosticsMojom.CaptivePortalProblem.kNoActiveNetworks: + problemStrings.push( + getString('CaptivePortalProblem_NoActiveNetworks')); + break; + case diagnosticsMojom.CaptivePortalProblem.kUnknownPortalState: + problemStrings.push( + getString('CaptivePortalProblem_UnknownPortalState')); + break; + case diagnosticsMojom.CaptivePortalProblem.kPortalSuspected: + problemStrings.push( + getString('CaptivePortalProblem_PortalSuspected')); + break; + case diagnosticsMojom.CaptivePortalProblem.kPortal: + problemStrings.push(getString('CaptivePortalProblem_Portal')); + break; + case diagnosticsMojom.CaptivePortalProblem.kProxyAuthRequired: + problemStrings.push( + getString('CaptivePortalProblem_ProxyAuthRequired')); + break; + case diagnosticsMojom.CaptivePortalProblem.kNoInternet: + problemStrings.push(getString('CaptivePortalProblem_NoInternet')); + break; + } + + case RoutineType.VIDEO_CONFERENCING: + switch (problem) { + case diagnosticsMojom.VideoConferencingProblem.kUdpFailure: + problemStrings.push( + getString('VideoConferencingProblem_UdpFailure')); + break; + case diagnosticsMojom.VideoConferencingProblem.kTcpFailure: + problemStrings.push( + getString('VideoConferencingProblem_TcpFailure')); + break; + case diagnosticsMojom.VideoConferencingProblem.kMediaFailure: + problemStrings.push( + getString('VideoConferencingProblem_MediaFailure')); + break; + } } } diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.html b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.html new file mode 100644 index 00000000000..d8434fc447b --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.html @@ -0,0 +1,3 @@ +<link rel="import" href="network_diagnostics_mojo.html"> + +<script src="network_diagnostics_types.js"></script> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.js b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.js new file mode 100644 index 00000000000..e67a463f6d3 --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_diagnostics_types.js @@ -0,0 +1,79 @@ +// Copyright 2020 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. + +// clang-format off +// #import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js'; +// #import 'chrome://resources/mojo/chromeos/services/network_health/public/mojom/network_diagnostics.mojom-lite.js'; +// clang-format on + +/** + * @fileoverview + * This file contains shared types for the network diagnostics components. + */ + +/** + * A routine response from the Network Diagnostics mojo service. + * @typedef {{ + * verdict: chromeos.networkDiagnostics.mojom.RoutineVerdict, + * }} + * RoutineResponse can optionally have a `problems` field, which is an array of + * enums relevant to the routine run. Unfortunately the closure compiler cannot + * handle optional object fields. + */ +/* #export */ let RoutineResponse; + +/** + * A network diagnostics routine. Holds descriptive information about the + * routine, and it's transient state. + * @typedef {{ + * name: string, + * type: !RoutineType, + * group: !RoutineGroup, + * func: function(), + * running: boolean, + * resultMsg: string, + * result: ?RoutineResponse, + * }} + */ +/* #export */ let Routine; + +/** + * Definition for all Network diagnostic routine types. This enum is intended + * to be used as an index in an array of routines. + * @enum {number} + */ +/* #export */ const RoutineType = { + LAN_CONNECTIVITY: 0, + SIGNAL_STRENGTH: 1, + GATEWAY_PING: 2, + SECURE_WIFI: 3, + DNS_RESOLVER: 4, + DNS_LATENCY: 5, + DNS_RESOLUTION: 6, + HTTP_FIREWALL: 7, + HTTPS_FIREWALL: 8, + HTTPS_LATENCY: 9, + CAPTIVE_PORTAL: 10, + VIDEO_CONFERENCING: 11, +}; + +/** + * Definition for different groups of network routines. + * @enum {number} + */ +/* #export */ const RoutineGroup = { + CONNECTION: 0, + WIFI: 1, + PORTAL: 2, + GATEWAY: 3, + FIREWALL: 4, + DNS: 5, + GOOGLE_SERVICES: 6, +}; + +/* #export */ const Icons = { + TEST_FAILED: 'test_failed.png', + TEST_NOT_RUN: 'test_not_run.png', + TEST_PASSED: 'test_passed.png' +}; diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_container.html b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_container.html new file mode 100644 index 00000000000..5f36e04b83a --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_container.html @@ -0,0 +1,41 @@ +<link rel="import" href="../../../html/polymer.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> +<link rel="import" href="chrome://resources/cr_elements/icons.html"> + +<dom-module id="network-health-container"> + <template> + <style> + .container { + border: 1.5px solid rgb(175, 175, 175); + border-radius: 10px; + margin: 10px; + padding: 5px; + } + + .container-header { + align-items: center; + cursor: pointer; + display: flex; + min-height: 30px; + } + + .container-name { + flex: 1; + font-size: 1rem; + } + </style> + + <div class="container"> + <div class="container-header" on-click="onClick_"> + <div class="container-name">[[label]]</div> + <slot name="header"></slot> + <iron-icon icon="[[getArrowIcon_(expanded)]]"></iron-icon> + </div> + <template is="dom-if" if="[[expanded]]"> + <slot></slot> + </template> + </div> + + </template> + <script src="network_health_container.js"></script> +</dom-module> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_container.js b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_container.js new file mode 100644 index 00000000000..a942baea3c6 --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_container.js @@ -0,0 +1,47 @@ +// Copyright 2021 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. + +/** + * @fileoverview Polymer element for a container used in displaying network + * health info. + */ + +Polymer({ + is: 'network-health-container', + + properties: { + /** + * Boolean flag if the container is expanded. + */ + expanded: { + type: Boolean, + value: false, + }, + + /** + * Container label. + */ + label: { + type: String, + value: '', + }, + }, + + /** + * Returns the correct arrow icon depending on if the container is expanded. + * @param {boolean} expanded + */ + getArrowIcon_(expanded) { + return expanded ? 'cr:expand-less' : 'cr:expand-more'; + }, + + /** + * Helper function to toggle the expanded properties when the routine group + * is clicked. + * @private + */ + onClick_() { + this.set('expanded', !this.expanded); + }, +}); diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.html b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.html new file mode 100644 index 00000000000..ec34eaa7dd0 --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.html @@ -0,0 +1,4 @@ +<link rel="import" href="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.html"> + +<script src="chrome://resources/mojo/chromeos/services/network_health/public/mojom/network_health.mojom-lite.js"></script> +<script src="network_health_mojo.js"></script> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.js b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.js new file mode 100644 index 00000000000..c923f0eb763 --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_mojo.js @@ -0,0 +1,16 @@ +// Copyright 2020 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. + +// clang-format off +// #import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js'; +// #import 'chrome://resources/mojo/chromeos/services/network_config/public/mojom/network_types.mojom-lite.js'; +// #import 'chrome://resources/mojo/chromeos/services/network_health/public/mojom/network_health.mojom-lite.js'; +// clang-format on + +/** + * @fileoverview Wrapper around Network Health mojom file and associated + * utilities. + * TODO(crbug/1111852): Remove this wrapper once Polymer2 no longer needs to be + * supported. These imports can be used directly. + */ diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.html b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.html index e739493b39e..e7c0869063a 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.html +++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.html @@ -1,51 +1,124 @@ <link rel="import" href="../../../html/polymer.html"> -<link rel="import" href="chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.html"> -<link rel="import" href="chrome://resources/mojo/chromeos/services/network_health/public/mojom/network_health.mojom.html"> <link rel="import" href="../../../cr_elements/shared_style_css.html"> <link rel="import" href="../../../html/i18n_behavior.html"> - +<link rel="import" href="../network/onc_mojo.html"> +<link rel="import" href="network_health_mojo.html"> <dom-module id="network-health-summary"> <template> <style> - table { - width: 100%; + .network-attribute-container { + align-items: center; + display: flex; + margin: 5px; + } + + .network-attribute-label { + flex: 1; + padding-inline-start: 10px; + } + + .network-attribute-value { + flex: 1; } - tr, - td { - border: 1px solid rgb(220, 220, 220); - font-size: 13px; - padding: 5px; + .open-settings-icon { + height: 15px; } - .table-header { - font-size: 15px; - font-weight: bold; - padding-bottom: 15px; + .type-icon { + height: 20px; + width: 20px; } </style> - <table> - <tr class="table-header"> - <td>[[i18n('OncName')]]</td> - <td>[[i18n('OncType')]]</td> - <td>[[i18n('NetworkHealthState')]]</td> - <td>[[i18n('OncWiFi-SignalStrength')]]</td> - <td>[[i18n('OncMacAddress')]]</td> - </tr> - <hr> - <template is="dom-repeat" - items="[[networkHealthState_.networks]]" as="network"> - <tr> - <td>[[network.name]]</td> - <td>[[getNetworkTypeString_(network.type)]]</td> - <td>[[getNetworkStateString_(network.state)]]</td> - <td>[[getSignalStrengthString_(network.signalStrength)]]</td> - <td>[[network.macAddress]]</td> - </tr> - </template> - </table> + <template is="dom-repeat" items="[[networkHealthState_.networks]]" + as="network"> + <network-health-container label="[[getNetworkTypeString_(network.type)]]"> + <span slot="header"> + <img class="type-icon" src="[[getNetworkTypeIcon_(network.type)]]"> + </span> + <template is="dom-if" if="[[network.name]]"> + <div class="network-attribute-container"> + <div class="network-attribute-label"> + [[i18n('OncName')]] + </div> + <span class="network-attribute-value"> + [[network.name]] + </span> + </div> + </template> + <div class="network-attribute-container"> + <div class="network-attribute-label"> + [[i18n('NetworkHealthState')]] + </div> + <span class="network-attribute-value"> + [[getNetworkStateString_(network.state)]] + </span> + </div> + <template is="dom-if" if="[[showPortalState_(network)]]"> + <div class="network-attribute-container"> + <div class="network-attribute-label"> + [[i18n('OncPortalState')]] + </div> + <span class="network-attribute-value"> + [[getPortalStateString_(network.portalState)]] + </span> + </div> + </template> + <template is="dom-if" if="[[network.signalStrength]]"> + <div class="network-attribute-container"> + <div class="network-attribute-label"> + [[i18n('OncWiFi-SignalStrength')]] + </div> + <span class="network-attribute-value"> + [[getSignalStrengthString_(network.signalStrength)]] + </span> + </div> + </template> + <template is="dom-if" if="[[network.ipv4Address]]"> + <div class="network-attribute-container"> + <div class="network-attribute-label"> + [[i18n('OncIpv4Address')]] + </div> + <span class="network-attribute-value"> + [[network.ipv4Address]] + </span> + </div> + </template> + <template is="dom-if" if="[[network.ipv6Addresses.length]]"> + <div class="network-attribute-container"> + <div class="network-attribute-label"> + [[i18n('OncIpv6Address')]] + </div> + <span class="network-attribute-value"> + [[joinAddresses_(network.ipv6Addresses)]] + </span> + </div> + </template> + <template is="dom-if" if="[[network.macAddress]]"> + <div class="network-attribute-container"> + <div class="network-attribute-label"> + [[i18n('OncMacAddress')]] + </div> + <span class="network-attribute-value"> + [[network.macAddress]] + </span> + </div> + </template> + <template is="dom-if" if="[[showSettingsLink_(network)]]"> + <div class="network-attribute-container"> + <a href="[[getNetworkUrl_(network)]]"> + <div class="network-attribute-label"> + [[i18n('OpenInSettings')]] + <iron-icon class="open-settings-icon" icon="cr:open-in-new"> + </iron-icon> + </div> + </a> + </div> + </template> + </network-health-container> + </template> </template> <script src="network_health_summary.js"></script> </dom-module> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.js b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.js index a681b7e9aea..e40500ccb6a 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/network_health_summary.js @@ -2,6 +2,13 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +const TechnologyIcons = { + CELLULAR: 'cellular_0.svg', + ETHERNET: 'ethernet.svg', + VPN: 'vpn.svg', + WIFI: 'wifi_0.svg', +}; + /** * @fileoverview Polymer element for displaying NetworkHealth properties. */ @@ -83,6 +90,46 @@ Polymer({ }, /** + * Returns a boolean flag to show the PortalState attribute. The information + * is not meaningful in all cases and should be hidden to prevent confusion. + * @private + * @param {chromeos.networkHealth.mojom.Network} network + * @return {boolean} + */ + showPortalState_(network) { + const NetworkState = chromeos.networkHealth.mojom.NetworkState; + const PortalState = chromeos.networkConfig.mojom.PortalState; + + if (network.state === NetworkState.kOnline && + network.portalState === PortalState.kOnline) { + return false; + } + + const notApplicableStates = [ + NetworkState.kUninitialized, + NetworkState.kDisabled, + NetworkState.kProhibited, + NetworkState.kConnecting, + NetworkState.kNotConnected, + ]; + if (notApplicableStates.includes(network.state)) { + return false; + } + + return true; + }, + + /** + * Returns a string for the given PortalState. + * @private + * @param {chromeos.networkConfig.mojom.PortalState} state + * @return {string} + */ + getPortalStateString_(state) { + return this.i18n('OncPortalState' + OncMojo.getPortalStateString(state)); + }, + + /** * Returns a string for the given NetworkType. * @private * @param {chromeos.networkConfig.mojom.NetworkType} type @@ -93,6 +140,29 @@ Polymer({ }, /** + * Returns a icon for the given NetworkType. + * @private + * @param {chromeos.networkConfig.mojom.NetworkType} type + * @return {string} + */ + getNetworkTypeIcon_(type) { + switch (type) { + case chromeos.networkConfig.mojom.NetworkType.kEthernet: + return TechnologyIcons.ETHERNET; + case chromeos.networkConfig.mojom.NetworkType.kWiFi: + return TechnologyIcons.WIFI; + case chromeos.networkConfig.mojom.NetworkType.kVPN: + return TechnologyIcons.VPN; + case chromeos.networkConfig.mojom.NetworkType.kTether: + case chromeos.networkConfig.mojom.NetworkType.kMobile: + case chromeos.networkConfig.mojom.NetworkType.kCellular: + return TechnologyIcons.CELLULAR; + default: + return ''; + } + }, + + /** * Returns a string for the given signal strength. * @private * @param {?chromeos.networkHealth.mojom.UInt32Value} signalStrength @@ -101,4 +171,40 @@ Polymer({ getSignalStrengthString_(signalStrength) { return signalStrength ? signalStrength.value.toString() : ''; }, + + /** + * Returns a boolean flag if the open to settings link should be shown. + * @private + * @param {chromeos.networkHealth.mojom.Network} network + * @return {boolean} + */ + showSettingsLink_(network) { + const validStates = [ + chromeos.networkHealth.mojom.NetworkState.kConnected, + chromeos.networkHealth.mojom.NetworkState.kConnecting, + chromeos.networkHealth.mojom.NetworkState.kPortal, + chromeos.networkHealth.mojom.NetworkState.kOnline + ]; + return validStates.includes(network.state); + }, + + /** + * Returns a URL for the network's settings page. + * @private + * @param {chromeos.networkHealth.mojom.Network} network + * @return {string} + */ + getNetworkUrl_(network) { + return 'chrome://os-settings/networkDetail?guid=' + network.guid; + }, + + /** + * Returns a concatenated list of strings. + * @private + * @param {!Array<string>} addresses + * @return {string} + */ + joinAddresses_(addresses) { + return addresses.join(', '); + }, }); diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/routine_group.html b/chromium/ui/webui/resources/cr_components/chromeos/network_health/routine_group.html new file mode 100644 index 00000000000..07fb6d31f53 --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/routine_group.html @@ -0,0 +1,54 @@ +<link rel="import" href="../../../html/i18n_behavior.html"> +<link rel="import" href="../../../html/polymer.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html"> +<link rel="import" href="network_diagnostics_mojo.html"> +<link rel="import" href="network_diagnostics_types.html"> +<link rel="import" href="network_health_container.html"> + +<dom-module id="routine-group"> + <template> + <style> + .routine-container { + align-items: center; + display: flex; + height: 20px; + margin: 5px; + padding: 5px; + } + .routine-icon { + height: 25px; + width: auto; + } + .routine-name { + flex: 1; + font-size: 0.8rem; + padding-inline-start: 10px; + } + </style> + + <network-health-container expanded="[[expanded]]" label="[[name]]"> + <span slot="header"> + <template is="dom-if" if="[[running]]"> + <paper-spinner-lite active></paper-spinner-lite> + </template> + <img class="routine-icon" hidden="[[!showGroupIcon]]" + src="[[getGroupIcon_(routines.*)]]"> + </span> + <template is="dom-repeat" items="[[routines]]" as="routine" + mutable-data> + <div class="routine-container" aria-label="[[i18n(routine.name)]]" + aria-description="[[routine.ariaDescription]]"> + <img class="routine-icon" src="[[getRoutineIcon_(routine.result)]]"> + <div aria-hidden="true" class="routine-name"> + [[i18n(routine.name)]] + </div> + <div aria-hidden="true" hidden="[[!routine.resultMsg]]"> + [[routine.resultMsg]] + </div> + </div> + </template> + </network-health-container> + + </template> + <script src="routine_group.js"></script> +</dom-module> diff --git a/chromium/ui/webui/resources/cr_components/chromeos/network_health/routine_group.js b/chromium/ui/webui/resources/cr_components/chromeos/network_health/routine_group.js new file mode 100644 index 00000000000..ee5926cb3f7 --- /dev/null +++ b/chromium/ui/webui/resources/cr_components/chromeos/network_health/routine_group.js @@ -0,0 +1,151 @@ +// Copyright 2020 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. + +/** + * @fileoverview Polymer element for a group of diagnostic routines. + */ + +Polymer({ + is: 'routine-group', + + behaviors: [ + I18nBehavior, + ], + + properties: { + /** + * List of routines to display in the group. + * @private {!Array<!Routine>} + */ + routines: { + type: Array, + value: [], + }, + + /** + * Localized name for the group of routines. + * @private {String} + */ + name: { + type: String, + value: '', + }, + + /** + * Boolean flag if any routines in the group are running. + * @private {Boolean} + */ + running: { + type: Boolean, + computed: 'routinesRunning_(routines.*)', + }, + + /** + * Boolean flag if the container is expanded. + * @private {Boolean} + */ + expanded: { + type: Boolean, + value: false, + }, + + /** + * Boolean flag if icon representing the group result should be shown. + * @private {Boolean} + */ + showGroupIcon: { + type: Boolean, + computed: 'showGroupIcon_(running, expanded)', + }, + }, + + /** + * Helper function to get the icon for a group of routines based on all of + * their results. + * @param {!PolymerDeepPropertyChange} routines + * @return {string} + * @private + */ + getGroupIcon_(routines) { + // Assume that all tests are complete and passing until proven otherwise. + let complete = true; + let failed = false; + + for (const routine of /** @type {!Array<!Routine>} */ (routines.base)) { + if (!routine.result) { + complete = false; + continue; + } + + switch (routine.result.verdict) { + case chromeos.networkDiagnostics.mojom.RoutineVerdict.kNoProblem: + continue; + case chromeos.networkDiagnostics.mojom.RoutineVerdict.kProblem: + failed = true; + break; + case chromeos.networkDiagnostics.mojom.RoutineVerdict.kNotRun: + complete = false; + break; + } + } + + if (failed) { + return Icons.TEST_FAILED; + } + if (!complete) { + return Icons.TEST_NOT_RUN; + } + + return Icons.TEST_PASSED; + }, + + /** + * Determine if the group routine icon should be showing. + * @param {boolean} running + * @param {boolean} expanded + * @return {boolean} + * @private + */ + showGroupIcon_(running, expanded) { + return !running && !expanded; + }, + + /** + * Helper function to get the icon for a routine based on the result. + * @param {!RoutineResponse} result + * @return {string} + * @private + */ + getRoutineIcon_(result) { + if (!result) { + return Icons.TEST_NOT_RUN; + } + + switch (result.verdict) { + case chromeos.networkDiagnostics.mojom.RoutineVerdict.kNoProblem: + return Icons.TEST_PASSED; + case chromeos.networkDiagnostics.mojom.RoutineVerdict.kProblem: + return Icons.TEST_FAILED; + case chromeos.networkDiagnostics.mojom.RoutineVerdict.kNotRun: + return Icons.TEST_NOT_RUN; + } + + return Icons.TEST_NOT_RUN; + }, + + /** + * Determine if any routines in the group are running. + * @param {!PolymerDeepPropertyChange} routines + * @return {boolean} + * @private + */ + routinesRunning_(routines) { + for (const routine of /** @type {!Array<!Routine>} */ (routines.base)) { + if (routine.running) { + return true; + } + } + return false; + }, +}); diff --git a/chromium/ui/webui/resources/cr_components/chromeos/os_cr_components.gni b/chromium/ui/webui/resources/cr_components/chromeos/os_cr_components.gni index b9f33603437..c9fff8cc3e5 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/os_cr_components.gni +++ b/chromium/ui/webui/resources/cr_components/chromeos/os_cr_components.gni @@ -11,12 +11,25 @@ cr_components_chromeos_namespace_rewrites = [ "cellularSetup.ButtonBarState|ButtonBarState", "cellularSetup.CellularSetupPageName|CellularSetupPageName", "cellular_setup.ESimPageName|ESimPageName", + "cellular_setup.ESimUiState|ESimUiState", "cellularSetup.PSimPageName|PSimPageName", "cellularSetup.PSimUIState|PSimUIState", "cellularSetup.getTimeoutMsForPSimUIState|getTimeoutMsForPSimUIState", "cellular_setup.getCellularSetupRemote|getCellularSetupRemote", "cellular_setup.setCellularSetupRemoteForTesting|setCellularSetupRemoteForTesting", + "cellular_setup.getESimManagerRemote|getESimManagerRemote", + "cellular_setup.setESimManagerRemoteForTesting|setESimManagerRemoteForTesting", + "cellular_setup.observeESimManager|observeESimManager", + "cellular_setup.getPendingESimProfiles|getPendingESimProfiles", + "cellular_setup.getEuicc|getEuicc", + "cellular_setup.getESimProfile|getESimProfile", "cellular_setup.CellularSetupDelegate|CellularSetupDelegate", + "multidevice_setup.BrowserProxy|BrowserProxy", + "multidevice_setup.BrowserProxyImpl|BrowserProxyImpl", + "multidevice_setup.MojoInterfaceProvider|MojoInterfaceProvider", + "multidevice_setup.MojoInterfaceProviderImpl|MojoInterfaceProviderImpl", + "multidevice_setup.MultiDeviceSetupDelegate|MultiDeviceSetupDelegate", + "multidevice_setup.PageName|PageName", "network_config.MojoInterfaceProvider|MojoInterfaceProvider", "network_config.MojoInterfaceProviderImpl|MojoInterfaceProviderImpl", "settings.LockScreenProgress|LockScreenProgress", @@ -26,11 +39,20 @@ cr_components_chromeos_namespace_rewrites = [ cr_components_chromeos_auto_imports = [ "ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.html|CrPolicyIndicatorType", + "ui/webui/resources/cr_elements/cr_container_shadow_behavior.html|CrContainerShadowBehavior", "ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_types.html|ButtonState,Button,ButtonBarState,CellularSetupPageName", "ui/webui/resources/cr_components/chromeos/cellular_setup/cellular_setup_delegate.html|CellularSetupDelegate", "ui/webui/resources/cr_components/chromeos/cellular_setup/subflow_behavior.html|SubflowBehavior", - "ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.html|setCellularSetupRemoteForTesting,getCellularSetupRemote", + "ui/webui/resources/cr_components/chromeos/cellular_setup/mojo_interface_provider.html|setCellularSetupRemoteForTesting,getCellularSetupRemote,setESimManagerRemoteForTesting,getESimManagerRemote,observeESimManager", + "ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_utils.html|getPendingESimProfiles,getEuicc,getESimProfile", + "ui/webui/resources/cr_components/chromeos/cellular_setup/esim_manager_listener_behavior.html|ESimManagerListenerBehavior", + "ui/webui/resources/cr_components/chromeos/cellular_setup/setup_loading_page.html|LoadingPageState", + "ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_browser_proxy.html|BrowserProxy,BrowserProxyImpl", + "ui/webui/resources/cr_components/chromeos/multidevice_setup/mojo_api.html|MojoInterfaceProvider,MojoInterfaceProviderImpl", + "ui/webui/resources/cr_components/chromeos/multidevice_setup/multidevice_setup_delegate.html|MultiDeviceSetupDelegate", + "ui/webui/resources/cr_components/chromeos/multidevice_setup/ui_page_container_behavior.html|UiPageContainerBehavior", "ui/webui/resources/cr_components/chromeos/network/cr_policy_network_behavior_mojo.html|CrPolicyNetworkBehaviorMojo", + "ui/webui/resources/cr_components/chromeos/network/cellular_utils.html|getSimSlotCount,hasActivePSimNetwork", "ui/webui/resources/cr_components/chromeos/network/onc_mojo.html|OncMojo", "ui/webui/resources/cr_components/chromeos/network/network_config_element_behavior.html|NetworkConfigElementBehavior", "ui/webui/resources/cr_components/chromeos/network/network_listener_behavior.html|NetworkListenerBehavior", diff --git a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/BUILD.gn index 03c04595dce..2307509d23e 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/BUILD.gn +++ b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/BUILD.gn @@ -8,6 +8,7 @@ import("//ui/webui/resources/tools/js_modulizer.gni") import("../os_cr_components.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":pin_keyboard", ":setup_pin_keyboard", @@ -83,8 +84,6 @@ js_library("setup_pin_keyboard.m") { extra_deps = [ ":setup_pin_keyboard_module" ] } -import("//tools/polymer/polymer.gni") - group("polymer3_elements") { public_deps = [ ":modulize", diff --git a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.js b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.js index 42e29c2a0fd..d3ae8d7f677 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.js +++ b/chromium/ui/webui/resources/cr_components/chromeos/quick_unlock/pin_keyboard.js @@ -92,6 +92,14 @@ Polymer({ value: false, }, + // Whether or not non-digit pins are allowed. + // If allowNonDigit is false, any characters typed in the pin dialog + // will be swallowed. + allowNonDigit: { + type: Boolean, + value: false, + }, + hasError: Boolean, disabled: { @@ -401,11 +409,16 @@ Polymer({ /** * Helper function to check whether a given |event| should be processed by - * the numeric only input. + * the input. * @param {Event} event The event object. * @private */ isValidEventForInput_(event) { + // Valid if the key is a non-digit and allowNonDigit is enabled. + if (this.allowNonDigit) { + return true; + } + // Valid if the key is a number, and shift is not pressed. if ((event.keyCode >= 48 && event.keyCode <= 57) && !event.shiftKey) { return true; @@ -453,10 +466,12 @@ Polymer({ return; } - // Do not pass events that are not numbers or special keys we care about. We - // use this instead of input type number because there are several issues - // with input type number, such as no selectionStart/selectionEnd and - // entered non numbers causes the caret to jump to the left. + // If only digits are allowed in the pin input (allowNonDigit is set to + // false), then do not pass events that are not numbers or special keys we + // care about. We use this instead of input type number because there are + // several issues with input type number, such as no + // selectionStart/selectionEnd and entered non numbers causes the caret to + // jump to the left. if (!this.isValidEventForInput_(event)) { event.preventDefault(); return; diff --git a/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/BUILD.gn b/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/BUILD.gn index 0bf953c6789..855cc63a062 100644 --- a/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/BUILD.gn +++ b/chromium/ui/webui/resources/cr_components/chromeos/smb_shares/BUILD.gn @@ -11,13 +11,6 @@ assert(is_chromeos, "SMB Shares is Chrome OS only.") # TODO(crbug.com/1031947): Fully convert this component to Polymer 3 once # chrome://os-settings has been migrated. -js_type_check("closure_compile") { - deps = [ - ":add_smb_share_dialog", - ":smb_browser_proxy", - ] -} - js_type_check("closure_compile_module") { is_polymer3 = true deps = [ @@ -26,24 +19,6 @@ js_type_check("closure_compile_module") { ] } -js_library("smb_browser_proxy") { - deps = [ "//ui/webui/resources/js:cr" ] -} - -js_library("add_smb_share_dialog") { - deps = [ - ":smb_browser_proxy", - "//ui/webui/resources/cr_elements/cr_button:cr_button", - "//ui/webui/resources/cr_elements/cr_checkbox:cr_checkbox", - "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog", - "//ui/webui/resources/cr_elements/cr_input:cr_input", - "//ui/webui/resources/js:cr", - "//ui/webui/resources/js:i18n_behavior", - "//ui/webui/resources/js:load_time_data", - "//ui/webui/resources/js:web_ui_listener_behavior", - ] -} - js_library("add_smb_share_dialog.m") { sources = [ "$root_gen_dir/ui/webui/resources/cr_components/chromeos/smb_shares/add_smb_share_dialog.m.js" ] deps = [ diff --git a/chromium/ui/webui/resources/cr_components/cr_components_images.grdp b/chromium/ui/webui/resources/cr_components/cr_components_images.grdp deleted file mode 100644 index c0884efcd49..00000000000 --- a/chromium/ui/webui/resources/cr_components/cr_components_images.grdp +++ /dev/null @@ -1,134 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<grit-part> - <!-- CustomizeThemes Images --> - <include name="IDR_WEBUI_CR_COMPONENTS_CUSTOMIZE_THEMES_COLORIZE_ICON_SVG" - file="cr_components/customize_themes/colorize.svg" - type="BINDATA" /> - <include name="IDR_WEBUI_CR_COMPONENTS_CUSTOMIZE_THEMES_BRUSH_ICON_SVG" - file="cr_components/customize_themes/brush.svg" - type="BINDATA" /> - <if expr="chromeos"> - <!-- MultiDeviceSetup Images --> - <include name="IDR_WEBUI_CHROMEOS_MULTIDEVICE_SETUP_START_SETUP_ICON_1X_PNG" - file="cr_components/chromeos/multidevice_setup/start_setup_icon_1x.png" - type="BINDATA" - compress="gzip" /> - <include name="IDR_WEBUI_CHROMEOS_MULTIDEVICE_SETUP_START_SETUP_ICON_2X_PNG" - file="cr_components/chromeos/multidevice_setup/start_setup_icon_2x.png" - type="BINDATA" - compress="gzip" /> - <include name="IDR_WEBUI_CHROMEOS_MULTIDEVICE_SETUP_SETUP_SUCCEEDED_ICON_1X_PNG" - file="cr_components/chromeos/multidevice_setup/setup_succeeded_icon_1x.png" - type="BINDATA" - compress="gzip" /> - <include name="IDR_WEBUI_CHROMEOS_MULTIDEVICE_SETUP_SETUP_SUCCEEDED_ICON_2X_PNG" - file="cr_components/chromeos/multidevice_setup/setup_succeeded_icon_2x.png" - type="BINDATA" - compress="gzip" /> - - <!-- CellularSetup Images --> - <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_ACTIVATION_CODE_PAGE_CAMERA_SVG" - file="cr_components/chromeos/cellular_setup/activation_code_page_camera.svg" - type="BINDATA" - compress="gzip" /> - <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_ACTIVATION_CODE_PAGE_CHECKED_SVG" - file="cr_components/chromeos/cellular_setup/activation_code_page_checked.svg" - type="BINDATA" - compress="gzip" /> - <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_ACTIVATION_CODE_PAGE_SWITCH_CAMERA_SVG" - file="cr_components/chromeos/cellular_setup/activation_code_page_switch_camera.svg" - type="BINDATA" - compress="gzip" /> - <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_ERROR_1X_PNG" - file="cr_components/chromeos/cellular_setup/error_1x.png" - type="BINDATA" - compress="gzip" /> - <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_ERROR_2X_PNG" - file="cr_components/chromeos/cellular_setup/error_2x.png" - type="BINDATA" - compress="gzip" /> - <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_FINAL_PAGE_SUCCESS_1X_PNG" - file="cr_components/chromeos/cellular_setup/final_page_success_1x.png" - type="BINDATA" - compress="gzip" /> - <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_FINAL_PAGE_SUCCESS_2X_PNG" - file="cr_components/chromeos/cellular_setup/final_page_success_2x.png" - type="BINDATA" - compress="gzip" /> - <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_PSIM_1X_PNG" - file="cr_components/chromeos/cellular_setup/psim_1x.png" - type="BINDATA" - compress="gzip" /> - <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_PSIM_2X_PNG" - file="cr_components/chromeos/cellular_setup/psim_2x.png" - type="BINDATA" - compress="gzip" /> - <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_ESIM_1X_PNG" - file="cr_components/chromeos/cellular_setup/esim_1x.png" - type="BINDATA" - compress="gzip" /> - <include name="IDR_WEBUI_CHROMEOS_CELLULAR_SETUP_ESIM_2X_PNG" - file="cr_components/chromeos/cellular_setup/esim_2x.png" - type="BINDATA" - compress="gzip" /> - - <!-- NetworkIcon Images --> - <include name="IDR_CR_ELEMENTS_CELLULAR_0_WITH_X_SVG" - file="cr_components/chromeos/network/cellular_0_with_x.svg" - type="BINDATA" /> - <include name="IDR_CR_ELEMENTS_CELLULAR_0_SVG" - file="cr_components/chromeos/network/cellular_0.svg" - type="BINDATA" /> - <include name="IDR_CR_ELEMENTS_CELLULAR_1_SVG" - file="cr_components/chromeos/network/cellular_1.svg" - type="BINDATA" /> - <include name="IDR_CR_ELEMENTS_CELLULAR_2_SVG" - file="cr_components/chromeos/network/cellular_2.svg" - type="BINDATA" /> - <include name="IDR_CR_ELEMENTS_CELLULAR_3_SVG" - file="cr_components/chromeos/network/cellular_3.svg" - type="BINDATA" /> - <include name="IDR_CR_ELEMENTS_CELLULAR_4_SVG" - file="cr_components/chromeos/network/cellular_4.svg" - type="BINDATA" /> - <include name="IDR_CR_ELEMENTS_CELLULAR_OFF_SVG" - file="cr_components/chromeos/network/cellular_off.svg" - type="BINDATA" /> - <include name="IDR_CR_ELEMENTS_ETHERNET_SVG" - file="cr_components/chromeos/network/ethernet.svg" type="BINDATA" /> - <include name="IDR_CR_ELEMENTS_VPN_SVG" - file="cr_components/chromeos/network/vpn.svg" type="BINDATA" /> - <include name="IDR_CR_ELEMENTS_WIFI_0_WITH_X_SVG" - file="cr_components/chromeos/network/wifi_0_with_x.svg" - type="BINDATA" /> - <include name="IDR_CR_ELEMENTS_WIFI_0_SVG" - file="cr_components/chromeos/network/wifi_0.svg" type="BINDATA" /> - <include name="IDR_CR_ELEMENTS_WIFI_1_SVG" - file="cr_components/chromeos/network/wifi_1.svg" type="BINDATA" /> - <include name="IDR_CR_ELEMENTS_WIFI_2_SVG" - file="cr_components/chromeos/network/wifi_2.svg" type="BINDATA" /> - <include name="IDR_CR_ELEMENTS_WIFI_3_SVG" - file="cr_components/chromeos/network/wifi_3.svg" type="BINDATA" /> - <include name="IDR_CR_ELEMENTS_WIFI_4_SVG" - file="cr_components/chromeos/network/wifi_4.svg" type="BINDATA" /> - <include name="IDR_CR_ELEMENTS_WIFI_OFF_SVG" - file="cr_components/chromeos/network/wifi_off.svg" type="BINDATA" /> - - <!-- NetworkDiagnostics Images --> - <include name="IDR_CR_COMPONENTS_CHROMEOS_NETWORK_DIAGNOSTICS_CANCELED_ICON" - file="cr_components/chromeos/network_health/test_canceled.png" - type="BINDATA" /> - <include name="IDR_CR_COMPONENTS_CHROMEOS_NETWORK_DIAGNOSTICS_FAILED_ICON" - file="cr_components/chromeos/network_health/test_failed.png" - type="BINDATA" /> - <include name="IDR_CR_COMPONENTS_CHROMEOS_NETWORK_DIAGNOSTICS_NOT_RUN_ICON" - file="cr_components/chromeos/network_health/test_not_run.png" - type="BINDATA" /> - <include name="IDR_CR_COMPONENTS_CHROMEOS_NETWORK_DIAGNOSTICS_PASSED_ICON" - file="cr_components/chromeos/network_health/test_passed.png" - type="BINDATA" /> - <include name="IDR_CR_COMPONENTS_CHROMEOS_NETWORK_DIAGNOSTICS_WARNING_ICON" - file="cr_components/chromeos/network_health/test_warning.png" - type="BINDATA" /> - </if> -</grit-part> diff --git a/chromium/ui/webui/resources/cr_components/customize_themes/BUILD.gn b/chromium/ui/webui/resources/cr_components/customize_themes/BUILD.gn index 2f2f94cf709..526e533a88a 100644 --- a/chromium/ui/webui/resources/cr_components/customize_themes/BUILD.gn +++ b/chromium/ui/webui/resources/cr_components/customize_themes/BUILD.gn @@ -8,7 +8,7 @@ import("//tools/polymer/html_to_js.gni") group("web_components") { public_deps = [ - ":mojom_js", + ":mojom_webui_js", ":web_components_local", ] } @@ -20,6 +20,8 @@ mojom("mojom") { "//mojo/public/mojom/base", "//skia/public/mojom", ] + + webui_module_path = "chrome://resources/cr_components/customize_themes/" } html_to_js("web_components_local") { @@ -31,6 +33,7 @@ html_to_js("web_components_local") { js_type_check("closure_compile") { is_polymer3 = true + closure_flags = default_closure_args + mojom_js_args deps = [ ":browser_proxy", ":customize_themes", @@ -41,9 +44,10 @@ js_type_check("closure_compile") { js_library("customize_themes") { deps = [ ":browser_proxy", - ":mojom_js_library_for_compile", + ":mojom_webui_js", ":theme_icon", - "//skia/public/mojom:mojom_js_library_for_compile", + "//skia/public/mojom:mojom_webui_js", + "//third_party/polymer/v3_0/components-chromium/paper-tooltip:paper-tooltip", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", "//ui/webui/resources/cr_elements/cr_grid", "//ui/webui/resources/js:i18n_behavior.m", @@ -58,7 +62,7 @@ js_library("theme_icon") { js_library("browser_proxy") { deps = [ - ":mojom_js_library_for_compile", + ":mojom_webui_js", "//ui/webui/resources/js:cr.m", ] } diff --git a/chromium/ui/webui/resources/cr_components/customize_themes/browser_proxy.js b/chromium/ui/webui/resources/cr_components/customize_themes/browser_proxy.js index a5d2c2a92df..ae7a46b3764 100644 --- a/chromium/ui/webui/resources/cr_components/customize_themes/browser_proxy.js +++ b/chromium/ui/webui/resources/cr_components/customize_themes/browser_proxy.js @@ -7,18 +7,16 @@ * interact with the browser. */ -import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js'; -import 'chrome://resources/mojo/skia/public/mojom/skcolor.mojom-lite.js'; -import './customize_themes.mojom-lite.js'; - import {addSingletonGetter} from 'chrome://resources/js/cr.m.js'; +import {CustomizeThemesClientCallbackRouter, CustomizeThemesHandlerFactory, CustomizeThemesHandlerFactoryRemote, CustomizeThemesHandlerInterface, CustomizeThemesHandlerRemote} from './customize_themes.mojom-webui.js'; + /** @interface */ export class CustomizeThemesBrowserProxy { - /** @return {customizeThemes.mojom.CustomizeThemesHandlerInterface} */ + /** @return {CustomizeThemesHandlerInterface} */ handler() {} - /** @return {customizeThemes.mojom.CustomizeThemesClientCallbackRouter} */ + /** @return {CustomizeThemesClientCallbackRouter} */ callbackRouter() {} /** @param {string} url */ @@ -28,16 +26,14 @@ export class CustomizeThemesBrowserProxy { /** @implements {CustomizeThemesBrowserProxy} */ export class CustomizeThemesBrowserProxyImpl { constructor() { - /** @private {customizeThemes.mojom.CustomizeThemesHandlerRemote} */ - this.handler_ = new customizeThemes.mojom.CustomizeThemesHandlerRemote(); + /** @private {!CustomizeThemesHandlerRemote} */ + this.handler_ = new CustomizeThemesHandlerRemote(); - /** @private {customizeThemes.mojom.CustomizeThemesClientCallbackRouter} */ - this.callbackRouter_ = - new customizeThemes.mojom.CustomizeThemesClientCallbackRouter(); + /** @private {!CustomizeThemesClientCallbackRouter} */ + this.callbackRouter_ = new CustomizeThemesClientCallbackRouter(); - /** @type {customizeThemes.mojom.CustomizeThemesHandlerFactoryRemote} */ - const factory = - customizeThemes.mojom.CustomizeThemesHandlerFactory.getRemote(); + /** @type {!CustomizeThemesHandlerFactoryRemote} */ + const factory = CustomizeThemesHandlerFactory.getRemote(); factory.createCustomizeThemesHandler( this.callbackRouter_.$.bindNewPipeAndPassRemote(), this.handler_.$.bindNewPipeAndPassReceiver()); diff --git a/chromium/ui/webui/resources/cr_components/customize_themes/customize_themes.html b/chromium/ui/webui/resources/cr_components/customize_themes/customize_themes.html index d2fc1a6db81..e4a252f11cf 100644 --- a/chromium/ui/webui/resources/cr_components/customize_themes/customize_themes.html +++ b/chromium/ui/webui/resources/cr_components/customize_themes/customize_themes.html @@ -1,4 +1,4 @@ -<style include="cr-hidden-style cr-icons"> +<style include="cr-hidden-style cr-icons cr-shared-style"> :host { --cr-customize-themes-grid-gap: 20px; --cr-customize-themes-icon-size: 72px; @@ -68,18 +68,21 @@ } #autogeneratedThemeContainer { - display: flex; - flex-direction: column; position: relative; } + /* colorPicker is placed on top of the theme icon to work around + https://crbug.com/1162053 */ #colorPicker { border: 0; - height: 0; + height: var(--cr-customize-themes-icon-size); + left: 0; margin: 0; padding: 0; + position: absolute; + top: 0; visibility: hidden; - width: 0; + width: var(--cr-customize-themes-icon-size); } #colorPickerIcon { @@ -116,6 +119,14 @@ } } + paper-tooltip { + --paper-tooltip-delay-in: 100ms; + --paper-tooltip-duration-in: 100ms; + --paper-tooltip-duration-out: 100ms; + --paper-tooltip-min-width: none; + --paper-tooltip-padding: 5px 4px; + } + </style> <div id="thirdPartyThemeContainer" hidden="[[!isThirdPartyTheme_(selectedTheme)]]"> <div id="thirdPartyTheme"> @@ -135,28 +146,49 @@ </cr-button> </div> </div> -<cr-grid id="themesContainer" columns="6"> - <div id="autogeneratedThemeContainer" title="[[i18n('colorPickerLabel')]]" - tabindex="0" on-click="onAutogeneratedThemeClick_"> - <cr-theme-icon id="autogeneratedTheme" - selected$="[[isThemeIconSelected_('autogenerated', selectedTheme)]]"> +<cr-grid id="themesContainer" columns="6" role="radiogroup"> + <div aria-label="[[i18n('colorPickerLabel')]]" + tabindex$="[[getTabIndex_('autogenerated', selectedTheme)]]" + on-click="onAutogeneratedThemeClick_" role="radio" + aria-checked$="[[getThemeIconCheckedStatus_('autogenerated', selectedTheme)]]"> + <div id="autogeneratedThemeContainer"> + <cr-theme-icon id="autogeneratedTheme" + selected$="[[isThemeIconSelected_('autogenerated', selectedTheme)]]"> + </cr-theme-icon> + <div id="colorPickerIcon"></div> + <input id="colorPicker" type="color" + on-change="onCustomFrameColorChange_"> + </div> + <paper-tooltip offset="0" fit-to-visible-bounds> + [[i18n('colorPickerLabel')]] + </paper-tooltip> + </div> + <div aria-label="[[i18n('defaultThemeLabel')]]" + tabindex$="[[getTabIndex_('default', selectedTheme)]]" + on-click="onDefaultThemeClick_" role="radio" + aria-checked$="[[getThemeIconCheckedStatus_('default', selectedTheme)]]"> + <cr-theme-icon id="defaultTheme" + selected$="[[isThemeIconSelected_('default', selectedTheme)]]"> </cr-theme-icon> - <div id="colorPickerIcon"></div> - <input id="colorPicker" type="color" on-change="onCustomFrameColorChange_"> - </input> + <paper-tooltip offset="0" fit-to-visible-bounds> + [[i18n('defaultThemeLabel')]] + </paper-tooltip> </div> - <cr-theme-icon id="defaultTheme" title="[[i18n('defaultThemeLabel')]]" - on-click="onDefaultThemeClick_" tabindex="0" - selected$="[[isThemeIconSelected_('default', selectedTheme)]]"> - </cr-theme-icon> <template is="dom-repeat" id="themes" items="[[chromeThemes_]]"> - <cr-theme-icon title="[[item.label]]" on-click="onChromeThemeClick_" - style="--cr-theme-icon-frame-color: - [[skColorToRgba_(item.colors.frame)]]; - --cr-theme-icon-active-tab-color: - [[skColorToRgba_(item.colors.activeTab)]];" - tabindex="0" - selected$="[[isThemeIconSelected_(item.id, selectedTheme)]]"> - </cr-theme-icon> + <div aria-label="[[item.label]]" + tabindex$="[[getTabIndex_(item.id, selectedTheme)]]" + on-click="onChromeThemeClick_" class="chrome-theme-wrapper" role="radio" + aria-checked$="[[getThemeIconCheckedStatus_(item.id, selectedTheme)]]"> + <cr-theme-icon + style="--cr-theme-icon-frame-color: + [[skColorToRgba_(item.colors.frame)]]; + --cr-theme-icon-active-tab-color: + [[skColorToRgba_(item.colors.activeTab)]];" + selected$="[[isThemeIconSelected_(item.id, selectedTheme)]]"> + </cr-theme-icon> + <paper-tooltip offset="0" fit-to-visible-bounds> + [[item.label]] + </paper-tooltip> + </div> </template> </cr-grid> diff --git a/chromium/ui/webui/resources/cr_components/customize_themes/customize_themes.js b/chromium/ui/webui/resources/cr_components/customize_themes/customize_themes.js index d5d84bbd109..f1260fcf3c4 100644 --- a/chromium/ui/webui/resources/cr_components/customize_themes/customize_themes.js +++ b/chromium/ui/webui/resources/cr_components/customize_themes/customize_themes.js @@ -7,11 +7,11 @@ import '../../cr_elements/cr_icon_button/cr_icon_button.m.js'; import '../../cr_elements/cr_icons_css.m.js'; import '../../cr_elements/cr_grid/cr_grid.js'; import '../../cr_elements/shared_vars_css.m.js'; -import 'chrome://resources/mojo/mojo/public/js/mojo_bindings_lite.js'; -import 'chrome://resources/mojo/skia/public/mojom/skcolor.mojom-lite.js'; -import './customize_themes.mojom-lite.js'; +import '../../cr_elements/shared_style_css.m.js'; import './theme_icon.js'; +import '//resources/polymer/v3_0/paper-tooltip/paper-tooltip.js'; +import {SkColor} from 'chrome://resources/mojo/skia/public/mojom/skcolor.mojom-webui.js'; import {html, mixinBehaviors, PolymerElement} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js'; import {assert} from '../../js/assert.m.js'; @@ -19,6 +19,7 @@ import {hexColorToSkColor, skColorToRgba} from '../../js/color_utils.js'; import {I18nBehavior} from '../../js/i18n_behavior.m.js'; import {CustomizeThemesBrowserProxyImpl} from './browser_proxy.js'; +import {ChromeTheme, CustomizeThemesClientCallbackRouter, CustomizeThemesHandlerRemote, Theme, ThemeType} from './customize_themes.mojom-webui.js'; /** * Element that lets the user configure the autogenerated theme. @@ -39,10 +40,11 @@ export class CustomizeThemesElement extends mixinBehaviors return { /** * An object describing the currently selected theme. - * @type {!customizeThemes.mojom.Theme} + * @type {?Theme} */ selectedTheme: { type: Object, + value: null, observer: 'onThemeChange_', notify: true, }, @@ -58,17 +60,17 @@ export class CustomizeThemesElement extends mixinBehaviors value: false, }, - /** @private {!Array<!customizeThemes.mojom.ChromeTheme>} */ + /** @private {!Array<!ChromeTheme>} */ chromeThemes_: Array, }; } constructor() { super(); - /** @private {customizeThemes.mojom.CustomizeThemesHandlerRemote} */ + /** @private {CustomizeThemesHandlerRemote} */ this.handler_ = CustomizeThemesBrowserProxyImpl.getInstance().handler(); - /** @private {customizeThemes.mojom.CustomizeThemesClientCallbackRouter} */ + /** @private {CustomizeThemesClientCallbackRouter} */ this.callbackRouter_ = CustomizeThemesBrowserProxyImpl.getInstance().callbackRouter(); @@ -142,8 +144,8 @@ export class CustomizeThemesElement extends mixinBehaviors /** @private */ onThemeChange_() { - if (this.selectedTheme.type !== - customizeThemes.mojom.ThemeType.kAutogenerated) { + if (!this.selectedTheme || + this.selectedTheme.type !== ThemeType.kAutogenerated) { return; } const rgbaFrameColor = @@ -188,29 +190,47 @@ export class CustomizeThemesElement extends mixinBehaviors return false; } if (id === 'autogenerated') { - return this.selectedTheme.type === - customizeThemes.mojom.ThemeType.kAutogenerated; + return this.selectedTheme.type === ThemeType.kAutogenerated; } else if (id === 'default') { - return this.selectedTheme.type === - customizeThemes.mojom.ThemeType.kDefault; + return this.selectedTheme.type === ThemeType.kDefault; } else { - return this.selectedTheme.type === - customizeThemes.mojom.ThemeType.kChrome && + return this.selectedTheme.type === ThemeType.kChrome && id === this.selectedTheme.info.chromeThemeId; } } /** + * @param {string|number} id + * @return {string} + * @private + */ + getTabIndex_(id) { + if (!this.selectedTheme && id === 'autogenerated') { + return '0'; + } + return this.isThemeIconSelected_(id) ? '0' : '-1'; + } + + /** + * @param {string|number} id + * @return {string} + * @private + */ + getThemeIconCheckedStatus_(id) { + return this.isThemeIconSelected_(id) ? 'true' : 'false'; + } + + /** * @return {boolean} * @private */ isThirdPartyTheme_() { - return this.selectedTheme.type === - customizeThemes.mojom.ThemeType.kThirdParty; + return !!this.selectedTheme && + this.selectedTheme.type === ThemeType.kThirdParty; } /** - * @param {skia.mojom.SkColor} skColor + * @param {SkColor} skColor * @return {string} * @private */ diff --git a/chromium/ui/webui/resources/cr_components/customize_themes/theme_icon.html b/chromium/ui/webui/resources/cr_components/customize_themes/theme_icon.html index 7a56940625d..9a70c8bda2a 100644 --- a/chromium/ui/webui/resources/cr_components/customize_themes/theme_icon.html +++ b/chromium/ui/webui/resources/cr_components/customize_themes/theme_icon.html @@ -1,6 +1,8 @@ <style> :host { --cr-theme-icon-size: 72px; + cursor: pointer; + display: block; } :host, diff --git a/chromium/ui/webui/resources/cr_components/managed_footnote/BUILD.gn b/chromium/ui/webui/resources/cr_components/managed_footnote/BUILD.gn index 0ec7f641f02..3f4a86dcdc7 100644 --- a/chromium/ui/webui/resources/cr_components/managed_footnote/BUILD.gn +++ b/chromium/ui/webui/resources/cr_components/managed_footnote/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":managed_footnote" ] } diff --git a/chromium/ui/webui/resources/cr_components/omnibox/BUILD.gn b/chromium/ui/webui/resources/cr_components/omnibox/BUILD.gn index b02454dcd94..978d475683c 100644 --- a/chromium/ui/webui/resources/cr_components/omnibox/BUILD.gn +++ b/chromium/ui/webui/resources/cr_components/omnibox/BUILD.gn @@ -6,7 +6,6 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/html_to_js.gni") js_type_check("closure_compile") { - uses_js_modules = true deps = [ ":cr_autocomplete_match_list" ] } diff --git a/chromium/ui/webui/resources/cr_components/omnibox/cr_autocomplete_match_list.js b/chromium/ui/webui/resources/cr_components/omnibox/cr_autocomplete_match_list.js index c5e48719093..7b22109424b 100644 --- a/chromium/ui/webui/resources/cr_components/omnibox/cr_autocomplete_match_list.js +++ b/chromium/ui/webui/resources/cr_components/omnibox/cr_autocomplete_match_list.js @@ -16,11 +16,14 @@ */ let AutocompleteMatch; +const staticHtmlPolicy = trustedTypes.createPolicy( + 'cr-autocomplete-match', {createHTML: () => `{__html_template__}`}); + class AutocompleteMatchElement extends HTMLElement { constructor() { super(); this.attachShadow({mode: 'open'}); - this.shadowRoot.innerHTML = `{__html_template__}`; + this.shadowRoot.innerHTML = staticHtmlPolicy.createHTML(''); } /** @param {!AutocompleteMatch} match */ @@ -47,8 +50,8 @@ export class AutocompleteMatchListElement extends HTMLElement { /** @param {!Array<!AutocompleteMatch>} matches */ updateMatches(matches) { - for (let i = 0; i < matches.length; i++) { - const shadowRoot = /** @type {!ParentNode} */ (this.shadowRoot); + const shadowRoot = /** @type {!ParentNode} */ (this.shadowRoot); + for (let i = 0; i < matches.length && i < shadowRoot.children.length; i++) { shadowRoot.children[i].updateMatch(matches[i]); } } diff --git a/chromium/ui/webui/resources/cr_elements/BUILD.gn b/chromium/ui/webui/resources/cr_elements/BUILD.gn index 708349fa816..abae49ca3a1 100644 --- a/chromium/ui/webui/resources/cr_elements/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/BUILD.gn @@ -2,8 +2,9 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/chromeos/ui_mode.gni") import("//third_party/closure_compiler/compile_js.gni") -import("//tools/grit/preprocess_grit.gni") +import("//tools/grit/preprocess_if_expr.gni") import("//tools/polymer/html_to_js.gni") import("//tools/polymer/polymer.gni") import("//ui/webui/resources/tools/generate_grd.gni") @@ -34,14 +35,14 @@ group("preprocess") { ] } -preprocess_grit("preprocess_src") { +preprocess_if_expr("preprocess_src") { in_folder = "./" out_folder = "$preprocess_folder" out_manifest = "$target_gen_dir/$preprocess_src_manifest" in_files = [ "cr_splitter/cr_splitter.js" ] } -preprocess_grit("preprocess_polymer2") { +preprocess_if_expr("preprocess_polymer2") { in_folder = "./" out_folder = "$preprocess_folder" out_manifest = "$target_gen_dir/$preprocess_polymer2_manifest" @@ -106,12 +107,8 @@ preprocess_grit("preprocess_polymer2") { "cr_toast/cr_toast_manager.js", "cr_toggle/cr_toggle.html", "cr_toggle/cr_toggle.js", - "cr_toolbar/cr_toolbar.html", - "cr_toolbar/cr_toolbar.js", "cr_toolbar/cr_toolbar_search_field.html", "cr_toolbar/cr_toolbar_search_field.js", - "cr_toolbar/cr_toolbar_selection_overlay.html", - "cr_toolbar/cr_toolbar_selection_overlay.js", "cr_view_manager/cr_view_manager.html", "cr_view_manager/cr_view_manager.js", "find_shortcut_behavior.html", @@ -134,7 +131,7 @@ preprocess_grit("preprocess_polymer2") { "shared_vars_css.html", ] - if (is_chromeos) { + if (is_chromeos_ash) { in_files += [ "chromeos/cros_color_overrides.html", "chromeos/cr_picture/cr_camera.html", @@ -154,7 +151,7 @@ preprocess_grit("preprocess_polymer2") { } } -preprocess_grit("preprocess_generated") { +preprocess_if_expr("preprocess_generated") { deps = [ ":polymer3_elements" ] in_folder = target_gen_dir out_folder = "$preprocess_folder" @@ -195,9 +192,9 @@ preprocess_grit("preprocess_generated") { "cr_toast/cr_toast_manager.m.js", "cr_toast/cr_toast.m.js", "cr_toggle/cr_toggle.m.js", - "cr_toolbar/cr_toolbar.m.js", + "cr_toolbar/cr_toolbar.js", "cr_toolbar/cr_toolbar_search_field.m.js", - "cr_toolbar/cr_toolbar_selection_overlay.m.js", + "cr_toolbar/cr_toolbar_selection_overlay.js", "cr_view_manager/cr_view_manager.m.js", "find_shortcut_behavior.m.js", "hidden_style_css.m.js", @@ -216,7 +213,7 @@ preprocess_grit("preprocess_generated") { "shared_vars_css.m.js", ] - if (is_chromeos) { + if (is_chromeos_ash) { in_files += [ "chromeos/cros_color_overrides.m.js", "chromeos/cr_picture/cr_camera.m.js", @@ -285,7 +282,7 @@ group("closure_compile") { "policy:closure_compile_module", ] - if (is_chromeos) { + if (is_chromeos_ash) { deps += [ "chromeos:closure_compile", @@ -298,6 +295,7 @@ group("closure_compile") { } js_type_check("cr_elements_resources") { + uses_legacy_modules = true deps = [ ":cr_container_shadow_behavior", ":cr_scrollable_behavior", @@ -426,7 +424,7 @@ group("polymer3_elements") { "policy:polymer3_elements", ] - if (is_chromeos) { + if (is_chromeos_ash) { public_deps += [ "chromeos:polymer3_elements", diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/BUILD.gn b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/BUILD.gn index fb064493ebc..5a3b0bc6507 100644 --- a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/BUILD.gn @@ -2,12 +2,14 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/chromeos/ui_mode.gni") import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") import("//ui/webui/resources/tools/js_modulizer.gni") import("../os_cr_elements.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_camera", ":cr_picture_list", @@ -74,7 +76,7 @@ js_library("png.m") { # platforms. js_library("cr_picture_types.m") { sources = [] - if (is_chromeos) { + if (is_chromeos_ash) { sources += [ "$root_gen_dir/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_types.m.js" ] } extra_deps = [ ":modulize" ] @@ -95,7 +97,7 @@ group("polymer3_elements") { # platforms. js_library("cr_picture_pane.m") { sources = [] - if (is_chromeos) { + if (is_chromeos_ash) { sources += [ "$root_gen_dir/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.m.js" ] } deps = [ @@ -111,7 +113,7 @@ js_library("cr_picture_pane.m") { # platforms. js_library("cr_camera.m") { sources = [] - if (is_chromeos) { + if (is_chromeos_ash) { sources += [ "$root_gen_dir/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.m.js" ] } deps = [ ":png.m" ] @@ -123,7 +125,7 @@ js_library("cr_camera.m") { # platforms. js_library("cr_picture_list.m") { sources = [] - if (is_chromeos) { + if (is_chromeos_ash) { sources += [ "$root_gen_dir/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.m.js" ] } deps = [ diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.js b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.js index 1b14deab74d..22fe07f57bd 100644 --- a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.js +++ b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_camera.js @@ -325,5 +325,5 @@ Polymer({ return videomode ? cameraLabel : videoLabel; }, }); - +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); })(); diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.js b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.js index 6630fd546e0..9ca122210bc 100644 --- a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.js +++ b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_list.js @@ -327,3 +327,4 @@ Polymer({ return url + '[0]@2x 2x'; }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.js b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.js index db3d118cfb5..5f39365ae83 100644 --- a/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.js +++ b/chromium/ui/webui/resources/cr_elements/chromeos/cr_picture/cr_picture_pane.js @@ -166,3 +166,4 @@ Polymer({ return url; }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/chromeos/os_cr_elements.gni b/chromium/ui/webui/resources/cr_elements/chromeos/os_cr_elements.gni index d8068b19601..b9c7dba0c96 100644 --- a/chromium/ui/webui/resources/cr_elements/chromeos/os_cr_elements.gni +++ b/chromium/ui/webui/resources/cr_elements/chromeos/os_cr_elements.gni @@ -7,6 +7,7 @@ import("//third_party/closure_compiler/compile_js.gni") cr_elements_chromeos_namespace_rewrites = [ "cr.png.convertImageSequenceToPng|convertImageSequenceToPng", "cr.png.isEncodedPngDataUrlAnimated|isEncodedPngDataUrlAnimated", + "cr.ui.Action|Action", ] cr_elements_chromeos_auto_imports = [ diff --git a/chromium/ui/webui/resources/cr_elements/cr_action_menu/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_action_menu/BUILD.gn index a9f68f48686..bed5943f049 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_action_menu/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_action_menu/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_action_menu" ] } @@ -13,6 +14,7 @@ js_library("cr_action_menu") { deps = [ "//ui/webui/resources/js:assert", "//ui/webui/resources/js:util", + "//ui/webui/resources/js/cr/ui:focus_outline_manager", "//ui/webui/resources/js/cr/ui:focus_row", "//ui/webui/resources/js/cr/ui:focus_without_ink", ] @@ -31,6 +33,7 @@ polymer_modulizer("cr_action_menu") { "ui/webui/resources/html/polymer.html|dom,html,Polymer", "ui/webui/resources/html/assert.html|assert", "ui/webui/resources/html/cr.html|isMac, isWindows", + "ui/webui/resources/html/cr/ui/focus_outline_manager.html|FocusOutlineManager", "ui/webui/resources/html/cr/ui/focus_row.html|FocusRow", "ui/webui/resources/html/util.html|getDeepActiveElement, hasKeyModifiers", ] @@ -48,6 +51,7 @@ js_library("cr_action_menu.m") { "//ui/webui/resources/js:assert.m", "//ui/webui/resources/js:cr.m", "//ui/webui/resources/js:util.m", + "//ui/webui/resources/js/cr/ui:focus_outline_manager.m", "//ui/webui/resources/js/cr/ui:focus_row.m", "//ui/webui/resources/js/cr/ui:focus_without_ink.m", ] diff --git a/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html b/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html index c8e1972cf47..e6d1e289a45 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html +++ b/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.html @@ -2,6 +2,7 @@ <link rel="import" href="../../html/assert.html"> <link rel="import" href="../../html/cr.html"> +<link rel="import" href="../../html/cr/ui/focus_outline_manager.html"> <link rel="import" href="../../html/cr/ui/focus_row.html"> <link rel="import" href="../../html/cr/ui/focus_without_ink.html"> <link rel="import" href="../../html/util.html"> diff --git a/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js b/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js index 22143432f9e..26ec3f46e5c 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js +++ b/chromium/ui/webui/resources/cr_elements/cr_action_menu/cr_action_menu.js @@ -50,6 +50,10 @@ let ShowAtConfig; /** @const {string} */ const DROPDOWN_ITEM_CLASS = 'dropdown-item'; +/** @const {string} */ +const SELECTABLE_DROPDOWN_ITEM_QUERY = + `.${DROPDOWN_ITEM_CLASS}:not([hidden]):not([disabled])`; + (function() { /** @const {number} */ @@ -254,8 +258,8 @@ Polymer({ return; } - const query = '.dropdown-item:not([disabled]):not([hidden])'; - const options = Array.from(this.querySelectorAll(query)); + const options = + Array.from(this.querySelectorAll(SELECTABLE_DROPDOWN_ITEM_QUERY)); if (options.length === 0) { return; } @@ -294,8 +298,8 @@ Polymer({ * @private */ onMouseover_(e) { - const query = '.dropdown-item:not([disabled])'; - const item = e.composedPath().find(el => el.matches && el.matches(query)); + const item = e.composedPath().find( + el => el.matches && el.matches(SELECTABLE_DROPDOWN_ITEM_QUERY)); (item || this.$.wrapper).focus(); }, @@ -424,6 +428,19 @@ Polymer({ doc.scrollTop = scrollTop; doc.scrollLeft = scrollLeft; this.addListeners_(); + + // Focus the first selectable item. + const openedByKey = cr.ui.FocusOutlineManager.forDocument(document).visible; + if (openedByKey) { + const firstSelectableItem = + this.querySelector(SELECTABLE_DROPDOWN_ITEM_QUERY); + if (firstSelectableItem) { + requestAnimationFrame(() => { + // Wait for the next animation frame for the dialog to become visible. + firstSelectableItem.focus(); + }); + } + } }, /** @private */ @@ -507,4 +524,5 @@ Polymer({ } }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); })(); diff --git a/chromium/ui/webui/resources/cr_elements/cr_button/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_button/BUILD.gn index aa1cc36cf99..7f6dae0aec2 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_button/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_button/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_button" ] } diff --git a/chromium/ui/webui/resources/cr_elements/cr_button/cr_button.js b/chromium/ui/webui/resources/cr_elements/cr_button/cr_button.js index f31d61c3a87..c82e93d0994 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_button/cr_button.js +++ b/chromium/ui/webui/resources/cr_elements/cr_button/cr_button.js @@ -207,3 +207,4 @@ Polymer({ return ripple; }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/cr_checkbox/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_checkbox/BUILD.gn index 74c4a13a2b8..f7f9dee0ef1 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_checkbox/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_checkbox/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_checkbox" ] } diff --git a/chromium/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.js b/chromium/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.js index dd96835d470..04709bcfb32 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.js +++ b/chromium/ui/webui/resources/cr_elements/cr_checkbox/cr_checkbox.js @@ -162,3 +162,4 @@ Polymer({ return ripple; }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/cr_dialog/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_dialog/BUILD.gn index 930c63c9e85..f80650e6e58 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_dialog/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_dialog/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_dialog" ] } diff --git a/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html b/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html index 2e14f41d854..66a36e9747a 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html +++ b/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.html @@ -71,7 +71,8 @@ :host ::slotted([slot=title]) { color: var(--cr-primary-text-color); flex: 1; - font-size: calc(15 / 13 * 100%); + font-family: var(--cr-dialog-font-family, inherit); + font-size: var(--cr-dialog-title-font-size, calc(15 / 13 * 100%)); line-height: 1; padding-bottom: var(--cr-dialog-title-slot-padding-bottom, 16px); padding-inline-end: var(--cr-dialog-title-slot-padding-end, 20px); diff --git a/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.js b/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.js index aa4bfb6175d..45b68193801 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.js +++ b/chromium/ui/webui/resources/cr_elements/cr_dialog/cr_dialog.js @@ -342,3 +342,4 @@ Polymer({ this.$$('.title-container').focus(); }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/cr_drawer/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_drawer/BUILD.gn index fa80a4450c4..5278be6707c 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_drawer/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_drawer/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_drawer" ] } diff --git a/chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.js b/chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.js index 0396618c9d7..b11ab231352 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.js +++ b/chromium/ui/webui/resources/cr_elements/cr_drawer/cr_drawer.js @@ -145,3 +145,4 @@ Polymer({ this.fire('close'); }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/cr_expand_button/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_expand_button/BUILD.gn index b95011cfb77..c0bc8f39ba2 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_expand_button/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_expand_button/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_expand_button" ] } diff --git a/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.js b/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.js index 6a31d9158e6..af8c2140091 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.js +++ b/chromium/ui/webui/resources/cr_elements/cr_expand_button/cr_expand_button.js @@ -32,9 +32,9 @@ Polymer({ }, /** A11y text descriptor for this control. */ - alt: { + ariaLabel: { type: String, - observer: 'onAltChange_', + observer: 'onAriaLabelChange_', }, tabIndex: { @@ -66,10 +66,10 @@ Polymer({ }, /** @private */ - onAltChange_() { - if (this.alt) { + onAriaLabelChange_() { + if (this.ariaLabel) { this.$.icon.removeAttribute('aria-labelledby'); - this.$.icon.setAttribute('aria-label', this.alt); + this.$.icon.setAttribute('aria-label', this.ariaLabel); } else { this.$.icon.removeAttribute('aria-label'); this.$.icon.setAttribute('aria-labelledby', 'label'); @@ -105,3 +105,4 @@ Polymer({ } }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/cr_fingerprint/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_fingerprint/BUILD.gn index bf19ba93144..d16e38bb1a2 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_fingerprint/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_fingerprint/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_fingerprint_progress_arc" ] } diff --git a/chromium/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.js b/chromium/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.js index 347fc7022dd..3425ce28f52 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.js +++ b/chromium/ui/webui/resources/cr_elements/cr_fingerprint/cr_fingerprint_progress_arc.js @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// #import {CrLottieElement} from '../cr_lottie/cr_lottie.m.js'; - /** @type {string} */ /* #export */ const FINGEPRINT_TICK_DARK_URL = 'chrome://theme/IDR_FINGERPRINT_COMPLETE_TICK_DARK'; @@ -424,4 +422,5 @@ Polymer({ return this.isComplete_; }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); })(); diff --git a/chromium/ui/webui/resources/cr_elements/cr_icon_button/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_icon_button/BUILD.gn index fa12081e5ff..ad2d8613851 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_icon_button/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_icon_button/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_icon_button" ] } diff --git a/chromium/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.html b/chromium/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.html index 31727bd9a17..6e931290d54 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.html +++ b/chromium/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.html @@ -58,6 +58,7 @@ -webkit-mask-position: center; -webkit-mask-repeat: no-repeat; -webkit-mask-size: var(--cr-icon-button-icon-size); + -webkit-transform: var(--cr-icon-image-transform, none); background-color: var(--cr-icon-button-fill-color); height: 100%; transition: background-color var(--cr-icon-button-transition); diff --git a/chromium/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.js b/chromium/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.js index efcd199a2ed..d06a35bee1c 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.js +++ b/chromium/ui/webui/resources/cr_elements/cr_icon_button/cr_icon_button.js @@ -263,3 +263,4 @@ Polymer({ return ripple; }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/cr_input/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_input/BUILD.gn index c8792942c65..5eebbd6a854 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_input/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_input/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_input" ] } diff --git a/chromium/ui/webui/resources/cr_elements/cr_input/cr_input.html b/chromium/ui/webui/resources/cr_elements/cr_input/cr_input.html index b12e77a65e0..13d6012b761 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_input/cr_input.html +++ b/chromium/ui/webui/resources/cr_elements/cr_input/cr_input.html @@ -81,7 +81,12 @@ form with cr-inputs that can be invalid, this space is also desired in order to have consistent spacing. - If spacing is not needed, apply "--cr-input-error-display: none". */ + If spacing is not needed, apply "--cr-input-error-display: none". + + When grouping cr-inputs horizontally, it might be helpful to set + --cr-input-error-white-space to "nowrap" and set a fixed width for + each cr-input so that a long error label does not shift the inputs + forward. */ color: var(--cr-input-error-color); display: var(--cr-input-error-display, block); font-size: var(--cr-form-field-label-font-size); @@ -89,6 +94,7 @@ line-height: var(--cr-form-field-label-line-height); margin: 8px 0; visibility: hidden; + white-space: var(--cr-input-error-white-space); } :host([invalid]) #error { diff --git a/chromium/ui/webui/resources/cr_elements/cr_input/cr_input.js b/chromium/ui/webui/resources/cr_elements/cr_input/cr_input.js index cd207120b59..1c455bbb1ad 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_input/cr_input.js +++ b/chromium/ui/webui/resources/cr_elements/cr_input/cr_input.js @@ -424,4 +424,5 @@ Polymer({ return !this.invalid; }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); })(); diff --git a/chromium/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html b/chromium/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html index 94fa57a6004..cf34040bf71 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html +++ b/chromium/ui/webui/resources/cr_elements/cr_input/cr_input_style_css.html @@ -55,6 +55,7 @@ color: var(--cr-input-color); font-family: inherit; font-size: inherit; + font-weight: inherit; line-height: inherit; min-height: var(--cr-input-min-height, auto); outline: none; @@ -95,7 +96,7 @@ :host([invalid]) #underline, :host([force-underline]) #underline, - :host([focused_]:not([readonly])) #underline { + :host([focused_]) #underline { opacity: 1; transition: opacity 120ms ease-in, width 180ms ease-out; width: 100%; diff --git a/chromium/ui/webui/resources/cr_elements/cr_lazy_render/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_lazy_render/BUILD.gn index f04a480c7bd..6a9231335a7 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_lazy_render/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_lazy_render/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_lazy_render" ] } diff --git a/chromium/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.js b/chromium/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.js index b3d2419dcd1..67124f7c885 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.js +++ b/chromium/ui/webui/resources/cr_elements/cr_lazy_render/cr_lazy_render.js @@ -70,3 +70,4 @@ Polymer({ } }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/cr_link_row/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_link_row/BUILD.gn index 7e22f871037..a8f9be64378 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_link_row/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_link_row/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_link_row" ] } diff --git a/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html b/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html index e5e41217d31..7b5da7ef4e6 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html +++ b/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.html @@ -80,8 +80,9 @@ </div> <slot></slot> <cr-icon-button id="icon" iron-icon="[[getIcon_(external)]]" role="link" - aria-roledescription$="[[roleDescription]]" aria-describedby="subLabel" - aria-labelledby="label" disabled="[[disabled]]"></cr-icon-button> + aria-roledescription$="[[roleDescription]]" + aria-labelledby="label subLabel" disabled="[[disabled]]"> + </cr-icon-button> </template> <script src="cr_link_row.js"></script> </dom-module> diff --git a/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.js b/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.js index 9f320e23a05..79308b13bf4 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.js +++ b/chromium/ui/webui/resources/cr_elements/cr_link_row/cr_link_row.js @@ -83,3 +83,4 @@ Polymer({ return this.external ? 'cr:open-in-new' : 'cr:arrow-right'; }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/cr_lottie/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_lottie/BUILD.gn index d6fac4abfac..3c561858ca9 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_lottie/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_lottie/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_lottie" ] } diff --git a/chromium/ui/webui/resources/cr_elements/cr_lottie/cr_lottie.js b/chromium/ui/webui/resources/cr_elements/cr_lottie/cr_lottie.js index 58f4216022c..06dd077ebc8 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_lottie/cr_lottie.js +++ b/chromium/ui/webui/resources/cr_elements/cr_lottie/cr_lottie.js @@ -273,3 +273,4 @@ Polymer({ } }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/cr_menu_selector/cr_menu_selector.js b/chromium/ui/webui/resources/cr_elements/cr_menu_selector/cr_menu_selector.js index 7b1254a8a3a..3f2225bc2bf 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_menu_selector/cr_menu_selector.js +++ b/chromium/ui/webui/resources/cr_elements/cr_menu_selector/cr_menu_selector.js @@ -46,9 +46,10 @@ export class CrMenuSelector extends HTMLElement { // If the focus was moved by keyboard and is coming in from a relatedTarget // that is not within this menu, move the focus to the first menu item. This // ensures that the first menu item is always the first focused item when - // focusing into the menu. + // focusing into the menu. A null relatedTarget means the focus was moved + // from outside the WebContents. const focusMovedWithKeyboard = this.focusOutlineManager_.visible; - const focusMovedFromOutside = e.relatedTarget && + const focusMovedFromOutside = e.relatedTarget === null || !this.contains(/** @type {!HTMLElement} */ (e.relatedTarget)); if (focusMovedWithKeyboard && focusMovedFromOutside) { this.getItems_()[0].focus(); diff --git a/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/BUILD.gn index 2ae5ef9b050..9090f8c61b6 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_profile_avatar_selector", ":cr_profile_avatar_selector_grid", diff --git a/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.html b/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.html index c8f6922e4f4..7bf7f4a1e7e 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.html +++ b/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.html @@ -2,13 +2,15 @@ <link rel="import" href="../cr_button/cr_button.html"> <link rel="import" href="../shared_vars_css.html"> +<link rel="import" href="../shared_style_css.html"> <link rel="import" href="../../html/icon.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-tooltip/paper-tooltip.html">; <link rel="import" href="cr_profile_avatar_selector_grid.html"> <dom-module id="cr-profile-avatar-selector"> <template> - <style> + <style include="cr-shared-style"> :host { --avatar-size: 96px; --avatar-spacing: 24px; @@ -60,15 +62,29 @@ cr-button { background-size: var(--avatar-size); } + + paper-tooltip { + --paper-tooltip-delay-in: 100ms; + --paper-tooltip-duration-in: 100ms; + --paper-tooltip-duration-out: 100ms; + --paper-tooltip-min-width: none; + } </style> - <cr-profile-avatar-selector-grid id="avatar-grid" + <cr-profile-avatar-selector-grid id="avatar-grid" role="radiogroup" ignore-modified-key-events="[[ignoreModifiedKeyEvents]]"> <template is="dom-repeat" items="[[avatars]]"> - <cr-button class$="avatar [[getSelectedClass_(item.selected)]]" - title="[[item.label]]" + <cr-button id="[[getAvatarId_(index)]]" aria-label="[[item.label]]" + tabindex$="[[getTabIndex_(index, item, tabFocusableAvatar_)]]" + class$="avatar [[getSelectedClass_(item, selectedAvatar)]]" style$="background-image: [[getIconImageSet_(item.url)]]" - on-click="onAvatarTap_"> + on-click="onAvatarTap_" + role="radio" + aria-checked$="[[getCheckedAttribute_(item, selectedAvatar)]]"> </cr-button> + <paper-tooltip for="[[getAvatarId_(index)]]" + offset="0" fit-to-visible-bounds> + [[item.label]] + </paper-tooltip> </template> </cr-profile-avatar-selector-grid> </template> diff --git a/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js b/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js index 96950a03fba..9b7a4e708c0 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js +++ b/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector.js @@ -40,20 +40,85 @@ Polymer({ notify: true, }, - /** @private {?HTMLElement} */ - selectedAvatarElement_: Object, - ignoreModifiedKeyEvents: { type: Boolean, value: false, }, + + /** + * The currently selected profile avatar icon index, or '-1' if none is + * selected. + * @type {number} + */ + tabFocusableAvatar_: { + type: Number, + computed: 'computeTabFocusableAvatar_(avatars, selectedAvatar)', + }, + }, + + /** + * @param {number} index + * @return {string} + * @private + */ + getAvatarId_(index) { + return 'avatarId' + index; + }, + + /** + * @param {number} index + * @param {!AvatarIcon} item + * @return {string} + * @private + */ + getTabIndex_(index, item) { + if (item.index === this.tabFocusableAvatar_) { + return '0'; + } + + // If no avatar is selected, focus the first element of the grid on 'tab'. + if (this.tabFocusableAvatar_ === -1 && index === 0) { + return '0'; + } + return '-1'; + }, + + /** + * @return {number} + * @private + */ + computeTabFocusableAvatar_() { + const selectedAvatar = + this.avatars.find(avatar => this.isAvatarSelected(avatar)); + return selectedAvatar ? selectedAvatar.index : -1; }, /** @private */ - getSelectedClass_(isSelected) { + getSelectedClass_(avatarItem) { // TODO(dpapad): Rename 'iron-selected' to 'selected' now that this CSS // class is not assigned by any iron-* behavior. - return isSelected ? 'iron-selected' : ''; + return this.isAvatarSelected(avatarItem) ? 'iron-selected' : ''; + }, + + /** + * @param {AvatarIcon} avatarItem + * @return {string} + * @private + */ + getCheckedAttribute_(avatarItem) { + return this.isAvatarSelected(avatarItem) ? 'true' : 'false'; + }, + + /** + * @param {AvatarIcon} avatarItem + * @return {boolean} + * @private + */ + isAvatarSelected(avatarItem) { + return !!avatarItem && + (avatarItem.selected || + (!!this.selectedAvatar && + this.selectedAvatar.index === avatarItem.index)); }, /** @@ -70,16 +135,10 @@ Polymer({ * @private */ onAvatarTap_(e) { - // Manual selection for profile creation - if (this.selectedAvatarElement_) { - this.selectedAvatarElement_.classList.remove('iron-selected'); - } - this.selectedAvatarElement_ = /** @type {!HTMLElement} */ (e.target); - this.selectedAvatarElement_.classList.add('iron-selected'); - // |selectedAvatar| is set to pass back selection to the owner of this // component. this.selectedAvatar = /** @type {!{model: {item: !AvatarIcon}}} */ (e).model.item; }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.js b/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.js index bc9417b1486..5e223742c5c 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.js +++ b/chromium/ui/webui/resources/cr_elements/cr_profile_avatar_selector/cr_profile_avatar_selector_grid.js @@ -95,3 +95,4 @@ Polymer({ assert(this.parentNode.activeElement === nextItem); } }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/cr_radio_button/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_radio_button/BUILD.gn index cdfd3e6b911..66890945890 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_radio_button/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_radio_button/BUILD.gn @@ -7,6 +7,7 @@ import("//tools/polymer/polymer.gni") import("../../tools/js_modulizer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_card_radio_button", ":cr_radio_button", diff --git a/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_card_radio_button.html b/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_card_radio_button.html index 68f46000969..7b27e3b2d48 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_card_radio_button.html +++ b/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_card_radio_button.html @@ -18,6 +18,13 @@ width: var(--cr-card-radio-button-width, 200px); } + /* TODO(crbug/1148515): Reenable the ripple effect after fixing + * paper-ripple to accomodate for cr-card-radio-button. + */ + paper-ripple { + --paper-ripple-opacity: 0; + } + :host([checked]) { border-color: var(--cr-checked-color); } diff --git a/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_behavior.js b/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_behavior.js index 245b9262d6e..047b8f04e89 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_behavior.js +++ b/chromium/ui/webui/resources/cr_elements/cr_radio_button/cr_radio_button_behavior.js @@ -144,3 +144,4 @@ const CrRadioButtonBehaviorImpl = { Polymer.PaperRippleBehavior, CrRadioButtonBehaviorImpl, ]; +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/cr_radio_group/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_radio_group/BUILD.gn index 0485ad82569..b1805b291b7 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_radio_group/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_radio_group/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_radio_group" ] } diff --git a/chromium/ui/webui/resources/cr_elements/cr_search_field/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_search_field/BUILD.gn index 7def963811c..1db5848958e 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_search_field/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_search_field/BUILD.gn @@ -7,6 +7,7 @@ import("//tools/polymer/polymer.gni") import("../../tools/js_modulizer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_search_field", ":cr_search_field_behavior", diff --git a/chromium/ui/webui/resources/cr_elements/cr_search_field/cr_search_field_behavior.js b/chromium/ui/webui/resources/cr_elements/cr_search_field/cr_search_field_behavior.js index 99ec7838878..a38bfd2059c 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_search_field/cr_search_field_behavior.js +++ b/chromium/ui/webui/resources/cr_elements/cr_search_field/cr_search_field_behavior.js @@ -171,3 +171,4 @@ onSearchTermInput() {} } +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/BUILD.gn index 0eafe64caa9..ce8dfdcbb55 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_searchable_drop_down" ] } diff --git a/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js b/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js index 06823f7b8f6..ff4fc193902 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js +++ b/chromium/ui/webui/resources/cr_elements/cr_searchable_drop_down/cr_searchable_drop_down.js @@ -119,15 +119,23 @@ Polymer({ /** @private {number} */ openDropdownTimeoutId_: 0, + /** @private {?ResizeObserver} */ + resizeObserver_: null, + /** @override */ attached() { this.pointerDownListener_ = this.onPointerDown_.bind(this); document.addEventListener('pointerdown', this.pointerDownListener_); + this.resizeObserver_ = new ResizeObserver(() => { + this.resizeDropdown_(); + }); + this.resizeObserver_.observe(this.$.search); }, /** @override */ detached() { document.removeEventListener('pointerdown', this.pointerDownListener_); + this.resizeObserver_.unobserve(this.$.search); }, /** @@ -145,6 +153,19 @@ Polymer({ } }, + /** + * Keeps the dropdown from expanding beyond the width of the search input when + * its width is specified as a percentage. + * @private + */ + resizeDropdown_() { + const dropdown = this.$$('iron-dropdown').containedElement; + const dropdownWidth = + Math.max(dropdown.offsetWidth, this.$.search.offsetWidth); + dropdown.style.width = `${dropdownWidth}px`; + this.enqueueDropdownRefit_(); + }, + /** @private */ openDropdown_() { this.$$('iron-dropdown').open(); @@ -439,7 +460,7 @@ Polymer({ * leave the user's text in the dropdown search bar when focus is changed. * @private */ - onBlur_ : function () { + onBlur_() { if (!this.updateValueOnInput) { this.$.search.value = this.value; } @@ -453,8 +474,9 @@ Polymer({ * |invalid| to false. * @private */ - updateInvalid_: function () { + updateInvalid_() { this.invalid = !this.updateValueOnInput && (this.value !== this.$.search.value); }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/cr_slider/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_slider/BUILD.gn index 1229cf7b414..232786c9f74 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_slider/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_slider/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_slider" ] } diff --git a/chromium/ui/webui/resources/cr_elements/cr_slider/cr_slider.js b/chromium/ui/webui/resources/cr_elements/cr_slider/cr_slider.js index 4d77f318a6e..2b0235e78d5 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_slider/cr_slider.js +++ b/chromium/ui/webui/resources/cr_elements/cr_slider/cr_slider.js @@ -470,6 +470,7 @@ cr.define('cr_slider', function() { }); // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return { SliderTick: SliderTick, }; diff --git a/chromium/ui/webui/resources/cr_elements/cr_tabs/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_tabs/BUILD.gn index ab8059dddfa..bd113ea3595 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_tabs/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_tabs/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_tabs" ] } diff --git a/chromium/ui/webui/resources/cr_elements/cr_tabs/cr_tabs.js b/chromium/ui/webui/resources/cr_elements/cr_tabs/cr_tabs.js index b0b555eb326..677c21b5671 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_tabs/cr_tabs.js +++ b/chromium/ui/webui/resources/cr_elements/cr_tabs/cr_tabs.js @@ -190,3 +190,4 @@ Polymer({ this.updateSelectionBar_(left, right - left); }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/cr_toast/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_toast/BUILD.gn index a29159d168d..af927112ecd 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_toast/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_toast/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_toast", ":cr_toast_manager", diff --git a/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.js b/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.js index 97b4d555467..c2cc82043ad 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.js +++ b/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast.js @@ -38,7 +38,7 @@ Polymer({ if (this.open && this.duration !== 0) { this.hideTimeoutId_ = window.setTimeout(() => { - this._setOpen(false); + this.hide(); }, this.duration); } }, @@ -59,6 +59,10 @@ Polymer({ // the same as a previous toast. this.removeAttribute('role'); + // Reset the aria-hidden attribute as screen readers need to access the + // contents of an opened toast. + this.removeAttribute('aria-hidden'); + this._setOpen(true); this.setAttribute('role', 'alert'); @@ -67,8 +71,13 @@ Polymer({ } }, - /** Hides the toast. */ + /** + * Hides the toast and ensures that screen readers cannot its contents while + * hidden. + */ hide() { + this.setAttribute('aria-hidden', 'true'); this._setOpen(false); }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast_manager.js b/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast_manager.js index 53009cdffbf..acc9637ba09 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast_manager.js +++ b/chromium/ui/webui/resources/cr_elements/cr_toast/cr_toast_manager.js @@ -102,6 +102,7 @@ cr.define('cr.toastManager', () => { }); // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return { getToastManager: getToastManager, }; diff --git a/chromium/ui/webui/resources/cr_elements/cr_toggle/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_toggle/BUILD.gn index 07edfe5313c..fa5439ec42d 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_toggle/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_toggle/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_toggle" ] } diff --git a/chromium/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.js b/chromium/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.js index f86716c8efb..ea32e2b2632 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.js +++ b/chromium/ui/webui/resources/cr_elements/cr_toggle/cr_toggle.js @@ -227,3 +227,4 @@ Polymer({ return ripple; }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/cr_toolbar/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_toolbar/BUILD.gn index 7d0f4a7203e..1f168042f4f 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_toolbar/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_toolbar/BUILD.gn @@ -6,11 +6,8 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { - deps = [ - ":cr_toolbar", - ":cr_toolbar_search_field", - ":cr_toolbar_selection_overlay", - ] + uses_legacy_modules = true + deps = [ ":cr_toolbar_search_field" ] } js_library("cr_toolbar_search_field") { @@ -19,13 +16,6 @@ js_library("cr_toolbar_search_field") { ] } -js_library("cr_toolbar_selection_overlay") { -} - -js_library("cr_toolbar") { - deps = [ ":cr_toolbar_search_field" ] -} - group("polymer3_elements") { public_deps = [ ":cr_toolbar_module", @@ -37,8 +27,7 @@ group("polymer3_elements") { polymer_modulizer("cr_toolbar") { js_file = "cr_toolbar.js" html_file = "cr_toolbar.html" - html_type = "dom-module" - auto_imports = [ "ui/webui/resources/html/polymer.html|html,Polymer" ] + html_type = "v3-ready" } polymer_modulizer("cr_toolbar_search_field") { @@ -51,27 +40,23 @@ polymer_modulizer("cr_toolbar_search_field") { polymer_modulizer("cr_toolbar_selection_overlay") { js_file = "cr_toolbar_selection_overlay.js" html_file = "cr_toolbar_selection_overlay.html" - html_type = "dom-module" + html_type = "v3-ready" } js_type_check("closure_compile_module") { is_polymer3 = true deps = [ - ":cr_toolbar.m", + ":cr_toolbar", ":cr_toolbar_search_field.m", - ":cr_toolbar_selection_overlay.m", + ":cr_toolbar_selection_overlay", ] } -js_library("cr_toolbar.m") { - sources = [ - "$root_gen_dir/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.m.js", - ] +js_library("cr_toolbar") { deps = [ ":cr_toolbar_search_field.m", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", ] - extra_deps = [ ":cr_toolbar_module" ] } js_library("cr_toolbar_search_field.m") { @@ -83,10 +68,9 @@ js_library("cr_toolbar_search_field.m") { extra_deps = [ ":cr_toolbar_search_field_module" ] } -js_library("cr_toolbar_selection_overlay.m") { - sources = [ "$root_gen_dir/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.m.js" ] +js_library("cr_toolbar_selection_overlay") { deps = [ + "//third_party/polymer/v3_0/components-chromium/iron-a11y-announcer:iron-a11y-announcer", "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled", ] - extra_deps = [ ":cr_toolbar_selection_overlay_module" ] } diff --git a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html index 98231ed6793..2470260a4b5 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html +++ b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.html @@ -1,15 +1,3 @@ -<link rel="import" href="../../html/polymer.html"> - -<link rel="import" href="../cr_icon_button/cr_icon_button.html"> -<link rel="import" href="../cr_icons_css.html"> -<link rel="import" href="../cr_toolbar/cr_toolbar_search_field.html"> -<link rel="import" href="../hidden_style_css.html"> -<link rel="import" href="../icons.html"> -<link rel="import" href="../shared_vars_css.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-media-query/iron-media-query.html"> - -<dom-module id="cr-toolbar"> - <template> <style include="cr-icons cr-hidden-style"> :host { align-items: center; @@ -135,6 +123,3 @@ <slot></slot> </div> </div> - </template> - <script src="cr_toolbar.js"></script> -</dom-module> diff --git a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.js b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.js index 46af1382867..f949fa1c2b0 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.js +++ b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar.js @@ -2,9 +2,21 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +import {html, Polymer} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import '../cr_icon_button/cr_icon_button.m.js'; +import '../cr_icons_css.m.js'; +import './cr_toolbar_search_field.m.js'; +import '../hidden_style_css.m.js'; +import '../icons.m.js'; +import '../shared_vars_css.m.js'; +import '//resources/polymer/v3_0/iron-media-query/iron-media-query.js'; + Polymer({ is: 'cr-toolbar', + _template: html`{__html_template__}`, + properties: { // Name to display in the toolbar, in titlecase. pageName: String, @@ -69,4 +81,20 @@ Polymer({ this.fire('cr-toolbar-menu-tap'); }, + focusMenuButton() { + requestAnimationFrame(() => { + // Wait for next animation frame in case dom-if has not applied yet and + // added the menu button. + const menuButton = this.shadowRoot.querySelector('#menuButton'); + if (menuButton) { + menuButton.focus(); + } + }); + }, + + /** @return {boolean} */ + isMenuFocused() { + return Boolean(this.shadowRoot.activeElement) && + this.shadowRoot.activeElement.id === 'menuButton'; + } }); diff --git a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html index 27a5c19e4ab..09d53868d35 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html +++ b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_search_field.html @@ -183,6 +183,7 @@ <label id="prompt" for="searchInput" aria-hidden="true">[[label]]</label> <input id="searchInput" aria-labelledby="prompt" + autocapitalize="off" autocomplete="off" type="search" on-input="onSearchTermInput" diff --git a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.html b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.html index 28243f0a16f..2cd069ff2f4 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.html +++ b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.html @@ -1,12 +1,3 @@ -<link rel="import" href="../../html/polymer.html"> - -<link rel="import" href="../cr_button/cr_button.html"> -<link rel="import" href="../cr_icon_button/cr_icon_button.html"> -<link rel="import" href="../icons.html"> -<link rel="import" href="../shared_vars_css.html"> - -<dom-module id="cr-toolbar-selection-overlay"> - <template> <style> :host { background-color: white; @@ -78,6 +69,3 @@ </cr-button> </div> </template> - </template> - <script src="cr_toolbar_selection_overlay.js"></script> -</dom-module> diff --git a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.js b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.js index 7a93044f0c2..280f185f5a2 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.js +++ b/chromium/ui/webui/resources/cr_elements/cr_toolbar/cr_toolbar_selection_overlay.js @@ -13,9 +13,19 @@ * tab-traversal. */ +import {Polymer, html} from '//resources/polymer/v3_0/polymer/polymer_bundled.min.js'; + +import {IronA11yAnnouncer} from '//resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js'; +import '../cr_button/cr_button.m.js'; +import '../cr_icon_button/cr_icon_button.m.js'; +import '../icons.m.js'; +import '../shared_vars_css.m.js'; + Polymer({ is: 'cr-toolbar-selection-overlay', + _template: html`{__html_template__}`, + properties: { show: { type: Boolean, @@ -42,6 +52,10 @@ Polymer({ 'updateSelectionLabel_(show, selectionLabel)', ], + hostAttributes: { + 'role': 'toolbar', + }, + /** @return {HTMLElement} */ get deleteButton() { return /** @type {HTMLElement} */ (this.$$('#delete')); @@ -64,6 +78,10 @@ Polymer({ this.debounce('updateSelectionLabel_', () => { this.selectionLabel_ = this.show ? this.selectionLabel : this.selectionLabel_; + this.setAttribute('aria-label', this.selectionLabel_); + + IronA11yAnnouncer.requestAvailability(); + this.fire('iron-announce', {text: this.selectionLabel}); }); }, diff --git a/chromium/ui/webui/resources/cr_elements/cr_view_manager/BUILD.gn b/chromium/ui/webui/resources/cr_elements/cr_view_manager/BUILD.gn index 8e2ab87baa3..14130ea192c 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_view_manager/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/cr_view_manager/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("//tools/polymer/polymer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_view_manager" ] } diff --git a/chromium/ui/webui/resources/cr_elements/cr_view_manager/cr_view_manager.js b/chromium/ui/webui/resources/cr_elements/cr_view_manager/cr_view_manager.js index ec1f2009cbc..10633d899f5 100644 --- a/chromium/ui/webui/resources/cr_elements/cr_view_manager/cr_view_manager.js +++ b/chromium/ui/webui/resources/cr_elements/cr_view_manager/cr_view_manager.js @@ -114,4 +114,5 @@ Polymer({ return Promise.all(promises); }, }); +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); })(); diff --git a/chromium/ui/webui/resources/cr_elements/icons.html b/chromium/ui/webui/resources/cr_elements/icons.html index a19c7bd7904..0d46919254f 100644 --- a/chromium/ui/webui/resources/cr_elements/icons.html +++ b/chromium/ui/webui/resources/cr_elements/icons.html @@ -87,6 +87,10 @@ blurry at 20 px). Please use 20 px icons when available. d="M9 2L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h16c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2h-3.17L15 2H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5 5-2.24 5-5 5z"> </path> </g> + <g id="work"> + <path d="M20 6h-4V4c0-1.11-.89-2-2-2h-4c-1.11 0-2 .89-2 2v2H4c-1.11 0-1.99.89-1.99 2L2 19c0 1.11.89 2 2 2h16c1.11 0 2-.89 2-2V8c0-1.11-.89-2-2-2zm-6 0h-4V4h4v2z"> + </path> + </g> </if> <g id="cancel"> <path diff --git a/chromium/ui/webui/resources/cr_elements/mwb_shared_style.html b/chromium/ui/webui/resources/cr_elements/mwb_shared_style.html index 0ad5679bedb..0dc24281c8e 100644 --- a/chromium/ui/webui/resources/cr_elements/mwb_shared_style.html +++ b/chromium/ui/webui/resources/cr_elements/mwb_shared_style.html @@ -1,32 +1,19 @@ <template> <style> ::-webkit-scrollbar-thumb { - background: var(--google-grey-refresh-300); - } - - /* TODO(crbug.com/1110109): Add WCAG compliant dark mode support. */ - @media (prefers-color-scheme: dark) { - ::-webkit-scrollbar-thumb { - background: var(--google-grey-refresh-500); - } + background-color: var(--mwb-scrollbar-thumb-color); } ::-webkit-scrollbar-thumb:hover { - background: var(--google-grey-refresh-500); - } - - @media (prefers-color-scheme: dark) { - ::-webkit-scrollbar-thumb:hover { - background: var(--google-grey-refresh-300); - } + background-color: var(--mwb-scrollbar-thumb-hover-color); } ::-webkit-scrollbar-track { - background: var(--mwb-background-color); + background-color: var(--mwb-scrollbar-track-color); } ::-webkit-scrollbar { - width: 4px; + width: var(--mwb-scrollbar-width); } .mwb-list-item { diff --git a/chromium/ui/webui/resources/cr_elements/mwb_shared_vars.html b/chromium/ui/webui/resources/cr_elements/mwb_shared_vars.html index b83244d4024..31a4ca151c4 100644 --- a/chromium/ui/webui/resources/cr_elements/mwb_shared_vars.html +++ b/chromium/ui/webui/resources/cr_elements/mwb_shared_vars.html @@ -2,20 +2,31 @@ <style> html { --mwb-background-color: white; + --mwb-icon-button-fill-color: var(--google-grey-refresh-700); + --mwb-icon-button-focus-ring-color: rgba(var(--google-blue-600-rgb), 0.4); + --mwb-icon-button-hover-background-color: rgba(var(--google-grey-900-rgb), 0.1); --mwb-icon-size: 16px; --mwb-item-height: 56px; --mwb-list-item-horizontal-margin: 16px; --mwb-list-item-hover-background-color: rgba(var(--google-grey-900-rgb), 0.1); --mwb-list-item-selected-background-color: rgba(var(--google-grey-900-rgb), 0.14); --mwb-primary-text-font-size: 13px; + --mwb-scrollbar-thumb-color: var(--google-grey-refresh-300); + --mwb-scrollbar-thumb-hover-color: var(--google-grey-refresh-500); + --mwb-scrollbar-track-color: var(--mwb-background-color); + --mwb-scrollbar-width: 4px; --mwb-secondary-text-font-size: 12px; } @media (prefers-color-scheme: dark) { html { --mwb-background-color: var(--google-grey-900); + --mwb-icon-button-fill-color: var(--google-grey-refresh-300); + --mwb-icon-button-hover-background-color: rgba(255, 255, 255, 0.1); --mwb-list-item-hover-background-color: rgb(55, 56, 58); /* #37383a */ --mwb-list-item-selected-background-color: rgb(68, 69, 71); /* #444547 */ + --mwb-scrollbar-thumb-color: var(--google-grey-refresh-500); + --mwb-scrollbar-thumb-hover-color: var(--google-grey-refresh-300); } } </style> diff --git a/chromium/ui/webui/resources/cr_elements/policy/BUILD.gn b/chromium/ui/webui/resources/cr_elements/policy/BUILD.gn index 0e61e9f13cc..63950e4423c 100644 --- a/chromium/ui/webui/resources/cr_elements/policy/BUILD.gn +++ b/chromium/ui/webui/resources/cr_elements/policy/BUILD.gn @@ -7,6 +7,7 @@ import("//tools/polymer/polymer.gni") import("../../tools/js_modulizer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":cr_policy_indicator", ":cr_policy_indicator_behavior", diff --git a/chromium/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js b/chromium/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js index 626549dd852..7f1e85363aa 100644 --- a/chromium/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js +++ b/chromium/ui/webui/resources/cr_elements/policy/cr_policy_indicator_behavior.js @@ -159,3 +159,4 @@ var CrPolicyStrings; return ''; }, }; +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.html b/chromium/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.html index 23962b2144f..21447b7dd55 100644 --- a/chromium/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.html +++ b/chromium/ui/webui/resources/cr_elements/policy/cr_tooltip_icon.html @@ -19,7 +19,7 @@ } </style> <iron-icon id="indicator" tabindex="0" aria-label$="[[iconAriaLabel]]" - aria-describedby="tooltip" icon="[[iconClass]]"></iron-icon> + aria-describedby="tooltip" icon="[[iconClass]]" role="img"></iron-icon> <paper-tooltip id="tooltip" for="indicator" position="[[tooltipPosition]]" fit-to-visible-bounds part="tooltip"> diff --git a/chromium/ui/webui/resources/cr_elements/shared_style_css.html b/chromium/ui/webui/resources/cr_elements/shared_style_css.html index e5f836283c7..a71eec20481 100644 --- a/chromium/ui/webui/resources/cr_elements/shared_style_css.html +++ b/chromium/ui/webui/resources/cr_elements/shared_style_css.html @@ -158,6 +158,29 @@ line-height: var(--cr-form-field-label-line-height); margin-bottom: 8px; } + + .cr-vertical-tab { + align-items: center; + display: flex; + } + + .cr-vertical-tab::before { + border-radius: 0 3px 3px 0; + content: ''; + display: block; + flex-shrink: 0; + height: var(--cr-vertical-tab-height, 100%); + width: 4px; + } + + .cr-vertical-tab.selected::before { + background: var(--cr-vertical-tab-selected-color, var(--cr-checked-color)); + } + + :host-context([dir=rtl]) .cr-vertical-tab::before { + /* Border-radius based on block/inline is not yet supported. */ + transform: scaleX(-1); + } </style> </template> </dom-module> diff --git a/chromium/ui/webui/resources/cr_elements/shared_vars_css.html b/chromium/ui/webui/resources/cr_elements/shared_vars_css.html index df1e1f42726..4e7eb2ad96d 100644 --- a/chromium/ui/webui/resources/cr_elements/shared_vars_css.html +++ b/chromium/ui/webui/resources/cr_elements/shared_vars_css.html @@ -152,7 +152,6 @@ * items etc. */ --cr-section-min-height: 48px; --cr-section-two-line-min-height: 64px; - --cr-section-three-line-min-height: 84px; --cr-section-padding: 20px; --cr-section-vertical-padding: 12px; diff --git a/chromium/ui/webui/resources/cr_elements_images.grdp b/chromium/ui/webui/resources/cr_elements_images.grdp deleted file mode 100644 index 61a8eab915c..00000000000 --- a/chromium/ui/webui/resources/cr_elements_images.grdp +++ /dev/null @@ -1,54 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<grit-part> - <!-- TODO(dschuyler): Many of these may be included for the unit tests which - don't appear to flatten the html. We may be able to avoid including - these if the browser_tests would not try to load them. --> - <include name="IDR_WEBUI_IMAGES_200_LOGO_GOOGLE_G_PNG" - file="images/200-logo_googleg.png" type="BINDATA" compress="gzip" /> - <include name="IDR_WEBUI_IMAGES_ARROW_DOWN_SVG" - file="images/arrow_down.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_ARROW_RIGHT_SVG" - file="images/arrow_right.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_BUSINESS" file="images/business.svg" - type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_DARK_ARROW_DOWN_SVG" - file="images/dark/arrow_down.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_DARK_ICON_SEARCH_SVG" - file="images/dark/icon_search.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_ICON_ARROW_BACK_SVG" - file="images/icon_arrow_back.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_ICON_ARROW_DROPDOWN_SVG" - file="images/icon_arrow_dropdown.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_ICON_CANCEL_SVG" - file="images/icon_cancel.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_ICON_CLEAR_SVG" - file="images/icon_clear.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_ICON_DELETE_GRAY_SVG" - file="images/icon_delete_gray.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_ICON_EDIT_SVG" - file="images/icon_edit.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_ICON_EXPAND_LESS_SVG" - file="images/icon_expand_less.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_ICON_EXPAND_MORE_SVG" - file="images/icon_expand_more.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_ICON_EXTERNAL_SVG" - file="images/open_in_new.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_ICON_MORE_VERT_SVG" - file="images/icon_more_vert.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_ICON_PICTURE_DELETE_SVG" - file="images/icon_picture_delete.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_ICON_REFRESH_SVG" - file="images/icon_refresh.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_ICON_SEARCH_SVG" - file="images/icon_search.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_ICON_SETTINGS_SVG" - file="images/icon_settings.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_ICON_VISIBILITY_SVG" - file="images/icon_visibility.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_ICON_VISIBILITY_OFF_SVG" - file="images/icon_visibility_off.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_ICON_COPY_CONTENT_SVG" - file="images/icon_copy_content.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_OPEN_IN_NEW_SVG" - file="images/open_in_new.svg" type="BINDATA" /> -</grit-part> diff --git a/chromium/ui/webui/resources/css/BUILD.gn b/chromium/ui/webui/resources/css/BUILD.gn index 755e164eae6..28641746bce 100644 --- a/chromium/ui/webui/resources/css/BUILD.gn +++ b/chromium/ui/webui/resources/css/BUILD.gn @@ -2,7 +2,7 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. -import("//tools/grit/preprocess_grit.gni") +import("//tools/grit/preprocess_if_expr.gni") import("//ui/webui/resources/tools/generate_grd.gni") include_polymer = !is_android && !is_ios @@ -18,7 +18,7 @@ generate_grd("build_grdp") { resource_path_prefix = "css" } -preprocess_grit("preprocess_src") { +preprocess_if_expr("preprocess_src") { in_folder = "./" out_folder = "$preprocess_folder" out_manifest = "$target_gen_dir/$preprocess_src_manifest" @@ -26,8 +26,6 @@ preprocess_grit("preprocess_src") { "action_link.css", "apps/common.css", "apps/topbutton_bar.css", - "bubble_button.css", - "bubble.css", "butter_bar.css", "chrome_shared.css", "dialogs.css", diff --git a/chromium/ui/webui/resources/css/bubble.css b/chromium/ui/webui/resources/css/bubble.css deleted file mode 100644 index cf76818ac07..00000000000 --- a/chromium/ui/webui/resources/css/bubble.css +++ /dev/null @@ -1,97 +0,0 @@ -/* Copyright (c) 2012 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. */ - -.bubble { - position: absolute; - white-space: normal; - /* Height is dynamic, width fixed. */ - width: 300px; - z-index: 9999; -} - -.bubble-content { - color: black; - line-height: 150%; - margin: 1px; - padding: 8px 11px 12px; - position: relative; - z-index: 3; -} - -/* When the close button is there, we need more padding on the right of the - * bubble. */ -.bubble-close:not([hidden]) ~ .bubble-content { - padding-inline-end: 22px; -} - -.bubble-close { - height: 16px; - position: absolute; - right: 6px; - top: 6px; - width: 16px; - z-index: 4; -} - -html[dir='rtl'] .bubble-close { - left: 6px; - right: auto; -} - -.bubble-close { - background-image: -webkit-image-set( - url(../../../resources/default_100_percent/close_2.png) 1x, - url(../../../resources/default_200_percent/close_2.png) 2x); -} - -.bubble-close:hover { - background-image: -webkit-image-set( - url(../../../resources/default_100_percent/close_2_hover.png) 1x, - url(../../../resources/default_200_percent/close_2_hover.png) 2x); -} - -.bubble-close:active { - background-image: -webkit-image-set( - url(../../../resources/default_100_percent/close_2_pressed.png) 1x, - url(../../../resources/default_200_percent/close_2_pressed.png) 2x); -} - -.bubble-shadow { - bottom: 0; - box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15); - left: 0; - position: absolute; - right: 0; - top: 0; - z-index: 1; -} - -.bubble-arrow { - box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.15); - height: 15px; - position: absolute; - transform: rotate(45deg); - width: 15px; - z-index: 2; -} - -.bubble-content, -.bubble-arrow { - background: white; -} - -.bubble-shadow, -.bubble-arrow { - border: 1px solid rgba(0, 0, 0, 0.3); -} - -.bubble-shadow, -.bubble-content { - border-radius: 6px; - box-sizing: border-box; -} - -.auto-close-bubble { - position: fixed; -} diff --git a/chromium/ui/webui/resources/css/bubble_button.css b/chromium/ui/webui/resources/css/bubble_button.css deleted file mode 100644 index d92c4a58cec..00000000000 --- a/chromium/ui/webui/resources/css/bubble_button.css +++ /dev/null @@ -1,20 +0,0 @@ -/* Copyright (c) 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. */ - -.bubble-button { - display: inline-block; - height: 0; - line-height: 1; - margin-inline-start: 4px; - vertical-align: middle; - width: 16px; -} - -.bubble-button > div { - background-size: 16px; - height: 16px; - position: relative; - top: -9px; - width: 16px; -} diff --git a/chromium/ui/webui/resources/css/controlled_indicator.css b/chromium/ui/webui/resources/css/controlled_indicator.css deleted file mode 100644 index 340ac931baa..00000000000 --- a/chromium/ui/webui/resources/css/controlled_indicator.css +++ /dev/null @@ -1,100 +0,0 @@ -/* 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. */ - -/* Controlled setting indicator and bubble. */ - -.controlled-setting-with-label input:disabled + span { - color: #999; -} - -.controlled-setting-indicator { - margin-inline-end: 0.3em; -} - -.controlled-setting-indicator:not([controlled-by]) { - display: none; -} - -.controlled-setting-indicator[controlled-by] > div { - background-position: 50%; - background-size: 18px; -} - -.controlled-setting-indicator:-webkit-any([controlled-by='recommended'], - [controlled-by='hasRecommendation']) > div, - .controlled-setting-indicator[controlled-by='policy'] > div { - background-image: url(../images/business.svg); -} - -.controlled-setting-indicator[controlled-by='owner'] > div { - background-image: url(../images/account_circle.svg); -} - -.controlled-setting-indicator[controlled-by='extension'] > div { - background-image: url(../images/extension.svg); -} - -<if expr="chromeos"> -.controlled-setting-indicator[controlled-by='shared'] > div { - background-image: url(../images/group.svg); -} -</if> - -.controlled-setting-indicator[controlled-by='child-custodian'] > div { - background-image: url(../images/account_child_invert.svg); -} - -.controlled-setting-indicator[controlled-by='supervised-user-custodian'] > div { - background-image: url(../images/supervisor_account.svg); -} - -.controlled-setting-bubble-action { - padding: 0 !important; -} - -.controlled-setting-bubble-header { - margin-top: 3px; -} - -.controlled-setting-bubble-content-row { - height: 35px; - position: relative; -} - -.controlled-setting-bubble-extension-name { - background-repeat: no-repeat; - font-weight: bold; - height: 24px; - margin-top: -9px; - overflow: hidden; - padding-inline-start: 30px; - padding-top: 3px; - position: absolute; - text-overflow: ellipsis; - top: 50%; - white-space: nowrap; - width: 215px; -} - -html[dir='rtl'] .controlled-setting-bubble-extension-name { - background-position: right top; -} - -.controlled-setting-bubble-extension-manage-link { - margin-left: -0.35em; - margin-top: -0.30em; - position: absolute; - top: 50%; -} - -.controlled-setting-bubble-extension-disable-button { - bottom: 0; - position: absolute; - right: 0; -} - -html[dir='rtl'] .controlled-setting-bubble-extension-disable-button { - left: 0; - right: auto; -} diff --git a/chromium/ui/webui/resources/html/BUILD.gn b/chromium/ui/webui/resources/html/BUILD.gn index c1eff1165a7..5ae61e89f5a 100644 --- a/chromium/ui/webui/resources/html/BUILD.gn +++ b/chromium/ui/webui/resources/html/BUILD.gn @@ -32,7 +32,6 @@ generate_grd("build_grdp") { "cr/ui/menu_button.html", "cr/ui/menu.html", "cr/ui/menu_item.html", - "cr/ui/overlay.html", "cr/ui/position_util.html", "cr/ui/splitter.html", "cr/ui/store_client.html", diff --git a/chromium/ui/webui/resources/html/cr/ui/overlay.html b/chromium/ui/webui/resources/html/cr/ui/overlay.html deleted file mode 100644 index 5251684beab..00000000000 --- a/chromium/ui/webui/resources/html/cr/ui/overlay.html +++ /dev/null @@ -1 +0,0 @@ -<script src="../../../js/cr/ui/overlay.js"></script> diff --git a/chromium/ui/webui/resources/html/test_loader.html b/chromium/ui/webui/resources/html/test_loader.html index 4aeb21f85a6..9eb3d485e7e 100644 --- a/chromium/ui/webui/resources/html/test_loader.html +++ b/chromium/ui/webui/resources/html/test_loader.html @@ -1,7 +1,9 @@ <!DOCTYPE html> <html> <body> - <script src="test_loader.js"></script> + <script src="chrome://test/mocha.js"></script> + <script src="chrome://test/mocha_adapter.js"></script> + <script type="module" src="test_loader.js"></script> </body> </html> diff --git a/chromium/ui/webui/resources/images/BUILD.gn b/chromium/ui/webui/resources/images/BUILD.gn new file mode 100644 index 00000000000..0cc5a5bdfbc --- /dev/null +++ b/chromium/ui/webui/resources/images/BUILD.gn @@ -0,0 +1,77 @@ +# Copyright 2020 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("//build/config/chromeos/ui_mode.gni") +import("//ui/webui/resources/tools/generate_grd.gni") + +generate_grd("build_grdp") { + grd_prefix = "webui_images" + out_grd = "$target_gen_dir/resources.grdp" + input_files_base_dir = rebase_path(".", "//") + input_files = [ + # Component apps common image resources - 1x + "apps/topbar_button_close.png", + "apps/topbar_button_maximize.png", + "apps/topbar_button_minimize.png", + + # Component apps common image resources - 2x + "2x/apps/topbar_button_close.png", + "2x/apps/topbar_button_maximize.png", + "2x/apps/topbar_button_minimize.png", + + # Non-apps images + "add.svg", + "cancel_red.svg", + "check_circle_green.svg", + "check.png", + "checkbox_black.png", + "checkbox_white.png", + "disabled_select.png", + "error.svg", + "icon_search.svg", + "icon_refresh.svg", + "select.png", + "throbber_medium.svg", + "throbber_small.svg", + ] + + if (!is_android && !is_ios) { + input_files += [ + "200-logo_googleg.png", + "arrow_down.svg", + "arrow_right.svg", + "business.svg", + "dark/arrow_down.svg", + "dark/icon_search.svg", + "icon_arrow_back.svg", + "icon_arrow_dropdown.svg", + "icon_cancel.svg", + "icon_clear.svg", + "icon_copy_content.svg", + "icon_delete_gray.svg", + "icon_edit.svg", + "icon_expand_less.svg", + "icon_expand_more.svg", + "icon_more_vert.svg", + "icon_picture_delete.svg", + "icon_settings.svg", + "icon_visibility_off.svg", + "icon_visibility.svg", + "open_in_new.svg", + ] + } + + if (is_chromeos_ash) { + input_files += [ + # Similar to error.svg except that it is white-filled instead of + # transparent-filled. Useful for badging images where the background may + # be red. + # TODO(dpapad) Move to + # chrome/browser/resources/settings/chromeos/os_people_page/, only used + # there. + "error_badge.svg", + ] + } + resource_path_prefix = "images" +} diff --git a/chromium/ui/webui/resources/images/icon_tabs.svg b/chromium/ui/webui/resources/images/icon_tabs.svg deleted file mode 100644 index ad673608b68..00000000000 --- a/chromium/ui/webui/resources/images/icon_tabs.svg +++ /dev/null @@ -1 +0,0 @@ -<svg width="24" height="24" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><path d="M0 0h24v24H0V0z"/><path d="M14 2H6c-1.1 0-1.99.9-1.99 2L4 20c0 1.1.89 2 1.99 2H18c1.1 0 2-.9 2-2V8l-6-6zm-1 7V3.5L18.5 9H13zM6 4h5v16H6V4zm5 7h7v9h-7v-9z" fill="#000"/></g></svg>
\ No newline at end of file diff --git a/chromium/ui/webui/resources/images/menu.svg b/chromium/ui/webui/resources/images/menu.svg deleted file mode 100644 index fc0da0efe53..00000000000 --- a/chromium/ui/webui/resources/images/menu.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" fill="#5F6368"><path d="M0 0h24v24H0z" fill="none"/><path d="M3 18h18v-2H3v2zm0-5h18v-2H3v2zm0-7v2h18V6H3z"/></svg>
\ No newline at end of file diff --git a/chromium/ui/webui/resources/images/supervisor_account.svg b/chromium/ui/webui/resources/images/supervisor_account.svg deleted file mode 100644 index 4d933d14849..00000000000 --- a/chromium/ui/webui/resources/images/supervisor_account.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" fill="#626262"><path d="M0 0h48v48H0z" fill="none"/><path d="M33 24c2.76 0 4.98-2.24 4.98-5s-2.22-5-4.98-5c-2.76 0-5 2.24-5 5s2.24 5 5 5zm-15-2c3.31 0 5.98-2.69 5.98-6s-2.67-6-5.98-6c-3.31 0-6 2.69-6 6s2.69 6 6 6zm15 6c-3.67 0-11 1.84-11 5.5V38h22v-4.5c0-3.66-7.33-5.5-11-5.5zm-15-2c-4.67 0-14 2.34-14 7v5h14v-4.5c0-1.7.67-4.67 4.74-6.94C21 26.19 19.31 26 18 26z"/></svg>
\ No newline at end of file diff --git a/chromium/ui/webui/resources/js/BUILD.gn b/chromium/ui/webui/resources/js/BUILD.gn index 597d8f7e369..b4dd498a817 100644 --- a/chromium/ui/webui/resources/js/BUILD.gn +++ b/chromium/ui/webui/resources/js/BUILD.gn @@ -2,8 +2,9 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/chromeos/ui_mode.gni") import("//third_party/closure_compiler/compile_js.gni") -import("//tools/grit/preprocess_grit.gni") +import("//tools/grit/preprocess_if_expr.gni") import("//ui/webui/resources/tools/generate_grd.gni") import("../tools/js_modulizer.gni") @@ -32,7 +33,7 @@ group("preprocess") { ] } -preprocess_grit("preprocess_src") { +preprocess_if_expr("preprocess_src") { in_folder = "./" out_folder = "$preprocess_folder" out_manifest = "$target_gen_dir/$preprocess_src_manifest" @@ -52,11 +53,12 @@ preprocess_grit("preprocess_src") { "plural_string_proxy.js", "promise_resolver.js", "test_loader.js", + "test_loader_util.js", "util.js", "webui_resource_test.js", ] - if (is_chromeos) { + if (is_chromeos_ash) { in_files += [ "i18n_template_process.js" ] } @@ -69,9 +71,16 @@ preprocess_grit("preprocess_src") { "web_ui_listener_behavior.js", ] } + + if (is_ios) { + in_files += [ + "ios/mojo_api.js", + "ios/web_ui.js", + ] + } } -preprocess_grit("preprocess_generated") { +preprocess_if_expr("preprocess_generated") { deps = [ ":modulize" ] in_folder = target_gen_dir out_folder = "$preprocess_folder" @@ -107,6 +116,7 @@ group("closure_compile") { } js_type_check("js_resources") { + uses_legacy_modules = true deps = [ ":action_link", ":assert", @@ -124,7 +134,7 @@ js_type_check("js_resources") { ":web_ui_listener_behavior", ":webui_resource_test", ] - if (is_chromeos) { + if (is_chromeos_ash) { deps += [ ":i18n_template_process" ] } if (is_ios) { diff --git a/chromium/ui/webui/resources/js/assert.js b/chromium/ui/webui/resources/js/assert.js index 7bb03af99fb..7c40d465eee 100644 --- a/chromium/ui/webui/resources/js/assert.js +++ b/chromium/ui/webui/resources/js/assert.js @@ -81,3 +81,5 @@ } return value; } + +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/js/color_utils.js b/chromium/ui/webui/resources/js/color_utils.js index e5b6c530cb7..4331132e423 100644 --- a/chromium/ui/webui/resources/js/color_utils.js +++ b/chromium/ui/webui/resources/js/color_utils.js @@ -6,12 +6,12 @@ * @fileoverview Helper functions for color manipulations. */ -import 'chrome://resources/mojo/skia/public/mojom/skcolor.mojom-lite.js'; +import {SkColor} from 'chrome://resources/mojo/skia/public/mojom/skcolor.mojom-webui.js'; /** * Converts an SkColor object to a string in the form * "rgba(<red>, <green>, <blue>, <alpha>)". - * @param {skia.mojom.SkColor} skColor The input color. + * @param {SkColor} skColor The input color. * @return {string} The rgba string. */ export function skColorToRgba(skColor) { @@ -25,7 +25,7 @@ export function skColorToRgba(skColor) { /** * Converts a string of the form "#rrggbb" to an SkColor object. * @param {string} hexColor The color string. - * @return {!skia.mojom.SkColor} The SkColor object, + * @return {!SkColor} The SkColor object, */ export function hexColorToSkColor(hexColor) { if (!/^#[0-9a-f]{6}$/.test(hexColor)) { diff --git a/chromium/ui/webui/resources/js/cr/BUILD.gn b/chromium/ui/webui/resources/js/cr/BUILD.gn index 3163c760db7..577de971dd2 100644 --- a/chromium/ui/webui/resources/js/cr/BUILD.gn +++ b/chromium/ui/webui/resources/js/cr/BUILD.gn @@ -6,6 +6,7 @@ import("//third_party/closure_compiler/compile_js.gni") import("../../tools/js_modulizer.gni") js_type_check("closure_compile") { + uses_legacy_modules = true deps = [ ":event_target", ":ui", @@ -13,7 +14,6 @@ js_type_check("closure_compile") { } js_type_check("closure_compile_modules") { - uses_js_modules = true deps = [ ":event_target.m", ":ui.m", diff --git a/chromium/ui/webui/resources/js/cr/event_target.js b/chromium/ui/webui/resources/js/cr/event_target.js index 86deebc53ea..1197eb52369 100644 --- a/chromium/ui/webui/resources/js/cr/event_target.js +++ b/chromium/ui/webui/resources/js/cr/event_target.js @@ -21,5 +21,6 @@ cr.define('cr', function() { /** @override */ NativeEventTarget.prototype.removeEventListener; // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return {EventTarget: NativeEventTarget}; }); diff --git a/chromium/ui/webui/resources/js/cr/ui.js b/chromium/ui/webui/resources/js/cr/ui.js index aefe25ca9ce..4fe73f481fd 100644 --- a/chromium/ui/webui/resources/js/cr/ui.js +++ b/chromium/ui/webui/resources/js/cr/ui.js @@ -210,6 +210,7 @@ cr.define('cr.ui', function() { } // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return { decorate: decorate, define: define, diff --git a/chromium/ui/webui/resources/js/cr/ui/BUILD.gn b/chromium/ui/webui/resources/js/cr/ui/BUILD.gn index 0e10c8d0ec2..88cf2c9bb64 100644 --- a/chromium/ui/webui/resources/js/cr/ui/BUILD.gn +++ b/chromium/ui/webui/resources/js/cr/ui/BUILD.gn @@ -2,8 +2,9 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//build/config/chromeos/ui_mode.gni") import("//third_party/closure_compiler/compile_js.gni") -import("//tools/grit/preprocess_grit.gni") +import("//tools/grit/preprocess_if_expr.gni") import("//ui/webui/resources/tools/generate_grd.gni") import("../../../tools/js_modulizer.gni") import("../../cr.gni") @@ -30,18 +31,14 @@ group("preprocess") { ] } -preprocess_grit("preprocess_src") { +preprocess_if_expr("preprocess_src") { in_folder = "./" out_folder = "$preprocess_folder" out_manifest = "$target_gen_dir/$preprocess_src_manifest" in_files = [ "array_data_model.js", - "bubble_button.js", - "bubble.js", - "card_slider.js", "command.js", "context_menu_handler.js", - "controlled_indicator.js", "dialogs.js", "drag_wrapper.js", "focus_grid.js", @@ -57,13 +54,11 @@ preprocess_grit("preprocess_src") { "menu_button.js", "menu_item.js", "menu.js", - "overlay.js", "position_util.js", "splitter.js", "store_client.js", "store.js", "tabs.js", - "touch_handler.js", "tree.js", ] @@ -74,22 +69,27 @@ preprocess_grit("preprocess_src") { ] } - if (is_chromeos) { + if (is_chromeos_ash) { in_files += [ "grid.js" ] } } -preprocess_grit("preprocess_generated") { +preprocess_if_expr("preprocess_generated") { deps = [ ":modulize" ] in_folder = target_gen_dir out_folder = "$preprocess_folder" out_manifest = "$target_gen_dir/$preprocess_gen_manifest" in_files = [ + "array_data_model.m.js", "drag_wrapper.m.js", "focus_grid.m.js", "focus_outline_manager.m.js", "focus_row.m.js", "keyboard_shortcut_list.m.js", + "list_item.m.js", + "list.m.js", + "list_selection_controller.m.js", + "list_selection_model.m.js", "store_client.m.js", "store.m.js", "tabs.m.js", @@ -98,27 +98,22 @@ preprocess_grit("preprocess_generated") { if (!is_android) { in_files += [ + "command.m.js", + "context_menu_handler.m.js", "focus_row_behavior.m.js", "focus_without_ink.m.js", + "menu_button.m.js", + "menu_item.m.js", + "menu.m.js", + "position_util.m.js", ] } - if (is_chromeos) { + if (is_chromeos_ash) { in_files += [ - "array_data_model.m.js", - "command.m.js", - "context_menu_handler.m.js", "dialogs.m.js", "grid.m.js", - "list_item.m.js", - "list.m.js", - "list_selection_controller.m.js", - "list_selection_model.m.js", "list_single_selection_model.m.js", - "menu_button.m.js", - "menu_item.m.js", - "menu.m.js", - "position_util.m.js", "splitter.m.js", ] } @@ -132,6 +127,7 @@ group("closure_compile") { } js_type_check("ui_resources") { + uses_legacy_modules = true deps = [ ":array_data_model", ":command", @@ -153,7 +149,6 @@ js_type_check("ui_resources") { ":menu", ":menu_button", ":menu_item", - ":overlay", ":position_util", ":splitter", ":store", @@ -162,7 +157,7 @@ js_type_check("ui_resources") { ":tree", ] - if (is_chromeos) { + if (is_chromeos_ash) { deps += [ ":grid" ] } } @@ -174,14 +169,6 @@ js_library("array_data_model") { ] } -js_library("bubble") { - deps = [ - "..:ui", - "../..:cr", - "../..:event_tracker", - ] -} - js_library("command") { deps = [ ":keyboard_shortcut_list", @@ -320,13 +307,6 @@ js_library("menu") { ] } -js_library("overlay") { - deps = [ - "../..:cr", - "../..:util", - ] -} - js_library("position_util") { deps = [ "../..:cr" ] } @@ -354,6 +334,7 @@ js_library("tabs") { ":focus_outline_manager", "..:ui", "../..:cr", + "../..:util", ] } diff --git a/chromium/ui/webui/resources/js/cr/ui/array_data_model.js b/chromium/ui/webui/resources/js/cr/ui/array_data_model.js index 1621859b64d..81da62d6986 100644 --- a/chromium/ui/webui/resources/js/cr/ui/array_data_model.js +++ b/chromium/ui/webui/resources/js/cr/ui/array_data_model.js @@ -453,5 +453,6 @@ cr.define('cr.ui', function() { } // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return {ArrayDataModel: ArrayDataModel}; }); diff --git a/chromium/ui/webui/resources/js/cr/ui/bubble.js b/chromium/ui/webui/resources/js/cr/ui/bubble.js deleted file mode 100644 index 7623e1513b5..00000000000 --- a/chromium/ui/webui/resources/js/cr/ui/bubble.js +++ /dev/null @@ -1,569 +0,0 @@ -// Copyright (c) 2012 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. - -// require: event_tracker.js - -cr.define('cr.ui', function() { - /** - * The arrow location specifies how the arrow and bubble are positioned in - * relation to the anchor node. - * @enum {string} - */ - const ArrowLocation = { - // The arrow is positioned at the top and the start of the bubble. In left - // to right mode this is the top left. The entire bubble is positioned below - // the anchor node. - TOP_START: 'top-start', - // The arrow is positioned at the top and the end of the bubble. In left to - // right mode this is the top right. The entire bubble is positioned below - // the anchor node. - TOP_END: 'top-end', - // The arrow is positioned at the bottom and the start of the bubble. In - // left to right mode this is the bottom left. The entire bubble is - // positioned above the anchor node. - BOTTOM_START: 'bottom-start', - // The arrow is positioned at the bottom and the end of the bubble. In - // left to right mode this is the bottom right. The entire bubble is - // positioned above the anchor node. - BOTTOM_END: 'bottom-end' - }; - - /** - * The bubble alignment specifies the position of the bubble in relation to - * the anchor node. - * @enum {string} - */ - const BubbleAlignment = { - // The bubble is positioned just above or below the anchor node (as - // specified by the arrow location) so that the arrow points at the midpoint - // of the anchor. - ARROW_TO_MID_ANCHOR: 'arrow-to-mid-anchor', - // The bubble is positioned just above or below the anchor node (as - // specified by the arrow location) so that its reference edge lines up with - // the edge of the anchor. - BUBBLE_EDGE_TO_ANCHOR_EDGE: 'bubble-edge-anchor-edge', - // The bubble is positioned so that it is entirely within view and does not - // obstruct the anchor element, if possible. The specified arrow location is - // taken into account as the preferred alignment but may be overruled if - // there is insufficient space (see BubbleBase.reposition for the exact - // placement algorithm). - ENTIRELY_VISIBLE: 'entirely-visible' - }; - - /** - * Abstract base class that provides common functionality for implementing - * free-floating informational bubbles with a triangular arrow pointing at an - * anchor node. - * @constructor - * @extends {HTMLDivElement} - * @implements {EventListener} - */ - const BubbleBase = cr.ui.define('div'); - - /** - * The horizontal distance between the tip of the arrow and the reference edge - * of the bubble (as specified by the arrow location). In pixels. - * @type {number} - * @const - */ - BubbleBase.ARROW_OFFSET = 30; - - /** - * Minimum horizontal spacing between edge of bubble and edge of viewport - * (when using the ENTIRELY_VISIBLE alignment). In pixels. - * @type {number} - * @const - */ - BubbleBase.MIN_VIEWPORT_EDGE_MARGIN = 2; - - /** - * This is used to create TrustedHTML. - * @type {!TrustedTypePolicy} - */ - const staticHtmlPolicy = trustedTypes.createPolicy('cr-ui-bubble-js-static', { - createHTML: () => { - return '<div class="bubble-content"></div>' + - '<div class="bubble-shadow"></div>' + - '<div class="bubble-arrow"></div>'; - }, - }); - - BubbleBase.prototype = { - // Set up the prototype chain. - __proto__: HTMLDivElement.prototype, - - /** - * @type {Node} - * @private - */ - anchorNode_: null, - - /** - * Initialization function for the cr.ui framework. - */ - decorate() { - this.className = 'bubble'; - // TODO(Jun.Kokatsu@microsoft.com): remove an empty string argument - // once supported. - // https://github.com/w3c/webappsec-trusted-types/issues/278 - this.innerHTML = staticHtmlPolicy.createHTML(''); - this.hidden = true; - this.bubbleAlignment = cr.ui.BubbleAlignment.ENTIRELY_VISIBLE; - }, - - /** - * Set the anchor node, i.e. the node that this bubble points at. Only - * available when the bubble is not being shown. - * @param {HTMLElement} node The new anchor node. - */ - set anchorNode(node) { - if (!this.hidden) { - return; - } - - this.anchorNode_ = node; - }, - - /** - * Set the conent of the bubble. Only available when the bubble is not being - * shown. - * @param {HTMLElement} node The root node of the new content. - */ - set content(node) { - if (!this.hidden) { - return; - } - - const bubbleContent = this.querySelector('.bubble-content'); - bubbleContent.innerHTML = trustedTypes.emptyHTML; - bubbleContent.appendChild(node); - }, - - /** - * Set the arrow location. Only available when the bubble is not being - * shown. - * @param {cr.ui.ArrowLocation} location The new arrow location. - */ - set arrowLocation(location) { - if (!this.hidden) { - return; - } - - this.arrowAtRight_ = location === cr.ui.ArrowLocation.TOP_END || - location === cr.ui.ArrowLocation.BOTTOM_END; - if (document.documentElement.dir === 'rtl') { - this.arrowAtRight_ = !this.arrowAtRight_; - } - this.arrowAtTop_ = location === cr.ui.ArrowLocation.TOP_START || - location === cr.ui.ArrowLocation.TOP_END; - }, - - /** - * Set the bubble alignment. Only available when the bubble is not being - * shown. - * @param {cr.ui.BubbleAlignment} alignment The new bubble alignment. - */ - set bubbleAlignment(alignment) { - if (!this.hidden) { - return; - } - - this.bubbleAlignment_ = alignment; - }, - - /** - * Update the position of the bubble. Whenever the layout may have changed, - * the bubble should either be repositioned by calling this function or - * hidden so that it does not point to a nonsensical location on the page. - */ - reposition() { - const documentWidth = document.documentElement.clientWidth; - const documentHeight = document.documentElement.clientHeight; - const anchor = this.anchorNode_.getBoundingClientRect(); - const anchorMid = (anchor.left + anchor.right) / 2; - const bubble = this.getBoundingClientRect(); - const arrow = this.querySelector('.bubble-arrow').getBoundingClientRect(); - - let left; - let top; - if (this.bubbleAlignment_ === cr.ui.BubbleAlignment.ENTIRELY_VISIBLE) { - // Work out horizontal placement. The bubble is initially positioned so - // that the arrow tip points toward the midpoint of the anchor and is - // BubbleBase.ARROW_OFFSET pixels from the reference edge and (as - // specified by the arrow location). If the bubble is not entirely - // within view, it is then shifted, preserving the arrow tip position. - left = this.arrowAtRight_ ? - anchorMid + BubbleBase.ARROW_OFFSET - bubble.width : - anchorMid - BubbleBase.ARROW_OFFSET; - const maxLeftPos = - documentWidth - bubble.width - BubbleBase.MIN_VIEWPORT_EDGE_MARGIN; - const minLeftPos = BubbleBase.MIN_VIEWPORT_EDGE_MARGIN; - if (document.documentElement.dir === 'rtl') { - left = Math.min(Math.max(left, minLeftPos), maxLeftPos); - } else { - left = Math.max(Math.min(left, maxLeftPos), minLeftPos); - } - const arrowTip = Math.min( - Math.max( - arrow.width / 2, - this.arrowAtRight_ ? left + bubble.width - anchorMid : - anchorMid - left), - bubble.width - arrow.width / 2); - - // Work out the vertical placement, attempting to fit the bubble - // entirely into view. The following placements are considered in - // decreasing order of preference: - // * Outside the anchor, arrow tip touching the anchor (arrow at - // top/bottom as specified by the arrow location). - // * Outside the anchor, arrow tip touching the anchor (arrow at - // bottom/top, opposite the specified arrow location). - // * Outside the anchor, arrow tip overlapping the anchor (arrow at - // top/bottom as specified by the arrow location). - // * Outside the anchor, arrow tip overlapping the anchor (arrow at - // bottom/top, opposite the specified arrow location). - // * Overlapping the anchor. - const offsetTop = Math.min( - documentHeight - anchor.bottom - bubble.height, arrow.height / 2); - const offsetBottom = - Math.min(anchor.top - bubble.height, arrow.height / 2); - if (offsetTop < 0 && offsetBottom < 0) { - top = 0; - this.updateArrowPosition_(false, false, arrowTip); - } else if ( - offsetTop > offsetBottom || - offsetTop === offsetBottom && this.arrowAtTop_) { - top = anchor.bottom + offsetTop; - this.updateArrowPosition_(true, true, arrowTip); - } else { - top = anchor.top - bubble.height - offsetBottom; - this.updateArrowPosition_(true, false, arrowTip); - } - } else { - if (this.bubbleAlignment_ === - cr.ui.BubbleAlignment.BUBBLE_EDGE_TO_ANCHOR_EDGE) { - left = this.arrowAtRight_ ? anchor.right - bubble.width : anchor.left; - } else { - left = this.arrowAtRight_ ? - anchorMid - this.clientWidth + BubbleBase.ARROW_OFFSET : - anchorMid - BubbleBase.ARROW_OFFSET; - } - top = this.arrowAtTop_ ? - anchor.bottom + arrow.height / 2 : - anchor.top - this.clientHeight - arrow.height / 2; - this.updateArrowPosition_( - true, this.arrowAtTop_, BubbleBase.ARROW_OFFSET); - } - - this.style.left = left + 'px'; - this.style.top = top + 'px'; - }, - - /** - * Show the bubble. - */ - show() { - if (!this.hidden) { - return; - } - - this.attachToDOM_(); - this.hidden = false; - this.reposition(); - - const doc = assert(this.ownerDocument); - this.eventTracker_ = new EventTracker; - this.eventTracker_.add(doc, 'keydown', this, true); - this.eventTracker_.add(doc, 'mousedown', this, true); - }, - - /** - * Hide the bubble. - */ - hide() { - if (this.hidden) { - return; - } - - this.eventTracker_.removeAll(); - this.hidden = true; - this.parentNode.removeChild(this); - }, - - /** - * Handle keyboard events, dismissing the bubble if necessary. - * @param {Event} event The event. - */ - handleEvent(event) { - // Close the bubble when the user presses <Esc>. - if (event.type === 'keydown' && event.keyCode === 27) { - this.hide(); - event.preventDefault(); - event.stopPropagation(); - } - }, - - /** - * Attach the bubble to the document's DOM. - * @private - */ - attachToDOM_() { - document.body.appendChild(this); - }, - - /** - * Update the arrow so that it appears at the correct position. - * @param {boolean} visible Whether the arrow should be visible. - * @param {boolean} atTop Whether the arrow should be at the top of the - * bubble. - * @param {number} tipOffset The horizontal distance between the tip of the - * arrow and the reference edge of the bubble (as specified by the arrow - * location). - * @private - */ - updateArrowPosition_(visible, atTop, tipOffset) { - const bubbleArrow = this.querySelector('.bubble-arrow'); - bubbleArrow.hidden = !visible; - if (!visible) { - return; - } - - let edgeOffset = (-bubbleArrow.clientHeight / 2) + 'px'; - bubbleArrow.style.top = atTop ? edgeOffset : 'auto'; - bubbleArrow.style.bottom = atTop ? 'auto' : edgeOffset; - - edgeOffset = (tipOffset - bubbleArrow.offsetWidth / 2) + 'px'; - bubbleArrow.style.left = this.arrowAtRight_ ? 'auto' : edgeOffset; - bubbleArrow.style.right = this.arrowAtRight_ ? edgeOffset : 'auto'; - }, - }; - - /** - * A bubble that remains open until the user explicitly dismisses it or clicks - * outside the bubble after it has been shown for at least the specified - * amount of time (making it less likely that the user will unintentionally - * dismiss the bubble). The bubble repositions itself on layout changes. - * @constructor - * @extends {cr.ui.BubbleBase} - */ - const Bubble = cr.ui.define('div'); - - Bubble.prototype = { - // Set up the prototype chain. - __proto__: BubbleBase.prototype, - - /** - * Initialization function for the cr.ui framework. - */ - decorate() { - BubbleBase.prototype.decorate.call(this); - - const close = document.createElement('div'); - close.className = 'bubble-close'; - this.insertBefore(close, this.querySelector('.bubble-content')); - - this.handleCloseEvent = this.hide; - this.deactivateToDismissDelay_ = 0; - this.bubbleAlignment = cr.ui.BubbleAlignment.ARROW_TO_MID_ANCHOR; - }, - - /** - * Handler for close events triggered when the close button is clicked. By - * default, set to this.hide. Only available when the bubble is not being - * shown. - * @param {function(): *} handler The new handler, a function with no - * parameters. - */ - set handleCloseEvent(handler) { - if (!this.hidden) { - return; - } - - this.handleCloseEvent_ = handler; - }, - - /** - * Set the delay before the user is allowed to click outside the bubble to - * dismiss it. Using a delay makes it less likely that the user will - * unintentionally dismiss the bubble. - * @param {number} delay The delay in milliseconds. - */ - set deactivateToDismissDelay(delay) { - this.deactivateToDismissDelay_ = delay; - }, - - /** - * Hide or show the close button. - * @param {boolean} isVisible True if the close button should be visible. - */ - set closeButtonVisible(isVisible) { - this.querySelector('.bubble-close').hidden = !isVisible; - }, - - /** - * Show the bubble. - */ - show() { - if (!this.hidden) { - return; - } - - BubbleBase.prototype.show.call(this); - - this.showTime_ = Date.now(); - this.eventTracker_.add(window, 'resize', this.reposition.bind(this)); - }, - - /** - * Handle keyboard and mouse events, dismissing the bubble if necessary. - * @param {Event} event The event. - * @suppress {checkTypes} - * TODO(vitalyp): remove suppression when the extern - * Node.prototype.contains() will be fixed. - */ - handleEvent(event) { - BubbleBase.prototype.handleEvent.call(this, event); - - if (event.type === 'mousedown') { - // Dismiss the bubble when the user clicks on the close button. - if (event.target === this.querySelector('.bubble-close')) { - this.handleCloseEvent_(); - // Dismiss the bubble when the user clicks outside it after the - // specified delay has passed. - } else if ( - !this.contains(event.target) && - Date.now() - this.showTime_ >= this.deactivateToDismissDelay_) { - this.hide(); - } - } - }, - }; - - /** - * A bubble that closes automatically when the user clicks or moves the focus - * outside the bubble and its target element, scrolls the underlying document - * or resizes the window. - * @constructor - * @extends {cr.ui.BubbleBase} - */ - const AutoCloseBubble = cr.ui.define('div'); - - AutoCloseBubble.prototype = { - // Set up the prototype chain. - __proto__: BubbleBase.prototype, - - /** - * Initialization function for the cr.ui framework. - */ - decorate() { - BubbleBase.prototype.decorate.call(this); - this.classList.add('auto-close-bubble'); - }, - - /** - * Set the DOM sibling node, i.e. the node as whose sibling the bubble - * should join the DOM to ensure that focusable elements inside the bubble - * follow the target element in the document's tab order. Only available - * when the bubble is not being shown. - * @param {HTMLElement} node The new DOM sibling node. - */ - set domSibling(node) { - if (!this.hidden) { - return; - } - - this.domSibling_ = node; - }, - - /** - * Show the bubble. - */ - show() { - if (!this.hidden) { - return; - } - - BubbleBase.prototype.show.call(this); - this.domSibling_.showingBubble = true; - - const doc = this.ownerDocument; - this.eventTracker_.add(doc, 'click', this, true); - this.eventTracker_.add(doc, 'mousewheel', this, true); - this.eventTracker_.add(doc, 'scroll', this, true); - this.eventTracker_.add(doc, 'elementFocused', this, true); - this.eventTracker_.add(window, 'resize', this); - }, - - /** - * Hide the bubble. - */ - hide() { - BubbleBase.prototype.hide.call(this); - this.domSibling_.showingBubble = false; - }, - - /** - * Handle events, closing the bubble when the user clicks or moves the focus - * outside the bubble and its target element, scrolls the underlying - * document or resizes the window. - * @param {Event} event The event. - * @suppress {checkTypes} - * TODO(vitalyp): remove suppression when the extern - * Node.prototype.contains() will be fixed. - */ - handleEvent(event) { - BubbleBase.prototype.handleEvent.call(this, event); - - let target; - switch (event.type) { - // Close the bubble when the user clicks outside it, except if it is a - // left-click on the bubble's target element (allowing the target to - // handle the event and close the bubble itself). - case 'mousedown': - case 'click': - target = assertInstanceof(event.target, Node); - if (event.button === 0 && this.anchorNode_.contains(target)) { - break; - } - // Close the bubble when the underlying document is scrolled. - case 'mousewheel': - case 'scroll': - target = assertInstanceof(event.target, Node); - if (this.contains(target)) { - break; - } - // Close the bubble when the window is resized. - case 'resize': - this.hide(); - break; - // Close the bubble when the focus moves to an element that is not the - // bubble target and is not inside the bubble. - case 'elementFocused': - target = assertInstanceof(event.target, Node); - if (!this.anchorNode_.contains(target) && !this.contains(target)) { - this.hide(); - } - break; - } - }, - - /** - * Attach the bubble to the document's DOM, making it a sibling of the - * |domSibling_| so that focusable elements inside the bubble follow the - * target element in the document's tab order. - * @private - */ - attachToDOM_() { - const parent = this.domSibling_.parentNode; - parent.insertBefore(this, this.domSibling_.nextSibling); - }, - }; - - return { - ArrowLocation: ArrowLocation, - AutoCloseBubble: AutoCloseBubble, - BubbleAlignment: BubbleAlignment, - BubbleBase: BubbleBase, - Bubble: Bubble, - }; -}); diff --git a/chromium/ui/webui/resources/js/cr/ui/bubble_button.js b/chromium/ui/webui/resources/js/cr/ui/bubble_button.js deleted file mode 100644 index b1accdd7a44..00000000000 --- a/chromium/ui/webui/resources/js/cr/ui/bubble_button.js +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright (c) 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. - -cr.define('cr.ui', function() { - /** - * An image button that brings up an informative bubble when activated by - * keyboard or mouse. - * @constructor - * @extends {HTMLSpanElement} - * @implements {EventListener} - */ - const BubbleButton = cr.ui.define('span'); - - BubbleButton.prototype = { - __proto__: HTMLSpanElement.prototype, - - /** - * Decorates the base element to show the proper icon. - */ - decorate() { - this.className = 'bubble-button'; - this.location = cr.ui.ArrowLocation.TOP_END; - this.image = document.createElement('div'); - this.image.tabIndex = 0; - this.image.setAttribute('role', 'button'); - this.image.addEventListener('click', this); - this.image.addEventListener('keydown', this); - this.image.addEventListener('mousedown', this); - this.appendChild(this.image); - }, - - /** - * Whether the button is currently showing a bubble. - * @type {boolean} - */ - get showingBubble() { - return this.image.classList.contains('showing-bubble'); - }, - set showingBubble(showing) { - this.image.classList.toggle('showing-bubble', showing); - }, - - /** - * Handle mouse and keyboard events, allowing the user to open and close an - * informative bubble. - * @param {Event} event Mouse or keyboard event. - */ - handleEvent(event) { - switch (event.type) { - // Toggle the bubble on left click. Let any other clicks propagate. - case 'click': - if (event.button !== 0) { - return; - } - break; - // Toggle the bubble when <Return> or <Space> is pressed. Let any other - // key presses propagate. - case 'keydown': - switch (event.keyCode) { - case 13: // Return. - case 32: // Space. - break; - default: - return; - } - break; - // Blur focus when a mouse button is pressed, matching the behavior of - // other Web UI elements. - case 'mousedown': - if (document.activeElement) { - document.activeElement.blur(); - } - event.preventDefault(); - return; - } - this.toggleBubble(); - event.preventDefault(); - event.stopPropagation(); - }, - - /** - * Abstract method: subclasses should overwrite it. There is no way to mark - * method as abstract for Closure Compiler, as of - * https://github.com/google/closure-compiler/issues/104. - * @type {!Function|undefined} - * @protected - */ - toggleBubble: assertNotReached, - }; - - // Export. - return {BubbleButton: BubbleButton}; -}); diff --git a/chromium/ui/webui/resources/js/cr/ui/card_slider.js b/chromium/ui/webui/resources/js/cr/ui/card_slider.js deleted file mode 100644 index af7e5904c55..00000000000 --- a/chromium/ui/webui/resources/js/cr/ui/card_slider.js +++ /dev/null @@ -1,693 +0,0 @@ -// Copyright (c) 2012 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. - -/** - * @fileoverview Card slider implementation. Allows you to create interactions - * that have items that can slide left to right to reveal additional items. - * Works by adding the necessary event handlers to a specific DOM structure - * including a frame, container and cards. - * - The frame defines the boundary of one item. Each card will be expanded to - * fill the width of the frame. This element is also overflow hidden so that - * the additional items left / right do not trigger horizontal scrolling. - * - The container is what all the touch events are attached to. This element - * will be expanded to be the width of all cards. - * - The cards are the individual viewable items. There should be one card for - * each item in the list. Only one card will be visible at a time. Two cards - * will be visible while you are transitioning between cards. - * - * This class is designed to work well on any hardware-accelerated touch device. - * It should still work on pre-hardware accelerated devices it just won't feel - * very good. It should also work well with a mouse. - */ - -// Use an anonymous function to enable strict mode just for this file (which -// will be concatenated with other files when embedded in Chrome -cr.define('cr.ui', function() { - 'use strict'; - - /** - * @constructor - * @param {!Element} frame The bounding rectangle that cards are visible in. - * @param {!Element} container The surrounding element that will have event - * listeners attached to it. - * @param {number} cardWidth The width of each card should have. - */ - function CardSlider(frame, container, cardWidth) { - /** - * @type {!Element} - * @private - */ - this.frame_ = frame; - - /** - * @type {!Element} - * @private - */ - this.container_ = container; - - /** - * Array of card elements. - * @type {!Array<!Element>} - * @private - */ - this.cards_ = []; - - /** - * Index of currently shown card. - * @type {number} - * @private - */ - this.currentCard_ = -1; - - /** - * @type {number} - * @private - */ - this.cardWidth_ = cardWidth; - - /** - * @type {!cr.ui.TouchHandler} - * @private - */ - this.touchHandler_ = new cr.ui.TouchHandler(this.container_); - } - - - /** - * The time to transition between cards when animating. Measured in ms. - * @type {number} - * @private - * @const - */ - CardSlider.TRANSITION_TIME_ = 200; - - - /** - * The minimum velocity required to transition cards if they did not drag past - * the halfway point between cards. Measured in pixels / ms. - * @type {number} - * @private - * @const - */ - CardSlider.TRANSITION_VELOCITY_THRESHOLD_ = 0.2; - - - CardSlider.prototype = { - /** - * The current left offset of the container relative to the frame. This - * position does not include deltas from active drag operations, and - * always aligns with a frame boundary. - * @type {number} - * @private - */ - currentLeft_: 0, - - /** - * Current offset relative to |currentLeft_| due to an active drag - * operation. - * @type {number} - * @private - */ - deltaX_: 0, - - /** - * Initialize all elements and event handlers. Must call after construction - * and before usage. - * @param {boolean} ignoreMouseWheelEvents If true, horizontal mouse wheel - * events will be ignored, rather than flipping between pages. - */ - initialize(ignoreMouseWheelEvents) { - const view = this.container_.ownerDocument.defaultView; - assert( - view.getComputedStyle(this.container_).display === '-webkit-box', - 'Container should be display -webkit-box.'); - assert( - view.getComputedStyle(this.frame_).overflow === 'hidden', - 'Frame should be overflow hidden.'); - assert( - view.getComputedStyle(this.container_).position === 'static', - 'Container should be position static.'); - - this.updateCardWidths_(); - - this.mouseWheelScrollAmount_ = 0; - this.mouseWheelCardSelected_ = false; - this.mouseWheelIsContinuous_ = false; - this.scrollClearTimeout_ = null; - if (!ignoreMouseWheelEvents) { - this.frame_.addEventListener( - 'mousewheel', this.onMouseWheel_.bind(this)); - } - this.container_.addEventListener( - 'transitionend', this.onTransitionEnd_.bind(this)); - - // Also support touch events in case a touch screen happens to be - // available. Note that this has minimal impact in the common case of - // no touch events (eg. we're mainly just adding listeners for events that - // will never trigger). - const TouchHandler = cr.ui.TouchHandler; - this.container_.addEventListener( - TouchHandler.EventType.TOUCH_START, this.onTouchStart_.bind(this)); - this.container_.addEventListener( - TouchHandler.EventType.DRAG_START, this.onDragStart_.bind(this)); - this.container_.addEventListener( - TouchHandler.EventType.DRAG_MOVE, this.onDragMove_.bind(this)); - this.container_.addEventListener( - TouchHandler.EventType.DRAG_END, this.onDragEnd_.bind(this)); - - this.touchHandler_.enable(/* opt_capture */ false); - }, - - /** - * Use in cases where the width of the frame has changed in order to update - * the width of cards. For example should be used when orientation changes - * in full width sliders. - * @param {number} newCardWidth Width all cards should have, in pixels. - */ - resize(newCardWidth) { - if (newCardWidth !== this.cardWidth_) { - this.cardWidth_ = newCardWidth; - - this.updateCardWidths_(); - - // Must upate the transform on the container to show the correct card. - this.transformToCurrentCard_(); - } - }, - - /** - * Sets the cards used. Can be called more than once to switch card sets. - * @param {!Array<!Element>} cards The individual viewable cards. - * @param {number} index Index of the card to in the new set of cards to - * navigate to. - */ - setCards(cards, index) { - assert( - index >= 0 && index < cards.length, - 'Invalid index in CardSlider#setCards'); - this.cards_ = cards; - - this.updateCardWidths_(); - this.updateSelectedCardAttributes_(); - - // Jump to the given card index. - this.selectCard(index, false, false, true); - }, - - /** - * Ensures that for all cards: - * - if the card is the current card, then it has 'selected-card' in its - * classList, and is visible for accessibility - * - if the card is not the selected card, then it does not have - * 'selected-card' in its classList, and is invisible for accessibility. - * @private - */ - updateSelectedCardAttributes_() { - for (let i = 0; i < this.cards_.length; i++) { - if (i === this.currentCard_) { - this.cards_[i].classList.add('selected-card'); - this.cards_[i].removeAttribute('aria-hidden'); - } else { - this.cards_[i].classList.remove('selected-card'); - this.cards_[i].setAttribute('aria-hidden', true); - } - } - }, - - /** - * Updates the width of each card. - * @private - */ - updateCardWidths_() { - for (let i = 0, card; card = this.cards_[i]; i++) { - card.style.width = this.cardWidth_ + 'px'; - } - }, - - /** - * Returns the index of the current card. - * @return {number} index of the current card. - */ - get currentCard() { - return this.currentCard_; - }, - - /** - * Allows setting the current card index. - * @param {number} index A new index to set the current index to. - * @return {number} The new index after having been set. - */ - set currentCard(index) { - return (this.currentCard_ = index); - }, - - /** - * Returns the number of cards. - * @return {number} number of cards. - */ - get cardCount() { - return this.cards_.length; - }, - - /** - * Returns the current card itself. - * @return {!Element} the currently shown card. - */ - get currentCardValue() { - return this.cards_[this.currentCard_]; - }, - - /** - * Returns the frame holding the cards. - * @return {Element} The frame used to position the cards. - */ - get frame() { - return this.frame_; - }, - - /** - * Handle horizontal scrolls to flip between pages. - * @private - */ - onMouseWheel_(e) { - if (e.wheelDeltaX === 0) { - return; - } - - // Continuous devices such as an Apple Touchpad or Apple MagicMouse will - // send arbitrary delta values. Conversly, standard mousewheels will - // send delta values in increments of 120. (There is of course a small - // chance we mistake a continuous device for a non-continuous device. - // Unfortunately there isn't a better way to do this until real touch - // events are available to desktop clients.) - const DISCRETE_DELTA = 120; - if (e.wheelDeltaX % DISCRETE_DELTA) { - this.mouseWheelIsContinuous_ = true; - } - - if (this.mouseWheelIsContinuous_) { - // For continuous devices, detect a page swipe when the accumulated - // delta matches a pre-defined threshhold. After changing the page, - // ignore wheel events for a short time before repeating this process. - if (this.mouseWheelCardSelected_) { - return; - } - this.mouseWheelScrollAmount_ += e.wheelDeltaX; - if (Math.abs(this.mouseWheelScrollAmount_) >= 600) { - let pagesToScroll = this.mouseWheelScrollAmount_ > 0 ? 1 : -1; - if (!isRTL()) { - pagesToScroll *= -1; - } - let newCardIndex = this.currentCard + pagesToScroll; - newCardIndex = - Math.min(this.cards_.length - 1, Math.max(0, newCardIndex)); - this.selectCard(newCardIndex, true); - this.mouseWheelCardSelected_ = true; - } - } else { - // For discrete devices, consider each wheel tick a page change. - let pagesToScroll = e.wheelDeltaX / DISCRETE_DELTA; - if (!isRTL()) { - pagesToScroll *= -1; - } - let newCardIndex = this.currentCard + pagesToScroll; - newCardIndex = - Math.min(this.cards_.length - 1, Math.max(0, newCardIndex)); - this.selectCard(newCardIndex, true); - } - - // We got a mouse wheel event, so cancel any pending scroll wheel timeout. - if (this.scrollClearTimeout_ !== null) { - clearTimeout(this.scrollClearTimeout_); - } - // If we didn't use up all the scroll, hold onto it for a little bit, but - // drop it after a delay. - if (this.mouseWheelScrollAmount_ !== 0) { - this.scrollClearTimeout_ = - setTimeout(this.clearMouseWheelScroll_.bind(this), 500); - } - }, - - /** - * Resets the amount of horizontal scroll we've seen to 0. See - * onMouseWheel_. - * @private - */ - clearMouseWheelScroll_() { - this.mouseWheelScrollAmount_ = 0; - this.mouseWheelCardSelected_ = false; - }, - - /** - * Handles the ends of transitions on transform (animated - * card switches). - * @param {Event} e The transitionend event. - * @private - */ - onTransitionEnd_(e) { - // Ignore irrelevant transitions that might bubble up. - if (e.target !== this.container_ || e.propertyName !== 'transform') { - return; - } - this.fireChangeEndedEvent_(true); - }, - - /** - * Dispatches a simple event to tell subscribers we're done moving to the - * newly selected card. - * @param {boolean} wasAnimated whether or not the change was animated. - * @private - */ - fireChangeEndedEvent_(wasAnimated) { - const e = document.createEvent('Event'); - e.initEvent('cardSlider:card_change_ended', true, true); - e.cardSlider = this; - e.changedTo = this.currentCard_; - e.wasAnimated = wasAnimated; - this.container_.dispatchEvent(e); - }, - - /** - * Add a card to the card slider at a particular index. If the card being - * added is inserted in front of the current card, cardSlider.currentCard - * will be adjusted accordingly (to current card + 1). - * @param {!Node} card A card that will be added to the card slider. - * @param {number} index An index at which the given |card| should be - * inserted. Must be positive and less than the number of cards. - */ - addCardAtIndex(card, index) { - assert(card instanceof Node, '|card| isn\'t a Node'); - this.assertValidIndex_(index); - this.cards_ = Array.prototype.concat.call( - this.cards_.slice(0, index), card, this.cards_.slice(index)); - - this.updateSelectedCardAttributes_(); - - if (this.currentCard_ === -1) { - this.currentCard_ = 0; - } else if (index <= this.currentCard_) { - this.selectCard(this.currentCard_ + 1, false, true, true); - } - - this.fireAddedEvent_(card, index); - }, - - /** - * Append a card to the end of the list. - * @param {!Element} card A card to add at the end of the card slider. - */ - appendCard(card) { - this.cards_.push(assertInstanceof(card, Element)); - this.fireAddedEvent_(card, this.cards_.length - 1); - }, - - /** - * Dispatches a simple event to tell interested subscribers that a card was - * added to this card slider. - * @param {Node} card The recently added card. - * @param {number} index The position of the newly added card. - * @private - */ - fireAddedEvent_(card, index) { - this.assertValidIndex_(index); - const e = document.createEvent('Event'); - e.initEvent('cardSlider:card_added', true, true); - e.addedIndex = index; - e.addedCard = card; - this.container_.dispatchEvent(e); - }, - - /** - * Returns the card at a particular index. - * @param {number} index The index of the card to return. - * @return {!Element} The card at the given index. - */ - getCardAtIndex(index) { - this.assertValidIndex_(index); - return this.cards_[index]; - }, - - /** - * Removes a card by index from the card slider. If the card to be removed - * is the current card or in front of the current card, the current card - * will be updated (to current card - 1). - * @param {!Element} card A card to be removed. - */ - removeCard(card) { - this.removeCardAtIndex( - this.cards_.indexOf(assertInstanceof(card, Element))); - }, - - /** - * Removes a card by index from the card slider. If the card to be removed - * is the current card or in front of the current card, the current card - * will be updated (to current card - 1). - * @param {number} index The index of the tile that should be removed. - */ - removeCardAtIndex(index) { - this.assertValidIndex_(index); - const removed = this.cards_.splice(index, 1).pop(); - - if (this.cards_.length === 0) { - this.currentCard_ = -1; - } else if (index < this.currentCard_) { - this.selectCard(this.currentCard_ - 1, false, true); - } - - this.fireRemovedEvent_(removed, index); - }, - - /** - * Dispatches a cardSlider:card_removed event so interested subscribers know - * when a card was removed from this card slider. - * @param {Node} card The recently removed card. - * @param {number} index The index of the card before it was removed. - * @private - */ - fireRemovedEvent_(card, index) { - const e = document.createEvent('Event'); - e.initEvent('cardSlider:card_removed', true, true); - e.removedCard = card; - e.removedIndex = index; - this.container_.dispatchEvent(e); - }, - - /** - * This re-syncs the transform that's used to position the frame in - * the likely event it needs to be updated by a card being inserted or - * removed in the flow. - */ - repositionFrame() { - this.transformToCurrentCard_(); - }, - - /** - * Checks the the given |index| exists in this.cards_. - * @param {number} index An index to check. - * @private - */ - assertValidIndex_(index) { - assert(index >= 0 && index < this.cards_.length); - }, - - /** - * Selects a new card, ensuring that it is a valid index, transforming the - * view and possibly calling the change card callback. - * @param {number} newCardIndex Index of card to show. - * @param {boolean=} opt_animate If true will animate transition from - * current position to new position. - * @param {boolean=} opt_dontNotify If true, don't tell subscribers that - * we've changed cards. - * @param {boolean=} opt_forceChange If true, ignore if the card already - * selected. - */ - selectCard(newCardIndex, opt_animate, opt_dontNotify, opt_forceChange) { - this.assertValidIndex_(newCardIndex); - - const previousCard = this.currentCardValue; - let isChangingCard = - !this.cards_[newCardIndex].classList.contains('selected-card'); - - if (typeof opt_forceChange !== 'undefined' && opt_forceChange) { - isChangingCard = true; - } - - if (isChangingCard) { - this.currentCard_ = newCardIndex; - this.updateSelectedCardAttributes_(); - } - - const willTransitionHappen = this.transformToCurrentCard_(opt_animate); - - if (isChangingCard && !opt_dontNotify) { - const event = document.createEvent('Event'); - event.initEvent('cardSlider:card_changed', true, true); - event.cardSlider = this; - event.wasAnimated = !!opt_animate; - this.container_.dispatchEvent(event); - - // We also dispatch an event on the cards themselves. - if (previousCard) { - cr.dispatchSimpleEvent(previousCard, 'carddeselected', true, true); - } - cr.dispatchSimpleEvent( - this.currentCardValue, 'cardselected', true, true); - } - - // If we're not changing, animated, or transitioning, fire a - // cardSlider:card_change_ended event right away. - if ((!isChangingCard || !opt_animate || !willTransitionHappen) && - !opt_dontNotify) { - this.fireChangeEndedEvent_(false); - } - }, - - /** - * Selects a card from the stack. Passes through to selectCard. - * @param {!Element} newCard The card that should be selected. - * @param {boolean=} opt_animate Whether to animate. - */ - selectCardByValue(newCard, opt_animate) { - const i = this.cards_.indexOf(newCard); - assert(i !== -1); - this.selectCard(i, opt_animate); - }, - - /** - * Centers the view on the card denoted by this.currentCard. Can either - * animate to that card or snap to it. - * @param {boolean=} opt_animate If true will animate transition from - * current position to new position. - * @return {boolean} Whether or not a transformation was necessary. - * @private - */ - transformToCurrentCard_(opt_animate) { - const prevLeft = this.currentLeft_; - this.currentLeft_ = -this.cardWidth_ * - (isRTL() ? this.cards_.length - this.currentCard - 1 : - this.currentCard); - - // If there's no change, return something to let the caller know there - // won't be a transition occuring. - if (prevLeft === this.currentLeft_ && this.deltaX_ === 0) { - return false; - } - - // Animate to the current card, which will either transition if the - // current card is new, or reset the existing card if we didn't drag - // enough to change cards. - let transition = ''; - if (opt_animate) { - transition = - 'transform ' + CardSlider.TRANSITION_TIME_ + 'ms ease-in-out'; - } - this.container_.style.transition = transition; - this.translateTo_(this.currentLeft_); - - return true; - }, - - /** - * Moves the view to the specified position. - * @param {number} x Horizontal position to move to. - * @private - */ - translateTo_(x) { - // We use a transform to slide because this is GPU accelerated on - // Chrome and iOS. Once Chrome does GPU acceleration on the position - // fixed-layout elements we could simply set the element's position to - // fixed and modify 'left' instead. - this.deltaX_ = x - this.currentLeft_; - this.container_.style.transform = 'translate3d(' + x + 'px, 0, 0)'; - }, - - /* Touch ******************************************************************/ - - /** - * Clear any transition that is in progress and enable dragging for the - * touch. - * @param {!Event} e The TouchHandler event. - * @private - */ - onTouchStart_(e) { - e = /** @type {!cr.ui.TouchHandler.Event} */ (e); - this.container_.style.transition = ''; - e.enableDrag = true; - }, - - /** - * Tell the TouchHandler that dragging is acceptable when the user begins by - * scrolling horizontally and there is more than one card to slide. - * @param {!Event} e The TouchHandler event. - * @private - */ - onDragStart_(e) { - e = /** @type {!cr.ui.TouchHandler.Event} */ (e); - e.enableDrag = - this.cardCount > 1 && Math.abs(e.dragDeltaX) > Math.abs(e.dragDeltaY); - }, - - /** - * On each drag move event reposition the container appropriately so the - * cards look like they are sliding. - * @param {!Event} e The TouchHandler event. - * @private - */ - onDragMove_(e) { - e = /** @type {!cr.ui.TouchHandler.Event} */ (e); - let deltaX = e.dragDeltaX; - // If dragging beyond the first or last card then apply a backoff so the - // dragging feels stickier than usual. - if (!this.currentCard && deltaX > 0 || - this.currentCard === (this.cards_.length - 1) && deltaX < 0) { - deltaX /= 2; - } - this.translateTo_(this.currentLeft_ + deltaX); - }, - - /** - * On drag end events we may want to transition to another card, depending - * on the ending position of the drag and the velocity of the drag. - * @param {!Event} e The TouchHandler event. - * @private - */ - onDragEnd_(e) { - e = /** @type {!cr.ui.TouchHandler.Event} */ (e); - const deltaX = e.dragDeltaX; - const velocity = this.touchHandler_.getEndVelocity().x; - const newX = this.currentLeft_ + deltaX; - let newCardIndex = Math.round(-newX / this.cardWidth_); - - if (newCardIndex === this.currentCard && - Math.abs(velocity) > CardSlider.TRANSITION_VELOCITY_THRESHOLD_) { - // The drag wasn't far enough to change cards but the velocity was - // high enough to transition anyways. If the velocity is to the left - // (negative) then the user wishes to go right (card + 1). - newCardIndex += velocity > 0 ? -1 : 1; - } - // Ensure that the new card index is valid. The new card index could be - // invalid if a swipe suggests scrolling off the end of the list of - // cards. - if (newCardIndex < 0) { - newCardIndex = 0; - } else if (newCardIndex >= this.cardCount) { - newCardIndex = this.cardCount - 1; - } - this.selectCard(newCardIndex, /* animate */ true); - }, - - /** - * Cancel any current touch/slide as if we saw a touch end - */ - cancelTouch() { - // Stop listening to any current touch - this.touchHandler_.cancelTouch(); - - // Ensure we're at a card bounary - this.transformToCurrentCard_(true); - }, - }; - - return {CardSlider: CardSlider}; -}); diff --git a/chromium/ui/webui/resources/js/cr/ui/command.js b/chromium/ui/webui/resources/js/cr/ui/command.js index 53257dff86a..73d14df8b83 100644 --- a/chromium/ui/webui/resources/js/cr/ui/command.js +++ b/chromium/ui/webui/resources/js/cr/ui/command.js @@ -301,6 +301,7 @@ cr.define('cr.ui', function() { // Export // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return { Command: Command, CanExecuteEvent: CanExecuteEvent, diff --git a/chromium/ui/webui/resources/js/cr/ui/context_menu_handler.js b/chromium/ui/webui/resources/js/cr/ui/context_menu_handler.js index 4a1bf527959..801d4bdd7ea 100644 --- a/chromium/ui/webui/resources/js/cr/ui/context_menu_handler.js +++ b/chromium/ui/webui/resources/js/cr/ui/context_menu_handler.js @@ -320,6 +320,7 @@ cr.define('cr.ui', function() { // Export // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return { contextMenuHandler: contextMenuHandler, }; diff --git a/chromium/ui/webui/resources/js/cr/ui/controlled_indicator.js b/chromium/ui/webui/resources/js/cr/ui/controlled_indicator.js deleted file mode 100644 index ad7c8556e45..00000000000 --- a/chromium/ui/webui/resources/js/cr/ui/controlled_indicator.js +++ /dev/null @@ -1,128 +0,0 @@ -// Copyright 2014 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. - -cr.define('cr.ui', function() { - /** @const */ const BubbleButton = cr.ui.BubbleButton; - - /** - * An indicator that can be placed on a UI element as a hint to the user that - * the value is controlled by some external entity such as policy or an - * extension. - * @constructor - * @extends {cr.ui.BubbleButton} - */ - const ControlledIndicator = cr.ui.define('span'); - - /** - * Only a single bubble can be shown at a time. |bubble| holds a reference to - * the bubble, if any. - * @private - */ - let bubble; - - ControlledIndicator.prototype = { - __proto__: cr.ui.BubbleButton.prototype, - - /** - * Decorates the base element to show the proper icon. - */ - decorate() { - cr.ui.BubbleButton.prototype.decorate.call(this); - this.classList.add('controlled-setting-indicator'); - }, - - /** - * Shows an informational bubble displaying |content|. - * @param {HTMLDivElement} content The content of the bubble. - */ - showBubble(content) { - this.hideBubble(); - - bubble = new cr.ui.AutoCloseBubble; - bubble.anchorNode = this.image; - bubble.domSibling = this; - bubble.arrowLocation = this.location; - bubble.content = content; - bubble.show(); - }, - - /** - * Hides the currently visible bubble, if any. - */ - hideBubble() { - if (bubble) { - bubble.hide(); - } - }, - - /** - * Returns a dictionary of the form { |controlled-by|: |bubbleText| }, where - * |controlled-by| is a valid value of the controlled-by property (see - * below), i.e. 'policy'. |bubbleText| is the default text to be shown for - * UI items with this controlled-by property value. The default - * implementation does not set any strings. - * @return {Object} - */ - getDefaultStrings() { - return {}; - }, - - /** - * Returns the text shown in the bubble. - * @return {string} - */ - getBubbleText() { - const defaultStrings = this.getDefaultStrings(); - let text = defaultStrings[this.controlledBy]; - - if (this.hasAttribute('text' + this.controlledBy)) { - text = this.getAttribute('text' + this.controlledBy); - } else if (this.controlledBy === 'extension' && this['extensionName']) { - text = defaultStrings['extensionWithName']; - } - - return text || ''; - }, - - /** - * Returns the DOM tree for a showing the message |text|. - * @param {string} text to be shown in the bubble. - */ - createDomTree(text) { - const content = document.createElement('div'); - content.textContent = text; - return content; - }, - - /** - * Open or close a bubble with further information about the pref. - * @override - */ - toggleBubble() { - if (this.showingBubble) { - this.hideBubble(); - } else { - this.showBubble(this.createDomTree(this.getBubbleText())); - } - }, - }; - - /** - * The status of the associated preference: - * - 'policy': A specific value is enforced by policy. - * - 'extension': A specific value is enforced by an extension. - * - 'recommended': A value is recommended by policy. The user could - * override this recommendation but has not done so. - * - 'hasRecommendation': A value is recommended by policy. The user has - * overridden this recommendation. - * - 'owner': A value is controlled by the owner of the device - * (Chrome OS only). - * - 'shared': A value belongs to the primary user but can be - * modified (Chrome OS only). - * - unset: The value is controlled by the user alone. - */ - cr.defineProperty(ControlledIndicator, 'controlledBy', cr.PropertyKind.ATTR); - - return {ControlledIndicator: ControlledIndicator}; -}); diff --git a/chromium/ui/webui/resources/js/cr/ui/dialogs.js b/chromium/ui/webui/resources/js/cr/ui/dialogs.js index 6c17b44d3b5..c645f29665a 100644 --- a/chromium/ui/webui/resources/js/cr/ui/dialogs.js +++ b/chromium/ui/webui/resources/js/cr/ui/dialogs.js @@ -18,6 +18,18 @@ cr.define('cr.ui.dialogs', function() { // so we can restore it when we're hidden. this.previousActiveElement_ = null; + /** + * If set true, BaseDialog assumes that focus traversal of elements inside + * the dialog due to 'Tab' key events is handled by its container (and the + * practical example is this.parentNode_ is a modal <dialog> element). + * + * The default is false: BaseDialog handles focus traversal for the entire + * DOM document. See findFocusableElements_(), also crbug.com/1078300. + * + * @protected {boolean} + */ + this.hasModalContainer = false; + /** @private{boolean} */ this.showing_ = false; @@ -245,14 +257,21 @@ cr.define('cr.ui.dialogs', function() { BaseDialog.prototype.show_ = function( title, opt_onOk, opt_onCancel, opt_onShow) { this.showing_ = true; - // Make all outside nodes unfocusable while the dialog is active. - this.deactivatedNodes_ = this.findFocusableElements_(this.document_); - this.tabIndexes_ = this.deactivatedNodes_.map(function(n) { - return n.getAttribute('tabindex'); - }); - this.deactivatedNodes_.forEach(function(n) { - n.tabIndex = -1; - }); + + // Modal containers manage dialog focus traversal. Otherwise, the focus + // is managed by |this| dialog, by making all outside nodes unfocusable + // while the dialog is shown. + if (!this.hasModalContainer) { + this.deactivatedNodes_ = this.findFocusableElements_(this.document_); + this.tabIndexes_ = this.deactivatedNodes_.map(function(n) { + return n.getAttribute('tabindex'); + }); + this.deactivatedNodes_.forEach(function(n) { + n.tabIndex = -1; + }); + } else { + this.deactivatedNodes_ = []; + } this.previousActiveElement_ = this.document_.activeElement; this.parentNode_.appendChild(this.container); @@ -288,7 +307,8 @@ cr.define('cr.ui.dialogs', function() { /** @param {Function=} opt_onHide */ BaseDialog.prototype.hide = function(opt_onHide) { this.showing_ = false; - // Restore focusability. + + // Restore focusability for the non-modal container case. for (let i = 0; i < this.deactivatedNodes_.length; i++) { const node = this.deactivatedNodes_[i]; if (this.tabIndexes_[i] === null) { @@ -301,13 +321,13 @@ cr.define('cr.ui.dialogs', function() { this.tabIndexes_ = null; this.container.classList.remove('shown'); + this.container.classList.remove('pulse'); if (this.previousActiveElement_) { this.previousActiveElement_.focus(); } else { this.document_.body.focus(); } - this.frame.classList.remove('pulse'); const self = this; setTimeout(function() { @@ -417,6 +437,7 @@ cr.define('cr.ui.dialogs', function() { }; // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return { BaseDialog: BaseDialog, AlertDialog: AlertDialog, diff --git a/chromium/ui/webui/resources/js/cr/ui/drag_wrapper.js b/chromium/ui/webui/resources/js/cr/ui/drag_wrapper.js index af78b675f05..3aae1c7d2bb 100644 --- a/chromium/ui/webui/resources/js/cr/ui/drag_wrapper.js +++ b/chromium/ui/webui/resources/js/cr/ui/drag_wrapper.js @@ -140,6 +140,7 @@ cr.define('cr.ui', function() { } // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return { DragWrapper: DragWrapper, DragWrapperDelegate: DragWrapperDelegate, diff --git a/chromium/ui/webui/resources/js/cr/ui/focus_grid.js b/chromium/ui/webui/resources/js/cr/ui/focus_grid.js index 48824fc0301..151749bba59 100644 --- a/chromium/ui/webui/resources/js/cr/ui/focus_grid.js +++ b/chromium/ui/webui/resources/js/cr/ui/focus_grid.js @@ -187,6 +187,7 @@ cr.define('cr.ui', function() { } // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return { FocusGrid: FocusGrid, }; diff --git a/chromium/ui/webui/resources/js/cr/ui/focus_outline_manager.js b/chromium/ui/webui/resources/js/cr/ui/focus_outline_manager.js index 461c172aee5..706afc3933a 100644 --- a/chromium/ui/webui/resources/js/cr/ui/focus_outline_manager.js +++ b/chromium/ui/webui/resources/js/cr/ui/focus_outline_manager.js @@ -87,5 +87,6 @@ cr.define('cr.ui', function() { } // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return {FocusOutlineManager: FocusOutlineManager}; }); diff --git a/chromium/ui/webui/resources/js/cr/ui/focus_row_behavior.js b/chromium/ui/webui/resources/js/cr/ui/focus_row_behavior.js index 1695e4ff438..2103e4f3648 100644 --- a/chromium/ui/webui/resources/js/cr/ui/focus_row_behavior.js +++ b/chromium/ui/webui/resources/js/cr/ui/focus_row_behavior.js @@ -383,6 +383,7 @@ cr.define('cr.ui', function() { }; // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return { FocusRowBehaviorDelegate, VirtualFocusRow, diff --git a/chromium/ui/webui/resources/js/cr/ui/focus_without_ink.js b/chromium/ui/webui/resources/js/cr/ui/focus_without_ink.js index 33219cba986..884e910dc70 100644 --- a/chromium/ui/webui/resources/js/cr/ui/focus_without_ink.js +++ b/chromium/ui/webui/resources/js/cr/ui/focus_without_ink.js @@ -48,5 +48,6 @@ cr.define('cr.ui', function() { }; // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return {focusWithoutInk: focusWithoutInk}; }); diff --git a/chromium/ui/webui/resources/js/cr/ui/grid.js b/chromium/ui/webui/resources/js/cr/ui/grid.js index 7c372342876..bdf950353a4 100644 --- a/chromium/ui/webui/resources/js/cr/ui/grid.js +++ b/chromium/ui/webui/resources/js/cr/ui/grid.js @@ -444,6 +444,7 @@ cr.define('cr.ui', function() { }; // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return { Grid: Grid, GridItem: GridItem, diff --git a/chromium/ui/webui/resources/js/cr/ui/keyboard_shortcut_list.js b/chromium/ui/webui/resources/js/cr/ui/keyboard_shortcut_list.js index 65f9c89fd48..0322d992dd3 100644 --- a/chromium/ui/webui/resources/js/cr/ui/keyboard_shortcut_list.js +++ b/chromium/ui/webui/resources/js/cr/ui/keyboard_shortcut_list.js @@ -91,6 +91,7 @@ cr.define('cr.ui', function() { } // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return { KeyboardShortcutList: KeyboardShortcutList, }; diff --git a/chromium/ui/webui/resources/js/cr/ui/list.js b/chromium/ui/webui/resources/js/cr/ui/list.js index d68e3160eca..c0eaff10884 100644 --- a/chromium/ui/webui/resources/js/cr/ui/list.js +++ b/chromium/ui/webui/resources/js/cr/ui/list.js @@ -1399,11 +1399,8 @@ cr.define('cr.ui', function() { * @param {Event} e The mouse event object. */ function handleMouseDown(e) { - e.target = /** @type {!HTMLElement} */ (e.target); - const listItem = this.getListItemAncestor(e.target); - if (!listItem) { - return; - } + const target = /** @type {!HTMLElement} */ (e.target); + const listItem = this.getListItemAncestor(target); const wasSelected = listItem && listItem.selected; this.handlePointerDownUp_(e); @@ -1422,7 +1419,7 @@ cr.define('cr.ui', function() { // // [1] For example, clicking non-focusable area gives focus on the first // form control in the item. - if (!containsFocusableElement(e.target, listItem) && + if (!containsFocusableElement(target, listItem) && listItem.contains(listItem.ownerDocument.activeElement)) { e.preventDefault(); } @@ -1473,6 +1470,7 @@ cr.define('cr.ui', function() { } // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return { List: List, Size: Size, diff --git a/chromium/ui/webui/resources/js/cr/ui/list_item.js b/chromium/ui/webui/resources/js/cr/ui/list_item.js index a2c1ba8f1d9..71164ca173a 100644 --- a/chromium/ui/webui/resources/js/cr/ui/list_item.js +++ b/chromium/ui/webui/resources/js/cr/ui/list_item.js @@ -90,5 +90,6 @@ cr.define('cr.ui', function() { ListItem.prototype, 'listIndex', cr.getPropertyDescriptor('listIndex')); // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return {ListItem: ListItem}; }); diff --git a/chromium/ui/webui/resources/js/cr/ui/list_selection_controller.js b/chromium/ui/webui/resources/js/cr/ui/list_selection_controller.js index 0692f919594..f6ed0f99bfe 100644 --- a/chromium/ui/webui/resources/js/cr/ui/list_selection_controller.js +++ b/chromium/ui/webui/resources/js/cr/ui/list_selection_controller.js @@ -308,5 +308,6 @@ cr.define('cr.ui', function() { }; // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return {ListSelectionController: ListSelectionController}; }); diff --git a/chromium/ui/webui/resources/js/cr/ui/list_selection_model.js b/chromium/ui/webui/resources/js/cr/ui/list_selection_model.js index bd49f601684..f3774d6e678 100644 --- a/chromium/ui/webui/resources/js/cr/ui/list_selection_model.js +++ b/chromium/ui/webui/resources/js/cr/ui/list_selection_model.js @@ -397,5 +397,6 @@ cr.define('cr.ui', function() { } // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return {ListSelectionModel: ListSelectionModel}; }); diff --git a/chromium/ui/webui/resources/js/cr/ui/menu.js b/chromium/ui/webui/resources/js/cr/ui/menu.js index 1f4fe262370..e45910eb444 100644 --- a/chromium/ui/webui/resources/js/cr/ui/menu.js +++ b/chromium/ui/webui/resources/js/cr/ui/menu.js @@ -400,5 +400,6 @@ cr.define('cr.ui', function() { // Export // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return {Menu: Menu}; }); diff --git a/chromium/ui/webui/resources/js/cr/ui/menu_button.js b/chromium/ui/webui/resources/js/cr/ui/menu_button.js index 3b9d998d110..0cfd92b6fb0 100644 --- a/chromium/ui/webui/resources/js/cr/ui/menu_button.js +++ b/chromium/ui/webui/resources/js/cr/ui/menu_button.js @@ -351,6 +351,7 @@ cr.define('cr.ui', function() { // Export // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return { HideType: HideType, MenuButton: MenuButton, diff --git a/chromium/ui/webui/resources/js/cr/ui/overlay.js b/chromium/ui/webui/resources/js/cr/ui/overlay.js deleted file mode 100644 index 4790f5b4461..00000000000 --- a/chromium/ui/webui/resources/js/cr/ui/overlay.js +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) 2012 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. - -/** - * @fileoverview Provides dialog-like behaviors for the tracing UI. - */ -cr.define('cr.ui.overlay', function() { - /** - * Gets the top, visible overlay. It makes the assumption that if multiple - * overlays are visible, the last in the byte order is topmost. - * TODO(estade): rely on aria-visibility instead? - * @return {HTMLElement} The overlay. - */ - function getTopOverlay() { - const overlays = /** @type !NodeList<!HTMLElement> */ ( - document.querySelectorAll('.overlay:not([hidden])')); - return overlays[overlays.length - 1]; - } - - /** - * Returns a visible default button of the overlay, if it has one. If the - * overlay has more than one, the first one will be returned. - * - * @param {HTMLElement} overlay The .overlay. - * @return {HTMLElement} The default button. - */ - function getDefaultButton(overlay) { - function isHidden(node) { - return node.hidden; - } - const defaultButtons = /** @type !NodeList<!HTMLElement> */ ( - overlay.querySelectorAll('.page .button-strip > .default-button')); - for (let i = 0; i < defaultButtons.length; i++) { - if (!findAncestor(defaultButtons[i], isHidden)) { - return defaultButtons[i]; - } - } - return null; - } - - /** @type {boolean} */ - let globallyInitialized = false; - - /** - * Makes initializations which must hook at the document level. - */ - function globalInitialization() { - if (!globallyInitialized) { - document.addEventListener('keydown', function(e) { - const overlay = getTopOverlay(); - if (!overlay) { - return; - } - - // Close the overlay on escape. - if (e.key === 'Escape') { - cr.dispatchSimpleEvent(overlay, 'cancelOverlay'); - } - - // Execute the overlay's default button on enter, unless focus is on an - // element that has standard behavior for the enter key. - const forbiddenTagNames = /^(A|BUTTON|SELECT|TEXTAREA)$/; - if (e.key === 'Enter' && - !forbiddenTagNames.test(document.activeElement.tagName)) { - const button = getDefaultButton(overlay); - if (button) { - button.click(); - // Executing the default button may result in focus moving to a - // different button. Calling preventDefault is necessary to not have - // that button execute as well. - e.preventDefault(); - } - } - }); - - window.addEventListener('resize', setMaxHeightAllPages); - globallyInitialized = true; - } - - setMaxHeightAllPages(); - } - - /** - * Sets the max-height of all pages in all overlays, based on the window - * height. - */ - function setMaxHeightAllPages() { - const pages = - document.querySelectorAll('.overlay .page:not(.not-resizable)'); - - const maxHeight = Math.min(0.9 * window.innerHeight, 640) + 'px'; - for (let i = 0; i < pages.length; i++) { - pages[i].style.maxHeight = maxHeight; - } - } - - /** - * Adds behavioral hooks for the given overlay. - * @param {HTMLElement} overlay The .overlay. - * - * TODO(crbug.com/425829): This function makes use of deprecated getter or - * setter functions. - * @suppress {deprecated} - */ - function setupOverlay(overlay) { - // Close the overlay on clicking any of the pages' close buttons. - const closeButtons = overlay.querySelectorAll('.page > .close-button'); - for (let i = 0; i < closeButtons.length; i++) { - closeButtons[i].addEventListener('click', function(e) { - if (cr.ui.FocusOutlineManager) { - cr.ui.FocusOutlineManager.forDocument(document).updateVisibility(); - } - cr.dispatchSimpleEvent(overlay, 'cancelOverlay'); - }); - } - - // TODO(crbug.com/425829): Remove above suppression once we no longer use - // deprecated functions defineSetter, and defineGetter. - // Remove the 'pulse' animation any time the overlay is hidden or shown. - // eslint-disable-next-line no-restricted-properties - overlay.__defineSetter__('hidden', function(value) { - this.classList.remove('pulse'); - if (value) { - this.setAttribute('hidden', true); - } else { - this.removeAttribute('hidden'); - } - }); - // eslint-disable-next-line no-restricted-properties - overlay.__defineGetter__('hidden', function() { - return this.hasAttribute('hidden'); - }); - - // Shake when the user clicks away. - overlay.addEventListener('click', function(e) { - // Only pulse if the overlay was the target of the click. - if (this !== e.target) { - return; - } - - // This may be null while the overlay is closing. - const overlayPage = this.querySelector('.page:not([hidden])'); - if (overlayPage) { - overlayPage.classList.add('pulse'); - } - }); - overlay.addEventListener('animationend', function(e) { - e.target.classList.remove('pulse'); - }); - } - - return { - getDefaultButton: getDefaultButton, - globalInitialization: globalInitialization, - setupOverlay: setupOverlay, - }; -}); diff --git a/chromium/ui/webui/resources/js/cr/ui/position_util.js b/chromium/ui/webui/resources/js/cr/ui/position_util.js index 40b59f7c1f9..8357b57d1ce 100644 --- a/chromium/ui/webui/resources/js/cr/ui/position_util.js +++ b/chromium/ui/webui/resources/js/cr/ui/position_util.js @@ -239,6 +239,7 @@ cr.define('cr.ui', function() { // Export // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return { AnchorType: AnchorType, positionPopupAroundElement: positionPopupAroundElement, diff --git a/chromium/ui/webui/resources/js/cr/ui/splitter.js b/chromium/ui/webui/resources/js/cr/ui/splitter.js index 0c214cf4fa9..93941da675d 100644 --- a/chromium/ui/webui/resources/js/cr/ui/splitter.js +++ b/chromium/ui/webui/resources/js/cr/ui/splitter.js @@ -278,5 +278,6 @@ cr.define('cr.ui', function() { }; // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return {Splitter: Splitter}; }); diff --git a/chromium/ui/webui/resources/js/cr/ui/store.js b/chromium/ui/webui/resources/js/cr/ui/store.js index c1d12c80505..d7d735ab7aa 100644 --- a/chromium/ui/webui/resources/js/cr/ui/store.js +++ b/chromium/ui/webui/resources/js/cr/ui/store.js @@ -159,6 +159,7 @@ cr.define('cr.ui', function() { } // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return { Action: Action, DeferredAction: DeferredAction, diff --git a/chromium/ui/webui/resources/js/cr/ui/store_client.js b/chromium/ui/webui/resources/js/cr/ui/store_client.js index 519efbacbb4..e2ba2efaadd 100644 --- a/chromium/ui/webui/resources/js/cr/ui/store_client.js +++ b/chromium/ui/webui/resources/js/cr/ui/store_client.js @@ -135,6 +135,7 @@ cr.define('cr.ui', function() { }; // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return { StoreClient: StoreClient, }; diff --git a/chromium/ui/webui/resources/js/cr/ui/tabs.js b/chromium/ui/webui/resources/js/cr/ui/tabs.js index 45d51ce3985..522ec843696 100644 --- a/chromium/ui/webui/resources/js/cr/ui/tabs.js +++ b/chromium/ui/webui/resources/js/cr/ui/tabs.js @@ -246,6 +246,7 @@ cr.define('cr.ui', function() { cr.getPropertyDescriptor('selected', cr.PropertyKind.BOOL_ATTR)); // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return { TabBox: TabBox, Tabs: Tabs, diff --git a/chromium/ui/webui/resources/js/cr/ui/touch_handler.js b/chromium/ui/webui/resources/js/cr/ui/touch_handler.js deleted file mode 100644 index d7135393662..00000000000 --- a/chromium/ui/webui/resources/js/cr/ui/touch_handler.js +++ /dev/null @@ -1,884 +0,0 @@ -// Copyright (c) 2012 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. - -/** - * @fileoverview Touch Handler. Class that handles all touch events and - * uses them to interpret higher level gestures and behaviors. TouchEvent is a - * built in mobile safari type: - * http://developer.apple.com/safari/library/documentation/UserExperience/Reference/TouchEventClassReference/TouchEvent/TouchEvent.html. - * This class is intended to work with all webkit browsers, tested on Chrome and - * iOS. - * - * The following types of gestures are currently supported. See the definition - * of TouchHandler.EventType for details. - * - * Single Touch: - * This provides simple single-touch events. Any secondary touch is - * ignored. - * - * Drag: - * A single touch followed by some movement. This behavior will handle all - * of the required events and report the properties of the drag to you - * while the touch is happening and at the end of the drag sequence. This - * behavior will NOT perform the actual dragging (redrawing the element) - * for you, this responsibility is left to the client code. - * - * Long press: - * When your element is touched and held without any drag occuring, the - * LONG_PRESS event will fire. - */ - -// Use an anonymous function to enable strict mode just for this file (which -// will be concatenated with other files when embedded in Chrome) -cr.define('cr.ui', function() { - 'use strict'; - - /** - * A TouchHandler attaches to an Element, listents for low-level touch (or - * mouse) events and dispatching higher-level events on the element. - * @param {!Element} element The element to listen on and fire events - * for. - * @constructor - */ - function TouchHandler(element) { - /** - * @type {!Element} - * @private - */ - this.element_ = element; - - /** - * The absolute sum of all touch y deltas. - * @type {number} - * @private - */ - this.totalMoveY_ = 0; - - /** - * The absolute sum of all touch x deltas. - * @type {number} - * @private - */ - this.totalMoveX_ = 0; - - /** - * An array of tuples where the first item is the horizontal component of a - * recent relevant touch and the second item is the touch's time stamp. Old - * touches are removed based on the max tracking time and when direction - * changes. - * @type {!Array<number>} - * @private - */ - this.recentTouchesX_ = []; - - /** - * An array of tuples where the first item is the vertical component of a - * recent relevant touch and the second item is the touch's time stamp. Old - * touches are removed based on the max tracking time and when direction - * changes. - * @type {!Array<number>} - * @private - */ - this.recentTouchesY_ = []; - - /** - * Used to keep track of all events we subscribe to so we can easily clean - * up - * @type {EventTracker} - * @private - */ - this.events_ = new EventTracker(); - } - - - /** - * DOM Events that may be fired by the TouchHandler at the element - */ - TouchHandler.EventType = { - // Fired whenever the element is touched as the only touch to the device. - // enableDrag defaults to false, set to true to permit dragging. - TOUCH_START: 'touchHandler:touch_start', - - // Fired when an element is held for a period of time. Prevents dragging - // from occuring (even if enableDrag was set to true). - LONG_PRESS: 'touchHandler:long_press', - - // If enableDrag was set to true at TOUCH_START, DRAG_START will fire when - // the touch first moves sufficient distance. enableDrag is set to true but - // can be reset to false to cancel the drag. - DRAG_START: 'touchHandler:drag_start', - - // If enableDrag was true after DRAG_START, DRAG_MOVE will fire whenever the - // touch is moved. - DRAG_MOVE: 'touchHandler:drag_move', - - // Fired just before TOUCH_END when a drag is released. Correlates 1:1 with - // a DRAG_START. - DRAG_END: 'touchHandler:drag_end', - - // Fired whenever a touch that is being tracked has been released. - // Correlates 1:1 with a TOUCH_START. - TOUCH_END: 'touchHandler:touch_end', - - // Fired whenever the element is tapped in a short time and no dragging is - // detected. - TAP: 'touchHandler:tap' - }; - - - /** - * The type of event sent by TouchHandler - * @constructor - * @extends {Event} - * @param {string} type The type of event (one of cr.ui.Grabber.EventType). - * @param {boolean} bubbles Whether or not the event should bubble. - * @param {number} clientX The X location of the touch. - * @param {number} clientY The Y location of the touch. - * @param {!Element} touchedElement The element at the current location of the - * touch. - */ - TouchHandler.Event = function( - type, bubbles, clientX, clientY, touchedElement) { - const event = document.createEvent('Event'); - event.initEvent(type, bubbles, true); - event.__proto__ = TouchHandler.Event.prototype; - - /** - * The X location of the touch affected - * @type {number} - */ - event.clientX = clientX; - - /** - * The Y location of the touch affected - * @type {number} - */ - event.clientY = clientY; - - /** - * The element at the current location of the touch. - * @type {!Element} - */ - event.touchedElement = touchedElement; - - return event; - }; - - TouchHandler.Event.prototype = { - __proto__: Event.prototype, - - /** - * For TOUCH_START and DRAG START events, set to true to enable dragging or - * false to disable dragging. - * @type {boolean|undefined} - */ - enableDrag: undefined, - - /** - * For DRAG events, provides the horizontal component of the - * drag delta. Drag delta is defined as the delta of the start touch - * position and the current drag position. - * @type {number|undefined} - */ - dragDeltaX: undefined, - - /** - * For DRAG events, provides the vertical component of the - * drag delta. - * @type {number|undefined} - */ - dragDeltaY: undefined - }; - - /** - * Maximum movement of touch required to be considered a tap. - * @type {number} - * @private - */ - TouchHandler.MAX_TRACKING_FOR_TAP_ = 8; - - /** - * The maximum number of ms to track a touch event. After an event is older - * than this value, it will be ignored in velocity calculations. - * @type {number} - * @private - */ - TouchHandler.MAX_TRACKING_TIME_ = 250; - - /** - * The maximum number of touches to track. - * @type {number} - * @private - */ - TouchHandler.MAX_TRACKING_TOUCHES_ = 5; - - /** - * The maximum velocity to return, in pixels per millisecond, that is used - * to guard against errors in calculating end velocity of a drag. This is a - * very fast drag velocity. - * @type {number} - * @private - */ - TouchHandler.MAXIMUM_VELOCITY_ = 5; - - /** - * The velocity to return, in pixel per millisecond, when the time stamps on - * the events are erroneous. The browser can return bad time stamps if the - * thread is blocked for the duration of the drag. This is a low velocity to - * prevent the content from moving quickly after a slow drag. It is less - * jarring if the content moves slowly after a fast drag. - * @type {number} - * @private - */ - TouchHandler.VELOCITY_FOR_INCORRECT_EVENTS_ = 1; - - /** - * The time, in milliseconds, that a touch must be held to be considered - * 'long'. - * @type {number} - * @private - */ - TouchHandler.TIME_FOR_LONG_PRESS_ = 500; - - TouchHandler.prototype = { - /** - * If defined, the identifer of the single touch that is active. Note that - * 0 is a valid touch identifier - it should not be treated equivalently to - * undefined. - * @type {number|undefined} - * @private - */ - activeTouch_: undefined, - - /** - * @type {boolean|undefined} - * @private - */ - tracking_: undefined, - - /** - * @type {number|undefined} - * @private - */ - startTouchX_: undefined, - - /** - * @type {number|undefined} - * @private - */ - startTouchY_: undefined, - - /** - * @type {number|undefined} - * @private - */ - endTouchX_: undefined, - - /** - * @type {number|undefined} - * @private - */ - endTouchY_: undefined, - - /** - * Time of the touchstart event. - * @type {number|undefined} - * @private - */ - startTime_: undefined, - - /** - * The time of the touchend event. - * @type {number|undefined} - * @private - */ - endTime_: undefined, - - /** - * @type {number|undefined} - * @private - */ - lastTouchX_: undefined, - - /** - * @type {number|undefined} - * @private - */ - lastTouchY_: undefined, - - /** - * @type {number|undefined} - * @private - */ - lastMoveX_: undefined, - - /** - * @type {number|undefined} - * @private - */ - lastMoveY_: undefined, - - /** - * @type {number|undefined} - * @private - */ - longPressTimeout_: undefined, - - /** - * If defined and true, the next click event should be swallowed - * @type {boolean|undefined} - * @private - */ - swallowNextClick_: undefined, - - /** - * @type {boolean} - * @private - */ - draggingEnabled_: false, - - /** - * Start listenting for events. - * @param {boolean=} opt_capture True if the TouchHandler should listen to - * during the capture phase. - * @param {boolean=} opt_mouse True if the TouchHandler should generate - * events for mouse input (in addition to touch input). - */ - enable(opt_capture, opt_mouse) { - const capture = !!opt_capture; - - // Just listen to start events for now. When a touch is occuring we'll - // want to be subscribed to move and end events on the document, but we - // don't want to incur the cost of lots of no-op handlers on the document. - this.events_.add( - this.element_, 'touchstart', this.onStart_.bind(this), capture); - if (opt_mouse) { - this.events_.add( - this.element_, 'mousedown', - this.mouseToTouchCallback_(this.onStart_.bind(this)), capture); - } - - // If the element is long-pressed, we may need to swallow a click - this.events_.add(this.element_, 'click', this.onClick_.bind(this), true); - }, - - /** - * Stop listening to all events. - */ - disable() { - this.stopTouching_(); - this.events_.removeAll(); - }, - - /** - * Wraps a callback with translations of mouse events to touch events. - * NOTE: These types really should be function(Event) but then we couldn't - * use this with bind (which operates on any type of function). Doesn't - * JSDoc support some sort of polymorphic types? - * @param {Function} callback The event callback. - * @return {Function} The wrapping callback. - * @private - */ - mouseToTouchCallback_(callback) { - return function(e) { - // Note that there may be synthesizes mouse events caused by touch - // events (a mouseDown after a touch-click). We leave it up to the - // client to worry about this if it matters to them (typically a short - // mouseDown/mouseUp without a click is no big problem and it's not - // obvious how we identify such synthesized events in a general way). - const touch = { - // any fixed value will do for the identifier - there will only - // ever be a single active 'touch' when using the mouse. - identifier: 0, - clientX: e.clientX, - clientY: e.clientY, - target: e.target - }; - e.touches = []; - e.targetTouches = []; - e.changedTouches = [touch]; - if (e.type !== 'mouseup') { - e.touches[0] = touch; - e.targetTouches[0] = touch; - } - callback(e); - }; - }, - - /** - * Begin tracking the touchable element, it is eligible for dragging. - * @private - */ - beginTracking_() { - this.tracking_ = true; - }, - - /** - * Stop tracking the touchable element, it is no longer dragging. - * @private - */ - endTracking_() { - this.tracking_ = false; - this.dragging_ = false; - this.totalMoveY_ = 0; - this.totalMoveX_ = 0; - }, - - /** - * Reset the touchable element as if we never saw the touchStart - * Doesn't dispatch any end events - be careful of existing listeners. - */ - cancelTouch() { - this.stopTouching_(); - this.endTracking_(); - // If clients needed to be aware of this, we could fire a cancel event - // here. - }, - - /** - * Record that touching has stopped - * @private - */ - stopTouching_() { - // Mark as no longer being touched - this.activeTouch_ = undefined; - - // If we're waiting for a long press, stop - window.clearTimeout(this.longPressTimeout_); - - // Stop listening for move/end events until there's another touch. - // We don't want to leave handlers piled up on the document. - // Note that there's no harm in removing handlers that weren't added, so - // rather than track whether we're using mouse or touch we do both. - this.events_.remove(document, 'touchmove'); - this.events_.remove(document, 'touchend'); - this.events_.remove(document, 'touchcancel'); - this.events_.remove(document, 'mousemove'); - this.events_.remove(document, 'mouseup'); - }, - - /** - * Touch start handler. - * @param {!TouchEvent} e The touchstart event. - * @private - */ - onStart_(e) { - // Only process single touches. If there is already a touch happening, or - // two simultaneous touches then just ignore them. - if (e.touches.length > 1) { - // Note that we could cancel an active touch here. That would make - // simultaneous touch behave similar to near-simultaneous. However, if - // the user is dragging something, an accidental second touch could be - // quite disruptive if it cancelled their drag. Better to just ignore - // it. - return; - } - - // It's still possible there could be an active "touch" if the user is - // simultaneously using a mouse and a touch input. - if (this.activeTouch_ !== undefined) { - return; - } - - const touch = e.targetTouches[0]; - this.activeTouch_ = touch.identifier; - - // We've just started touching so shouldn't swallow any upcoming click - if (this.swallowNextClick_) { - this.swallowNextClick_ = false; - } - - this.disableTap_ = false; - - // Sign up for end/cancel notifications for this touch. - // Note that we do this on the document so that even if the user drags - // their finger off the element, we'll still know what they're doing. - if (e.type === 'mousedown') { - this.events_.add( - document, 'mouseup', - this.mouseToTouchCallback_(this.onEnd_.bind(this)), false); - } else { - this.events_.add(document, 'touchend', this.onEnd_.bind(this), false); - this.events_.add( - document, 'touchcancel', this.onEnd_.bind(this), false); - } - - // This timeout is cleared on touchEnd and onDrag - // If we invoke the function then we have a real long press - window.clearTimeout(this.longPressTimeout_); - this.longPressTimeout_ = window.setTimeout( - this.onLongPress_.bind(this), TouchHandler.TIME_FOR_LONG_PRESS_); - - // Dispatch the TOUCH_START event - this.draggingEnabled_ = - !!this.dispatchEvent_(TouchHandler.EventType.TOUCH_START, touch); - - // We want dragging notifications - if (e.type === 'mousedown') { - this.events_.add( - document, 'mousemove', - this.mouseToTouchCallback_(this.onMove_.bind(this)), false); - } else { - this.events_.add(document, 'touchmove', this.onMove_.bind(this), false); - } - - this.startTouchX_ = this.lastTouchX_ = touch.clientX; - this.startTouchY_ = this.lastTouchY_ = touch.clientY; - this.startTime_ = e.timeStamp; - - this.recentTouchesX_ = []; - this.recentTouchesY_ = []; - this.recentTouchesX_.push(touch.clientX, e.timeStamp); - this.recentTouchesY_.push(touch.clientY, e.timeStamp); - - this.beginTracking_(); - }, - - /** - * Given a list of Touches, find the one matching our activeTouch - * identifier. Note that Chrome currently always uses 0 as the identifier. - * In that case we'll end up always choosing the first element in the list. - * @param {TouchList} touches The list of Touch objects to search. - * @return {!Touch|undefined} The touch matching our active ID if any. - * @private - */ - findActiveTouch_(touches) { - assert(this.activeTouch_ !== undefined, 'Expecting an active touch'); - // A TouchList isn't actually an array, so we shouldn't use - // Array.prototype.filter/some, etc. - for (let i = 0; i < touches.length; i++) { - if (touches[i].identifier === this.activeTouch_) { - return touches[i]; - } - } - return undefined; - }, - - /** - * Touch move handler. - * @param {!TouchEvent} e The touchmove event. - * @private - */ - onMove_(e) { - if (!this.tracking_) { - return; - } - - // Our active touch should always be in the list of touches still active - assert(this.findActiveTouch_(e.touches), 'Missing touchEnd'); - - const that = this; - const touch = this.findActiveTouch_(e.changedTouches); - if (!touch) { - return; - } - - const clientX = touch.clientX; - const clientY = touch.clientY; - - const moveX = this.lastTouchX_ - clientX; - const moveY = this.lastTouchY_ - clientY; - this.totalMoveX_ += Math.abs(moveX); - this.totalMoveY_ += Math.abs(moveY); - this.lastTouchX_ = clientX; - this.lastTouchY_ = clientY; - - const couldBeTap = - this.totalMoveY_ <= TouchHandler.MAX_TRACKING_FOR_TAP_ || - this.totalMoveX_ <= TouchHandler.MAX_TRACKING_FOR_TAP_; - - if (!couldBeTap) { - this.disableTap_ = true; - } - - if (this.draggingEnabled_ && !this.dragging_ && !couldBeTap) { - // If we're waiting for a long press, stop - window.clearTimeout(this.longPressTimeout_); - - // Dispatch the DRAG_START event and record whether dragging should be - // allowed or not. Note that this relies on the current value of - // startTouchX/Y - handlers may use the initial drag delta to determine - // if dragging should be permitted. - this.dragging_ = - this.dispatchEvent_(TouchHandler.EventType.DRAG_START, touch); - - if (this.dragging_) { - // Update the start position here so that drag deltas have better - // values but don't touch the recent positions so that velocity - // calculations can still use touchstart position in the time and - // distance delta. - this.startTouchX_ = clientX; - this.startTouchY_ = clientY; - this.startTime_ = e.timeStamp; - } else { - this.endTracking_(); - } - } - - if (this.dragging_) { - this.dispatchEvent_(TouchHandler.EventType.DRAG_MOVE, touch); - - this.removeTouchesInWrongDirection_( - this.recentTouchesX_, this.lastMoveX_, moveX); - this.removeTouchesInWrongDirection_( - this.recentTouchesY_, this.lastMoveY_, moveY); - this.removeOldTouches_(this.recentTouchesX_, e.timeStamp); - this.removeOldTouches_(this.recentTouchesY_, e.timeStamp); - this.recentTouchesX_.push(clientX, e.timeStamp); - this.recentTouchesY_.push(clientY, e.timeStamp); - } - - this.lastMoveX_ = moveX; - this.lastMoveY_ = moveY; - }, - - /** - * Filters the provided recent touches array to remove all touches except - * the last if the move direction has changed. - * @param {!Array<number>} recentTouches An array of tuples where the first - * item is the x or y component of the recent touch and the second item - * is the touch time stamp. - * @param {number|undefined} lastMove The x or y component of the previous - * move. - * @param {number} recentMove The x or y component of the most recent move. - * @private - */ - removeTouchesInWrongDirection_(recentTouches, lastMove, recentMove) { - if (lastMove && recentMove && recentTouches.length > 2 && - (lastMove > 0 ^ recentMove > 0)) { - recentTouches.splice(0, recentTouches.length - 2); - } - }, - - /** - * Filters the provided recent touches array to remove all touches older - * than the max tracking time or the 5th most recent touch. - * @param {!Array<number>} recentTouches An array of tuples where the first - * item is the x or y component of the recent touch and the second item - * is the touch time stamp. - * @param {number} recentTime The time of the most recent event. - * @private - */ - removeOldTouches_(recentTouches, recentTime) { - while (recentTouches.length && - recentTime - recentTouches[1] > - TouchHandler.MAX_TRACKING_TIME_ || - recentTouches.length > TouchHandler.MAX_TRACKING_TOUCHES_ * 2) { - recentTouches.splice(0, 2); - } - }, - - /** - * Touch end handler. - * @param {!TouchEvent} e The touchend event. - * @private - */ - onEnd_(e) { - const that = this; - assert(this.activeTouch_ !== undefined, 'Expect to already be touching'); - - // If the touch we're tracking isn't changing here, ignore this touch end. - const touch = this.findActiveTouch_(e.changedTouches); - if (!touch) { - // In most cases, our active touch will be in the 'touches' collection, - // but we can't assert that because occasionally two touchend events can - // occur at almost the same time with both having empty 'touches' lists. - // I.e., 'touches' seems like it can be a bit more up to date than the - // current event. - return; - } - - // This is touchEnd for the touch we're monitoring - assert( - !this.findActiveTouch_(e.touches), 'Touch ended also still active'); - - // Indicate that touching has finished - this.stopTouching_(); - - if (this.tracking_) { - const clientX = touch.clientX; - const clientY = touch.clientY; - - if (this.dragging_) { - this.endTime_ = e.timeStamp; - this.endTouchX_ = clientX; - this.endTouchY_ = clientY; - - this.removeOldTouches_(this.recentTouchesX_, e.timeStamp); - this.removeOldTouches_(this.recentTouchesY_, e.timeStamp); - - this.dispatchEvent_(TouchHandler.EventType.DRAG_END, touch); - - // Note that in some situations we can get a click event here as well. - // For now this isn't a problem, but we may want to consider having - // some logic that hides clicks that appear to be caused by a touchEnd - // used for dragging. - } - - this.endTracking_(); - } - this.draggingEnabled_ = false; - - // Note that we dispatch the touchEnd event last so that events at - // different levels of semantics nest nicely (similar to how DOM - // drag-and-drop events are nested inside of the mouse events that trigger - // them). - this.dispatchEvent_(TouchHandler.EventType.TOUCH_END, touch); - if (!this.disableTap_) { - this.dispatchEvent_(TouchHandler.EventType.TAP, touch); - } - }, - - /** - * Get end velocity of the drag. This method is specific to drag behavior, - * so if touch behavior and drag behavior is split then this should go with - * drag behavior. End velocity is defined as deltaXY / deltaTime where - * deltaXY is the difference between endPosition and the oldest recent - * position, and deltaTime is the difference between endTime and the oldest - * recent time stamp. - * @return {Object} The x and y velocity. - */ - getEndVelocity() { - // Note that we could move velocity to just be an end-event parameter. - let velocityX = this.recentTouchesX_.length ? - (this.endTouchX_ - this.recentTouchesX_[0]) / - (this.endTime_ - this.recentTouchesX_[1]) : - 0; - let velocityY = this.recentTouchesY_.length ? - (this.endTouchY_ - this.recentTouchesY_[0]) / - (this.endTime_ - this.recentTouchesY_[1]) : - 0; - - velocityX = this.correctVelocity_(velocityX); - velocityY = this.correctVelocity_(velocityY); - - return {x: velocityX, y: velocityY}; - }, - - /** - * Correct erroneous velocities by capping the velocity if we think it's too - * high, or setting it to a default velocity if know that the event data is - * bad. - * @param {number} velocity The x or y velocity component. - * @return {number} The corrected velocity. - * @private - */ - correctVelocity_(velocity) { - let absVelocity = Math.abs(velocity); - - // We add to recent touches for each touchstart and touchmove. If we have - // fewer than 3 touches (6 entries), we assume that the thread was blocked - // for the duration of the drag and we received events in quick succession - // with the wrong time stamps. - if (absVelocity > TouchHandler.MAXIMUM_VELOCITY_) { - absVelocity = this.recentTouchesY_.length < 3 ? - TouchHandler.VELOCITY_FOR_INCORRECT_EVENTS_ : - TouchHandler.MAXIMUM_VELOCITY_; - } - return absVelocity * (velocity < 0 ? -1 : 1); - }, - - /** - * Handler when an element has been pressed for a long time - * @private - */ - onLongPress_() { - // Swallow any click that occurs on this element without an intervening - // touch start event. This simple click-busting technique should be - // sufficient here since a real click should have a touchstart first. - this.swallowNextClick_ = true; - this.disableTap_ = true; - - // Dispatch to the LONG_PRESS - assert(typeof this.startTouchX_ === 'number'); - assert(typeof this.startTouchY_ === 'number'); - this.dispatchEventXY_( - TouchHandler.EventType.LONG_PRESS, this.element_, - /** @type {number} */ (this.startTouchX_), - /** @type {number} */ (this.startTouchY_)); - }, - - /** - * Click handler - used to swallow clicks after a long-press - * @param {!Event} e The click event. - * @private - */ - onClick_(e) { - if (this.swallowNextClick_) { - e.preventDefault(); - e.stopPropagation(); - this.swallowNextClick_ = false; - } - }, - - /** - * Dispatch a TouchHandler event to the element - * @param {string} eventType The event to dispatch. - * @param {Touch} touch The touch triggering this event. - * @return {boolean|undefined} The value of enableDrag after dispatching - * the event. - * @private - */ - dispatchEvent_(eventType, touch) { - // Determine which element was touched. For mouse events, this is always - // the event/touch target. But for touch events, the target is always the - // target of the touchstart (and it's unlikely we can change this - // since the common implementation of touch dragging relies on it). Since - // touch is our primary scenario (which we want to emulate with mouse), - // we'll treat both cases the same and not depend on the target. - /** @type {Element} */ - let touchedElement; - if (eventType === TouchHandler.EventType.TOUCH_START) { - touchedElement = assertInstanceof(touch.target, Element); - } else { - touchedElement = assert(this.element_.ownerDocument.elementFromPoint( - touch.clientX, touch.clientY)); - } - - return this.dispatchEventXY_( - eventType, touchedElement, touch.clientX, touch.clientY); - }, - - /** - * Dispatch a TouchHandler event to the element - * @param {string} eventType The event to dispatch. - * @param {!Element} touchedElement - * @param {number} clientX The X location for the event. - * @param {number} clientY The Y location for the event. - * @return {boolean|undefined} The value of enableDrag after dispatching - * the event. - * @private - */ - dispatchEventXY_(eventType, touchedElement, clientX, clientY) { - const isDrag = - (eventType === TouchHandler.EventType.DRAG_START || - eventType === TouchHandler.EventType.DRAG_MOVE || - eventType === TouchHandler.EventType.DRAG_END); - - // Drag events don't bubble - we're really just dragging the element, - // not affecting its parent at all. - const bubbles = !isDrag; - - const event = new TouchHandler.Event( - eventType, bubbles, clientX, clientY, touchedElement); - - // Set enableDrag when it can be overridden - if (eventType === TouchHandler.EventType.TOUCH_START) { - event.enableDrag = false; - } else if (eventType === TouchHandler.EventType.DRAG_START) { - event.enableDrag = true; - } - - if (isDrag) { - event.dragDeltaX = clientX - this.startTouchX_; - event.dragDeltaY = clientY - this.startTouchY_; - } - - this.element_.dispatchEvent(event); - return event.enableDrag; - } - }; - - return {TouchHandler: TouchHandler}; -}); diff --git a/chromium/ui/webui/resources/js/cr/ui/tree.js b/chromium/ui/webui/resources/js/cr/ui/tree.js index 3ce3a3c79e8..94a78f1d122 100644 --- a/chromium/ui/webui/resources/js/cr/ui/tree.js +++ b/chromium/ui/webui/resources/js/cr/ui/tree.js @@ -783,5 +783,6 @@ cr.define('cr.ui', function() { // Export // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return {Tree: Tree, TreeItem: TreeItem}; }); diff --git a/chromium/ui/webui/resources/js/event_tracker.js b/chromium/ui/webui/resources/js/event_tracker.js index bad9b7f73d1..21fe8f72a22 100644 --- a/chromium/ui/webui/resources/js/event_tracker.js +++ b/chromium/ui/webui/resources/js/event_tracker.js @@ -89,3 +89,5 @@ * capture: boolean}} */ EventTracker.Entry; + +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/js/i18n_behavior.js b/chromium/ui/webui/resources/js/i18n_behavior.js index 022702fa77b..01acdcdba65 100644 --- a/chromium/ui/webui/resources/js/i18n_behavior.js +++ b/chromium/ui/webui/resources/js/i18n_behavior.js @@ -143,3 +143,5 @@ * }} */ I18nBehavior.Proto; + +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/js/icon.js b/chromium/ui/webui/resources/js/icon.js index 8376d8c7141..d0af7fd3c0d 100644 --- a/chromium/ui/webui/resources/js/icon.js +++ b/chromium/ui/webui/resources/js/icon.js @@ -154,6 +154,7 @@ cr.define('cr.icon', function() { } // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return { getFavicon: getFavicon, getFaviconForPageURL: getFaviconForPageURL, diff --git a/chromium/ui/webui/resources/js/list_property_update_behavior.js b/chromium/ui/webui/resources/js/list_property_update_behavior.js index 6812f5419cd..5a9f75a2abd 100644 --- a/chromium/ui/webui/resources/js/list_property_update_behavior.js +++ b/chromium/ui/webui/resources/js/list_property_update_behavior.js @@ -21,44 +21,62 @@ /* #export */ const ListPropertyUpdateBehavior = { /** * @param {string} propertyPath - * @param {function(!Object): string} itemUidGetter + * @param {function(!Object): (!Object|string)} identityGetter * @param {!Array<!Object>} updatedList - * @param {boolean} uidBasedUpdate + * @param {boolean=} identityBasedUpdate * @returns {boolean} True if notifySplices was called. */ - updateList(propertyPath, itemUidGetter, updatedList, uidBasedUpdate = false) { - const list = this.get(propertyPath); - const splices = Polymer.ArraySplice.calculateSplices( - updatedList.map(itemUidGetter), list.map(itemUidGetter)); + updateList( + propertyPath, identityGetter, updatedList, identityBasedUpdate = false) { + return updateListProperty( + this, propertyPath, identityGetter, updatedList, identityBasedUpdate); + }, +}; + +/** + * @param {Object} instance + * @param {string} propertyPath + * @param {function(!Object): (!Object|string)} identityGetter + * @param {!Array<!Object>} updatedList + * @param {boolean=} identityBasedUpdate + * @returns {boolean} True if notifySplices was called. + */ +/* #export */ function updateListProperty( + instance, propertyPath, identityGetter, updatedList, + identityBasedUpdate = false) { + const list = instance.get(propertyPath); + const splices = Polymer.ArraySplice.calculateSplices( + updatedList.map(identityGetter), list.map(identityGetter)); + + splices.forEach(splice => { + const index = splice.index; + const deleteCount = splice.removed.length; + // Transform splices to the expected format of notifySplices(). + // Convert !Array<string> to !Array<!Object>. + splice.removed = list.slice(index, index + deleteCount); + splice.object = list; + splice.type = 'splice'; - splices.forEach(splice => { - const index = splice.index; - const deleteCount = splice.removed.length; - // Transform splices to the expected format of notifySplices(). - // Convert !Array<string> to !Array<!Object>. - splice.removed = list.slice(index, index + deleteCount); - splice.object = list; - splice.type = 'splice'; + const added = updatedList.slice(index, index + splice.addedCount); + const spliceParams = [index, deleteCount].concat(added); + list.splice.apply(list, spliceParams); + }); - const added = updatedList.slice(index, index + splice.addedCount); - const spliceParams = [index, deleteCount].concat(added); - list.splice.apply(list, spliceParams); + let updated = splices.length > 0; + if (!identityBasedUpdate) { + list.forEach((item, index) => { + const updatedItem = updatedList[index]; + if (JSON.stringify(item) !== JSON.stringify(updatedItem)) { + instance.set([propertyPath, index], updatedItem); + updated = true; + } }); + } - let updated = splices.length > 0; - if (!uidBasedUpdate) { - list.forEach((item, index) => { - const updatedItem = updatedList[index]; - if (JSON.stringify(item) !== JSON.stringify(updatedItem)) { - this.set([propertyPath, index], updatedItem); - updated = true; - } - }); - } + if (splices.length > 0) { + instance.notifySplices(propertyPath, splices); + } + return updated; +} - if (splices.length > 0) { - this.notifySplices(propertyPath, splices); - } - return updated; - }, -}; +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/js/load_time_data.js b/chromium/ui/webui/resources/js/load_time_data.js index a4e3054b620..2935f76e1d7 100644 --- a/chromium/ui/webui/resources/js/load_time_data.js +++ b/chromium/ui/webui/resources/js/load_time_data.js @@ -243,3 +243,5 @@ function LoadTimeData(){} // local. window.loadTimeData = loadTimeData; })(); + +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/js/parse_html_subset.js b/chromium/ui/webui/resources/js/parse_html_subset.js index b5d25c37a42..95407fff946 100644 --- a/chromium/ui/webui/resources/js/parse_html_subset.js +++ b/chromium/ui/webui/resources/js/parse_html_subset.js @@ -84,14 +84,10 @@ * This policy maps a given string to a `TrustedHTML` object * without performing any validation. Callsites must ensure * that the resulting object will only be used in inert - * documents. + * documents. Initialized lazily. * @type {!TrustedTypePolicy} */ let unsanitizedPolicy; - if (window.trustedTypes) { - unsanitizedPolicy = trustedTypes.createPolicy( - 'parse-html-subset', {createHTML: untrustedHTML => untrustedHTML}); - } /** * @param {!Array<string>} optTags an Array to merge. @@ -154,6 +150,10 @@ r.selectNode(doc.body); if (window.trustedTypes) { + if (!unsanitizedPolicy) { + unsanitizedPolicy = trustedTypes.createPolicy( + 'parse-html-subset', {createHTML: untrustedHTML => untrustedHTML}); + } s = unsanitizedPolicy.createHTML(s); } @@ -181,3 +181,5 @@ return df; }; })(); + +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/js/plural_string_proxy.js b/chromium/ui/webui/resources/js/plural_string_proxy.js index 5d38a70d862..801a4149222 100644 --- a/chromium/ui/webui/resources/js/plural_string_proxy.js +++ b/chromium/ui/webui/resources/js/plural_string_proxy.js @@ -20,6 +20,32 @@ export class PluralStringProxy { * string for |messageName| with |itemCount| items. */ getPluralString(messageName, itemCount) {} + + /** + * Fetches both plural strings, concatenated to one string with a comma. + * @param {!string} messageName1 The name of the first message. + * @param {!number} itemCount1 The number of items in the first message. + * @param {!string} messageName2 The name of the second message. + * @param {!number} itemCount2 The number of items in the second message. + * @return {!Promise<string>} Promise resolved with the appropriate plural + * strings for both messages, concatenated with a comma+whitespace in + * between them. + */ + getPluralStringTupleWithComma( + messageName1, itemCount1, messageName2, itemCount2) {} + + /** + * Fetches both plural strings, concatenated to one string with periods. + * @param {!string} messageName1 The name of the first message. + * @param {!number} itemCount1 The number of items in the first message. + * @param {!string} messageName2 The name of the second message. + * @param {!number} itemCount2 The number of items in the second message. + * @return {!Promise<string>} Promise resolved with the appropriate plural + * strings for both messages, concatenated with a period+whitespace after + * the first message, and a period after the second message. + */ + getPluralStringTupleWithPeriods( + messageName1, itemCount1, messageName2, itemCount2) {} } /** @implements {PluralStringProxy} */ @@ -28,6 +54,22 @@ export class PluralStringProxyImpl { getPluralString(messageName, itemCount) { return sendWithPromise('getPluralString', messageName, itemCount); } + + /** @override */ + getPluralStringTupleWithComma( + messageName1, itemCount1, messageName2, itemCount2) { + return sendWithPromise( + 'getPluralStringTupleWithComma', messageName1, itemCount1, messageName2, + itemCount2); + } + + /** @override */ + getPluralStringTupleWithPeriods( + messageName1, itemCount1, messageName2, itemCount2) { + return sendWithPromise( + 'getPluralStringTupleWithPeriods', messageName1, itemCount1, + messageName2, itemCount2); + } } addSingletonGetter(PluralStringProxyImpl); diff --git a/chromium/ui/webui/resources/js/promise_resolver.js b/chromium/ui/webui/resources/js/promise_resolver.js index 20a88b42947..cd78115b6b1 100644 --- a/chromium/ui/webui/resources/js/promise_resolver.js +++ b/chromium/ui/webui/resources/js/promise_resolver.js @@ -80,3 +80,5 @@ assertNotReached(); } }; + +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/js/search_highlight_utils.js b/chromium/ui/webui/resources/js/search_highlight_utils.js index f76e24f1d9e..aca22d545df 100644 --- a/chromium/ui/webui/resources/js/search_highlight_utils.js +++ b/chromium/ui/webui/resources/js/search_highlight_utils.js @@ -169,6 +169,7 @@ cr.define('cr.search_highlight_utils', function() { } // #cr_define_end + console.warn('crbug/1173575, non-JS module files deprecated.'); return { Range, createEmptySearchBubble, diff --git a/chromium/ui/webui/resources/js/test_loader.js b/chromium/ui/webui/resources/js/test_loader.js index dd40a21410b..54e0dcb8652 100644 --- a/chromium/ui/webui/resources/js/test_loader.js +++ b/chromium/ui/webui/resources/js/test_loader.js @@ -15,11 +15,7 @@ // chrome://test/ data source only exists in a testing context, so using this // script in production will result in a failed network request. -(function() { -const params = new URLSearchParams(window.location.search); -const module = params.get('module'); -const script = document.createElement('script'); -script.type = 'module'; -script.src = `chrome://test/${module}`; -document.body.appendChild(script); -})(); +import {assert} from 'chrome://resources/js/assert.m.js'; +import {loadTestModule} from './test_loader_util.js'; + +assert(loadTestModule()); diff --git a/chromium/ui/webui/resources/js/test_loader_util.js b/chromium/ui/webui/resources/js/test_loader_util.js new file mode 100644 index 00000000000..f3f042387b0 --- /dev/null +++ b/chromium/ui/webui/resources/js/test_loader_util.js @@ -0,0 +1,17 @@ +// Copyright 2021 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. + +/** @return {boolean} Whether a test module was loaded. */ +export function loadTestModule() { + const params = new URLSearchParams(window.location.search); + const module = params.get('module'); + if (!module) { + return false; + } + const script = document.createElement('script'); + script.type = 'module'; + script.src = `chrome://test/${module}`; + document.body.appendChild(script); + return true; +} diff --git a/chromium/ui/webui/resources/js/util.js b/chromium/ui/webui/resources/js/util.js index 69091dfda6c..f4c4b01be7a 100644 --- a/chromium/ui/webui/resources/js/util.js +++ b/chromium/ui/webui/resources/js/util.js @@ -337,3 +337,5 @@ /* #export */ function isTextInputElement(el) { return el.tagName === 'INPUT' || el.tagName === 'TEXTAREA'; } + +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/js/web_ui_listener_behavior.js b/chromium/ui/webui/resources/js/web_ui_listener_behavior.js index e5c09b9d644..837518397f7 100644 --- a/chromium/ui/webui/resources/js/web_ui_listener_behavior.js +++ b/chromium/ui/webui/resources/js/web_ui_listener_behavior.js @@ -46,3 +46,5 @@ } }, }; + +/* #ignore */ console.warn('crbug/1173575, non-JS module files deprecated.'); diff --git a/chromium/ui/webui/resources/tools/generate_grd.py b/chromium/ui/webui/resources/tools/generate_grd.py index d65706e61ae..1b01dc7e4bb 100644 --- a/chromium/ui/webui/resources/tools/generate_grd.py +++ b/chromium/ui/webui/resources/tools/generate_grd.py @@ -5,7 +5,7 @@ # Generates a grit grd file from a list of input manifest files. This is useful # for preventing the need to list JS files in multiple locations, as files can # be listed just once in the BUILD.gn file as inputs for a build rule that knows -# how to output such a manifest (e.g. preprocess_grit). +# how to output such a manifest (e.g. preprocess_if_expr). # # Variables: # manifest-files: @@ -147,11 +147,19 @@ def main(argv): if args.input_files != None: assert(args.input_files_base_dir) + args.input_files_base_dir = args.input_files_base_dir.replace('\\', '/') + args.root_gen_dir = args.root_gen_dir.replace('\\', '/') + + # Detect whether the input files reside under $root_src_dir or + # $root_gen_dir. + base_dir = os.path.join('${root_src_dir}', args.input_files_base_dir) + if args.input_files_base_dir.startswith(args.root_gen_dir + '/'): + base_dir = args.input_files_base_dir.replace(args.root_gen_dir + '/', '${root_gen_dir}/') + for filename in args.input_files: - filepath = os.path.join( - args.input_files_base_dir, filename).replace('\\', '/') + filepath = os.path.join(base_dir, filename).replace('\\', '/') grd_file.write(_generate_include_row( - args.grd_prefix, filename, '${root_src_dir}/' + filepath, + args.grd_prefix, filename, filepath, resource_path_rewrites, args.resource_path_prefix)) if args.manifest_files != None: diff --git a/chromium/ui/webui/resources/tools/generate_grd_test.py b/chromium/ui/webui/resources/tools/generate_grd_test.py index c42d4f7eafe..70b0c5b0725 100755 --- a/chromium/ui/webui/resources/tools/generate_grd_test.py +++ b/chromium/ui/webui/resources/tools/generate_grd_test.py @@ -111,6 +111,15 @@ class GenerateGrdTest(unittest.TestCase): input_files = [ 'images/test_svg.svg', 'test_html_in_src.html' ], input_files_base_dir = 'test_src_dir') + def testSuccessWithGeneratedInputFiles(self): + # For generated |input_files|, |input_files_base_dir| must be a + # sub-directory of |root_gen_dir|. + base_dir = os.path.join(_CWD, pathToHere, 'tests', 'foo', 'bar') + self._run_test_( + 'expected_grd_with_generated_input_files.grd', + input_files = [ 'baz/a.svg', 'b.svg' ], + input_files_base_dir = base_dir) + def testSuccessWithGrdpFiles(self): self._run_test_( EXPECTED_GRD_WITH_GRDP_FILES, diff --git a/chromium/ui/webui/resources/tools/js_modulizer.gni b/chromium/ui/webui/resources/tools/js_modulizer.gni index f70bc47aa11..1fb046a68b3 100644 --- a/chromium/ui/webui/resources/tools/js_modulizer.gni +++ b/chromium/ui/webui/resources/tools/js_modulizer.gni @@ -25,7 +25,8 @@ common_namespace_rewrites = [ "cr.ui.focusWithoutInk|focusWithoutInk", "cr.ui.KeyboardShortcutList|KeyboardShortcutList", "cr.ui.Store|Store", - "Polymer.dom.flush|flush", + "Polymer.dom.|", + "Polymer.dom(|dom(", "Polymer.IronA11yAnnouncer|IronA11yAnnouncer", "Polymer.PaperRippleBehavior|PaperRippleBehavior", "Polymer.RenderStatus.afterNextRender|afterNextRender", diff --git a/chromium/ui/webui/resources/webui_resources.grd b/chromium/ui/webui/resources/webui_resources.grd index 461cd851af1..50939260fc8 100644 --- a/chromium/ui/webui/resources/webui_resources.grd +++ b/chromium/ui/webui/resources/webui_resources.grd @@ -16,73 +16,27 @@ without changes to the corresponding grd file. --> <include name="IDR_WEBUI_JS_JSTEMPLATE_COMPILED_JS" file="../../../third_party/jstemplate/jstemplate_compiled.js" resource_path="js/jstemplate_compiled.js" type="BINDATA"/> - <!-- Roboto Font. Roboto-Regular and Roboto-Light is already available on - Android, and Roboto-Medium is not used on Android. All 6 weights of - Roboto are available on Chrome OS.--> - <if expr="not is_android and not chromeos"> - <include name="IDR_WEBUI_ROBOTO_ROBOTO_REGULAR_WOFF2" file="roboto/roboto-regular.woff2" type="BINDATA" /> - <include name="IDR_WEBUI_ROBOTO_ROBOTO_MEDIUM_WOFF2" file="roboto/roboto-medium.woff2" type="BINDATA" /> - <include name="IDR_WEBUI_ROBOTO_ROBOTO_BOLD_WOFF2" file="roboto/roboto-bold.woff2" type="BINDATA" /> + <if expr="chromeos"> + <include name="IDR_WEBUI_CROS_COLORS_CSS" + file="${root_gen_dir}/ui/chromeos/colors/cros_colors.generated.css" + resource_path="chromeos/colors/cros_colors.generated.css" + type="chrome_html" + use_base_dir="false" /> </if> - - <!-- Component apps common image resources - 1x --> - <!-- Misc buttons --> - <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_CLOSE_PNG" - file="images/apps/topbar_button_close.png" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_MAXIMIZE_PNG" - file="images/apps/topbar_button_maximize.png" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_MINIMIZE_PNG" - file="images/apps/topbar_button_minimize.png" type="BINDATA" /> - - <!-- Component apps common image resources - 2x --> - <!-- Misc buttons --> - <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_2X_CLOSE_PNG" - file="images/2x/apps/topbar_button_close.png" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_2X_MAXIMIZE_PNG" - file="images/2x/apps/topbar_button_maximize.png" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_APPS_TOPBAR_BUTTON_2X_MINIMIZE_PNG" - file="images/2x/apps/topbar_button_minimize.png" type="BINDATA" /> - - <!-- Non-apps images --> - <include name="IDR_WEBUI_IMAGES_ADD_SVG" - file="images/add.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_CHECK_PNG" - file="images/check.png" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_CHECKBOX_BLACK_PNG" - file="images/checkbox_black.png" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_CHECKBOX_WHITE_PNG" - file="images/checkbox_white.png" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_DISABLED_SELECT_PNG" - file="images/disabled_select.png" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_ERROR_SVG" - file="images/error.svg" type="BINDATA" /> - <!-- Similar to IDR_WEBUI_IMAGES_ERROR except that it is white-filled instead of transparent-filled. Useful for badging images where the background may be red. --> - <include name="IDR_WEBUI_IMAGES_ERROR_BADGE_SVG" - file="images/error_badge.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_SELECT_PNG" - file="images/select.png" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_THROBBER_MEDIUM_SVG" - file="images/throbber_medium.svg" type="BINDATA" /> - <include name="IDR_WEBUI_IMAGES_THROBBER_SMALL_SVG" - file="images/throbber_small.svg" type="BINDATA" /> - - <if expr="not is_android"> - <part file="cr_components/cr_components_images.grdp" /> - <part file="cr_elements_images.grdp" /> + <if expr="not is_android and not is_ios"> + <include name="IDR_LOTTIE_LOTTIE_WORKER_MIN_JS" + file="../../../third_party/lottie/lottie_worker.min.js" + resource_path="lottie/lottie_worker.min.js" + type="BINDATA" /> </if> </includes> <structures> - <structure name="IDR_WEBUI_CSS_CONTROLLED_INDICATOR_CSS" - file="css/controlled_indicator.css" type="chrome_html" flattenhtml="true" /> <structure name="IDR_WEBUI_CSS_MENU_CSS" file="css/menu.css" type="chrome_html" flattenhtml="true" /> <structure name="IDR_WEBUI_CSS_MENU_BUTTON_CSS" file="css/menu_button.css" type="chrome_html" flattenhtml="true" /> - <structure name="IDR_WEBUI_CSS_OVERLAY_CSS" - file="css/overlay.css" type="chrome_html" - flattenhtml="true" /> <structure name="IDR_WEBUI_CSS_SPINNER_CSS" file="css/spinner.css" type="chrome_html" flattenhtml="true" /> @@ -92,25 +46,10 @@ without changes to the corresponding grd file. --> <structure name="IDR_WEBUI_CSS_WIDGETS_CSS" file="css/widgets.css" type="chrome_html" flattenhtml="true" /> - <if expr="chromeos"> - <structure name="IDR_WEBUI_CROS_COLORS_CSS" - file="${root_gen_dir}/ui/chromeos/colors/cros_colors.generated.css" - type="chrome_html" - use_base_dir="false" /> - </if> - - <if expr="is_ios"> - <structure name="IDR_WEBUI_JS_IOS_WEB_UI" - file="js/ios/web_ui.js" type="chrome_html" /> - <structure name="IDR_WEBUI_JS_IOS_MOJO_API" - file="js/ios/mojo_api.js" type="chrome_html" /> - </if> - - <if expr="not is_android and not is_ios"> - <structure name="IDR_LOTTIE_LOTTIE_WORKER_MIN_JS" - file="../../../third_party/lottie/lottie_worker.min.js" - type="chrome_html" /> + <structure name="IDR_WEBUI_CSS_OVERLAY_CSS" + file="css/overlay.css" type="chrome_html" + flattenhtml="true" /> </if> </structures> </release> |