summaryrefslogtreecommitdiffstats
path: root/chromium/chrome/browser/resources/extensions
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@qt.io>2020-03-11 11:32:04 +0100
committerAllan Sandfeld Jensen <allan.jensen@qt.io>2020-03-18 13:40:17 +0000
commit31ccca0778db85c159634478b4ec7997f6704860 (patch)
tree3d33fc3afd9d5ec95541e1bbe074a9cf8da12a0e /chromium/chrome/browser/resources/extensions
parent248b70b82a40964d5594eb04feca0fa36716185d (diff)
BASELINE: Update Chromium to 80.0.3987.136
Change-Id: I98e1649aafae85ba3a83e67af00bb27ef301db7b Reviewed-by: Jüri Valdmann <juri.valdmann@qt.io>
Diffstat (limited to 'chromium/chrome/browser/resources/extensions')
-rw-r--r--chromium/chrome/browser/resources/extensions/BUILD.gn378
-rw-r--r--chromium/chrome/browser/resources/extensions/activity_log/BUILD.gn105
-rw-r--r--chromium/chrome/browser/resources/extensions/activity_log/activity_log.html166
-rw-r--r--chromium/chrome/browser/resources/extensions/activity_log/activity_log.js278
-rw-r--r--chromium/chrome/browser/resources/extensions/activity_log/activity_log_history.html178
-rw-r--r--chromium/chrome/browser/resources/extensions/activity_log/activity_log_history.js731
-rw-r--r--chromium/chrome/browser/resources/extensions/activity_log/activity_log_history_item.html195
-rw-r--r--chromium/chrome/browser/resources/extensions/activity_log/activity_log_history_item.js171
-rw-r--r--chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream.html154
-rw-r--r--chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream.js398
-rw-r--r--chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.html248
-rw-r--r--chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.js285
-rw-r--r--chromium/chrome/browser/resources/extensions/checkup_image.svg1
-rw-r--r--chromium/chrome/browser/resources/extensions/checkup_image_dark.svg1
-rw-r--r--chromium/chrome/browser/resources/extensions/code_section.html236
-rw-r--r--chromium/chrome/browser/resources/extensions/code_section.js352
-rw-r--r--chromium/chrome/browser/resources/extensions/detail_view.html779
-rw-r--r--chromium/chrome/browser/resources/extensions/detail_view.js724
-rw-r--r--chromium/chrome/browser/resources/extensions/drag_and_drop_handler.html3
-rw-r--r--chromium/chrome/browser/resources/extensions/drag_and_drop_handler.js178
-rw-r--r--chromium/chrome/browser/resources/extensions/drop_overlay.html91
-rw-r--r--chromium/chrome/browser/resources/extensions/drop_overlay.js20
-rw-r--r--chromium/chrome/browser/resources/extensions/error_page.html395
-rw-r--r--chromium/chrome/browser/resources/extensions/error_page.js742
-rw-r--r--chromium/chrome/browser/resources/extensions/extensions.html8
-rw-r--r--chromium/chrome/browser/resources/extensions/extensions.js17
-rw-r--r--chromium/chrome/browser/resources/extensions/extensions_resources.grd300
-rw-r--r--chromium/chrome/browser/resources/extensions/extensions_resources_vulcanized.grd15
-rw-r--r--chromium/chrome/browser/resources/extensions/host_permissions_toggle_list.html112
-rw-r--r--chromium/chrome/browser/resources/extensions/host_permissions_toggle_list.js138
-rw-r--r--chromium/chrome/browser/resources/extensions/icons.html3
-rw-r--r--chromium/chrome/browser/resources/extensions/icons.js9
-rw-r--r--chromium/chrome/browser/resources/extensions/install_warnings_dialog.html77
-rw-r--r--chromium/chrome/browser/resources/extensions/install_warnings_dialog.js40
-rw-r--r--chromium/chrome/browser/resources/extensions/item.html605
-rw-r--r--chromium/chrome/browser/resources/extensions/item.js843
-rw-r--r--chromium/chrome/browser/resources/extensions/item_behavior.html1
-rw-r--r--chromium/chrome/browser/resources/extensions/item_behavior.js48
-rw-r--r--chromium/chrome/browser/resources/extensions/item_list.html231
-rw-r--r--chromium/chrome/browser/resources/extensions/item_list.js218
-rw-r--r--chromium/chrome/browser/resources/extensions/item_util.html4
-rw-r--r--chromium/chrome/browser/resources/extensions/item_util.js253
-rw-r--r--chromium/chrome/browser/resources/extensions/keyboard_shortcut_delegate.html1
-rw-r--r--chromium/chrome/browser/resources/extensions/keyboard_shortcut_delegate.js64
-rw-r--r--chromium/chrome/browser/resources/extensions/keyboard_shortcuts.html205
-rw-r--r--chromium/chrome/browser/resources/extensions/keyboard_shortcuts.js174
-rw-r--r--chromium/chrome/browser/resources/extensions/kiosk_browser_proxy.html2
-rw-r--r--chromium/chrome/browser/resources/extensions/kiosk_browser_proxy.js117
-rw-r--r--chromium/chrome/browser/resources/extensions/kiosk_dialog.html235
-rw-r--r--chromium/chrome/browser/resources/extensions/kiosk_dialog.js338
-rw-r--r--chromium/chrome/browser/resources/extensions/load_error.html91
-rw-r--r--chromium/chrome/browser/resources/extensions/load_error.js134
-rw-r--r--chromium/chrome/browser/resources/extensions/manager.html234
-rw-r--r--chromium/chrome/browser/resources/extensions/manager.js1140
-rw-r--r--chromium/chrome/browser/resources/extensions/navigation_helper.html6
-rw-r--r--chromium/chrome/browser/resources/extensions/navigation_helper.js408
-rw-r--r--chromium/chrome/browser/resources/extensions/options_dialog.html133
-rw-r--r--chromium/chrome/browser/resources/extensions/options_dialog.js238
-rw-r--r--chromium/chrome/browser/resources/extensions/pack_dialog.html111
-rw-r--r--chromium/chrome/browser/resources/extensions/pack_dialog.js234
-rw-r--r--chromium/chrome/browser/resources/extensions/pack_dialog_alert.html55
-rw-r--r--chromium/chrome/browser/resources/extensions/pack_dialog_alert.js155
-rw-r--r--chromium/chrome/browser/resources/extensions/runtime_host_permissions.html231
-rw-r--r--chromium/chrome/browser/resources/extensions/runtime_host_permissions.js429
-rw-r--r--chromium/chrome/browser/resources/extensions/runtime_hosts_dialog.html59
-rw-r--r--chromium/chrome/browser/resources/extensions/runtime_hosts_dialog.js409
-rw-r--r--chromium/chrome/browser/resources/extensions/service.html6
-rw-r--r--chromium/chrome/browser/resources/extensions/service.js803
-rw-r--r--chromium/chrome/browser/resources/extensions/shared_style.html143
-rw-r--r--chromium/chrome/browser/resources/extensions/shared_style.js12
-rw-r--r--chromium/chrome/browser/resources/extensions/shared_vars.html5
-rw-r--r--chromium/chrome/browser/resources/extensions/shared_vars.js12
-rw-r--r--chromium/chrome/browser/resources/extensions/shortcut_input.html74
-rw-r--r--chromium/chrome/browser/resources/extensions/shortcut_input.js433
-rw-r--r--chromium/chrome/browser/resources/extensions/shortcut_util.html3
-rw-r--r--chromium/chrome/browser/resources/extensions/shortcut_util.js364
-rw-r--r--chromium/chrome/browser/resources/extensions/sidebar.html160
-rw-r--r--chromium/chrome/browser/resources/extensions/sidebar.js83
-rw-r--r--chromium/chrome/browser/resources/extensions/strings.html2
-rw-r--r--chromium/chrome/browser/resources/extensions/toggle_row.html78
-rw-r--r--chromium/chrome/browser/resources/extensions/toggle_row.js116
-rw-r--r--chromium/chrome/browser/resources/extensions/toolbar.html234
-rw-r--r--chromium/chrome/browser/resources/extensions/toolbar.js356
83 files changed, 8817 insertions, 9001 deletions
diff --git a/chromium/chrome/browser/resources/extensions/BUILD.gn b/chromium/chrome/browser/resources/extensions/BUILD.gn
index 734470fdaf4..49c26aa9c38 100644
--- a/chromium/chrome/browser/resources/extensions/BUILD.gn
+++ b/chromium/chrome/browser/resources/extensions/BUILD.gn
@@ -5,6 +5,7 @@
import("//chrome/common/features.gni")
import("//third_party/closure_compiler/compile_js.gni")
import("//tools/grit/grit_rule.gni")
+import("//tools/polymer/polymer.gni")
import("../optimize_webui.gni")
if (optimize_webui) {
@@ -13,16 +14,15 @@ if (optimize_webui) {
optimize_webui("build") {
host = "extensions"
- html_in_files = [ "extensions.html" ]
- html_out_files = [ "vulcanized.html" ]
- insert_in_head = "<base href=\"chrome://extensions\">"
input = rebase_path("$target_gen_dir/$unpak_folder", root_build_dir)
- js_out_files = [ "crisper.js" ]
- replace_for_html_imports_polyfill = "crisper.js"
+ js_out_files = [ "extensions.rollup.js" ]
+ js_module_in_files = [ "extensions.js" ]
deps = [
":unpak",
+ "../../../../ui/webui/resources:modulize",
]
+ excludes = [ "chrome://resources/js/cr.m.js" ]
}
unpak("unpak") {
@@ -39,7 +39,14 @@ if (optimize_webui) {
# The .grd contains references to generated files.
source_is_generated = true
+ grit_flags = [
+ "-E",
+ "root_gen_dir=" + rebase_path(root_gen_dir, root_build_dir),
+ ]
+ deps = [
+ ":polymer3_elements",
+ ]
defines = chrome_grit_defines
outputs = [
"grit/extensions_resources.h",
@@ -53,12 +60,195 @@ if (optimize_webui) {
group("closure_compile") {
deps = [
- ":extensions_resources",
- "activity_log:closure_compile",
+ ":extensions_module_resources",
+ "activity_log:closure_compile_module",
]
}
-js_type_check("extensions_resources") {
+group("polymer3_elements") {
+ deps = [
+ ":code_section_module",
+ ":detail_view_module",
+ ":drop_overlay_module",
+ ":error_page_module",
+ ":host_permissions_toggle_list_module",
+ ":icons_module",
+ ":install_warnings_dialog_module",
+ ":item_list_module",
+ ":item_module",
+ ":keyboard_shortcuts_module",
+ ":load_error_module",
+ ":manager_module",
+ ":options_dialog_module",
+ ":pack_dialog_alert_module",
+ ":pack_dialog_module",
+ ":runtime_host_permissions_module",
+ ":runtime_hosts_dialog_module",
+ ":shared_style_module",
+ ":shared_vars_module",
+ ":shortcut_input_module",
+ ":sidebar_module",
+ ":toggle_row_module",
+ ":toolbar_module",
+ "activity_log:polymer3_elements",
+ ]
+ if (is_chromeos) {
+ deps += [ ":kiosk_dialog_module" ]
+ }
+}
+
+polymer_modulizer("code_section") {
+ js_file = "code_section.js"
+ html_file = "code_section.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("detail_view") {
+ js_file = "detail_view.js"
+ html_file = "detail_view.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("drop_overlay") {
+ js_file = "drop_overlay.js"
+ html_file = "drop_overlay.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("error_page") {
+ js_file = "error_page.js"
+ html_file = "error_page.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("host_permissions_toggle_list") {
+ js_file = "host_permissions_toggle_list.js"
+ html_file = "host_permissions_toggle_list.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("icons") {
+ js_file = "icons.js"
+ html_file = "icons.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("install_warnings_dialog") {
+ js_file = "install_warnings_dialog.js"
+ html_file = "install_warnings_dialog.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("item") {
+ js_file = "item.js"
+ html_file = "item.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("item_list") {
+ js_file = "item_list.js"
+ html_file = "item_list.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("keyboard_shortcuts") {
+ js_file = "keyboard_shortcuts.js"
+ html_file = "keyboard_shortcuts.html"
+ html_type = "v3-ready"
+}
+
+if (is_chromeos) {
+ polymer_modulizer("kiosk_dialog") {
+ js_file = "kiosk_dialog.js"
+ html_file = "kiosk_dialog.html"
+ html_type = "v3-ready"
+ }
+}
+
+polymer_modulizer("load_error") {
+ js_file = "load_error.js"
+ html_file = "load_error.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("manager") {
+ js_file = "manager.js"
+ html_file = "manager.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("options_dialog") {
+ js_file = "options_dialog.js"
+ html_file = "options_dialog.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("pack_dialog") {
+ js_file = "pack_dialog.js"
+ html_file = "pack_dialog.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("pack_dialog_alert") {
+ js_file = "pack_dialog_alert.js"
+ html_file = "pack_dialog_alert.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("runtime_host_permissions") {
+ js_file = "runtime_host_permissions.js"
+ html_file = "runtime_host_permissions.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("runtime_hosts_dialog") {
+ js_file = "runtime_hosts_dialog.js"
+ html_file = "runtime_hosts_dialog.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("shared_style") {
+ js_file = "shared_style.js"
+ html_file = "shared_style.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("shared_vars") {
+ js_file = "shared_vars.js"
+ html_file = "shared_vars.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("shortcut_input") {
+ js_file = "shortcut_input.js"
+ html_file = "shortcut_input.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("sidebar") {
+ js_file = "sidebar.js"
+ html_file = "sidebar.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("toggle_row") {
+ js_file = "toggle_row.js"
+ html_file = "toggle_row.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("toolbar") {
+ js_file = "toolbar.js"
+ html_file = "toolbar.html"
+ html_type = "v3-ready"
+}
+
+js_type_check("extensions_module_resources") {
+ closure_flags = default_closure_args + [
+ "js_module_root=../../chrome/browser/resources/extensions/",
+ "js_module_root=./gen/chrome/browser/resources/extensions/",
+ ]
+ is_polymer3 = true
deps = [
":code_section",
":detail_view",
@@ -74,7 +264,6 @@ js_type_check("extensions_resources") {
":keyboard_shortcut_delegate",
":keyboard_shortcuts",
":kiosk_browser_proxy",
- ":kiosk_dialog",
":load_error",
":manager",
":navigation_helper",
@@ -87,15 +276,19 @@ js_type_check("extensions_resources") {
":shortcut_input",
":shortcut_util",
":sidebar",
+ ":toggle_row",
":toolbar",
]
+ if (is_chromeos) {
+ deps += [ ":kiosk_dialog" ]
+ }
}
js_library("code_section") {
deps = [
- "//ui/webui/resources/js:cr",
- "//ui/webui/resources/js:i18n_behavior",
- "//ui/webui/resources/js:load_time_data",
+ "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+ "//ui/webui/resources/js:i18n_behavior.m",
+ "//ui/webui/resources/js:load_time_data.m",
]
externs_list = [ "$externs_path/developer_private.js" ]
}
@@ -106,31 +299,26 @@ js_library("detail_view") {
":item_behavior",
":item_util",
":navigation_helper",
- "//ui/webui/resources/cr_elements:cr_container_shadow_behavior",
- "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu",
- "//ui/webui/resources/js:assert",
- "//ui/webui/resources/js:cr",
- "//ui/webui/resources/js:load_time_data",
- "//ui/webui/resources/js/cr/ui:focus_without_ink",
+ "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+ "//ui/webui/resources/cr_elements:cr_container_shadow_behavior.m",
+ "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu.m",
+ "//ui/webui/resources/js:load_time_data.m",
+ "//ui/webui/resources/js/cr/ui:focus_without_ink.m",
]
externs_list = [ "$externs_path/developer_private.js" ]
}
-js_library("drag_and_drop_handler") {
+js_library("drop_overlay") {
deps = [
- ":service",
- "//ui/webui/resources/js:assert",
- "//ui/webui/resources/js:cr",
- "//ui/webui/resources/js/cr/ui:drag_wrapper",
+ ":drag_and_drop_handler",
+ "//ui/webui/resources/js/cr/ui:drag_wrapper.m",
]
}
-js_library("drop_overlay") {
+js_library("drag_and_drop_handler") {
deps = [
- ":drag_and_drop_handler",
- "//ui/webui/resources/js:cr",
- "//ui/webui/resources/js:load_time_data",
- "//ui/webui/resources/js/cr/ui:drag_wrapper",
+ ":service",
+ "//ui/webui/resources/js/cr/ui:drag_wrapper.m",
]
}
@@ -139,10 +327,9 @@ js_library("error_page") {
":code_section",
":item_util",
":navigation_helper",
- "//ui/webui/resources/cr_elements:cr_container_shadow_behavior",
- "//ui/webui/resources/js:cr",
- "//ui/webui/resources/js/cr/ui:focus_outline_manager",
- "//ui/webui/resources/js/cr/ui:focus_without_ink",
+ "//ui/webui/resources/cr_elements:cr_container_shadow_behavior.m",
+ "//ui/webui/resources/js/cr/ui:focus_outline_manager.m",
+ "//ui/webui/resources/js/cr/ui:focus_without_ink.m",
]
externs_list = [
"$externs_path/developer_private.js",
@@ -152,15 +339,16 @@ js_library("error_page") {
js_library("host_permissions_toggle_list") {
deps = [
- "//ui/webui/resources/js:cr",
+ ":item",
]
externs_list = [ "$externs_path/developer_private.js" ]
}
js_library("install_warnings_dialog") {
deps = [
- "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
]
+ externs_list = [ "$externs_path/developer_private.js" ]
}
js_library("item") {
@@ -168,19 +356,18 @@ js_library("item") {
":item_behavior",
":item_util",
":navigation_helper",
- "//ui/webui/resources/cr_elements/cr_toast:cr_toast_manager",
- "//ui/webui/resources/js:assert",
- "//ui/webui/resources/js:cr",
- "//ui/webui/resources/js:i18n_behavior",
- "//ui/webui/resources/js:load_time_data",
+ "//third_party/polymer/v3_0/components-chromium/polymer:polymer_bundled",
+ "//ui/webui/resources/cr_elements/cr_toast:cr_toast_manager.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:i18n_behavior.m",
+ "//ui/webui/resources/js:load_time_data.m",
]
externs_list = [ "$externs_path/developer_private.js" ]
}
js_library("item_behavior") {
deps = [
- "//ui/webui/resources/js:cr",
- "//ui/webui/resources/js:load_time_data",
+ "//ui/webui/resources/js:load_time_data.m",
]
externs_list = [ "$externs_path/developer_private.js" ]
}
@@ -188,11 +375,9 @@ js_library("item_behavior") {
js_library("item_list") {
deps = [
":item",
- "//third_party/polymer/v1_0/components-chromium/iron-a11y-announcer:iron-a11y-announcer-extracted",
- "//ui/webui/resources/cr_elements:cr_container_shadow_behavior",
- "//ui/webui/resources/js:assert",
- "//ui/webui/resources/js:cr",
- "//ui/webui/resources/js:i18n_behavior",
+ "//third_party/polymer/v3_0/components-chromium/iron-a11y-announcer:iron-a11y-announcer",
+ "//ui/webui/resources/cr_elements:cr_container_shadow_behavior.m",
+ "//ui/webui/resources/js:i18n_behavior.m",
]
externs_list = [
"$externs_path/developer_private.js",
@@ -203,17 +388,14 @@ js_library("item_list") {
js_library("item_util") {
deps = [
":navigation_helper",
- "//ui/webui/resources/js:assert",
- "//ui/webui/resources/js:cr",
- "//ui/webui/resources/js:load_time_data",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:load_time_data.m",
]
externs_list = [ "$externs_path/developer_private.js" ]
}
js_library("keyboard_shortcut_delegate") {
- deps = [
- "//ui/webui/resources/js:cr",
- ]
+ deps = []
externs_list = [ "$externs_path/developer_private.js" ]
}
@@ -221,9 +403,7 @@ js_library("keyboard_shortcuts") {
deps = [
":item_behavior",
":keyboard_shortcut_delegate",
- "//ui/webui/resources/cr_elements:cr_container_shadow_behavior",
- "//ui/webui/resources/js:assert",
- "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/cr_elements:cr_container_shadow_behavior.m",
]
externs_list = [
"$externs_path/developer_private.js",
@@ -233,24 +413,24 @@ js_library("keyboard_shortcuts") {
js_library("kiosk_browser_proxy") {
deps = [
- ":item_behavior",
- "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js:cr.m",
]
}
-js_library("kiosk_dialog") {
- deps = [
- ":kiosk_browser_proxy",
- "//ui/webui/resources/js:cr",
- "//ui/webui/resources/js:web_ui_listener_behavior",
- ]
+if (is_chromeos) {
+ js_library("kiosk_dialog") {
+ deps = [
+ ":item_behavior",
+ ":kiosk_browser_proxy",
+ "//ui/webui/resources/js:web_ui_listener_behavior.m",
+ ]
+ }
}
js_library("load_error") {
deps = [
- "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog",
- "//ui/webui/resources/js:assert",
- "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
+ "//ui/webui/resources/js:assert.m",
]
externs_list = [ "$externs_path/developer_private.js" ]
}
@@ -269,46 +449,39 @@ js_library("manager") {
":sidebar",
":toolbar",
"activity_log:activity_log",
- "//ui/webui/resources/cr_elements/cr_drawer:cr_drawer",
- "//ui/webui/resources/cr_elements/cr_view_manager:cr_view_manager",
- "//ui/webui/resources/js:assert",
- "//ui/webui/resources/js:cr",
- "//ui/webui/resources/js:load_time_data",
+ "//ui/webui/resources/cr_elements/cr_drawer:cr_drawer.m",
+ "//ui/webui/resources/cr_elements/cr_view_manager:cr_view_manager.m",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:load_time_data.m",
]
externs_list = [ "$externs_path/developer_private.js" ]
}
js_library("navigation_helper") {
deps = [
- "//ui/webui/resources/js:assert",
- "//ui/webui/resources/js:cr",
- "//ui/webui/resources/js:load_time_data",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:load_time_data.m",
]
+ externs_list = [ "$externs_path/developer_private.js" ]
}
js_library("options_dialog") {
deps = [
":item_behavior",
":navigation_helper",
- "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog",
- "//ui/webui/resources/js:assert",
- "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
]
externs_list = [ "$externs_path/developer_private.js" ]
}
js_library("pack_dialog") {
- deps = [
- "//ui/webui/resources/js:cr",
- ]
externs_list = [ "$externs_path/developer_private.js" ]
}
js_library("pack_dialog_alert") {
deps = [
- "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog",
- "//ui/webui/resources/js:cr",
- "//ui/webui/resources/js:load_time_data",
+ "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
+ "//ui/webui/resources/js:load_time_data.m",
]
externs_list = [ "$externs_path/developer_private.js" ]
}
@@ -317,17 +490,19 @@ js_library("runtime_host_permissions") {
deps = [
":item",
":runtime_hosts_dialog",
- "//ui/webui/resources/cr_elements/cr_radio_button:cr_radio_button",
- "//ui/webui/resources/cr_elements/cr_radio_group:cr_radio_group",
+ "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu.m",
+ "//ui/webui/resources/cr_elements/cr_radio_button:cr_radio_button.m",
+ "//ui/webui/resources/cr_elements/cr_radio_group:cr_radio_group.m",
+ "//ui/webui/resources/js/cr/ui:focus_without_ink.m",
]
externs_list = [ "$externs_path/developer_private.js" ]
}
js_library("runtime_hosts_dialog") {
deps = [
- "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog",
- "//ui/webui/resources/cr_elements/cr_input:cr_input",
- "//ui/webui/resources/js:load_time_data",
+ "//ui/webui/resources/cr_elements/cr_dialog:cr_dialog.m",
+ "//ui/webui/resources/cr_elements/cr_input:cr_input.m",
+ "//ui/webui/resources/js:load_time_data.m",
]
}
@@ -343,9 +518,8 @@ js_library("service") {
"activity_log:activity_log",
"activity_log:activity_log_history",
"activity_log:activity_log_stream",
- "//ui/webui/resources/js:assert",
- "//ui/webui/resources/js:cr",
- "//ui/webui/resources/js:load_time_data",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:cr.m",
]
externs_list = [
"$externs_path/activity_log_private.js",
@@ -359,35 +533,35 @@ js_library("shortcut_input") {
deps = [
":keyboard_shortcut_delegate",
":shortcut_util",
- "//ui/webui/resources/js:assert",
- "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js:assert.m",
]
externs_list = [ "$externs_path/developer_private.js" ]
}
js_library("shortcut_util") {
deps = [
- "//ui/webui/resources/js:assert",
- "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js:assert.m",
+ "//ui/webui/resources/js:cr.m",
]
}
js_library("sidebar") {
deps = [
":navigation_helper",
- "//ui/webui/resources/js:assert",
- "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/js:assert.m",
]
externs_list = [ "$externs_path/metrics_private.js" ]
}
+js_library("toggle_row") {
+}
+
js_library("toolbar") {
deps = [
- "//third_party/polymer/v1_0/components-chromium/iron-a11y-announcer:iron-a11y-announcer-extracted",
- "//ui/webui/resources/cr_elements/cr_toast:cr_toast_manager",
- "//ui/webui/resources/js:cr",
- "//ui/webui/resources/js:i18n_behavior",
- "//ui/webui/resources/js:util",
+ "//third_party/polymer/v3_0/components-chromium/iron-a11y-announcer:iron-a11y-announcer",
+ "//ui/webui/resources/cr_elements/cr_toast:cr_toast_manager.m",
+ "//ui/webui/resources/js:i18n_behavior.m",
+ "//ui/webui/resources/js:util.m",
]
externs_list = [ "$externs_path/metrics_private.js" ]
}
diff --git a/chromium/chrome/browser/resources/extensions/activity_log/BUILD.gn b/chromium/chrome/browser/resources/extensions/activity_log/BUILD.gn
index be1754ad8ff..d562aa8ca3d 100644
--- a/chromium/chrome/browser/resources/extensions/activity_log/BUILD.gn
+++ b/chromium/chrome/browser/resources/extensions/activity_log/BUILD.gn
@@ -1,10 +1,56 @@
-# 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.
+#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.
import("//third_party/closure_compiler/compile_js.gni")
+import("//tools/polymer/polymer.gni")
-js_type_check("closure_compile") {
+polymer_modulizer("activity_log") {
+ js_file = "activity_log.js"
+ html_file = "activity_log.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("activity_log_history") {
+ js_file = "activity_log_history.js"
+ html_file = "activity_log_history.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("activity_log_history_item") {
+ js_file = "activity_log_history_item.js"
+ html_file = "activity_log_history_item.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("activity_log_stream") {
+ js_file = "activity_log_stream.js"
+ html_file = "activity_log_stream.html"
+ html_type = "v3-ready"
+}
+
+polymer_modulizer("activity_log_stream_item") {
+ js_file = "activity_log_stream_item.js"
+ html_file = "activity_log_stream_item.html"
+ html_type = "v3-ready"
+}
+
+group("polymer3_elements") {
+ deps = [
+ ":activity_log_history_item_module",
+ ":activity_log_history_module",
+ ":activity_log_module",
+ ":activity_log_stream_item_module",
+ ":activity_log_stream_module",
+ ]
+}
+
+js_type_check("closure_compile_module") {
+ closure_flags = default_closure_args + [
+ "js_module_root=../../chrome/browser/resources/extensions/",
+ "js_module_root=./gen/chrome/browser/resources/extensions/",
+ ]
+ is_polymer3 = true
deps = [
":activity_log",
":activity_log_history",
@@ -14,53 +60,46 @@ js_type_check("closure_compile") {
]
}
-js_library("activity_log_history_item") {
+js_library("activity_log") {
deps = [
- "//ui/webui/resources/js:cr",
+ ":activity_log_history",
+ ":activity_log_stream",
+ "..:item_behavior",
+ "..:navigation_helper",
+ "//ui/webui/resources/cr_elements:cr_container_shadow_behavior.m",
+ "//ui/webui/resources/js:i18n_behavior.m",
+ "//ui/webui/resources/js/cr/ui:focus_without_ink.m",
+ ]
+ externs_list = [
+ "$externs_path/activity_log_private.js",
+ "$externs_path/developer_private.js",
]
- externs_list = [ "$externs_path/activity_log_private.js" ]
}
js_library("activity_log_history") {
deps = [
":activity_log_history_item",
- "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu",
- "//ui/webui/resources/cr_elements/cr_search_field:cr_search_field",
- "//ui/webui/resources/js:cr",
+ "//ui/webui/resources/cr_elements/cr_action_menu:cr_action_menu.m",
+ "//ui/webui/resources/cr_elements/cr_search_field:cr_search_field.m",
]
externs_list = [ "$externs_path/activity_log_private.js" ]
}
+js_library("activity_log_history_item") {
+ deps = []
+ externs_list = [ "$externs_path/activity_log_private.js" ]
+}
+
js_library("activity_log_stream") {
deps = [
":activity_log_stream_item",
- "//third_party/polymer/v1_0/components-chromium/iron-list:iron-list-extracted",
- "//ui/webui/resources/cr_elements/cr_search_field:cr_search_field",
- "//ui/webui/resources/js:cr",
+ "//third_party/polymer/v3_0/components-chromium/iron-list:iron-list",
+ "//ui/webui/resources/cr_elements/cr_search_field:cr_search_field.m",
]
externs_list = [ "$externs_path/activity_log_private.js" ]
}
js_library("activity_log_stream_item") {
- deps = [
- "//ui/webui/resources/js:cr",
- ]
+ deps = []
externs_list = [ "$externs_path/activity_log_private.js" ]
}
-
-js_library("activity_log") {
- deps = [
- ":activity_log_history",
- ":activity_log_stream",
- "..:item_behavior",
- "..:navigation_helper",
- "//ui/webui/resources/cr_elements:cr_container_shadow_behavior",
- "//ui/webui/resources/js:cr",
- "//ui/webui/resources/js:i18n_behavior",
- "//ui/webui/resources/js/cr/ui:focus_without_ink",
- ]
- externs_list = [
- "$externs_path/activity_log_private.js",
- "$externs_path/developer_private.js",
- ]
-}
diff --git a/chromium/chrome/browser/resources/extensions/activity_log/activity_log.html b/chromium/chrome/browser/resources/extensions/activity_log/activity_log.html
index 6a10765807b..c3167d20755 100644
--- a/chromium/chrome/browser/resources/extensions/activity_log/activity_log.html
+++ b/chromium/chrome/browser/resources/extensions/activity_log/activity_log.html
@@ -1,103 +1,79 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="cr-icons cr-shared-style shared-style">
+ #clear-activities-button {
+ margin-inline-start: 8px;
+ }
-<link rel="import" href="chrome://resources/cr_elements/cr_container_shadow_behavior.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_tabs/cr_tabs.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">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.html">
-<link rel="import" href="chrome://resources/html/i18n_behavior.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html">
-<link rel="import" href="activity_log_history.html">
-<link rel="import" href="activity_log_stream.html">
-<link rel="import" href="../item_behavior.html">
-<link rel="import" href="../navigation_helper.html">
-<link rel="import" href="../shared_style.html">
-<link rel="import" href="../shared_vars.html">
+ #closeButton {
+ margin-inline-end: 16px;
+ }
-<dom-module id="extensions-activity-log">
- <template>
- <style include="cr-icons cr-shared-style shared-style">
- #clear-activities-button {
- margin-inline-start: 8px;
- }
+ #icon {
+ height: 24px;
+ margin-inline-end: 12px;
+ width: 24px;
+ }
- #closeButton {
- margin-inline-end: 16px;
- }
+ cr-tabs {
+ --cr-tabs-font-size: inherit;
+ --cr-tabs-height: 40px;
+ border-bottom: 1px solid var(--google-grey-refresh-300);
+ }
- #icon {
- height: 24px;
- margin-inline-end: 12px;
- width: 24px;
- }
+ .page-content {
+ display: flex;
+ flex-direction: column;
+ padding-bottom: 0;
+ }
- cr-tabs {
- --cr-tabs-font-size: inherit;
- --cr-tabs-height: 40px;
- border-bottom: 1px solid var(--google-grey-refresh-300);
- }
+ iron-pages {
+ flex: 1;
+ position: relative;
+ }
- .page-content {
- display: flex;
- flex-direction: column;
- padding-bottom: 0;
- }
-
- iron-pages {
- flex: 1;
- position: relative;
- }
-
- activity-log-history,
- activity-log-stream {
- bottom: 0;
- position: absolute;
- top: 0;
- width: 100%;
- }
- </style>
- <div class="page-container" id="container">
- <div class="page-content">
- <div class="page-header">
- <cr-icon-button class="icon-arrow-back no-overlap" id="closeButton"
- aria-label="$i18n{back}" on-click="onCloseButtonTap_">
- </cr-icon-button>
- <template is="dom-if" if="[[!extensionInfo.isPlaceholder]]">
- <img id="icon" src="[[extensionInfo.iconUrl]]"
- alt$="[[appOrExtension(
- extensionInfo.type,
- '$i18nPolymer{appIcon}',
- '$i18nPolymer{extensionIcon}')]]">
- </template>
- <div class="cr-title-text">
- [[getActivityLogHeading_(extensionInfo)]]
- </div>
- </div>
- <cr-tabs selected="{{selectedSubpage_}}" tab-names="[[tabNames_]]">
- </cr-tabs>
- <iron-pages selected="[[selectedSubpage_]]">
- <div>
- <template is="dom-if"
- if="[[isHistoryTabSelected_(selectedSubpage_)]]" restamp>
- <activity-log-history extension-id="[[extensionInfo.id]]"
- delegate="[[delegate]]">
- </activity-log-history>
- </template>
- </div>
- <div>
- <template is="dom-if"
- if="[[isStreamTabSelected_(selectedSubpage_)]]">
- <activity-log-stream extension-id="[[extensionInfo.id]]"
- delegate="[[delegate]]">
- </activity-log-stream>
- </template>
- </div>
- </iron-pages>
+ activity-log-history,
+ activity-log-stream {
+ bottom: 0;
+ position: absolute;
+ top: 0;
+ width: 100%;
+ }
+</style>
+<div class="page-container" id="container">
+ <div class="page-content">
+ <div class="page-header">
+ <cr-icon-button class="icon-arrow-back no-overlap" id="closeButton"
+ aria-label="$i18n{back}" on-click="onCloseButtonTap_">
+ </cr-icon-button>
+ <template is="dom-if" if="[[!extensionInfo.isPlaceholder]]">
+ <img id="icon" src="[[extensionInfo.iconUrl]]"
+ alt$="[[appOrExtension(
+ extensionInfo.type,
+ '$i18nPolymer{appIcon}',
+ '$i18nPolymer{extensionIcon}')]]">
+ </template>
+ <div class="cr-title-text">
+ [[getActivityLogHeading_(extensionInfo)]]
</div>
</div>
- </template>
- <script src="activity_log.js"></script>
-</dom-module>
+ <cr-tabs selected="{{selectedSubpage_}}" tab-names="[[tabNames_]]">
+ </cr-tabs>
+ <iron-pages selected="[[selectedSubpage_]]">
+ <div>
+ <template is="dom-if"
+ if="[[isHistoryTabSelected_(selectedSubpage_)]]" restamp>
+ <activity-log-history extension-id="[[extensionInfo.id]]"
+ delegate="[[delegate]]">
+ </activity-log-history>
+ </template>
+ </div>
+ <div>
+ <template is="dom-if"
+ if="[[isStreamTabSelected_(selectedSubpage_)]]">
+ <activity-log-stream extension-id="[[extensionInfo.id]]"
+ delegate="[[delegate]]">
+ </activity-log-stream>
+ </template>
+ </div>
+ </iron-pages>
+ </div>
+</div>
diff --git a/chromium/chrome/browser/resources/extensions/activity_log/activity_log.js b/chromium/chrome/browser/resources/extensions/activity_log/activity_log.js
index 3f3d33e0990..6bf480f9927 100644
--- a/chromium/chrome/browser/resources/extensions/activity_log/activity_log.js
+++ b/chromium/chrome/browser/resources/extensions/activity_log/activity_log.js
@@ -2,6 +2,28 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
+import 'chrome://resources/cr_elements/cr_icons_css.m.js';
+import 'chrome://resources/cr_elements/cr_tabs/cr_tabs.m.js';
+import 'chrome://resources/cr_elements/shared_style_css.m.js';
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+import 'chrome://resources/polymer/v3_0/iron-pages/iron-pages.js';
+import './activity_log_stream.js';
+import '../strings.m.js';
+import '../shared_style.js';
+import '../shared_vars.js';
+
+import {CrContainerShadowBehavior} from 'chrome://resources/cr_elements/cr_container_shadow_behavior.m.js';
+import {focusWithoutInk} from 'chrome://resources/js/cr/ui/focus_without_ink.m.js';
+import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+import {afterNextRender, html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {ItemBehavior} from '../item_behavior.js';
+import {navigation, Page} from '../navigation_helper.js';
+
+import {ActivityLogDelegate} from './activity_log_history.js';
+
/**
* Subpages/views for the activity log. HISTORY shows extension activities
* fetched from the activity log database with some fields such as args
@@ -15,150 +37,140 @@ const ActivityLogSubpage = {
STREAM: 1
};
-cr.define('extensions', function() {
- 'use strict';
+/**
+ * A struct used as a placeholder for chrome.developerPrivate.ExtensionInfo
+ * for this component if the extensionId from the URL does not correspond to
+ * installed extension.
+ * @typedef {{
+ * id: string,
+ * isPlaceholder: boolean,
+ * }}
+ */
+export let ActivityLogExtensionPlaceholder;
- /**
- * A struct used as a placeholder for chrome.developerPrivate.ExtensionInfo
- * for this component if the extensionId from the URL does not correspond to
- * installed extension.
- * @typedef {{
- * id: string,
- * isPlaceholder: boolean,
- * }}
- */
- let ActivityLogExtensionPlaceholder;
-
- const ActivityLog = Polymer({
- is: 'extensions-activity-log',
-
- behaviors: [
- CrContainerShadowBehavior,
- I18nBehavior,
- extensions.ItemBehavior,
- ],
-
- properties: {
- /**
- * The underlying ExtensionInfo for the details being displayed.
- * @type {!chrome.developerPrivate.ExtensionInfo|
- * !extensions.ActivityLogExtensionPlaceholder}
- */
- extensionInfo: Object,
-
- /** @type {!extensions.ActivityLogDelegate} */
- delegate: Object,
-
- /** @private {!ActivityLogSubpage} */
- selectedSubpage_: {
- type: Number,
- value: ActivityLogSubpage.NONE,
- observer: 'onSelectedSubpageChanged_',
- },
-
- /** @private {Array<string>} */
- tabNames_: {
- type: Array,
- value: () => ([
- loadTimeData.getString('activityLogHistoryTabHeading'),
- loadTimeData.getString('activityLogStreamTabHeading'),
- ]),
- }
- },
+Polymer({
+ is: 'extensions-activity-log',
- listeners: {
- 'view-enter-start': 'onViewEnterStart_',
- 'view-exit-finish': 'onViewExitFinish_',
- },
+ _template: html`{__html_template__}`,
- /**
- * Focuses the back button when page is loaded and set the activie view to
- * be HISTORY when we navigate to the page.
- * @private
- */
- onViewEnterStart_: function() {
- this.selectedSubpage_ = ActivityLogSubpage.HISTORY;
- Polymer.RenderStatus.afterNextRender(
- this, () => cr.ui.focusWithoutInk(this.$.closeButton));
- },
+ behaviors: [
+ CrContainerShadowBehavior,
+ I18nBehavior,
+ ItemBehavior,
+ ],
+ properties: {
/**
- * Set |selectedSubpage_| to NONE to remove the active view from the DOM.
- * @private
+ * The underlying ExtensionInfo for the details being displayed.
+ * @type {!chrome.developerPrivate.ExtensionInfo|
+ * !ActivityLogExtensionPlaceholder}
*/
- onViewExitFinish_: function() {
- this.selectedSubpage_ = ActivityLogSubpage.NONE;
- // clear the stream if the user is exiting the activity log page.
- const activityLogStream = this.$$('activity-log-stream');
- if (activityLogStream) {
- activityLogStream.clearStream();
- }
- },
+ extensionInfo: Object,
- /**
- * @private
- * @return {string}
- */
- getActivityLogHeading_: function() {
- const headingName = this.extensionInfo.isPlaceholder ?
- this.i18n('missingOrUninstalledExtension') :
- this.extensionInfo.name;
- return this.i18n('activityLogPageHeading', headingName);
- },
+ /** @type {!ActivityLogDelegate} */
+ delegate: Object,
- /**
- * @private
- * @return {boolean}
- */
- isHistoryTabSelected_: function() {
- return this.selectedSubpage_ === ActivityLogSubpage.HISTORY;
+ /** @private {!ActivityLogSubpage} */
+ selectedSubpage_: {
+ type: Number,
+ value: ActivityLogSubpage.NONE,
+ observer: 'onSelectedSubpageChanged_',
},
- /**
- * @private
- * @return {boolean}
- */
- isStreamTabSelected_: function() {
- return this.selectedSubpage_ === ActivityLogSubpage.STREAM;
- },
+ /** @private {Array<string>} */
+ tabNames_: {
+ type: Array,
+ value: () => ([
+ loadTimeData.getString('activityLogHistoryTabHeading'),
+ loadTimeData.getString('activityLogStreamTabHeading'),
+ ]),
+ }
+ },
+
+ listeners: {
+ 'view-enter-start': 'onViewEnterStart_',
+ 'view-exit-finish': 'onViewExitFinish_',
+ },
- /**
- * @private
- * @param {!ActivityLogSubpage} newTab
- * @param {!ActivityLogSubpage} oldTab
- */
- onSelectedSubpageChanged_: function(newTab, oldTab) {
- const activityLogStream = this.$$('activity-log-stream');
- if (activityLogStream) {
- if (newTab === ActivityLogSubpage.STREAM) {
- // Start the stream if the user is switching to the real-time tab.
- // This will not handle the first tab switch to the real-time tab as
- // the stream has not been attached to the DOM yet, and is handled
- // instead by the stream's |attached| method.
- activityLogStream.startStream();
- } else if (oldTab === ActivityLogSubpage.STREAM) {
- // Pause the stream if the user is navigating away from the real-time
- // tab.
- activityLogStream.pauseStream();
- }
- }
- },
+ /**
+ * Focuses the back button when page is loaded and set the activie view to
+ * be HISTORY when we navigate to the page.
+ * @private
+ */
+ onViewEnterStart_: function() {
+ this.selectedSubpage_ = ActivityLogSubpage.HISTORY;
+ afterNextRender(this, () => focusWithoutInk(this.$.closeButton));
+ },
- /** @private */
- onCloseButtonTap_: function() {
- if (this.extensionInfo.isPlaceholder) {
- extensions.navigation.navigateTo({page: extensions.Page.LIST});
- } else {
- extensions.navigation.navigateTo({
- page: extensions.Page.DETAILS,
- extensionId: this.extensionInfo.id
- });
- }
- },
- });
+ /**
+ * Set |selectedSubpage_| to NONE to remove the active view from the DOM.
+ * @private
+ */
+ onViewExitFinish_: function() {
+ this.selectedSubpage_ = ActivityLogSubpage.NONE;
+ // clear the stream if the user is exiting the activity log page.
+ const activityLogStream = this.$$('activity-log-stream');
+ if (activityLogStream) {
+ activityLogStream.clearStream();
+ }
+ },
- return {
- ActivityLog: ActivityLog,
- ActivityLogExtensionPlaceholder: ActivityLogExtensionPlaceholder,
- };
+ /**
+ * @private
+ * @return {string}
+ */
+ getActivityLogHeading_: function() {
+ const headingName = this.extensionInfo.isPlaceholder ?
+ this.i18n('missingOrUninstalledExtension') :
+ this.extensionInfo.name;
+ return this.i18n('activityLogPageHeading', headingName);
+ },
+
+ /**
+ * @private
+ * @return {boolean}
+ */
+ isHistoryTabSelected_: function() {
+ return this.selectedSubpage_ === ActivityLogSubpage.HISTORY;
+ },
+
+ /**
+ * @private
+ * @return {boolean}
+ */
+ isStreamTabSelected_: function() {
+ return this.selectedSubpage_ === ActivityLogSubpage.STREAM;
+ },
+
+ /**
+ * @private
+ * @param {!ActivityLogSubpage} newTab
+ * @param {!ActivityLogSubpage} oldTab
+ */
+ onSelectedSubpageChanged_: function(newTab, oldTab) {
+ const activityLogStream = this.$$('activity-log-stream');
+ if (activityLogStream) {
+ if (newTab === ActivityLogSubpage.STREAM) {
+ // Start the stream if the user is switching to the real-time tab.
+ // This will not handle the first tab switch to the real-time tab as
+ // the stream has not been attached to the DOM yet, and is handled
+ // instead by the stream's |attached| method.
+ activityLogStream.startStream();
+ } else if (oldTab === ActivityLogSubpage.STREAM) {
+ // Pause the stream if the user is navigating away from the real-time
+ // tab.
+ activityLogStream.pauseStream();
+ }
+ }
+ },
+
+ /** @private */
+ onCloseButtonTap_: function() {
+ if (this.extensionInfo.isPlaceholder) {
+ navigation.navigateTo({page: Page.LIST});
+ } else {
+ navigation.navigateTo(
+ {page: Page.DETAILS, extensionId: this.extensionInfo.id});
+ }
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/activity_log/activity_log_history.html b/chromium/chrome/browser/resources/extensions/activity_log/activity_log_history.html
index 41cb1feabd4..1e614d5acdf 100644
--- a/chromium/chrome/browser/resources/extensions/activity_log/activity_log_history.html
+++ b/chromium/chrome/browser/resources/extensions/activity_log/activity_log_history.html
@@ -1,106 +1,90 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="shared-style">
+ :host {
+ --activity-log-call-and-count-width: 514px;
+ --activity-type-width: 85px;
+ --activity-count-width: 100px;
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/html/promise_resolver.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_search_field/cr_search_field.html">
-<link rel="import" href="activity_log_history_item.html">
-<link rel="import" href="../shared_style.html">
+ display: flex;
+ flex-direction: column;
+ }
-<dom-module id="activity-log-history">
- <template>
- <style include="shared-style">
- :host {
- --activity-log-call-and-count-width: 514px;
- --activity-type-width: 85px;
- --activity-count-width: 100px;
+ cr-search-field {
+ align-self: center;
+ margin-inline-end: auto;
+ }
- display: flex;
- flex-direction: column;
- }
+ cr-icon-button {
+ margin: 0;
+ }
- cr-search-field {
- align-self: center;
- margin-inline-end: auto;
- }
+ .activity-table-headings {
+ width: var(--activity-log-call-and-count-width);
+ }
- cr-icon-button {
- margin: 0;
- }
+ #activity-list {
+ overflow-y: auto;
+ }
- .activity-table-headings {
- width: var(--activity-log-call-and-count-width);
- }
+ #activity-type {
+ flex: 0 var(--activity-type-width);
+ }
- #activity-list {
- overflow-y: auto;
- }
+ #activity-key {
+ flex: 1;
+ margin-inline-start: 10px;
+ }
- #activity-type {
- flex: 0 var(--activity-type-width);
- }
-
- #activity-key {
- flex: 1;
- margin-inline-start: 10px;
- }
-
- #activity-count {
- flex: 0 var(--activity-count-width);
- text-align: end;
- }
- </style>
- <div class="activity-subpage-header">
- <cr-search-field label="$i18n{activityLogSearchLabel}"
- on-search-changed="onSearchChanged_">
- </cr-search-field >
- <cr-button class="clear-activities-button"
- on-click="onClearActivitiesClick_">
- $i18n{clearActivities}
- </cr-button>
- <cr-icon-button id="more-actions" iron-icon="cr:more-vert"
- title="$i18n{activityLogMoreActionsLabel}"
- on-click="onMoreActionsClick_"></cr-icon-button>
- <cr-action-menu>
- <button id="expand-all-button" class="dropdown-item"
- on-click="onExpandAllClick_">
- $i18n{activityLogExpandAll}
- </button>
- <button id="collapse-all-button" class="dropdown-item"
- on-click="onCollapseAllClick_">
- $i18n{activityLogCollapseAll}
- </button>
- <button id="export-button" class="dropdown-item"
- on-click="onExportClick_">
- $i18n{activityLogExportHistory}
- </button>
- </cr-action-menu>
- </div>
- <div id="loading-activities" class="activity-message"
- hidden$="[[!shouldShowLoadingMessage_(
- pageState_)]]">
- <span>$i18n{loadingActivities}</span>
- </div>
- <div id="no-activities" class="activity-message"
- hidden$="[[!shouldShowEmptyActivityLogMessage_(
- pageState_, activityData_)]]">
- <span>$i18n{noActivities}</span>
- </div>
- <div class="activity-table-headings"
- hidden$="[[!shouldShowActivities_(pageState_, activityData_)]]">
- <span id="activity-type">$i18n{activityLogTypeColumn}</span>
- <span id="activity-key">$i18n{activityLogNameColumn}</span>
- <span id="activity-count">$i18n{activityLogCountColumn}</span>
- </div>
- <div id="activity-list"
- hidden$="[[!shouldShowActivities_(pageState_, activityData_)]]">
- <template is="dom-repeat" items="[[activityData_]]">
- <activity-log-history-item data="[[item]]">
- </activity-log-history-item>
- </template>
- </div>
+ #activity-count {
+ flex: 0 var(--activity-count-width);
+ text-align: end;
+ }
+</style>
+<div class="activity-subpage-header">
+ <cr-search-field label="$i18n{activityLogSearchLabel}"
+ on-search-changed="onSearchChanged_">
+ </cr-search-field >
+ <cr-button class="clear-activities-button"
+ on-click="onClearActivitiesClick_">
+ $i18n{clearActivities}
+ </cr-button>
+ <cr-icon-button id="more-actions" iron-icon="cr:more-vert"
+ title="$i18n{activityLogMoreActionsLabel}"
+ on-click="onMoreActionsClick_"></cr-icon-button>
+ <cr-action-menu role-description="$i18n{menu}">
+ <button id="expand-all-button" class="dropdown-item"
+ on-click="onExpandAllClick_">
+ $i18n{activityLogExpandAll}
+ </button>
+ <button id="collapse-all-button" class="dropdown-item"
+ on-click="onCollapseAllClick_">
+ $i18n{activityLogCollapseAll}
+ </button>
+ <button id="export-button" class="dropdown-item"
+ on-click="onExportClick_">
+ $i18n{activityLogExportHistory}
+ </button>
+ </cr-action-menu>
+</div>
+<div id="loading-activities" class="activity-message"
+ hidden$="[[!shouldShowLoadingMessage_(
+ pageState_)]]">
+ <span>$i18n{loadingActivities}</span>
+</div>
+<div id="no-activities" class="activity-message"
+ hidden$="[[!shouldShowEmptyActivityLogMessage_(
+ pageState_, activityData_)]]">
+ <span>$i18n{noActivities}</span>
+</div>
+<div class="activity-table-headings"
+ hidden$="[[!shouldShowActivities_(pageState_, activityData_)]]">
+ <span id="activity-type">$i18n{activityLogTypeColumn}</span>
+ <span id="activity-key">$i18n{activityLogNameColumn}</span>
+ <span id="activity-count">$i18n{activityLogCountColumn}</span>
+</div>
+<div id="activity-list"
+ hidden$="[[!shouldShowActivities_(pageState_, activityData_)]]">
+ <template is="dom-repeat" items="[[activityData_]]">
+ <activity-log-history-item data="[[item]]">
+ </activity-log-history-item>
</template>
- <script src="activity_log_history.js"></script>
-</dom-module>
+</div>
diff --git a/chromium/chrome/browser/resources/extensions/activity_log/activity_log_history.js b/chromium/chrome/browser/resources/extensions/activity_log/activity_log_history.js
index fda97f585e2..a28281eaa9d 100644
--- a/chromium/chrome/browser/resources/extensions/activity_log/activity_log_history.js
+++ b/chromium/chrome/browser/resources/extensions/activity_log/activity_log_history.js
@@ -2,415 +2,422 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
-
+import 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.m.js';
+import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
+import 'chrome://resources/cr_elements/cr_search_field/cr_search_field.m.js';
+import '../shared_style.js';
+
+import {assert} from 'chrome://resources/js/assert.m.js';
+import {PromiseResolver} from 'chrome://resources/js/promise_resolver.m.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {ActivityGroup} from './activity_log_history_item.js';
+
+/**
+ * The different states the activity log page can be in. Initial state is
+ * LOADING because we call the activity log API whenever a user navigates to
+ * the page. LOADED is the state where the API call has returned a successful
+ * result.
+ * @enum {string}
+ */
+export const ActivityLogPageState = {
+ LOADING: 'loading',
+ LOADED: 'loaded'
+};
+
+/** @interface */
+export class ActivityLogDelegate {
/**
- * The different states the activity log page can be in. Initial state is
- * LOADING because we call the activity log API whenever a user navigates to
- * the page. LOADED is the state where the API call has returned a successful
- * result.
- * @enum {string}
+ * @param {string} extensionId
+ * @return {!Promise<!chrome.activityLogPrivate.ActivityResultSet>}
*/
- const ActivityLogPageState = {LOADING: 'loading', LOADED: 'loaded'};
-
- /** @interface */
- class ActivityLogDelegate {
- /**
- * @param {string} extensionId
- * @return {!Promise<!chrome.activityLogPrivate.ActivityResultSet>}
- */
- getExtensionActivityLog(extensionId) {}
-
- /**
- * @param {string} extensionId
- * @param {string} searchTerm
- * @return {!Promise<!chrome.activityLogPrivate.ActivityResultSet>}
- */
- getFilteredExtensionActivityLog(extensionId, searchTerm) {}
-
- /**
- * @param {!Array<string>} activityIds
- * @return {!Promise<void>}
- */
- deleteActivitiesById(activityIds) {}
-
- /**
- * @param {string} extensionId
- * @return {!Promise<void>}
- */
- deleteActivitiesFromExtension(extensionId) {}
-
- /**
- * @param {string} rawActivityData
- * @param {string} fileName
- */
- downloadActivities(rawActivityData, fileName) {}
- }
+ getExtensionActivityLog(extensionId) {}
/**
- * Content scripts activities do not have an API call, so we use the names of
- * the scripts executed (specified as a stringified JSON array in the args
- * field) as the keys for an activity group instead.
- * @private
- * @param {!chrome.activityLogPrivate.ExtensionActivity} activity
- * @return {!Array<string>}
+ * @param {string} extensionId
+ * @param {string} searchTerm
+ * @return {!Promise<!chrome.activityLogPrivate.ActivityResultSet>}
*/
- function getActivityGroupKeysForContentScript_(activity) {
- assert(
- activity.activityType ===
- chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT);
-
- if (!activity.args) {
- return [];
- }
-
- const parsedArgs = JSON.parse(activity.args);
- assert(Array.isArray(parsedArgs), 'Invalid API data.');
- return /** @type {!Array<string>} */ (parsedArgs);
- }
+ getFilteredExtensionActivityLog(extensionId, searchTerm) {}
/**
- * Web request activities can have extra information which describes what the
- * web request does in more detail than just the api_call. This information
- * is in activity.other.webRequest and we use this to generate more activity
- * group keys if possible.
- * @private
- * @param {!chrome.activityLogPrivate.ExtensionActivity} activity
- * @return {!Array<string>}
+ * @param {!Array<string>} activityIds
+ * @return {!Promise<void>}
*/
- function getActivityGroupKeysForWebRequest_(activity) {
- assert(
- activity.activityType ===
- chrome.activityLogPrivate.ExtensionActivityType.WEB_REQUEST);
-
- const apiCall = activity.apiCall;
- const other = activity.other;
+ deleteActivitiesById(activityIds) {}
- if (!other || !other.webRequest) {
- return [apiCall];
- }
+ /**
+ * @param {string} extensionId
+ * @return {!Promise<void>}
+ */
+ deleteActivitiesFromExtension(extensionId) {}
- const webRequest = /** @type {!Object} */ (JSON.parse(other.webRequest));
- assert(typeof webRequest === 'object', 'Invalid API data');
+ /**
+ * @param {string} rawActivityData
+ * @param {string} fileName
+ */
+ downloadActivities(rawActivityData, fileName) {}
+}
+
+/**
+ * Content scripts activities do not have an API call, so we use the names of
+ * the scripts executed (specified as a stringified JSON array in the args
+ * field) as the keys for an activity group instead.
+ * @private
+ * @param {!chrome.activityLogPrivate.ExtensionActivity} activity
+ * @return {!Array<string>}
+ */
+function getActivityGroupKeysForContentScript_(activity) {
+ assert(
+ activity.activityType ===
+ chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT);
+
+ if (!activity.args) {
+ return [];
+ }
- // If there is extra information in the other.webRequest object,
- // construct a group for each consisting of the API call and each object key
- // in other.webRequest. Otherwise we default to just the API call.
- return Object.keys(webRequest).length === 0 ?
- [apiCall] :
- Object.keys(webRequest).map(field => `${apiCall} (${field})`);
+ const parsedArgs = JSON.parse(activity.args);
+ assert(Array.isArray(parsedArgs), 'Invalid API data.');
+ return /** @type {!Array<string>} */ (parsedArgs);
+}
+
+/**
+ * Web request activities can have extra information which describes what the
+ * web request does in more detail than just the api_call. This information
+ * is in activity.other.webRequest and we use this to generate more activity
+ * group keys if possible.
+ * @private
+ * @param {!chrome.activityLogPrivate.ExtensionActivity} activity
+ * @return {!Array<string>}
+ */
+function getActivityGroupKeysForWebRequest_(activity) {
+ assert(
+ activity.activityType ===
+ chrome.activityLogPrivate.ExtensionActivityType.WEB_REQUEST);
+
+ const apiCall = activity.apiCall;
+ const other = activity.other;
+
+ if (!other || !other.webRequest) {
+ return [apiCall];
}
- /**
- * Group activity log entries by a key determined from each entry. Usually
- * this would be the activity's API call though content script and web
- * requests have different keys. We currently assume that every API call
- * matches to one activity type.
- * @param {!Array<!chrome.activityLogPrivate.ExtensionActivity>}
- * activityData
- * @return {!Map<string, !extensions.ActivityGroup>}
- */
- function groupActivities(activityData) {
- const groupedActivities = new Map();
-
- for (const activity of activityData) {
- const activityId = activity.activityId;
- const activityType = activity.activityType;
- const count = activity.count;
- const pageUrl = activity.pageUrl;
-
- const isContentScript = activityType ===
- chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT;
- const isWebRequest = activityType ===
- chrome.activityLogPrivate.ExtensionActivityType.WEB_REQUEST;
-
- let activityGroupKeys = [activity.apiCall];
- if (isContentScript) {
- activityGroupKeys = getActivityGroupKeysForContentScript_(activity);
- } else if (isWebRequest) {
- activityGroupKeys = getActivityGroupKeysForWebRequest_(activity);
- }
+ const webRequest = /** @type {!Object} */ (JSON.parse(other.webRequest));
+ assert(typeof webRequest === 'object', 'Invalid API data');
+
+ // If there is extra information in the other.webRequest object,
+ // construct a group for each consisting of the API call and each object key
+ // in other.webRequest. Otherwise we default to just the API call.
+ return Object.keys(webRequest).length === 0 ?
+ [apiCall] :
+ Object.keys(webRequest).map(field => `${apiCall} (${field})`);
+}
+
+/**
+ * Group activity log entries by a key determined from each entry. Usually
+ * this would be the activity's API call though content script and web
+ * requests have different keys. We currently assume that every API call
+ * matches to one activity type.
+ * @param {!Array<!chrome.activityLogPrivate.ExtensionActivity>}
+ * activityData
+ * @return {!Map<string, !ActivityGroup>}
+ */
+function groupActivities(activityData) {
+ const groupedActivities = new Map();
+
+ for (const activity of activityData) {
+ const activityId = activity.activityId;
+ const activityType = activity.activityType;
+ const count = activity.count;
+ const pageUrl = activity.pageUrl;
+
+ const isContentScript = activityType ===
+ chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT;
+ const isWebRequest = activityType ===
+ chrome.activityLogPrivate.ExtensionActivityType.WEB_REQUEST;
+
+ let activityGroupKeys = [activity.apiCall];
+ if (isContentScript) {
+ activityGroupKeys = getActivityGroupKeysForContentScript_(activity);
+ } else if (isWebRequest) {
+ activityGroupKeys = getActivityGroupKeysForWebRequest_(activity);
+ }
- for (const key of activityGroupKeys) {
- if (!groupedActivities.has(key)) {
- const activityGroup = {
- activityIds: new Set([activityId]),
- key,
- count,
- activityType,
- countsByUrl: pageUrl ? new Map([[pageUrl, count]]) : new Map(),
- expanded: false,
- };
- groupedActivities.set(key, activityGroup);
- } else {
- const activityGroup = groupedActivities.get(key);
- activityGroup.activityIds.add(activityId);
- activityGroup.count += count;
-
- if (pageUrl) {
- const currentCount = activityGroup.countsByUrl.get(pageUrl) || 0;
- activityGroup.countsByUrl.set(pageUrl, currentCount + count);
- }
+ for (const key of activityGroupKeys) {
+ if (!groupedActivities.has(key)) {
+ const activityGroup = {
+ activityIds: new Set([activityId]),
+ key,
+ count,
+ activityType,
+ countsByUrl: pageUrl ? new Map([[pageUrl, count]]) : new Map(),
+ expanded: false,
+ };
+ groupedActivities.set(key, activityGroup);
+ } else {
+ const activityGroup = groupedActivities.get(key);
+ activityGroup.activityIds.add(activityId);
+ activityGroup.count += count;
+
+ if (pageUrl) {
+ const currentCount = activityGroup.countsByUrl.get(pageUrl) || 0;
+ activityGroup.countsByUrl.set(pageUrl, currentCount + count);
}
}
}
-
- return groupedActivities;
}
- /**
- * Sort activities by the total count for each activity group key. Resolve
- * ties by the alphabetical order of the key.
- * @param {!Map<string, !extensions.ActivityGroup>} groupedActivities
- * @return {!Array<!extensions.ActivityGroup>}
- */
- function sortActivitiesByCallCount(groupedActivities) {
- return Array.from(groupedActivities.values()).sort((a, b) => {
- if (a.count != b.count) {
- return b.count - a.count;
- }
- if (a.key < b.key) {
- return -1;
- }
- if (a.key > b.key) {
- return 1;
- }
- return 0;
- });
- }
+ return groupedActivities;
+}
+
+/**
+ * Sort activities by the total count for each activity group key. Resolve
+ * ties by the alphabetical order of the key.
+ * @param {!Map<string, !ActivityGroup>} groupedActivities
+ * @return {!Array<!ActivityGroup>}
+ */
+function sortActivitiesByCallCount(groupedActivities) {
+ return Array.from(groupedActivities.values()).sort((a, b) => {
+ if (a.count != b.count) {
+ return b.count - a.count;
+ }
+ if (a.key < b.key) {
+ return -1;
+ }
+ if (a.key > b.key) {
+ return 1;
+ }
+ return 0;
+ });
+}
- const ActivityLogHistory = Polymer({
- is: 'activity-log-history',
-
- properties: {
- /** @type {!string} */
- extensionId: String,
-
- /** @type {!extensions.ActivityLogDelegate} */
- delegate: Object,
-
- /**
- * An array representing the activity log. Stores activities grouped by
- * API call or content script name sorted in descending order of the call
- * count.
- * @private {!Array<!extensions.ActivityGroup>}
- */
- activityData_: {
- type: Array,
- value: () => [],
- },
-
- /** @private {extensions.ActivityLogPageState} */
- pageState_: {
- type: String,
- value: ActivityLogPageState.LOADING,
- },
-
- /** @private */
- lastSearch_: {
- type: String,
- value: '',
- },
- },
+Polymer({
+ is: 'activity-log-history',
- listeners: {
- 'delete-activity-log-item': 'deleteItem_',
- },
+ _template: html`{__html_template__}`,
- /**
- * A promise resolver for any external files waiting for the
- * GetExtensionActivity API call to finish.
- * Currently only used for extension_settings_browsertest.cc
- * @private {PromiseResolver}
- */
- dataFetchedResolver_: null,
+ properties: {
+ /** @type {!string} */
+ extensionId: String,
- /**
- * The stringified API response from the activityLogPrivate API with
- * individual activities sorted in ascending order by timestamp; used for
- * exporting the activity log.
- * @private {string}
- */
- rawActivities_: '',
+ /** @type {!ActivityLogDelegate} */
+ delegate: Object,
/**
- * Expose only the promise of dataFetchedResolver_.
- * @return {!Promise<void>}
+ * An array representing the activity log. Stores activities grouped by
+ * API call or content script name sorted in descending order of the call
+ * count.
+ * @private {!Array<!ActivityGroup>}
*/
- whenDataFetched: function() {
- return this.dataFetchedResolver_.promise;
+ activityData_: {
+ type: Array,
+ value: () => [],
},
- /** @override */
- attached: function() {
- this.dataFetchedResolver_ = new PromiseResolver();
- this.refreshActivities_();
+ /** @private {ActivityLogPageState} */
+ pageState_: {
+ type: String,
+ value: ActivityLogPageState.LOADING,
},
- /**
- * @private
- * @return {boolean}
- */
- shouldShowEmptyActivityLogMessage_: function() {
- return this.pageState_ === ActivityLogPageState.LOADED &&
- this.activityData_.length === 0;
+ /** @private */
+ lastSearch_: {
+ type: String,
+ value: '',
},
+ },
- /**
- * @private
- * @return {boolean}
- */
- shouldShowLoadingMessage_: function() {
- return this.pageState_ === ActivityLogPageState.LOADING;
- },
+ listeners: {
+ 'delete-activity-log-item': 'deleteItem_',
+ },
- /**
- * @private
- * @return {boolean}
- */
- shouldShowActivities_: function() {
- return this.pageState_ === ActivityLogPageState.LOADED &&
- this.activityData_.length > 0;
- },
+ /**
+ * A promise resolver for any external files waiting for the
+ * GetExtensionActivity API call to finish.
+ * Currently only used for extension_settings_browsertest.cc
+ * @private {PromiseResolver}
+ */
+ dataFetchedResolver_: null,
- /** @private */
- onClearActivitiesClick_: function() {
- this.delegate.deleteActivitiesFromExtension(this.extensionId).then(() => {
- this.processActivities_([]);
- });
- },
+ /**
+ * The stringified API response from the activityLogPrivate API with
+ * individual activities sorted in ascending order by timestamp; used for
+ * exporting the activity log.
+ * @private {string}
+ */
+ rawActivities_: '',
- /** @private */
- onMoreActionsClick_: function() {
- this.$$('cr-action-menu').showAt(assert(this.$$('cr-icon-button')));
- },
+ /**
+ * Expose only the promise of dataFetchedResolver_.
+ * @return {!Promise<void>}
+ */
+ whenDataFetched: function() {
+ return this.dataFetchedResolver_.promise;
+ },
- /**
- * @private
- * @param {boolean} expanded
- */
- expandItems_: function(expanded) {
- // Do not use .filter here as we need the original index of the item
- // in |activityData_|.
- this.activityData_.forEach((item, index) => {
- if (item.countsByUrl.size > 0) {
- this.set(`activityData_.${index}.expanded`, expanded);
- }
- });
- this.$$('cr-action-menu').close();
- },
+ /** @override */
+ attached: function() {
+ this.dataFetchedResolver_ = new PromiseResolver();
+ this.refreshActivities_();
+ },
- /** @private */
- onExpandAllClick_: function() {
- this.expandItems_(true);
- },
+ /**
+ * @private
+ * @return {boolean}
+ */
+ shouldShowEmptyActivityLogMessage_: function() {
+ return this.pageState_ === ActivityLogPageState.LOADED &&
+ this.activityData_.length === 0;
+ },
- /** @private */
- onCollapseAllClick_: function() {
- this.expandItems_(false);
- },
+ /**
+ * @private
+ * @return {boolean}
+ */
+ shouldShowLoadingMessage_: function() {
+ return this.pageState_ === ActivityLogPageState.LOADING;
+ },
- /** @private */
- onExportClick_: function() {
- const fileName = `exported_activity_log_${this.extensionId}.json`;
- this.delegate.downloadActivities(this.rawActivities_, fileName);
- },
+ /**
+ * @private
+ * @return {boolean}
+ */
+ shouldShowActivities_: function() {
+ return this.pageState_ === ActivityLogPageState.LOADED &&
+ this.activityData_.length > 0;
+ },
+
+ /** @private */
+ onClearActivitiesClick_: function() {
+ this.delegate.deleteActivitiesFromExtension(this.extensionId).then(() => {
+ this.processActivities_([]);
+ });
+ },
- /**
- * @private
- * @param {!CustomEvent<!Array<string>>} e
- */
- deleteItem_: function(e) {
- const activityIds = e.detail;
- this.delegate.deleteActivitiesById(activityIds).then(() => {
- // It is possible for multiple activities displayed to have the same
- // underlying activity ID. This happens when we split content script and
- // web request activities by fields other than their API call. For
- // consistency, we will re-fetch the activity log.
- this.refreshActivities_();
- });
- },
+ /** @private */
+ onMoreActionsClick_: function() {
+ this.$$('cr-action-menu').showAt(assert(this.$$('cr-icon-button')));
+ },
- /**
- * @private
- * @param {!Array<!chrome.activityLogPrivate.ExtensionActivity>}
- * activityData
- */
- processActivities_: function(activityData) {
- this.pageState_ = ActivityLogPageState.LOADED;
-
- // Sort |activityData| in ascending order based on the activity's
- // timestamp; Used for |this.encodedRawActivities|.
- activityData.sort((a, b) => a.time - b.time);
- this.rawActivities_ = JSON.stringify(activityData);
-
- this.activityData_ =
- sortActivitiesByCallCount(groupActivities(activityData));
- if (!this.dataFetchedResolver_.isFulfilled) {
- this.dataFetchedResolver_.resolve();
+ /**
+ * @private
+ * @param {boolean} expanded
+ */
+ expandItems_: function(expanded) {
+ // Do not use .filter here as we need the original index of the item
+ // in |activityData_|.
+ this.activityData_.forEach((item, index) => {
+ if (item.countsByUrl.size > 0) {
+ this.set(`activityData_.${index}.expanded`, expanded);
}
- },
+ });
+ this.$$('cr-action-menu').close();
+ },
- /**
- * @private
- * @return {!Promise<void>}
- */
- refreshActivities_: function() {
- if (this.lastSearch_ === '') {
- return this.getActivityLog_();
- }
+ /** @private */
+ onExpandAllClick_: function() {
+ this.expandItems_(true);
+ },
- return this.getFilteredActivityLog_(this.lastSearch_);
- },
+ /** @private */
+ onCollapseAllClick_: function() {
+ this.expandItems_(false);
+ },
- /**
- * @private
- * @return {!Promise<void>}
- */
- getActivityLog_: function() {
- this.pageState_ = ActivityLogPageState.LOADING;
- return this.delegate.getExtensionActivityLog(this.extensionId)
- .then(result => {
- this.processActivities_(result.activities);
- });
- },
+ /** @private */
+ onExportClick_: function() {
+ const fileName = `exported_activity_log_${this.extensionId}.json`;
+ this.delegate.downloadActivities(this.rawActivities_, fileName);
+ },
- /**
- * @private
- * @param {string} searchTerm
- * @return {!Promise<void>}
- */
- getFilteredActivityLog_: function(searchTerm) {
- this.pageState_ = ActivityLogPageState.LOADING;
- return this.delegate
- .getFilteredExtensionActivityLog(this.extensionId, searchTerm)
- .then(result => {
- this.processActivities_(result.activities);
- });
- },
+ /**
+ * @private
+ * @param {!CustomEvent<!Array<string>>} e
+ */
+ deleteItem_: function(e) {
+ const activityIds = e.detail;
+ this.delegate.deleteActivitiesById(activityIds).then(() => {
+ // It is possible for multiple activities displayed to have the same
+ // underlying activity ID. This happens when we split content script and
+ // web request activities by fields other than their API call. For
+ // consistency, we will re-fetch the activity log.
+ this.refreshActivities_();
+ });
+ },
- /**
- * @private
- * @param {!CustomEvent<string>} e
- */
- onSearchChanged_: function(e) {
- // Remove all whitespaces from the search term, as API call names and
- // urls should not contain any whitespace. As of now, only single term
- // search queries are allowed.
- const searchTerm = e.detail.replace(/\s+/g, '');
- if (searchTerm === this.lastSearch_) {
- return;
- }
+ /**
+ * @private
+ * @param {!Array<!chrome.activityLogPrivate.ExtensionActivity>}
+ * activityData
+ */
+ processActivities_: function(activityData) {
+ this.pageState_ = ActivityLogPageState.LOADED;
+
+ // Sort |activityData| in ascending order based on the activity's
+ // timestamp; Used for |this.encodedRawActivities|.
+ activityData.sort((a, b) => a.time - b.time);
+ this.rawActivities_ = JSON.stringify(activityData);
+
+ this.activityData_ =
+ sortActivitiesByCallCount(groupActivities(activityData));
+ if (!this.dataFetchedResolver_.isFulfilled) {
+ this.dataFetchedResolver_.resolve();
+ }
+ },
- this.lastSearch_ = searchTerm;
- this.refreshActivities_();
- },
- });
+ /**
+ * @private
+ * @return {!Promise<void>}
+ */
+ refreshActivities_: function() {
+ if (this.lastSearch_ === '') {
+ return this.getActivityLog_();
+ }
+
+ return this.getFilteredActivityLog_(this.lastSearch_);
+ },
+
+ /**
+ * @private
+ * @return {!Promise<void>}
+ */
+ getActivityLog_: function() {
+ this.pageState_ = ActivityLogPageState.LOADING;
+ return this.delegate.getExtensionActivityLog(this.extensionId)
+ .then(result => {
+ this.processActivities_(result.activities);
+ });
+ },
+
+ /**
+ * @private
+ * @param {string} searchTerm
+ * @return {!Promise<void>}
+ */
+ getFilteredActivityLog_: function(searchTerm) {
+ this.pageState_ = ActivityLogPageState.LOADING;
+ return this.delegate
+ .getFilteredExtensionActivityLog(this.extensionId, searchTerm)
+ .then(result => {
+ this.processActivities_(result.activities);
+ });
+ },
+
+ /**
+ * @private
+ * @param {!CustomEvent<string>} e
+ */
+ onSearchChanged_: function(e) {
+ // Remove all whitespaces from the search term, as API call names and
+ // urls should not contain any whitespace. As of now, only single term
+ // search queries are allowed.
+ const searchTerm = e.detail.replace(/\s+/g, '');
+ if (searchTerm === this.lastSearch_) {
+ return;
+ }
- return {
- ActivityLogDelegate: ActivityLogDelegate,
- ActivityLogHistory: ActivityLogHistory,
- ActivityLogPageState: ActivityLogPageState,
- };
+ this.lastSearch_ = searchTerm;
+ this.refreshActivities_();
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/activity_log/activity_log_history_item.html b/chromium/chrome/browser/resources/extensions/activity_log/activity_log_history_item.html
index 5ed47ab1996..2315557edd3 100644
--- a/chromium/chrome/browser/resources/extensions/activity_log/activity_log_history_item.html
+++ b/chromium/chrome/browser/resources/extensions/activity_log/activity_log_history_item.html
@@ -1,117 +1,102 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="cr-icons cr-shared-style shared-style">
+ :host {
+ border-top: var(--cr-separator-line);
+ display: block;
+ /* Unequal padding on left/right side as the cr-icon-button's width is
+ * greater than the delete icon's width. */
+ padding-bottom: 8px;
+ padding-inline-end: 8px;
+ padding-inline-start: var(--cr-section-padding);
+ padding-top: 8px;
+ }
-<link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
-<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="../shared_style.html">
-<link rel="import" href="../shared_vars.html">
+ #activity-item-main-row {
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ /* Match separator height. */
+ min-height: calc(var(--cr-section-min-height) - var(--separator-gap));
+ }
-<dom-module id="activity-log-history-item">
- <template>
- <style include="cr-icons cr-shared-style shared-style">
- :host {
- border-top: var(--cr-separator-line);
- display: block;
- /* Unequal padding on left/right side as the cr-icon-button's width is
- * greater than the delete icon's width. */
- padding-bottom: 8px;
- padding-inline-end: 8px;
- padding-inline-start: var(--cr-section-padding);
- padding-top: 8px;
- }
+ #activity-item-main-row .separator {
+ margin: 0 calc(
+ var(--cr-section-padding) + var(--cr-icon-ripple-margin));
+ }
- #activity-item-main-row {
- align-items: center;
- display: flex;
- flex-direction: row;
- /* Match separator height. */
- min-height: calc(var(--cr-section-min-height) - var(--separator-gap));
- }
+ #activity-item-main-row cr-expand-button {
+ margin-inline-end: 6px;
+ }
- #activity-item-main-row .separator {
- margin: 0 calc(
- var(--cr-section-padding) + var(--cr-icon-ripple-margin));
- }
+ #activity-call-and-count {
+ display: flex;
+ flex: 1;
+ flex-direction: row;
+ margin-inline-end: auto;
+ max-width: var(--activity-log-call-and-count-width);
+ }
- #activity-item-main-row cr-expand-button {
- margin-inline-end: 6px;
- }
+ #activity-delete {
+ margin: 0;
+ }
- #activity-call-and-count {
- display: flex;
- flex: 1;
- flex-direction: row;
- margin-inline-end: auto;
- max-width: var(--activity-log-call-and-count-width);
- }
+ #activity-type {
+ flex: 0 var(--activity-type-width);
+ }
- #activity-delete {
- margin: 0;
- }
+ #activity-key {
+ flex: 1;
+ margin-inline-start: 10px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
- #activity-type {
- flex: 0 var(--activity-type-width);
- }
+ #activity-count {
+ flex: 0 var(--activity-count-width);
+ text-align: end;
+ }
- #activity-key {
- flex: 1;
- margin-inline-start: 10px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
+ .page-url {
+ display: flex;
+ flex-direction: row;
+ margin-bottom: 10px;
+ max-width: var(--activity-log-call-and-count-width);
+ }
- #activity-count {
- flex: 0 var(--activity-count-width);
- text-align: end;
- }
-
- .page-url {
- display: flex;
- flex-direction: row;
- margin-bottom: 10px;
- max-width: var(--activity-log-call-and-count-width);
- }
-
- .page-url-link {
- flex-grow: 1;
- margin-inline-end: 20px;
- margin-inline-start: 16px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
- </style>
- <div actionable$="[[isExpandable_]]"
- id="activity-item-main-row"
- on-click="onExpandTap_">
- <div id="activity-call-and-count">
- <span id="activity-type">[[data.activityType]]</span>
- <span id="activity-key" title="[[data.key]]">[[data.key]]</span>
- <span id="activity-count">[[data.count]]</span>
- </div>
- <cr-expand-button expanded="{{data.expanded}}"
- hidden$="[[!isExpandable_]]">
- </cr-expand-button>
- <div class="separator" hidden$="[[!isExpandable_]]"></div>
- <cr-icon-button id="activity-delete" class="icon-delete-gray"
- aria-describedby="api-call" aria-label="$i18n{clearEntry}"
- on-click="onDeleteTap_"></cr-icon-button>
- </div>
- <div id="page-url-list" hidden$="[[!data.expanded]]">
- <template is="dom-repeat" items="[[getPageUrls_(data)]]">
- <div class="page-url">
- <a class="page-url-link" href="[[item.page]]" target="_blank"
- title="[[item.page]]">[[item.page]]</a>
- <span class="page-url-count"
- hidden$="[[!shouldShowPageUrlCount_(data)]]">
- [[item.count]]
- </span>
- </div>
- </template>
+ .page-url-link {
+ flex-grow: 1;
+ margin-inline-end: 20px;
+ margin-inline-start: 16px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+</style>
+<div actionable$="[[isExpandable_]]"
+ id="activity-item-main-row"
+ on-click="onExpandTap_">
+ <div id="activity-call-and-count">
+ <span id="activity-type">[[data.activityType]]</span>
+ <span id="activity-key" title="[[data.key]]">[[data.key]]</span>
+ <span id="activity-count">[[data.count]]</span>
+ </div>
+ <cr-expand-button expanded="{{data.expanded}}"
+ hidden$="[[!isExpandable_]]">
+ </cr-expand-button>
+ <div class="separator" hidden$="[[!isExpandable_]]"></div>
+ <cr-icon-button id="activity-delete" class="icon-delete-gray"
+ aria-describedby="api-call" aria-label="$i18n{clearEntry}"
+ on-click="onDeleteTap_"></cr-icon-button>
+</div>
+<div id="page-url-list" hidden$="[[!data.expanded]]">
+ <template is="dom-repeat" items="[[getPageUrls_(data)]]">
+ <div class="page-url">
+ <a class="page-url-link" href="[[item.page]]" target="_blank"
+ title="[[item.page]]">[[item.page]]</a>
+ <span class="page-url-count"
+ hidden$="[[!shouldShowPageUrlCount_(data)]]">
+ [[item.count]]
+ </span>
</div>
</template>
- <script src="activity_log_history_item.js"></script>
-</dom-module>
+</div>
diff --git a/chromium/chrome/browser/resources/extensions/activity_log/activity_log_history_item.js b/chromium/chrome/browser/resources/extensions/activity_log/activity_log_history_item.js
index f91b27f95e4..1ed2d728fcd 100644
--- a/chromium/chrome/browser/resources/extensions/activity_log/activity_log_history_item.js
+++ b/chromium/chrome/browser/resources/extensions/activity_log/activity_log_history_item.js
@@ -2,103 +2,104 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
+import 'chrome://resources/cr_elements/cr_expand_button/cr_expand_button.m.js';
+import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
+import 'chrome://resources/cr_elements/cr_icons_css.m.js';
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+import '../shared_style.js';
+import '../shared_vars.js';
- /**
- * @typedef {{
- * activityIds: !Set<string>,
- * key: string,
- * count: number,
- * activityType: !chrome.activityLogPrivate.ExtensionActivityFilter,
- * countsByUrl: !Map<string, number>,
- * expanded: boolean
- * }}
- */
- let ActivityGroup;
-
- /**
- * A struct used to describe each url and its associated counts. The id is
- * unique for each item in the list of URLs and is used for the tooltip.
- * @typedef {{
- * page: string,
- * count: number
- * }}
- */
- let PageUrlItem;
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
- const ActivityLogHistoryItem = Polymer({
- is: 'activity-log-history-item',
+/**
+ * @typedef {{
+ * activityIds: !Set<string>,
+ * key: string,
+ * count: number,
+ * activityType: !chrome.activityLogPrivate.ExtensionActivityFilter,
+ * countsByUrl: !Map<string, number>,
+ * expanded: boolean
+ * }}
+ */
+export let ActivityGroup;
- properties: {
- /**
- * The underlying ActivityGroup that provides data for the
- * ActivityLogItem displayed.
- * @type {!extensions.ActivityGroup}
- */
- data: Object,
+/**
+ * A struct used to describe each url and its associated counts. The id is
+ * unique for each item in the list of URLs and is used for the tooltip.
+ * @typedef {{
+ * page: string,
+ * count: number
+ * }}
+ */
+let PageUrlItem;
- /** @private */
- isExpandable_: {
- type: Boolean,
- computed: 'computeIsExpandable_(data.countsByUrl)',
- },
- },
+Polymer({
+ is: 'activity-log-history-item',
- /**
- * @private
- * @return {boolean}
- */
- computeIsExpandable_: function() {
- return this.data.countsByUrl.size > 0;
- },
+ _template: html`{__html_template__}`,
+ properties: {
/**
- * Sort the page URLs by the number of times it was associated with the key
- * for this ActivityGroup (API call or content script invocation.) Resolve
- * ties by the alphabetical order of the page URL.
- * @private
- * @return {!Array<PageUrlItem>}
+ * The underlying ActivityGroup that provides data for the
+ * ActivityLogItem displayed.
+ * @type {!ActivityGroup}
*/
- getPageUrls_: function() {
- return Array.from(this.data.countsByUrl.entries())
- .map(e => ({page: e[0], count: e[1]}))
- .sort(function(a, b) {
- if (a.count != b.count) {
- return b.count - a.count;
- }
- return a.page < b.page ? -1 : (a.page > b.page ? 1 : 0);
- });
- },
+ data: Object,
/** @private */
- onDeleteTap_: function(e) {
- e.stopPropagation();
- this.fire(
- 'delete-activity-log-item',
- Array.from(this.data.activityIds.values()));
+ isExpandable_: {
+ type: Boolean,
+ computed: 'computeIsExpandable_(data.countsByUrl)',
},
+ },
- /** @private */
- onExpandTap_: function() {
- if (this.isExpandable_) {
- this.set('data.expanded', !this.data.expanded);
- }
- },
+ /**
+ * @private
+ * @return {boolean}
+ */
+ computeIsExpandable_: function() {
+ return this.data.countsByUrl.size > 0;
+ },
- /**
- * Show the call count for a particular page URL if more than one page
- * URL is associated with the key for this ActivityGroup.
- * @private
- * @return {boolean}
- */
- shouldShowPageUrlCount_: function() {
- return this.data.countsByUrl.size > 1;
- },
- });
+ /**
+ * Sort the page URLs by the number of times it was associated with the key
+ * for this ActivityGroup (API call or content script invocation.) Resolve
+ * ties by the alphabetical order of the page URL.
+ * @private
+ * @return {!Array<PageUrlItem>}
+ */
+ getPageUrls_: function() {
+ return Array.from(this.data.countsByUrl.entries())
+ .map(e => ({page: e[0], count: e[1]}))
+ .sort(function(a, b) {
+ if (a.count != b.count) {
+ return b.count - a.count;
+ }
+ return a.page < b.page ? -1 : (a.page > b.page ? 1 : 0);
+ });
+ },
+
+ /** @private */
+ onDeleteTap_: function(e) {
+ e.stopPropagation();
+ this.fire(
+ 'delete-activity-log-item', Array.from(this.data.activityIds.values()));
+ },
+
+ /** @private */
+ onExpandTap_: function() {
+ if (this.isExpandable_) {
+ this.set('data.expanded', !this.data.expanded);
+ }
+ },
- return {
- ActivityLogHistoryItem: ActivityLogHistoryItem,
- ActivityGroup: ActivityGroup,
- };
+ /**
+ * Show the call count for a particular page URL if more than one page
+ * URL is associated with the key for this ActivityGroup.
+ * @private
+ * @return {boolean}
+ */
+ shouldShowPageUrlCount_: function() {
+ return this.data.countsByUrl.size > 1;
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream.html b/chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream.html
index 0d78032b425..fdeef54f4de 100644
--- a/chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream.html
+++ b/chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream.html
@@ -1,92 +1,78 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="shared-style">
+ :host {
+ --activity-log-call-and-time-width: 575px;
+ --activity-type-width: 85px;
+ --activity-time-width: 100px;
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_search_field/cr_search_field.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html">
-<link rel="import" href="activity_log_stream_item.html">
-<link rel="import" href="../shared_style.html">
+ display: flex;
+ flex-direction: column;
+ }
-<dom-module id="activity-log-stream">
- <template>
- <style include="shared-style">
- :host {
- --activity-log-call-and-time-width: 575px;
- --activity-type-width: 85px;
- --activity-time-width: 100px;
-
- display: flex;
- flex-direction: column;
- }
+ cr-search-field {
+ align-self: center;
+ margin-inline-end: auto;
+ }
- cr-search-field {
- align-self: center;
- margin-inline-end: auto;
- }
+ .activity-table-headings {
+ width: var(--activity-log-call-and-time-width);
+ }
- .activity-table-headings {
- width: var(--activity-log-call-and-time-width);
- }
+ #activity-type {
+ flex: 0 var(--activity-type-width);
+ }
- #activity-type {
- flex: 0 var(--activity-type-width);
- }
+ #activity-key {
+ flex: 1;
+ margin-inline-start: 10px;
+ }
- #activity-key {
- flex: 1;
- margin-inline-start: 10px;
- }
+ #activity-time {
+ flex: 0 var(--activity-time-width);
+ text-align: end;
+ }
- #activity-time {
- flex: 0 var(--activity-time-width);
- text-align: end;
- }
-
- iron-list {
- flex: 1;
- }
- </style>
- <div class="activity-subpage-header">
- <cr-search-field label="$i18n{activityLogSearchLabel}"
- on-search-changed="onSearchChanged_">
- </cr-search-field >
- <cr-button id="toggle-stream-button" on-click="onToggleButtonClick_">
- <span hidden$="[[isStreamOn_]]">
- $i18n{startActivityStream}
- </span>
- <span hidden$="[[!isStreamOn_]]">
- $i18n{stopActivityStream}
- </span>
- </cr-button>
- <cr-button class="clear-activities-button" on-click="clearStream">
- $i18n{clearActivities}
- </cr-button>
- </div>
- <div id="empty-stream-message" class="activity-message"
- hidden$="[[!isStreamEmpty_(activityStream_.length)]]">
- <span id="stream-stopped-message" hidden$="[[isStreamOn_]]">
- $i18n{emptyStreamStopped}
- </span>
- <span id="stream-started-message" hidden$="[[!isStreamOn_]]">
- $i18n{emptyStreamStarted}
- </span>
- </div>
- <div id="empty-search-message" class="activity-message"
- hidden$="[[!shouldShowEmptySearchMessage_(
- activityStream_.length, filteredActivityStream_.length)]]">
- $i18n{noSearchResults}
- </div>
- <div class="activity-table-headings"
- hidden$="[[isFilteredStreamEmpty_(filteredActivityStream_.length)]]">
- <span id="activity-type">$i18n{activityLogTypeColumn}</span>
- <span id="activity-key">$i18n{activityLogNameColumn}</span>
- <span id="activity-time">$i18n{activityLogTimeColumn}</span>
- </div>
- <iron-list items="[[filteredActivityStream_]]">
- <template>
- <activity-log-stream-item data="[[item]]"></activity-log-stream-item>
- </template>
- </iron-list>
+ iron-list {
+ flex: 1;
+ }
+</style>
+<div class="activity-subpage-header">
+ <cr-search-field label="$i18n{activityLogSearchLabel}"
+ on-search-changed="onSearchChanged_">
+ </cr-search-field >
+ <cr-button id="toggle-stream-button" on-click="onToggleButtonClick_">
+ <span hidden$="[[isStreamOn_]]">
+ $i18n{startActivityStream}
+ </span>
+ <span hidden$="[[!isStreamOn_]]">
+ $i18n{stopActivityStream}
+ </span>
+ </cr-button>
+ <cr-button class="clear-activities-button" on-click="clearStream">
+ $i18n{clearActivities}
+ </cr-button>
+</div>
+<div id="empty-stream-message" class="activity-message"
+ hidden$="[[!isStreamEmpty_(activityStream_.length)]]">
+ <span id="stream-stopped-message" hidden$="[[isStreamOn_]]">
+ $i18n{emptyStreamStopped}
+ </span>
+ <span id="stream-started-message" hidden$="[[!isStreamOn_]]">
+ $i18n{emptyStreamStarted}
+ </span>
+</div>
+<div id="empty-search-message" class="activity-message"
+ hidden$="[[!shouldShowEmptySearchMessage_(
+ activityStream_.length, filteredActivityStream_.length)]]">
+ $i18n{noSearchResults}
+</div>
+<div class="activity-table-headings"
+ hidden$="[[isFilteredStreamEmpty_(filteredActivityStream_.length)]]">
+ <span id="activity-type">$i18n{activityLogTypeColumn}</span>
+ <span id="activity-key">$i18n{activityLogNameColumn}</span>
+ <span id="activity-time">$i18n{activityLogTimeColumn}</span>
+</div>
+<iron-list items="[[filteredActivityStream_]]">
+ <template>
+ <activity-log-stream-item data="[[item]]"></activity-log-stream-item>
</template>
- <script src="activity_log_stream.js"></script>
-</dom-module>
+</iron-list>
diff --git a/chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream.js b/chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream.js
index 6d96a757375..7b74faf5714 100644
--- a/chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream.js
+++ b/chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream.js
@@ -2,230 +2,232 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
-
- /** @interface */
- class ActivityLogEventDelegate {
- /** @return {!ChromeEvent} */
- getOnExtensionActivity() {}
+import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import 'chrome://resources/cr_elements/cr_search_field/cr_search_field.m.js';
+import 'chrome://resources/polymer/v3_0/iron-list/iron-list.js';
+import '../shared_style.js';
+
+import {assert} from 'chrome://resources/js/assert.m.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {StreamArgItem, StreamItem} from './activity_log_stream_item.js';
+
+
+/** @interface */
+export class ActivityLogEventDelegate {
+ /** @return {!ChromeEvent} */
+ getOnExtensionActivity() {}
+}
+
+/**
+ * Process activity for the stream. In the case of content scripts, we split
+ * the activity for every script invoked.
+ * @param {!chrome.activityLogPrivate.ExtensionActivity}
+ * activity
+ * @return {!Array<!StreamItem>}
+ */
+function processActivityForStream(activity) {
+ const activityType = activity.activityType;
+ const timestamp = activity.time;
+ const isContentScript = activityType ===
+ chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT;
+
+ const args = isContentScript ? JSON.stringify([]) : activity.args;
+
+ let streamItemNames = [activity.apiCall];
+
+ // TODO(kelvinjiang): Reuse logic from activity_log_history and refactor
+ // some of the processing code into a separate file in a follow up CL.
+ if (isContentScript) {
+ streamItemNames = activity.args ? JSON.parse(activity.args) : [];
+ assert(Array.isArray(streamItemNames), 'Invalid data for script names.');
}
- /**
- * Process activity for the stream. In the case of content scripts, we split
- * the activity for every script invoked.
- * @param {!chrome.activityLogPrivate.ExtensionActivity}
- * activity
- * @return {!Array<!extensions.StreamItem>}
- */
- function processActivityForStream(activity) {
- const activityType = activity.activityType;
- const timestamp = activity.time;
- const isContentScript = activityType ===
- chrome.activityLogPrivate.ExtensionActivityType.CONTENT_SCRIPT;
+ const other = activity.other;
+ const webRequestInfo = other && other.webRequest;
- const args = isContentScript ? JSON.stringify([]) : activity.args;
+ return streamItemNames.map(name => ({
+ args,
+ argUrl: activity.argUrl,
+ activityType,
+ name,
+ pageUrl: activity.pageUrl,
+ timestamp,
+ webRequestInfo,
+ expanded: false,
+ }));
+}
- let streamItemNames = [activity.apiCall];
+Polymer({
+ is: 'activity-log-stream',
- // TODO(kelvinjiang): Reuse logic from activity_log_history and refactor
- // some of the processing code into a separate file in a follow up CL.
- if (isContentScript) {
- streamItemNames = activity.args ? JSON.parse(activity.args) : [];
- assert(Array.isArray(streamItemNames), 'Invalid data for script names.');
- }
+ _template: html`{__html_template__}`,
- const other = activity.other;
- const webRequestInfo = other && other.webRequest;
-
- return streamItemNames.map(name => ({
- args,
- argUrl: activity.argUrl,
- activityType,
- name,
- pageUrl: activity.pageUrl,
- timestamp,
- webRequestInfo,
- expanded: false,
- }));
- }
+ properties: {
+ /** @type {string} */
+ extensionId: String,
+
+ /** @type {!ActivityLogEventDelegate} */
+ delegate: Object,
- const ActivityLogStream = Polymer({
- is: 'activity-log-stream',
-
- properties: {
- /** @type {string} */
- extensionId: String,
-
- /** @type {!extensions.ActivityLogEventDelegate} */
- delegate: Object,
-
- /** @private */
- isStreamOn_: {
- type: Boolean,
- value: false,
- },
-
- /** @private {!Array<!extensions.StreamItem>} */
- activityStream_: {
- type: Array,
- value: () => [],
- },
-
- /** @private {!Array<!extensions.StreamItem>} */
- filteredActivityStream_: {
- type: Array,
- computed:
- 'computeFilteredActivityStream_(activityStream_.*, lastSearch_)',
- },
-
- /** @private */
- lastSearch_: {
- type: String,
- value: '',
- },
+ /** @private */
+ isStreamOn_: {
+ type: Boolean,
+ value: false,
},
- listeners: {
- 'resize-stream': 'onResizeStream_',
+ /** @private {!Array<!StreamItem>} */
+ activityStream_: {
+ type: Array,
+ value: () => [],
},
- /**
- * Instance of |extensionActivityListener_| bound to |this|.
- * @private {!Function}
- */
- listenerInstance_: () => {},
-
- /** @override */
- attached: function() {
- // Since this component is not restamped, this will only be called once
- // in its lifecycle.
- this.listenerInstance_ = this.extensionActivityListener_.bind(this);
- this.startStream();
+ /** @private {!Array<!StreamItem>} */
+ filteredActivityStream_: {
+ type: Array,
+ computed:
+ 'computeFilteredActivityStream_(activityStream_.*, lastSearch_)',
},
/** @private */
- onResizeStream_: function(e) {
- this.$$('iron-list').notifyResize();
+ lastSearch_: {
+ type: String,
+ value: '',
},
+ },
- clearStream: function() {
- this.splice('activityStream_', 0, this.activityStream_.length);
- },
+ listeners: {
+ 'resize-stream': 'onResizeStream_',
+ },
- startStream: function() {
- if (this.isStreamOn_) {
- return;
- }
+ /**
+ * Instance of |extensionActivityListener_| bound to |this|.
+ * @private {!Function}
+ */
+ listenerInstance_: () => {},
+
+ /** @override */
+ attached: function() {
+ // Since this component is not restamped, this will only be called once
+ // in its lifecycle.
+ this.listenerInstance_ = this.extensionActivityListener_.bind(this);
+ this.startStream();
+ },
+
+ /** @private */
+ onResizeStream_: function(e) {
+ this.$$('iron-list').notifyResize();
+ },
+
+ clearStream: function() {
+ this.splice('activityStream_', 0, this.activityStream_.length);
+ },
+
+ startStream: function() {
+ if (this.isStreamOn_) {
+ return;
+ }
- this.isStreamOn_ = true;
- this.delegate.getOnExtensionActivity().addListener(
- this.listenerInstance_);
- },
+ this.isStreamOn_ = true;
+ this.delegate.getOnExtensionActivity().addListener(this.listenerInstance_);
+ },
- pauseStream: function() {
- if (!this.isStreamOn_) {
- return;
- }
+ pauseStream: function() {
+ if (!this.isStreamOn_) {
+ return;
+ }
- this.delegate.getOnExtensionActivity().removeListener(
- this.listenerInstance_);
- this.isStreamOn_ = false;
- },
+ this.delegate.getOnExtensionActivity().removeListener(
+ this.listenerInstance_);
+ this.isStreamOn_ = false;
+ },
- /** @private */
- onToggleButtonClick_: function() {
- if (this.isStreamOn_) {
- this.pauseStream();
- } else {
- this.startStream();
- }
- },
+ /** @private */
+ onToggleButtonClick_: function() {
+ if (this.isStreamOn_) {
+ this.pauseStream();
+ } else {
+ this.startStream();
+ }
+ },
- /**
- * @private
- * @return {boolean}
- */
- isStreamEmpty_: function() {
- return this.activityStream_.length == 0;
- },
+ /**
+ * @private
+ * @return {boolean}
+ */
+ isStreamEmpty_: function() {
+ return this.activityStream_.length == 0;
+ },
- /**
- * @private
- * @return {boolean}
- */
- isFilteredStreamEmpty_: function() {
- return this.filteredActivityStream_.length == 0;
- },
+ /**
+ * @private
+ * @return {boolean}
+ */
+ isFilteredStreamEmpty_: function() {
+ return this.filteredActivityStream_.length == 0;
+ },
- /**
- * @private
- * @return {boolean}
- */
- shouldShowEmptySearchMessage_: function() {
- return !this.isStreamEmpty_() && this.isFilteredStreamEmpty_();
- },
+ /**
+ * @private
+ * @return {boolean}
+ */
+ shouldShowEmptySearchMessage_: function() {
+ return !this.isStreamEmpty_() && this.isFilteredStreamEmpty_();
+ },
- /**
- * @private
- * @param {!chrome.activityLogPrivate.ExtensionActivity} activity
- */
- extensionActivityListener_: function(activity) {
- if (activity.extensionId != this.extensionId) {
- return;
- }
-
- this.splice(
- 'activityStream_', this.activityStream_.length, 0,
- ...processActivityForStream(activity));
-
- // Used to update the scrollbar.
- this.$$('iron-list').notifyResize();
- },
+ /**
+ * @private
+ * @param {!chrome.activityLogPrivate.ExtensionActivity} activity
+ */
+ extensionActivityListener_: function(activity) {
+ if (activity.extensionId != this.extensionId) {
+ return;
+ }
- /**
- * @private
- * @param {!CustomEvent<string>} e
- */
- onSearchChanged_: function(e) {
- // Remove all whitespaces from the search term, as API call names and
- // URLs should not contain any whitespace. As of now, only single term
- // search queries are allowed.
- const searchTerm = e.detail.replace(/\s+/g, '').toLowerCase();
- if (searchTerm === this.lastSearch_) {
- return;
- }
-
- this.lastSearch_ = searchTerm;
- },
+ this.splice(
+ 'activityStream_', this.activityStream_.length, 0,
+ ...processActivityForStream(activity));
- /**
- * @private
- * @return {!Array<!extensions.StreamItem>}
- */
- computeFilteredActivityStream_: function() {
- if (!this.lastSearch_) {
- return this.activityStream_.slice();
- }
-
- // Match on these properties for each activity.
- const propNames = [
- 'name',
- 'pageUrl',
- 'activityType',
- ];
-
- return this.activityStream_.filter(act => {
- return propNames.some(prop => {
- return act[prop] &&
- act[prop].toLowerCase().includes(this.lastSearch_);
- });
- });
- },
- });
+ // Used to update the scrollbar.
+ this.$$('iron-list').notifyResize();
+ },
- return {
- ActivityLogStream: ActivityLogStream,
- ActivityLogEventDelegate: ActivityLogEventDelegate,
- };
+ /**
+ * @private
+ * @param {!CustomEvent<string>} e
+ */
+ onSearchChanged_: function(e) {
+ // Remove all whitespaces from the search term, as API call names and
+ // URLs should not contain any whitespace. As of now, only single term
+ // search queries are allowed.
+ const searchTerm = e.detail.replace(/\s+/g, '').toLowerCase();
+ if (searchTerm === this.lastSearch_) {
+ return;
+ }
+
+ this.lastSearch_ = searchTerm;
+ },
+
+ /**
+ * @private
+ * @return {!Array<!StreamItem>}
+ */
+ computeFilteredActivityStream_: function() {
+ if (!this.lastSearch_) {
+ return this.activityStream_.slice();
+ }
+
+ // Match on these properties for each activity.
+ const propNames = [
+ 'name',
+ 'pageUrl',
+ 'activityType',
+ ];
+
+ return this.activityStream_.filter(act => {
+ return propNames.some(prop => {
+ return act[prop] && act[prop].toLowerCase().includes(this.lastSearch_);
+ });
+ });
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.html b/chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.html
index eca08d5f538..9fbffdac333 100644
--- a/chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.html
+++ b/chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.html
@@ -1,132 +1,118 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
-
-<link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
-<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="../shared_style.html">
-<link rel="import" href="../shared_vars.html">
-
-<dom-module id="activity-log-stream-item">
- <template>
- <style include="cr-icons cr-shared-style shared-style">
- :host {
- border-top: var(--cr-separator-line);
- display: block;
- padding: 8px var(--cr-section-padding);
- }
-
- cr-expand-button {
- --cr-expand-button-disabled-display: none;
-
- /* Match separator height. */
- height: calc(var(--cr-section-min-height) - var(--separator-gap));
- }
-
- cr-expand-button[disabled] {
- opacity: 1;
- }
-
- #activity-call-and-time {
- display: flex;
- flex: 1;
- flex-direction: row;
- margin-inline-end: auto;
- max-width: var(--activity-log-call-and-time-width);
- }
-
- #activity-type {
- min-width: var(--activity-type-width);
- }
-
- #activity-name {
- flex: 1;
- margin-inline-start: 10px;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- }
-
- #activity-time {
- min-width: var(--activity-time-width);
- text-align: end;
- }
-
- #expanded-data {
- display: flex;
- flex-direction: column;
- margin-inline-start: 16px;
- max-width: var(--activity-log-call-and-time-width);
- }
-
- #page-url-link {
- margin-bottom: 10px;
- margin-inline-end: auto;
- overflow: hidden;
- text-overflow: ellipsis;
- white-space: nowrap;
- width: 100%;
- }
-
- #args-list,
- #web-request-section {
- display: flex;
- flex-direction: column;
- margin-bottom: 10px;
- }
-
- .expanded-data-heading {
- font-weight: 500;
- }
-
- .list-item {
- display: flex;
- margin-top: 10px;
- }
-
- .index {
- min-width: 3em; /* Allow 3 digits of space */
- }
-
- .arg,
- #web-request-details {
- overflow: hidden;
- overflow-wrap: break-word;
- }
-
- #web-request-details {
- margin-top: 10px;
- }
- </style>
- <cr-expand-button expanded="[[data.expanded]]"
- disabled="[[!isExpandable_]]" on-click="onExpandClick_">
- <div id="activity-call-and-time">
- <span id="activity-type">[[data.activityType]]</span>
- <span id="activity-name" title="[[data.name]]">[[data.name]]</span>
- <span id="activity-time">[[getFormattedTime_(data.timeStamp)]]</span>
- </div>
- </cr-expand-button>
- <div id="expanded-data" hidden$="[[!data.expanded]]">
- <a id="page-url-link" href="[[data.pageUrl]]" target="_blank"
- hidden$="[[!hasPageUrl_(data.pageUrl)]]"
- title="[[data.pageUrl]]">[[data.pageUrl]]</a>
- <div id="args-list" hidden$="[[!hasArgs_(argsList_)]]">
- <span class="expanded-data-heading">
- $i18n{activityArgumentsHeading}
- </span>
- <template is="dom-repeat" items="[[argsList_]]">
- <div class="list-item">
- <span class="index">[[item.index]]</span>
- <span class="arg">[[item.arg]]</span>
- </div>
- </template>
- </div>
- <div id="web-request-section"
- hidden$="[[!hasWebRequestInfo_(data.webRequestInfo)]]">
- <span class="expanded-data-heading">$i18n{webRequestInfoHeading}</span>
- <span id="web-request-details">[[data.webRequestInfo]]</span>
+<style include="cr-icons cr-shared-style shared-style">
+ :host {
+ border-top: var(--cr-separator-line);
+ display: block;
+ padding: 8px var(--cr-section-padding);
+ }
+
+ cr-expand-button {
+ --cr-expand-button-disabled-display: none;
+
+ /* Match separator height. */
+ height: calc(var(--cr-section-min-height) - var(--separator-gap));
+ }
+
+ cr-expand-button[disabled] {
+ opacity: 1;
+ }
+
+ #activity-call-and-time {
+ display: flex;
+ flex: 1;
+ flex-direction: row;
+ margin-inline-end: auto;
+ max-width: var(--activity-log-call-and-time-width);
+ }
+
+ #activity-type {
+ min-width: var(--activity-type-width);
+ }
+
+ #activity-name {
+ flex: 1;
+ margin-inline-start: 10px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ }
+
+ #activity-time {
+ min-width: var(--activity-time-width);
+ text-align: end;
+ }
+
+ #expanded-data {
+ display: flex;
+ flex-direction: column;
+ margin-inline-start: 16px;
+ max-width: var(--activity-log-call-and-time-width);
+ }
+
+ #page-url-link {
+ margin-bottom: 10px;
+ margin-inline-end: auto;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ width: 100%;
+ }
+
+ #args-list,
+ #web-request-section {
+ display: flex;
+ flex-direction: column;
+ margin-bottom: 10px;
+ }
+
+ .expanded-data-heading {
+ font-weight: 500;
+ }
+
+ .list-item {
+ display: flex;
+ margin-top: 10px;
+ }
+
+ .index {
+ min-width: 3em; /* Allow 3 digits of space */
+ }
+
+ .arg,
+ #web-request-details {
+ overflow: hidden;
+ overflow-wrap: break-word;
+ }
+
+ #web-request-details {
+ margin-top: 10px;
+ }
+</style>
+<cr-expand-button expanded="[[data.expanded]]"
+ disabled="[[!isExpandable_]]" on-click="onExpandClick_">
+ <div id="activity-call-and-time">
+ <span id="activity-type">[[data.activityType]]</span>
+ <span id="activity-name" title="[[data.name]]">[[data.name]]</span>
+ <span id="activity-time">[[getFormattedTime_(data.timeStamp)]]</span>
+ </div>
+</cr-expand-button>
+<div id="expanded-data" hidden$="[[!data.expanded]]">
+ <a id="page-url-link" href="[[data.pageUrl]]" target="_blank"
+ hidden$="[[!hasPageUrl_(data.pageUrl)]]"
+ title="[[data.pageUrl]]">[[data.pageUrl]]</a>
+ <div id="args-list" hidden$="[[!hasArgs_(argsList_)]]">
+ <span class="expanded-data-heading">
+ $i18n{activityArgumentsHeading}
+ </span>
+ <template is="dom-repeat" items="[[argsList_]]">
+ <div class="list-item">
+ <span class="index">[[item.index]]</span>
+ <span class="arg">[[item.arg]]</span>
</div>
- </div>
- </template>
- <script src="activity_log_stream_item.js"></script>
-</dom-module>
+ </template>
+ </div>
+ <div id="web-request-section"
+ hidden$="[[!hasWebRequestInfo_(data.webRequestInfo)]]">
+ <span class="expanded-data-heading">$i18n{webRequestInfoHeading}</span>
+ <span id="web-request-details">[[data.webRequestInfo]]</span>
+ </div>
+</div>
diff --git a/chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.js b/chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.js
index 9a2e477ee0d..e7025078fbc 100644
--- a/chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.js
+++ b/chromium/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.js
@@ -2,161 +2,160 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
+import 'chrome://resources/cr_elements/cr_expand_button/cr_expand_button.m.js';
+import 'chrome://resources/cr_elements/cr_icons_css.m.js';
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+import '../shared_style.js';
+import '../shared_vars.js';
+
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+/**
+ * @typedef {{
+ * name: string,
+ * timestamp: number,
+ * activityType: !chrome.activityLogPrivate.ExtensionActivityFilter,
+ * pageUrl: string,
+ * argUrl: string,
+ * args: string,
+ * webRequestInfo: (string|undefined),
+ * expanded: boolean
+ * }}
+ */
+export let StreamItem;
+
+/**
+ * A struct used to describe each argument for an activity (each item in
+ * the parsed version of |data.args|). Contains the argument's value itself
+ * and its index.
+ * @typedef {{
+ * arg: string,
+ * index: number
+ * }}
+ */
+export let StreamArgItem;
+
+/**
+ * Placeholder for arg_url that can occur in |StreamItem.args|. Sometimes we
+ * see this as '\u003Carg_url>' (opening arrow is unicode converted) but
+ * string comparison with the non-unicode value still returns true so we
+ * don't need to convert.
+ * @type {string}
+ */
+export const ARG_URL_PLACEHOLDER = '<arg_url>';
+
+/**
+ * Regex pattern for |ARG_URL_PLACEHOLDER| for String.replace. A regex of the
+ * exact string with a global search flag is needed to replace all
+ * occurrences.
+ * @type {!RegExp}
+ */
+const ARG_URL_PLACEHOLDER_REGEX = /"<arg_url>"/g;
+
+Polymer({
+ is: 'activity-log-stream-item',
+
+ _template: html`{__html_template__}`,
+
+ properties: {
+ /**
+ * The underlying ActivityGroup that provides data for the
+ * ActivityLogItem displayed.
+ * @type {!StreamItem}
+ */
+ data: Object,
+
+ /** @private {!Array<!StreamArgItem>} */
+ argsList_: {
+ type: Array,
+ computed: 'computeArgsList_(data.args)',
+ },
+
+ /** @private */
+ isExpandable_: {
+ type: Boolean,
+ computed: 'computeIsExpandable_(data)',
+ },
+ },
/**
- * @typedef {{
- * name: string,
- * timestamp: number,
- * activityType: !chrome.activityLogPrivate.ExtensionActivityFilter,
- * pageUrl: string,
- * argUrl: string,
- * args: string,
- * webRequestInfo: (string|undefined),
- * expanded: boolean
- * }}
+ * @private
+ * @return {boolean}
*/
- let StreamItem;
+ computeIsExpandable_: function() {
+ return this.hasPageUrl_() || this.hasArgs_() || this.hasWebRequestInfo_();
+ },
/**
- * A struct used to describe each argument for an activity (each item in
- * the parsed version of |data.args|). Contains the argument's value itself
- * and its index.
- * @typedef {{
- * arg: string,
- * index: number
- * }}
+ * @private
+ * @return {string}
*/
- let StreamArgItem;
+ getFormattedTime_: function() {
+ // Format the activity's time to HH:MM:SS.mmm format. Use ToLocaleString
+ // for HH:MM:SS and padLeft for milliseconds.
+ const activityDate = new Date(this.data.timestamp);
+ const timeString = activityDate.toLocaleTimeString(undefined, {
+ hour12: false,
+ hour: '2-digit',
+ minute: '2-digit',
+ second: '2-digit',
+ });
+
+ const ms = activityDate.getMilliseconds().toString().padStart(3, '0');
+ return `${timeString}.${ms}`;
+ },
/**
- * Placeholder for arg_url that can occur in |StreamItem.args|. Sometimes we
- * see this as '\u003Carg_url>' (opening arrow is unicode converted) but
- * string comparison with the non-unicode value still returns true so we
- * don't need to convert.
- * @type {string}
+ * @private
+ * @return {boolean}
*/
- const ARG_URL_PLACEHOLDER = '<arg_url>';
+ hasPageUrl_: function() {
+ return !!this.data.pageUrl;
+ },
/**
- * Regex pattern for |ARG_URL_PLACEHOLDER| for String.replace. A regex of the
- * exact string with a global search flag is needed to replace all
- * occurrences.
- * @type {!RegExp}
+ * @private
+ * @return {boolean}
*/
- const ARG_URL_PLACEHOLDER_REGEX = /"<arg_url>"/g;
-
- const ActivityLogStreamItem = Polymer({
- is: 'activity-log-stream-item',
-
- properties: {
- /**
- * The underlying ActivityGroup that provides data for the
- * ActivityLogItem displayed.
- * @type {!extensions.StreamItem}
- */
- data: Object,
-
- /** @private {!Array<!extensions.StreamArgItem>} */
- argsList_: {
- type: Array,
- computed: 'computeArgsList_(data.args)',
- },
-
- /** @private */
- isExpandable_: {
- type: Boolean,
- computed: 'computeIsExpandable_(data)',
- },
- },
+ hasArgs_: function() {
+ return this.argsList_.length > 0;
+ },
- /**
- * @private
- * @return {boolean}
- */
- computeIsExpandable_: function() {
- return this.hasPageUrl_() || this.hasArgs_() || this.hasWebRequestInfo_();
- },
-
- /**
- * @private
- * @return {string}
- */
- getFormattedTime_: function() {
- // Format the activity's time to HH:MM:SS.mmm format. Use ToLocaleString
- // for HH:MM:SS and padLeft for milliseconds.
- const activityDate = new Date(this.data.timestamp);
- const timeString = activityDate.toLocaleTimeString(undefined, {
- hour12: false,
- hour: '2-digit',
- minute: '2-digit',
- second: '2-digit',
- });
-
- const ms = activityDate.getMilliseconds().toString().padStart(3, '0');
- return `${timeString}.${ms}`;
- },
-
- /**
- * @private
- * @return {boolean}
- */
- hasPageUrl_: function() {
- return !!this.data.pageUrl;
- },
-
- /**
- * @private
- * @return {boolean}
- */
- hasArgs_: function() {
- return this.argsList_.length > 0;
- },
-
- /**
- * @private
- * @return {boolean}
- */
- hasWebRequestInfo_: function() {
- return !!this.data.webRequestInfo && this.data.webRequestInfo != '{}';
- },
-
- /**
- * @private
- * @return {!Array<!extensions.StreamArgItem>}
- */
- computeArgsList_: function() {
- const parsedArgs = JSON.parse(this.data.args);
- if (!Array.isArray(parsedArgs)) {
- return [];
- }
-
- // Replace occurrences AFTER parsing then stringifying as the JSON
- // serializer on the C++ side escapes certain characters such as '<' and
- // parsing un-escapes these characters.
- // See EscapeSpecialCodePoint in base/json/string_escape.cc.
- return parsedArgs.map(
- (arg, i) => ({
- arg: JSON.stringify(arg).replace(
- ARG_URL_PLACEHOLDER_REGEX, `"${this.data.argUrl}"`),
- index: i + 1,
- }));
- },
+ /**
+ * @private
+ * @return {boolean}
+ */
+ hasWebRequestInfo_: function() {
+ return !!this.data.webRequestInfo && this.data.webRequestInfo != '{}';
+ },
- /** @private */
- onExpandClick_: function() {
- if (this.isExpandable_) {
- this.set('data.expanded', !this.data.expanded);
- this.fire('resize-stream');
- }
- },
- });
-
- return {
- ActivityLogStreamItem: ActivityLogStreamItem,
- StreamItem: StreamItem,
- StreamArgItem: StreamArgItem,
- ARG_URL_PLACEHOLDER: ARG_URL_PLACEHOLDER,
- };
+ /**
+ * @private
+ * @return {!Array<!StreamArgItem>}
+ */
+ computeArgsList_: function() {
+ const parsedArgs = JSON.parse(this.data.args);
+ if (!Array.isArray(parsedArgs)) {
+ return [];
+ }
+
+ // Replace occurrences AFTER parsing then stringifying as the JSON
+ // serializer on the C++ side escapes certain characters such as '<' and
+ // parsing un-escapes these characters.
+ // See EscapeSpecialCodePoint in base/json/string_escape.cc.
+ return parsedArgs.map(
+ (arg, i) => ({
+ arg: JSON.stringify(arg).replace(
+ ARG_URL_PLACEHOLDER_REGEX, `"${this.data.argUrl}"`),
+ index: i + 1,
+ }));
+ },
+
+ /** @private */
+ onExpandClick_: function() {
+ if (this.isExpandable_) {
+ this.set('data.expanded', !this.data.expanded);
+ this.fire('resize-stream');
+ }
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/checkup_image.svg b/chromium/chrome/browser/resources/extensions/checkup_image.svg
new file mode 100644
index 00000000000..2965cae3980
--- /dev/null
+++ b/chromium/chrome/browser/resources/extensions/checkup_image.svg
@@ -0,0 +1 @@
+<svg width="270" height="117" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient x1="22.739%" y1="50%" x2="50%" y2="50%" id="a"><stop stop-color="#E8EAED" offset="0%"/><stop stop-color="#FFF" offset="100%"/></linearGradient><path id="b" d="M0 .195h94.65v14.023H0z"/><path id="d" d="M.062.195h136.716v14.023H.062z"/><path id="f" d="M0 116.114h217.344V.426H0z"/><path d="M35.238 19.048h-2.857v-7.62a3.808 3.808 0 0 0-3.81-3.809h-7.619V4.762A4.764 4.764 0 0 0 16.19 0a4.764 4.764 0 0 0-4.761 4.762v2.857h-7.62a3.792 3.792 0 0 0-3.79 3.81l-.01 7.238h2.848A5.146 5.146 0 0 1 8 23.81a5.146 5.146 0 0 1-5.143 5.142H.01L0 36.19A3.808 3.808 0 0 0 3.81 40h7.238v-2.857A5.146 5.146 0 0 1 16.19 32a5.146 5.146 0 0 1 5.143 5.143V40h7.238a3.808 3.808 0 0 0 3.81-3.81v-7.619h2.857A4.764 4.764 0 0 0 40 23.81a4.764 4.764 0 0 0-4.762-4.762z" id="h"/><path id="j" d="M0 0h12v12H0z"/></defs><g fill="none" fill-rule="evenodd"><path fill="url(#a)" transform="matrix(-1 0 0 1 57 0)" d="M0 109h57v7H0z"/><g transform="translate(51)"><path d="M.79 104.807V5.166a3.954 3.954 0 0 1 3.95-3.95h15.503v103.59H.79z" fill="#F8F9FA"/><path d="M21.033.426H4.74A4.74 4.74 0 0 0 0 5.166v100.43h21.033V.426zm-1.58 1.58v102.01H1.58V5.167a3.164 3.164 0 0 1 3.16-3.16h14.713z" fill="#E8EAED"/><path d="M7.801 104.807V5.166a3.954 3.954 0 0 1 3.95-3.95h123.73a3.954 3.954 0 0 1 3.95 3.95v99.64H7.801z" fill="#FFF"/><path d="M135.482.426H11.751a4.74 4.74 0 0 0-4.74 4.74v100.43h133.21V5.166a4.74 4.74 0 0 0-4.739-4.74m0 1.58a3.163 3.163 0 0 1 3.16 3.16v98.85H8.592V5.167a3.163 3.163 0 0 1 3.159-3.16h123.731" fill="#E8EAED"/><path d="M4.74 115.324a3.954 3.954 0 0 1-3.95-3.95v-8.493h93.07v12.443H4.74z" fill="#F8F9FA"/><g transform="translate(0 101.896)"><mask id="c" fill="#fff"><use xlink:href="#b"/></mask><path d="M94.65.195H0V9.48a4.74 4.74 0 0 0 4.739 4.74h89.91V.194zm-1.58 1.58v10.863H4.739a3.164 3.164 0 0 1-3.16-3.16V1.776H93.07z" fill="#E8EAED" mask="url(#c)"/></g><path d="M85.367 115.324a3.954 3.954 0 0 1-3.95-3.95v-8.493h135.137v8.493a3.954 3.954 0 0 1-3.95 3.95H85.367z" fill="#FFF"/><g transform="translate(80.565 101.896)"><mask id="e" fill="#fff"><use xlink:href="#d"/></mask><path d="M136.778.195H.062V9.48a4.74 4.74 0 0 0 4.74 4.74h127.237a4.74 4.74 0 0 0 4.74-4.74V.195zm-1.58 1.58v7.704a3.163 3.163 0 0 1-3.159 3.16H4.801a3.164 3.164 0 0 1-3.16-3.16V1.775h133.557z" fill="#E8EAED" mask="url(#e)"/></g><path d="M163.629 109.102h-29.287a2.884 2.884 0 0 1-2.884-2.884v-4.127h35.055v4.127a2.884 2.884 0 0 1-2.884 2.884" fill="#E8EAED"/><mask id="g" fill="#fff"><use xlink:href="#f"/></mask><path fill="#F8F9FA" mask="url(#g)" d="M18.318 94.29h110.597V11.734H18.318z"/><path d="M17.528 95.08h112.177V10.943H17.528V95.08zm1.58-1.58h109.018V12.522H19.108V93.5z" fill="#E8EAED" mask="url(#g)"/></g><g transform="translate(106 32)"><mask id="i" fill="#fff"><use xlink:href="#h"/></mask><use fill="#3C4043" fill-rule="nonzero" xlink:href="#h"/><g mask="url(#i)" fill="#1A73E8"><path d="M-3.81-1.905h46v46h-46z"/></g></g><path d="M162.83 24.905L166 24l-3.17-.906a5.714 5.714 0 0 1-3.924-3.924L158 16l-.906 3.17a5.714 5.714 0 0 1-3.924 3.924L150 24l3.17.905a5.714 5.714 0 0 1 3.924 3.925L158 32l.906-3.17a5.714 5.714 0 0 1 3.924-3.925m9.585 43.548L174 68l-1.585-.453a2.856 2.856 0 0 1-1.962-1.962L170 64l-.453 1.585a2.856 2.856 0 0 1-1.962 1.962L166 68l1.585.453a2.856 2.856 0 0 1 1.962 1.962L170 72l.453-1.585a2.856 2.856 0 0 1 1.962-1.962" fill="#FBBC04"/><g transform="translate(74 80)"><mask id="k" fill="#fff"><use xlink:href="#j"/></mask><path d="M9.623 6.68L12 6l-2.377-.68A4.284 4.284 0 0 1 6.68 2.378L6 0l-.68 2.377A4.284 4.284 0 0 1 2.379 5.32L0 6l2.378.68A4.283 4.283 0 0 1 5.32 9.623L6 12l.68-2.377A4.283 4.283 0 0 1 9.623 6.68" fill="#FBBC04" mask="url(#k)"/></g></g></svg> \ No newline at end of file
diff --git a/chromium/chrome/browser/resources/extensions/checkup_image_dark.svg b/chromium/chrome/browser/resources/extensions/checkup_image_dark.svg
new file mode 100644
index 00000000000..b68b1840157
--- /dev/null
+++ b/chromium/chrome/browser/resources/extensions/checkup_image_dark.svg
@@ -0,0 +1 @@
+<svg width="270" height="117" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><linearGradient x1="23.421%" y1="50%" x2="64.093%" y2="50%" id="a"><stop offset="0%"/><stop stop-color="#28292C" offset="100%"/></linearGradient><path id="b" d="M0 116h218V0H0z"/><path d="M35.238 19.048h-2.857v-7.62a3.808 3.808 0 0 0-3.81-3.809h-7.619V4.762A4.764 4.764 0 0 0 16.19 0a4.764 4.764 0 0 0-4.761 4.762v2.857h-7.62a3.792 3.792 0 0 0-3.79 3.81l-.01 7.238h2.848A5.146 5.146 0 0 1 8 23.81a5.146 5.146 0 0 1-5.143 5.142H.01L0 36.19A3.808 3.808 0 0 0 3.81 40h7.238v-2.857A5.146 5.146 0 0 1 16.19 32a5.146 5.146 0 0 1 5.143 5.143V40h7.238a3.808 3.808 0 0 0 3.81-3.81v-7.619h2.857A4.764 4.764 0 0 0 40 23.81a4.764 4.764 0 0 0-4.762-4.762z" id="d"/><path id="f" d="M0 0h12v12H0z"/></defs><g fill="none" fill-rule="evenodd"><path fill="url(#a)" transform="matrix(-1 0 0 1 57 0)" d="M0 109h57v7H0z"/><g transform="translate(50)"><path d="M2 104V10.793C2 5.945 6.037 2 11 2h9v102H2z" fill="#2A2B2E"/><path d="M21 0H10.5C4.702 0 0 4.702 0 10.5V105h21V0zm-3.5 3.5v98h-14v-91c0-3.859 3.14-7 7-7h7z" fill="#3B3F42"/><path d="M9 104V10.793C9 5.945 12.94 2 17.784 2h112.432C135.06 2 139 5.945 139 10.793V104H9z" fill="#1F2123"/><path d="M130.421 0H17.58C11.738 0 7 4.702 7 10.5V105h134V10.5C141 4.702 136.262 0 130.421 0m0 3.5c3.89 0 7.053 3.141 7.053 7v91H10.526v-91c0-3.859 3.163-7 7.053-7H130.42" fill="#3B3F42"/><path d="M10.75 114C5.925 114 2 109.888 2 104.833V103h91v11H10.75z" fill="#2A2B2E"/><path d="M95 102H0v3.5c0 5.798 4.727 10.5 10.556 10.5H95v-14zm-3.519 3.5v7H10.556c-3.881 0-7.037-3.141-7.037-7H91.48z" fill="#3B3F42"/><path d="M90.816 114c-4.861 0-8.816-4.112-8.816-9.167V103h134v1.833c0 5.055-3.955 9.167-8.816 9.167H90.816z" fill="#1F2123"/><path d="M218 102H81v3.5c0 5.798 4.72 10.5 10.538 10.5h115.924c5.819 0 10.538-4.702 10.538-10.5V102zm-3.513 3.5c0 3.859-3.15 7-7.025 7H91.538c-3.874 0-7.025-3.141-7.025-7h129.974z" fill="#3B3F42"/><path d="M160.61 109h-22.219a6.39 6.39 0 0 1-6.391-6.39V102h35v.61a6.39 6.39 0 0 1-6.39 6.39" fill="#3B3F42"/><mask id="c" fill="#fff"><use xlink:href="#b"/></mask><path fill="#2A2B2E" mask="url(#c)" d="M19 93h109V12H19z"/><path d="M17 95h113V11H17v84zm3.531-3.5H126.47v-77H20.53v77z" fill="#3B3F42" mask="url(#c)"/></g><g transform="translate(106 32)"><mask id="e" fill="#fff"><use xlink:href="#d"/></mask><use fill="#3C4043" fill-rule="nonzero" xlink:href="#d"/><g mask="url(#e)" fill="#1A73E8"><path d="M-3.81-1.905h46v46h-46z"/></g></g><path d="M162.83 24.905L166 24l-3.17-.906a5.714 5.714 0 0 1-3.924-3.924L158 16l-.906 3.17a5.714 5.714 0 0 1-3.924 3.924L150 24l3.17.905a5.714 5.714 0 0 1 3.924 3.925L158 32l.906-3.17a5.714 5.714 0 0 1 3.924-3.925m9.585 43.548L174 68l-1.585-.453a2.856 2.856 0 0 1-1.962-1.962L170 64l-.453 1.585a2.856 2.856 0 0 1-1.962 1.962L166 68l1.585.453a2.856 2.856 0 0 1 1.962 1.962L170 72l.453-1.585a2.856 2.856 0 0 1 1.962-1.962" fill="#FBBC04"/><g transform="translate(74 80)"><mask id="g" fill="#fff"><use xlink:href="#f"/></mask><path d="M9.623 6.68L12 6l-2.377-.68A4.284 4.284 0 0 1 6.68 2.378L6 0l-.68 2.377A4.284 4.284 0 0 1 2.379 5.32L0 6l2.378.68A4.283 4.283 0 0 1 5.32 9.623L6 12l.68-2.377A4.283 4.283 0 0 1 9.623 6.68" fill="#FBBC04" mask="url(#g)"/></g></g></svg> \ No newline at end of file
diff --git a/chromium/chrome/browser/resources/extensions/code_section.html b/chromium/chrome/browser/resources/extensions/code_section.html
index b4721b10309..7fc90e97518 100644
--- a/chromium/chrome/browser/resources/extensions/code_section.html
+++ b/chromium/chrome/browser/resources/extensions/code_section.html
@@ -1,141 +1,127 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="cr-hidden-style">
+ :host {
+ --container-bg: white;
+ --line-bg: var(--paper-grey-300);
+ --main-color: var(--paper-grey-800);
+ display: block;
+ }
-<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
-<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/html/i18n_behavior.html">
-<link rel="import" href="chrome://resources/html/load_time_data.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
+ @media (prefers-color-scheme: dark) {
+ :host {
+ --container-bg: rgba(0, 0, 0, .4);
+ --line-bg: var(--google-grey-800);
+ --main-color: var(--cr-primary-text-color);
+ }
+ }
-<dom-module id="extensions-code-section">
- <template>
- <style include="cr-hidden-style">
- :host {
- --container-bg: white;
- --line-bg: var(--paper-grey-300);
- --main-color: var(--paper-grey-800);
- display: block;
- }
+ #scroll-container {
+ background: var(--container-bg);
+ height: 100%;
+ overflow: auto;
+ position: relative;
+ }
- @media (prefers-color-scheme: dark) {
- :host {
- --container-bg: rgba(0, 0, 0, .4);
- --line-bg: var(--google-grey-800);
- --main-color: var(--cr-primary-text-color);
- }
- }
+ @media (prefers-color-scheme: light) {
+ #scroll-container {
+ border: 1px solid var(--paper-grey-500);
+ }
+ }
- #scroll-container {
- background: var(--container-bg);
- height: 100%;
- overflow: auto;
- position: relative;
- }
+ #main {
+ color: var(--main-color);
+ display: flex;
+ font-family: monospace;
+ min-height: 100%;
+ }
- @media (prefers-color-scheme: light) {
- #scroll-container {
- border: 1px solid var(--paper-grey-500);
- }
- }
+ #line-numbers {
+ background: var(--line-bg);
+ display: flex;
+ flex-direction: column;
+ padding: 0 8px;
+ text-align: end;
+ }
- #main {
- color: var(--main-color);
- display: flex;
- font-family: monospace;
- min-height: 100%;
- }
+ @media (prefers-color-scheme: light) {
+ #line-numbers {
+ border-inline-end: 1px solid var(--paper-grey-500);
+ }
+ }
- #line-numbers {
- background: var(--line-bg);
- display: flex;
- flex-direction: column;
- padding: 0 8px;
- text-align: end;
- }
+ #source {
+ display: flex;
+ flex-direction: column;
+ margin-inline-start: 4px;
+ }
- @media (prefers-color-scheme: light) {
- #line-numbers {
- border-inline-end: 1px solid var(--paper-grey-500);
- }
- }
+ #line-numbers span,
+ #source span {
+ white-space: pre;
+ }
- #source {
- display: flex;
- flex-direction: column;
- margin-inline-start: 4px;
- }
+ #no-code {
+ text-align: center;
+ }
- #line-numbers span,
- #source span {
- white-space: pre;
- }
+ @media (prefers-color-scheme: light) {
+ #no-code {
+ color: var(--paper-grey-800);
+ }
- #no-code {
- text-align: center;
- }
+ .more-code {
+ color: var(--paper-grey-500);
+ }
+ }
- @media (prefers-color-scheme: light) {
- #no-code {
- color: var(--paper-grey-800);
- }
+ #highlight-description {
+ height: 0;
+ overflow: hidden;
+ }
- .more-code {
- color: var(--paper-grey-500);
- }
- }
-
- #highlight-description {
- height: 0;
- overflow: hidden;
- }
-
- @media (prefers-color-scheme: dark) {
- mark {
- background-color: var(--google-yellow-refresh-300);
- color: var(--google-grey-900);
- }
- }
- </style>
- <div id="scroll-container" hidden="[[!highlighted_]]" dir="ltr">
- <div id="main">
- <!-- Line numbers are not useful to a screenreader -->
- <div id="line-numbers" aria-hidden="true">
- <div class="more-code before" hidden="[[!truncatedBefore_]]">
- ...
- </div>
- <span>[[lineNumbers_]]</span>
- <div class="more-code after" hidden="[[!truncatedAfter_]]">
- ...
- </div>
- </div>
- <div id="source">
- <div class="more-code before" hidden="[[!truncatedBefore_]]">
- [[getLinesNotShownLabel_(
- truncatedBefore_,
- '$i18nPolymer{errorLinesNotShownSingular}',
- '$i18nPolymer{errorLinesNotShownPlural}')]]
- </div>
- <span><!-- Whitespace is preserved in this span. Ignore new lines.
- --><span>[[before_]]</span><!--
- --><mark aria-label$="[[highlighted_]]"
- aria-describedby="highlight-description"><!--
- --><span aria-hidden="true">[[highlighted_]]</span><!--
- --></mark><!--
- --><span>[[after_]]</span><!--
- --></span>
- <div class="more-code after" hidden="[[!truncatedAfter_]]">
- [[getLinesNotShownLabel_(
- truncatedAfter_,
- '$i18nPolymer{errorLinesNotShownSingular}',
- '$i18nPolymer{errorLinesNotShownPlural}')]]
- </div>
- </div>
+ @media (prefers-color-scheme: dark) {
+ mark {
+ background-color: var(--google-yellow-refresh-300);
+ color: var(--google-grey-900);
+ }
+ }
+</style>
+<div id="scroll-container" hidden="[[!highlighted_]]" dir="ltr">
+ <div id="main">
+ <!-- Line numbers are not useful to a screenreader -->
+ <div id="line-numbers" aria-hidden="true">
+ <div class="more-code before" hidden="[[!truncatedBefore_]]">
+ ...
+ </div>
+ <span>[[lineNumbers_]]</span>
+ <div class="more-code after" hidden="[[!truncatedAfter_]]">
+ ...
</div>
</div>
- <div id="no-code" hidden="[[!showNoCode_]]">[[couldNotDisplayCode]]</div>
- <div id="highlight-description" aria-hidden="true">
- [[highlightDescription_]]
+ <div id="source">
+ <div class="more-code before" hidden="[[!truncatedBefore_]]">
+ [[getLinesNotShownLabel_(
+ truncatedBefore_,
+ '$i18nPolymer{errorLinesNotShownSingular}',
+ '$i18nPolymer{errorLinesNotShownPlural}')]]
+ </div>
+ <span><!-- Whitespace is preserved in this span. Ignore new lines.
+ --><span>[[before_]]</span><!--
+ --><mark aria-label$="[[highlighted_]]"
+ aria-describedby="highlight-description"><!--
+ --><span aria-hidden="true">[[highlighted_]]</span><!--
+ --></mark><!--
+ --><span>[[after_]]</span><!--
+ --></span>
+ <div class="more-code after" hidden="[[!truncatedAfter_]]">
+ [[getLinesNotShownLabel_(
+ truncatedAfter_,
+ '$i18nPolymer{errorLinesNotShownSingular}',
+ '$i18nPolymer{errorLinesNotShownPlural}')]]
+ </div>
</div>
- </template>
- <script src="code_section.js"></script>
-</dom-module>
+ </div>
+</div>
+<div id="no-code" hidden="[[!showNoCode_]]">[[couldNotDisplayCode]]</div>
+<div id="highlight-description" aria-hidden="true">
+ [[highlightDescription_]]
+</div>
diff --git a/chromium/chrome/browser/resources/extensions/code_section.js b/chromium/chrome/browser/resources/extensions/code_section.js
index 3577af2687a..9a24dd366bb 100644
--- a/chromium/chrome/browser/resources/extensions/code_section.js
+++ b/chromium/chrome/browser/resources/extensions/code_section.js
@@ -2,196 +2,202 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
+import 'chrome://resources/cr_elements/hidden_style_css.m.js';
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+import 'chrome://resources/polymer/v3_0/paper-styles/color.js';
+import './strings.m.js';
- /**
- * @param {number} totalCount
- * @param {number} oppositeCount
- * @return {number}
- */
- function visibleLineCount(totalCount, oppositeCount) {
- // We limit the number of lines shown for DOM performance.
- const MAX_VISIBLE_LINES = 1000;
- const max =
- Math.max(MAX_VISIBLE_LINES / 2, MAX_VISIBLE_LINES - oppositeCount);
- return Math.min(max, totalCount);
- }
-
- const CodeSection = Polymer({
- is: 'extensions-code-section',
-
- behaviors: [I18nBehavior],
-
- properties: {
- /**
- * The code this object is displaying.
- * @type {?chrome.developerPrivate.RequestFileSourceResponse}
- */
- code: {
- type: Object,
- value: null,
- },
-
- isActive: Boolean,
-
- /** @private Highlighted code. */
- highlighted_: String,
-
- /** @private Code before the highlighted section. */
- before_: String,
-
- /** @private Code after the highlighted section. */
- after_: String,
-
- /** @private */
- showNoCode_: {
- type: Boolean,
- computed: 'computeShowNoCode_(isActive, highlighted_)',
- },
-
- /** @private Description for the highlighted section. */
- highlightDescription_: String,
-
- /** @private */
- lineNumbers_: String,
-
- /** @private */
- truncatedBefore_: Number,
-
- /** @private */
- truncatedAfter_: Number,
-
- /**
- * The string to display if no |code| is set (e.g. because we couldn't
- * load the relevant source file).
- * @type {string}
- */
- couldNotDisplayCode: String,
- },
+import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
- observers: [
- 'onCodeChanged_(code.*)',
- ],
- /**
- * @private
- */
- onCodeChanged_: function() {
- if (!this.code ||
- (!this.code.beforeHighlight && !this.code.highlight &&
- !this.code.afterHighlight)) {
- this.highlighted_ = '';
- this.highlightDescription_ = '';
- this.before_ = '';
- this.after_ = '';
- this.lineNumbers_ = '';
- return;
- }
-
- const before = this.code.beforeHighlight;
- const highlight = this.code.highlight;
- const after = this.code.afterHighlight;
-
- const linesBefore = before ? before.split('\n') : [];
- const linesAfter = after ? after.split('\n') : [];
- const visibleLineCountBefore =
- visibleLineCount(linesBefore.length, linesAfter.length);
- const visibleLineCountAfter =
- visibleLineCount(linesAfter.length, linesBefore.length);
-
- const visibleBefore =
- linesBefore.slice(linesBefore.length - visibleLineCountBefore)
- .join('\n');
- let visibleAfter = linesAfter.slice(0, visibleLineCountAfter).join('\n');
- // If the last character is a \n, force it to be rendered.
- if (visibleAfter.charAt(visibleAfter.length - 1) == '\n') {
- visibleAfter += ' ';
- }
-
- this.highlighted_ = highlight;
- this.highlightDescription_ = this.getAccessibilityHighlightDescription_(
- linesBefore.length, highlight.split('\n').length);
- this.before_ = visibleBefore;
- this.after_ = visibleAfter;
- this.truncatedBefore_ = linesBefore.length - visibleLineCountBefore;
- this.truncatedAfter_ = linesAfter.length - visibleLineCountAfter;
-
- const visibleCode = visibleBefore + highlight + visibleAfter;
-
- this.setLineNumbers_(
- this.truncatedBefore_ + 1,
- this.truncatedBefore_ + visibleCode.split('\n').length);
- this.scrollToHighlight_(visibleLineCountBefore);
- },
+/**
+ * @param {number} totalCount
+ * @param {number} oppositeCount
+ * @return {number}
+ */
+function visibleLineCount(totalCount, oppositeCount) {
+ // We limit the number of lines shown for DOM performance.
+ const MAX_VISIBLE_LINES = 1000;
+ const max =
+ Math.max(MAX_VISIBLE_LINES / 2, MAX_VISIBLE_LINES - oppositeCount);
+ return Math.min(max, totalCount);
+}
+Polymer({
+ is: 'extensions-code-section',
+
+ _template: html`{__html_template__}`,
+
+ behaviors: [I18nBehavior],
+
+ properties: {
/**
- * @param {number} lineCount
- * @param {string} stringSingular
- * @param {string} stringPluralTemplate
- * @return {string}
- * @private
+ * The code this object is displaying.
+ * @type {?chrome.developerPrivate.RequestFileSourceResponse}
*/
- getLinesNotShownLabel_(lineCount, stringSingular, stringPluralTemplate) {
- return lineCount == 1 ?
- stringSingular :
- loadTimeData.substituteString(stringPluralTemplate, lineCount);
+ code: {
+ type: Object,
+ value: null,
},
- /**
- * @param {number} start
- * @param {number} end
- * @private
- */
- setLineNumbers_: function(start, end) {
- let lineNumbers = '';
- for (let i = start; i <= end; ++i) {
- lineNumbers += i + '\n';
- }
+ isActive: Boolean,
- this.lineNumbers_ = lineNumbers;
+ /** @private Highlighted code. */
+ highlighted_: String,
+
+ /** @private Code before the highlighted section. */
+ before_: String,
+
+ /** @private Code after the highlighted section. */
+ after_: String,
+
+ /** @private */
+ showNoCode_: {
+ type: Boolean,
+ computed: 'computeShowNoCode_(isActive, highlighted_)',
},
- /**
- * @param {number} linesBeforeHighlight
- * @private
- */
- scrollToHighlight_: function(linesBeforeHighlight) {
- const CSS_LINE_HEIGHT = 20;
+ /** @private Description for the highlighted section. */
+ highlightDescription_: String,
- // Count how many pixels is above the highlighted code.
- const highlightTop = linesBeforeHighlight * CSS_LINE_HEIGHT;
+ /** @private */
+ lineNumbers_: String,
- // Find the position to show the highlight roughly in the middle.
- const targetTop = highlightTop - this.clientHeight * 0.5;
+ /** @private */
+ truncatedBefore_: Number,
- this.$['scroll-container'].scrollTo({top: targetTop});
- },
+ /** @private */
+ truncatedAfter_: Number,
/**
- * @param {number} lineStart
- * @param {number} numLines
- * @return {string}
- * @private
+ * The string to display if no |code| is set (e.g. because we couldn't
+ * load the relevant source file).
+ * @type {string}
*/
- getAccessibilityHighlightDescription_: function(lineStart, numLines) {
- if (numLines > 1) {
- return this.i18n(
- 'accessibilityErrorMultiLine', lineStart.toString(),
- (lineStart + numLines - 1).toString());
- } else {
- return this.i18n('accessibilityErrorLine', lineStart.toString());
- }
- },
+ couldNotDisplayCode: String,
+ },
- /**
- * @private
- * @return {boolean}
- */
- computeShowNoCode_: function() {
- return this.isActive && !this.highlighted_;
- },
- });
+ observers: [
+ 'onCodeChanged_(code.*)',
+ ],
- return {CodeSection: CodeSection};
+ /**
+ * @private
+ */
+ onCodeChanged_: function() {
+ if (!this.code ||
+ (!this.code.beforeHighlight && !this.code.highlight &&
+ !this.code.afterHighlight)) {
+ this.highlighted_ = '';
+ this.highlightDescription_ = '';
+ this.before_ = '';
+ this.after_ = '';
+ this.lineNumbers_ = '';
+ return;
+ }
+
+ const before = this.code.beforeHighlight;
+ const highlight = this.code.highlight;
+ const after = this.code.afterHighlight;
+
+ const linesBefore = before ? before.split('\n') : [];
+ const linesAfter = after ? after.split('\n') : [];
+ const visibleLineCountBefore =
+ visibleLineCount(linesBefore.length, linesAfter.length);
+ const visibleLineCountAfter =
+ visibleLineCount(linesAfter.length, linesBefore.length);
+
+ const visibleBefore =
+ linesBefore.slice(linesBefore.length - visibleLineCountBefore)
+ .join('\n');
+ let visibleAfter = linesAfter.slice(0, visibleLineCountAfter).join('\n');
+ // If the last character is a \n, force it to be rendered.
+ if (visibleAfter.charAt(visibleAfter.length - 1) == '\n') {
+ visibleAfter += ' ';
+ }
+
+ this.highlighted_ = highlight;
+ this.highlightDescription_ = this.getAccessibilityHighlightDescription_(
+ linesBefore.length, highlight.split('\n').length);
+ this.before_ = visibleBefore;
+ this.after_ = visibleAfter;
+ this.truncatedBefore_ = linesBefore.length - visibleLineCountBefore;
+ this.truncatedAfter_ = linesAfter.length - visibleLineCountAfter;
+
+ const visibleCode = visibleBefore + highlight + visibleAfter;
+
+ this.setLineNumbers_(
+ this.truncatedBefore_ + 1,
+ this.truncatedBefore_ + visibleCode.split('\n').length);
+ this.scrollToHighlight_(visibleLineCountBefore);
+ },
+
+ /**
+ * @param {number} lineCount
+ * @param {string} stringSingular
+ * @param {string} stringPluralTemplate
+ * @return {string}
+ * @private
+ */
+ getLinesNotShownLabel_(lineCount, stringSingular, stringPluralTemplate) {
+ return lineCount == 1 ?
+ stringSingular :
+ loadTimeData.substituteString(stringPluralTemplate, lineCount);
+ },
+
+ /**
+ * @param {number} start
+ * @param {number} end
+ * @private
+ */
+ setLineNumbers_: function(start, end) {
+ let lineNumbers = '';
+ for (let i = start; i <= end; ++i) {
+ lineNumbers += i + '\n';
+ }
+
+ this.lineNumbers_ = lineNumbers;
+ },
+
+ /**
+ * @param {number} linesBeforeHighlight
+ * @private
+ */
+ scrollToHighlight_: function(linesBeforeHighlight) {
+ const CSS_LINE_HEIGHT = 20;
+
+ // Count how many pixels is above the highlighted code.
+ const highlightTop = linesBeforeHighlight * CSS_LINE_HEIGHT;
+
+ // Find the position to show the highlight roughly in the middle.
+ const targetTop = highlightTop - this.clientHeight * 0.5;
+
+ this.$['scroll-container'].scrollTo({top: targetTop});
+ },
+
+ /**
+ * @param {number} lineStart
+ * @param {number} numLines
+ * @return {string}
+ * @private
+ */
+ getAccessibilityHighlightDescription_: function(lineStart, numLines) {
+ if (numLines > 1) {
+ return this.i18n(
+ 'accessibilityErrorMultiLine', lineStart.toString(),
+ (lineStart + numLines - 1).toString());
+ } else {
+ return this.i18n('accessibilityErrorLine', lineStart.toString());
+ }
+ },
+
+ /**
+ * @private
+ * @return {boolean}
+ */
+ computeShowNoCode_: function() {
+ return this.isActive && !this.highlighted_;
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/detail_view.html b/chromium/chrome/browser/resources/extensions/detail_view.html
index 23cdc7bc32e..6f63a2a978f 100644
--- a/chromium/chrome/browser/resources/extensions/detail_view.html
+++ b/chromium/chrome/browser/resources/extensions/detail_view.html
@@ -1,448 +1,413 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="iron-flex cr-shared-style cr-icons action-link
+ shared-style">
+ :host {
+ --iron-icon-fill-color: var(--cr-secondary-text-color);
+ display: block;
+ height: 100%;
+ }
-<link rel="import" href="chrome://resources/cr_elements/cr_container_shadow_behavior.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_link_row/cr_link_row.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
-<link rel="import" href="chrome://resources/cr_elements/icons.html">
-<link rel="import" href="chrome://resources/cr_elements/policy/cr_tooltip_icon.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">
-<link rel="import" href="chrome://resources/html/action_link.html">
-<link rel="import" href="chrome://resources/cr_elements/action_link_css.html">
-<link rel="import" href="chrome://resources/html/cr.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-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="chrome://resources/polymer/v1_0/paper-styles/color.html">
-<link rel="import" href="item_behavior.html">
-<link rel="import" href="item_util.html">
-<link rel="import" href="host_permissions_toggle_list.html">
-<link rel="import" href="navigation_helper.html">
-<link rel="import" href="runtime_host_permissions.html">
-<link rel="import" href="shared_style.html">
-<link rel="import" href="shared_vars.html">
-<link rel="import" href="strings.html">
-<link rel="import" href="toggle_row.html">
+ #enable-section {
+ margin-bottom: 8px;
+ }
-<dom-module id="extensions-detail-view">
- <template>
- <style include="iron-flex cr-shared-style cr-icons action-link
- shared-style">
- :host {
- --iron-icon-fill-color: var(--cr-secondary-text-color);
- display: block;
- height: 100%;
- }
+ #enable-section cr-tooltip-icon {
+ margin-inline-end: 20px;
+ }
- #enable-section {
- margin-bottom: 8px;
- }
+ #enable-section span {
+ color: var(--cr-secondary-text-color);
+ font-weight: 500;
+ }
- #enable-section cr-tooltip-icon {
- margin-inline-end: 20px;
- }
+ #enable-section .enabled-text {
+ color: var(--google-blue-500);
+ }
- #enable-section span {
- color: var(--cr-secondary-text-color);
- font-weight: 500;
- }
+ @media (prefers-color-scheme: dark) {
+ #enable-section .enabled-text {
+ color: var(--google-blue-refresh-300);
+ }
+ }
- #enable-section .enabled-text {
- color: var(--google-blue-500);
- }
+ #icon {
+ height: 24px;
+ margin-inline-end: 12px;
+ margin-inline-start: 16px;
+ width: 24px;
+ }
- @media (prefers-color-scheme: dark) {
- #enable-section .enabled-text {
- color: var(--google-blue-refresh-300);
- }
- }
+ #name {
+ flex-grow: 1;
+ }
- #icon {
- height: 24px;
- margin-inline-end: 12px;
- margin-inline-start: 16px;
- width: 24px;
- }
+ .section {
+ @apply --cr-section;
+ }
- #name {
- flex-grow: 1;
- }
+ .section.block {
+ box-sizing: border-box;
+ display: block;
+ padding-bottom: var(--cr-section-vertical-padding);
+ padding-top: var(--cr-section-vertical-padding);
+ }
- .section {
- @apply --cr-section;
- }
+ .section.continuation {
+ border-top: none;
+ }
- .section.block {
- box-sizing: border-box;
- display: block;
- padding-bottom: var(--cr-section-vertical-padding);
- padding-top: var(--cr-section-vertical-padding);
- }
+ .section.control-line {
+ justify-content: space-between;
+ }
- .section.continuation {
- border-top: none;
- }
+ .section:first-child {
+ border: none;
+ }
- .section.control-line {
- justify-content: space-between;
- }
+ .section-content {
+ color: var(--cr-secondary-text-color);
+ }
- .section:first-child {
- border: none;
- }
+ .actionable {
+ cursor: pointer;
+ }
- .section-content {
- color: var(--cr-secondary-text-color);
- }
+ .inspectable-view {
+ height: 20px;
+ width: auto; /* override the default button size of 24x24 */
+ }
- .actionable {
- cursor: pointer;
- }
+ @media (prefers-color-scheme: light) {
+ .warning .action-button {
+ background: white;
+ color: var(--google-blue-500);
+ }
- .inspectable-view {
- height: 20px;
- width: auto; /* override the default button size of 24x24 */
- }
+ #reload-button {
+ color: var(--google-blue-500);
+ }
+ }
- @media (prefers-color-scheme: light) {
- .warning .action-button {
- background: white;
- color: var(--google-blue-500);
- }
+ .warning span {
+ color: var(--error-color);
+ flex: 1;
+ }
- #reload-button {
- color: var(--google-blue-500);
- }
- }
+ .warning-icon {
+ --iron-icon-fill-color: var(--error-color);
+ flex-shrink: 0;
+ height: 18px;
+ margin-inline-end: 8px;
+ width: 18px;
+ }
- .warning span {
- color: var(--error-color);
- flex: 1;
- }
+ ul {
+ margin: 0;
+ padding-inline-start: 20px;
+ }
- .warning-icon {
- --iron-icon-fill-color: var(--error-color);
- flex-shrink: 0;
- height: 18px;
- margin-inline-end: 8px;
- width: 18px;
- }
+ #options-section .control-line:first-child {
+ border-top: var(--cr-separator-line);
+ }
- ul {
- margin: 0;
- padding-inline-start: 20px;
- }
+ extensions-toggle-row {
+ @apply --cr-section;
+ box-sizing: border-box;
+ padding-inline-end: 0;
+ padding-inline-start: 0;
+ --toggle-row-label-horizontal-padding: var(--cr-section-padding);
+ --toggle-row-label-vertical-padding: var(--cr-section-vertical-padding);
+ }
- #options-section .control-line:first-child {
- border-top: var(--cr-separator-line);
- }
+ #load-path {
+ word-break: break-all;
+ }
- extensions-toggle-row {
- @apply --cr-section;
- box-sizing: border-box;
- padding-inline-end: 0;
- padding-inline-start: 0;
- --toggle-row-label-horizontal-padding: var(--cr-section-padding);
- --toggle-row-label-vertical-padding: var(--cr-section-vertical-padding);
- }
+ #load-path > a[is='action-link'] {
+ display: inline;
+ }
- #load-path {
- word-break: break-all;
- }
+ #size {
+ align-items: center;
+ display: flex;
+ }
- #load-path > a[is='action-link'] {
- display: inline;
- }
-
- #size {
- align-items: center;
- display: flex;
- }
-
- paper-spinner-lite {
- @apply --cr-icon-height-width;
- }
- </style>
- <div class="page-container" id="container">
- <div class="page-content">
- <div class="page-header">
- <cr-icon-button class="icon-arrow-back no-overlap" id="closeButton"
- aria-label="$i18n{back}" on-click="onCloseButtonTap_">
- </cr-icon-button>
- <img id="icon" src="[[data.iconUrl]]"
- alt$="[[appOrExtension(
- data.type,
- '$i18nPolymer{appIcon}',
- '$i18nPolymer{extensionIcon}')]]">
- <span id="name" class="cr-title-text" role="heading" aria-level="1">
- [[data.name]]
- </span>
- </div>
- <div class="section continuation control-line" id="enable-section">
- <span class$="[[computeEnabledStyle_(data.state)]]">
- [[computeEnabledText_(data.state, '$i18nPolymer{itemOn}',
- '$i18nPolymer{itemOff}')]]
- </span>
- <div class="layout horizontal">
- <cr-tooltip-icon hidden$="[[!data.controlledInfo]]"
- tooltip-text="[[data.controlledInfo.text]]"
- icon-class="[[getIndicatorIcon_(data.controlledInfo.type)]]"
- icon-aria-label="[[data.controlledInfo.type]]">
- </cr-tooltip-icon>
- <template is="dom-if" if="[[isTerminated_(data.state)]]">
- <cr-button id="terminated-reload-button" class="action-button"
- on-click="onReloadTap_">
- $i18n{itemReload}
- </cr-button>
- </template>
- <cr-toggle id="enable-toggle"
- aria-label$="[[appOrExtension(
- data.type,
- '$i18nPolymer{appEnabled}',
- '$i18nPolymer{extensionEnabled}')]]"
- aria-describedby="name"
- checked="[[isEnabled_(data.state)]]"
- on-change="onEnableChange_"
- disabled="[[!isEnableToggleEnabled_(data.*)]]"
- hidden$="[[isTerminated_(data.state)]]">
- </cr-toggle>
- </div>
+ paper-spinner-lite {
+ @apply --cr-icon-height-width;
+ }
+</style>
+<div class="page-container" id="container">
+ <div class="page-content">
+ <div class="page-header">
+ <cr-icon-button class="icon-arrow-back no-overlap" id="closeButton"
+ aria-label="$i18n{back}" on-click="onCloseButtonTap_">
+ </cr-icon-button>
+ <img id="icon" src="[[data.iconUrl]]"
+ alt$="[[appOrExtension(
+ data.type,
+ '$i18nPolymer{appIcon}',
+ '$i18nPolymer{extensionIcon}')]]">
+ <span id="name" class="cr-title-text" role="heading" aria-level="1">
+ [[data.name]]
+ </span>
+ </div>
+ <div class="section continuation control-line" id="enable-section">
+ <span class$="[[computeEnabledStyle_(data.state)]]">
+ [[computeEnabledText_(data.state, '$i18nPolymer{itemOn}',
+ '$i18nPolymer{itemOff}')]]
+ </span>
+ <div class="layout horizontal">
+ <cr-tooltip-icon hidden$="[[!data.controlledInfo]]"
+ tooltip-text="[[data.controlledInfo.text]]"
+ icon-class="[[getIndicatorIcon_(data.controlledInfo.type)]]"
+ icon-aria-label="[[data.controlledInfo.type]]">
+ </cr-tooltip-icon>
+ <template is="dom-if" if="[[isTerminated_(data.state)]]">
+ <cr-button id="terminated-reload-button" class="action-button"
+ on-click="onReloadTap_">
+ $i18n{itemReload}
+ </cr-button>
+ </template>
+ <cr-toggle id="enable-toggle"
+ aria-label$="[[appOrExtension(
+ data.type,
+ '$i18nPolymer{appEnabled}',
+ '$i18nPolymer{extensionEnabled}')]]"
+ aria-describedby="name"
+ checked="[[isEnabled_(data.state)]]"
+ on-change="onEnableChange_"
+ disabled="[[!isEnableToggleEnabled_(data.*)]]"
+ hidden$="[[isTerminated_(data.state)]]">
+ </cr-toggle>
+ </div>
+ </div>
+ <div id="warnings" hidden$="[[!hasWarnings_(data.*)]]">
+ <div id="runtime-warnings" hidden$="[[!data.runtimeWarnings.length]]"
+ class="section continuation warning control-line">
+ <iron-icon class="warning-icon" icon="cr:error"></iron-icon>
+ <span>
+ <template is="dom-repeat" items="[[data.runtimeWarnings]]">
+ [[item]]
+ </template>
+ </span>
+ <template is="dom-if" if="[[!isTerminated_(data.state)]]">
+ <cr-button id="warnings-reload-button" class="action-button"
+ on-click="onReloadTap_">
+ $i18n{itemReload}
+ </cr-button>
+ </template>
+ </div>
+ <div class="section continuation warning" id="suspicious-warning"
+ hidden$="[[!data.disableReasons.suspiciousInstall]]">
+ <iron-icon class="warning-icon" icon="cr:warning"></iron-icon>
+ <span>
+ $i18n{itemSuspiciousInstall}
+ <a target="_blank" href="$i18n{suspiciousInstallHelpUrl}">
+ $i18n{learnMore}
+ </a>
+ </span>
+ </div>
+ <div class="section continuation warning control-line"
+ id="corrupted-warning"
+ hidden$="[[!data.disableReasons.corruptInstall]]">
+ <iron-icon class="warning-icon" icon="cr:warning"></iron-icon>
+ <span>$i18n{itemCorruptInstall}</span>
+ <cr-button id="repair-button" class="action-button"
+ on-click="onRepairTap_">
+ $i18n{itemRepair}
+ </cr-button>
+ </div>
+ <div class="section continuation warning" id="blacklisted-warning"
+ hidden$="[[!data.blacklistText]]">
+ <iron-icon class="warning-icon" icon="cr:warning"></iron-icon>
+ <span>[[data.blacklistText]]</span>
+ </div>
+ <div class="section continuation warning" id="update-required-warning"
+ hidden$="[[!data.disableReasons.updateRequired]]">
+ <iron-icon class="warning-icon" icon="cr:warning"></iron-icon>
+ <span>$i18n{updateRequiredByPolicy}</span>
+ </div>
+ </div>
+ <div class="section continuation block">
+ <div class="section-title" role="heading" aria-level="2">
+ $i18n{itemDescriptionLabel}
+ </div>
+ <div class="section-content" id="description">
+ [[getDescription_(data.description, '$i18nPolymer{noDescription}')]]
+ </div>
+ </div>
+ <div class="section block">
+ <div class="section-title" role="heading" aria-level="2">
+ $i18n{itemVersion}
+ </div>
+ <div class="section-content">[[data.version]]</div>
+ </div>
+ <div class="section block">
+ <div class="section-title" role="heading" aria-level="2">
+ $i18n{itemSize}
+ </div>
+ <div class="section-content" id="size">
+ <span>[[size_]]</span>
+ <paper-spinner-lite active="[[!size_]]" hidden="[[size_]]">
+ </paper-spinner-lite>
+ </div>
+ </div>
+ <div class="section block" id="id-section" hidden$="[[!inDevMode]]">
+ <div class="section-title" role="heading" aria-level="2">
+ $i18n{itemIdHeading}
+ </div>
+ <div class="section-content">[[data.id]]</div>
+ </div>
+ <template is="dom-if" if="[[inDevMode]]">
+ <div class="section block" id="inspectable-views">
+ <div class="section-title" role="heading" aria-level="2">
+ $i18n{itemInspectViews}
</div>
- <div id="warnings" hidden$="[[!hasWarnings_(data.*)]]">
- <div id="runtime-warnings" hidden$="[[!data.runtimeWarnings.length]]"
- class="section continuation warning control-line">
- <iron-icon class="warning-icon" icon="cr:error"></iron-icon>
- <span>
- <template is="dom-repeat" items="[[data.runtimeWarnings]]">
- [[item]]
- </template>
- </span>
- <template is="dom-if" if="[[!isTerminated_(data.state)]]">
- <cr-button id="warnings-reload-button" class="action-button"
- on-click="onReloadTap_">
- $i18n{itemReload}
- </cr-button>
+ <div class="section-content">
+ <ul id="inspect-views">
+ <li hidden="[[data.views.length]]">
+ $i18n{noActiveViews}
+ </li>
+ <template is="dom-repeat" items="[[data.views]]">
+ <li>
+ <a is="action-link" class="inspectable-view"
+ on-click="onInspectTap_">
+ [[computeInspectLabel_(item)]]
+ </a>
+ </li>
</template>
- </div>
- <div class="section continuation warning" id="suspicious-warning"
- hidden$="[[!data.disableReasons.suspiciousInstall]]">
- <iron-icon class="warning-icon" icon="cr:warning"></iron-icon>
- <span>
- $i18n{itemSuspiciousInstall}
- <a target="_blank" href="$i18n{suspiciousInstallHelpUrl}">
- $i18n{learnMore}
- </a>
- </span>
- </div>
- <div class="section continuation warning control-line"
- id="corrupted-warning"
- hidden$="[[!data.disableReasons.corruptInstall]]">
- <iron-icon class="warning-icon" icon="cr:warning"></iron-icon>
- <span>$i18n{itemCorruptInstall}</span>
- <cr-button id="repair-button" class="action-button"
- on-click="onRepairTap_">
- $i18n{itemRepair}
- </cr-button>
- </div>
- <div class="section continuation warning" id="blacklisted-warning"
- hidden$="[[!data.blacklistText]]">
- <iron-icon class="warning-icon" icon="cr:warning"></iron-icon>
- <span>[[data.blacklistText]]</span>
- </div>
- <div class="section continuation warning" id="update-required-warning"
- hidden$="[[!data.disableReasons.updateRequired]]">
- <iron-icon class="warning-icon" icon="cr:warning"></iron-icon>
- <span>$i18n{updateRequiredByPolicy}</span>
- </div>
- </div>
- <div class="section continuation block">
- <div class="section-title" role="heading" aria-level="2">
- $i18n{itemDescriptionLabel}
- </div>
- <div class="section-content" id="description">
- [[getDescription_(data.description, '$i18nPolymer{noDescription}')]]
- </div>
- </div>
- <div class="section block">
- <div class="section-title" role="heading" aria-level="2">
- $i18n{itemVersion}
- </div>
- <div class="section-content">[[data.version]]</div>
+ </ul>
</div>
- <div class="section block">
- <div class="section-title" role="heading" aria-level="2">
- $i18n{itemSize}
- </div>
- <div class="section-content" id="size">
- <span>[[size_]]</span>
- <paper-spinner-lite active="[[!size_]]" hidden="[[size_]]">
- </paper-spinner-lite>
- </div>
- </div>
- <div class="section block" id="id-section" hidden$="[[!inDevMode]]">
- <div class="section-title" role="heading" aria-level="2">
- $i18n{itemIdHeading}
- </div>
- <div class="section-content">[[data.id]]</div>
- </div>
- <template is="dom-if" if="[[inDevMode]]">
- <div class="section block" id="inspectable-views">
- <div class="section-title" role="heading" aria-level="2">
- $i18n{itemInspectViews}
- </div>
- <div class="section-content">
- <ul id="inspect-views">
- <li hidden="[[data.views.length]]">
- $i18n{noActiveViews}
- </li>
- <template is="dom-repeat" items="[[data.views]]">
- <li>
- <a is="action-link" class="inspectable-view"
- on-click="onInspectTap_">
- [[computeInspectLabel_(item)]]
- </a>
- </li>
+ </div>
+ </template>
+ <div class="section block">
+ <div class="section-title" role="heading" aria-level="2">
+ $i18n{itemPermissions}
+ </div>
+ <div class="section-content">
+ <span id="no-permissions" hidden$="[[hasPermissions_(data.*)]]">
+ $i18n{itemPermissionsEmpty}
+ </span>
+ <ul id="permissions-list"
+ hidden$="[[!data.permissions.simplePermissions.length]]">
+ <template is="dom-repeat"
+ items="[[data.permissions.simplePermissions]]">
+ <li>
+ [[item.message]]
+ <ul hidden="[[!item.submessages.length]]">
+ <template is="dom-repeat" items="[[item.submessages]]">
+ <li>[[item]]</li>
</template>
</ul>
- </div>
- </div>
+ </li>
+ </template>
+ </ul>
+ </div>
+ </div>
+ <div class="section block">
+ <div class="section-title" role="heading" aria-level="2">
+ $i18n{itemSiteAccess}
+ </div>
+ <div class="section-content">
+ <span id="no-site-access"
+ hidden$="[[showSiteAccessContent_(data.*)]]">
+ $i18n{itemSiteAccessEmpty}
+ </span>
+ <template is="dom-if"
+ if="[[showFreeformRuntimeHostPermissions_(data.*)]]">
+ <extensions-runtime-host-permissions
+ permissions="[[data.permissions.runtimeHostPermissions]]"
+ delegate="[[delegate]]"
+ item-id="[[data.id]]">
+ </extensions-runtime-host-permissions>
</template>
- <div class="section block">
- <div class="section-title" role="heading" aria-level="2">
- $i18n{itemPermissions}
- </div>
- <div class="section-content">
- <span id="no-permissions" hidden$="[[hasPermissions_(data.*)]]">
- $i18n{itemPermissionsEmpty}
- </span>
- <ul id="permissions-list"
- hidden$="[[!data.permissions.simplePermissions.length]]">
- <template is="dom-repeat"
- items="[[data.permissions.simplePermissions]]">
- <li>
- [[item.message]]
- <ul hidden="[[!item.submessages.length]]">
- <template is="dom-repeat" items="[[item.submessages]]">
- <li>[[item]]</li>
- </template>
- </ul>
- </li>
- </template>
- </ul>
- </div>
+ <template is="dom-if"
+ if="[[showHostPermissionsToggleList_(data.*)]]">
+ <extensions-host-permissions-toggle-list
+ permissions="[[data.permissions.runtimeHostPermissions]]"
+ delegate="[[delegate]]"
+ item-id="[[data.id]]">
+ </extensions-host-permissions-toggle-list>
+ </template>
+ </div>
+ </div>
+ <template is="dom-if"
+ if="[[hasDependentExtensions_(data.dependentExtensions.splices)]]">
+ <div class="section block">
+ <div class="section-title" role="heading" aria-level="2">
+ $i18n{itemDependencies}
</div>
- <div class="section block">
- <div class="section-title" role="heading" aria-level="2">
- $i18n{itemSiteAccess}
- </div>
- <div class="section-content">
- <span id="no-site-access"
- hidden$="[[showSiteAccessContent_(data.*)]]">
- $i18n{itemSiteAccessEmpty}
- </span>
- <template is="dom-if"
- if="[[showFreeformRuntimeHostPermissions_(data.*)]]">
- <extensions-runtime-host-permissions
- permissions="[[data.permissions.runtimeHostPermissions]]"
- delegate="[[delegate]]"
- item-id="[[data.id]]">
- </extensions-runtime-host-permissions>
+ <div class="section-content">
+ <ul id="dependent-extensions-list">
+ <template is="dom-repeat" items="[[data.dependentExtensions]]">
+ <li>[[computeDependentEntry_(item)]]</li>
</template>
- <template is="dom-if"
- if="[[showHostPermissionsToggleList_(data.*)]]">
- <extensions-host-permissions-toggle-list
- permissions="[[data.permissions.runtimeHostPermissions]]"
- delegate="[[delegate]]"
- item-id="[[data.id]]">
- </extensions-host-permissions-toggle-list>
- </template>
- </div>
+ </ul>
</div>
+ </div>
+ </template>
+ <template is="dom-if" if="[[shouldShowOptionsSection_(data.*)]]">
+ <div id="options-section">
<template is="dom-if"
- if="[[hasDependentExtensions_(data.dependentExtensions.splices)]]">
- <div class="section block">
- <div class="section-title" role="heading" aria-level="2">
- $i18n{itemDependencies}
+ if="[[shouldShowIncognitoOption_(
+ data.incognitoAccess.isEnabled, incognitoAvailable)]]">
+ <extensions-toggle-row id="allow-incognito"
+ checked="[[data.incognitoAccess.isActive]]"
+ on-change="onAllowIncognitoChange_">
+ <div>
+ <div>$i18n{itemAllowIncognito}</div>
+ <div class="section-content">$i18n{incognitoInfoWarning}</div>
</div>
- <div class="section-content">
- <ul id="dependent-extensions-list">
- <template is="dom-repeat" items="[[data.dependentExtensions]]">
- <li>[[computeDependentEntry_(item)]]</li>
- </template>
- </ul>
- </div>
- </div>
+ </extensions-toggle-row>
</template>
- <template is="dom-if" if="[[shouldShowOptionsSection_(data.*)]]">
- <div id="options-section">
- <template is="dom-if"
- if="[[shouldShowIncognitoOption_(
- data.incognitoAccess.isEnabled, incognitoAvailable)]]">
- <extensions-toggle-row id="allow-incognito"
- checked="[[data.incognitoAccess.isActive]]"
- on-change="onAllowIncognitoChange_">
- <div>
- <div>$i18n{itemAllowIncognito}</div>
- <div class="section-content">$i18n{incognitoInfoWarning}</div>
- </div>
- </extensions-toggle-row>
- </template>
- <template is="dom-if" if="[[data.fileAccess.isEnabled]]">
- <extensions-toggle-row id="allow-on-file-urls"
- checked="[[data.fileAccess.isActive]]"
- on-change="onAllowOnFileUrlsChange_">
- <span>$i18n{itemAllowOnFileUrls}</span>
- </extensions-toggle-row>
- </template>
- <template is="dom-if" if="[[data.errorCollection.isEnabled]]">
- <extensions-toggle-row id="collect-errors"
- checked="[[data.errorCollection.isActive]]"
- on-change="onCollectErrorsChange_">
- <span>$i18n{itemCollectErrors}</span>
- </extensions-toggle-row>
- </template>
- </div>
+ <template is="dom-if" if="[[data.fileAccess.isEnabled]]">
+ <extensions-toggle-row id="allow-on-file-urls"
+ checked="[[data.fileAccess.isActive]]"
+ on-change="onAllowOnFileUrlsChange_">
+ <span>$i18n{itemAllowOnFileUrls}</span>
+ </extensions-toggle-row>
</template>
- <cr-link-row class="hr" id="extensions-options"
- disabled="[[!isEnabled_(data.state)]]"
- hidden="[[!shouldShowOptionsLink_(data.*)]]"
- label="$i18n{itemOptions}" on-click="onExtensionOptionsTap_"
- external></cr-link-row>
- <cr-link-row class="hr"
- id="extensionsActivityLogLink" hidden$="[[!showActivityLog]]"
- label="$i18n{viewActivityLog}" on-click="onActivityLogTap_">
- </cr-link-row>
- <cr-link-row class="hr" hidden="[[!data.manifestHomePageUrl.length]]"
- id="extensionWebsite" label="$i18n{extensionWebsite}"
- on-click="onExtensionWebSiteTap_" external></cr-link-row>
- <cr-link-row class="hr" hidden="[[!data.webStoreUrl.length]]"
- id="viewInStore" label="$i18n{viewInStore}"
- on-click="onViewInStoreTap_" external></cr-link-row>
- <div class="section block">
- <div class="section-title" role="heading" aria-level="2">
- $i18n{itemSource}
- </div>
- <div id="source" class="section-content">
- [[computeSourceString_(data.*)]]
- </div>
- <div id="load-path" class="section-content"
- hidden$="[[!data.prettifiedPath]]">
- <span>$i18n{itemExtensionPath}</span>
- <a is="action-link" on-click="onLoadPathTap_">
- [[data.prettifiedPath]]
- </a>
- </div>
- </div>
- <cr-link-row class="hr" id="remove-extension"
- hidden="[[isControlled_(data.controlledInfo)]]"
- label="$i18n{itemRemoveExtension}" on-click="onRemoveTap_">
- </cr-link-row>
+ <template is="dom-if" if="[[data.errorCollection.isEnabled]]">
+ <extensions-toggle-row id="collect-errors"
+ checked="[[data.errorCollection.isActive]]"
+ on-change="onCollectErrorsChange_">
+ <span>$i18n{itemCollectErrors}</span>
+ </extensions-toggle-row>
+ </template>
+ </div>
+ </template>
+ <cr-link-row class="hr" id="extensions-options"
+ disabled="[[!isEnabled_(data.state)]]"
+ hidden="[[!shouldShowOptionsLink_(data.*)]]"
+ label="$i18n{itemOptions}" on-click="onExtensionOptionsTap_"
+ external></cr-link-row>
+ <cr-link-row class="hr"
+ id="extensionsActivityLogLink" hidden$="[[!showActivityLog]]"
+ label="$i18n{viewActivityLog}" on-click="onActivityLogTap_">
+ </cr-link-row>
+ <cr-link-row class="hr" hidden="[[!data.manifestHomePageUrl.length]]"
+ id="extensionWebsite" label="$i18n{extensionWebsite}"
+ on-click="onExtensionWebSiteTap_" external></cr-link-row>
+ <cr-link-row class="hr" hidden="[[!data.webStoreUrl.length]]"
+ id="viewInStore" label="$i18n{viewInStore}"
+ on-click="onViewInStoreTap_" external></cr-link-row>
+ <div class="section block">
+ <div class="section-title" role="heading" aria-level="2">
+ $i18n{itemSource}
+ </div>
+ <div id="source" class="section-content">
+ [[computeSourceString_(data.*)]]
+ </div>
+ <div id="load-path" class="section-content"
+ hidden$="[[!data.prettifiedPath]]">
+ <span>$i18n{itemExtensionPath}</span>
+ <a is="action-link" on-click="onLoadPathTap_">
+ [[data.prettifiedPath]]
+ </a>
</div>
</div>
- </template>
- <script src="detail_view.js"></script>
-</dom-module>
+ <cr-link-row class="hr" id="remove-extension"
+ hidden="[[isControlled_(data.controlledInfo)]]"
+ label="$i18n{itemRemoveExtension}" on-click="onRemoveTap_">
+ </cr-link-row>
+ </div>
+</div>
diff --git a/chromium/chrome/browser/resources/extensions/detail_view.js b/chromium/chrome/browser/resources/extensions/detail_view.js
index 53d33c481d0..562c6ba0fb4 100644
--- a/chromium/chrome/browser/resources/extensions/detail_view.js
+++ b/chromium/chrome/browser/resources/extensions/detail_view.js
@@ -2,359 +2,381 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
-
- const DetailView = Polymer({
- is: 'extensions-detail-view',
-
- behaviors: [
- CrContainerShadowBehavior,
- extensions.ItemBehavior,
- ],
-
- properties: {
- /**
- * The underlying ExtensionInfo for the details being displayed.
- * @type {!chrome.developerPrivate.ExtensionInfo}
- */
- data: Object,
-
- /** @private */
- size_: String,
-
- /** @type {!extensions.ItemDelegate} */
- delegate: Object,
-
- /** Whether the user has enabled the UI's developer mode. */
- inDevMode: Boolean,
-
- /** Whether "allow in incognito" option should be shown. */
- incognitoAvailable: Boolean,
-
- /** Whether "View Activity Log" link should be shown. */
- showActivityLog: Boolean,
-
- /** Whether the user navigated to this page from the activity log page. */
- fromActivityLog: Boolean,
- },
-
- observers: [
- 'onItemIdChanged_(data.id, delegate)',
- ],
-
- listeners: {
- 'view-enter-start': 'onViewEnterStart_',
- },
-
- /**
- * Focuses the extensions options button. This should be used after the
- * dialog closes.
- */
- focusOptionsButton: function() {
- this.$$('#extensions-options').focus();
- },
-
- /**
- * Focuses the back button when page is loaded.
- * @private
- */
- onViewEnterStart_: function() {
- const elementToFocus = this.fromActivityLog ?
- this.$.extensionsActivityLogLink :
- this.$.closeButton;
-
- Polymer.RenderStatus.afterNextRender(
- this, () => cr.ui.focusWithoutInk(elementToFocus));
- },
-
- /** @private */
- onItemIdChanged_: function() {
- // Clear the size, since this view is reused, such that no obsolete size
- // is displayed.:
- this.size_ = '';
- this.delegate.getExtensionSize(this.data.id).then(size => {
- this.size_ = size;
- });
- },
-
- /** @private */
- onActivityLogTap_: function() {
- extensions.navigation.navigateTo(
- {page: extensions.Page.ACTIVITY_LOG, extensionId: this.data.id});
- },
-
+import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
+import 'chrome://resources/cr_elements/cr_icons_css.m.js';
+import 'chrome://resources/cr_elements/cr_link_row/cr_link_row.m.js';
+import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.m.js';
+import 'chrome://resources/cr_elements/icons.m.js';
+import 'chrome://resources/cr_elements/policy/cr_tooltip_icon.m.js';
+import 'chrome://resources/cr_elements/shared_style_css.m.js';
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+import 'chrome://resources/js/action_link.js';
+import 'chrome://resources/cr_elements/action_link_css.m.js';
+import 'chrome://resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js';
+import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
+import 'chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js';
+import 'chrome://resources/polymer/v3_0/paper-styles/color.js';
+import './host_permissions_toggle_list.js';
+import './runtime_host_permissions.js';
+import './shared_style.js';
+import './shared_vars.js';
+import './strings.m.js';
+import './toggle_row.js';
+
+import {CrContainerShadowBehavior} from 'chrome://resources/cr_elements/cr_container_shadow_behavior.m.js';
+import {focusWithoutInk} from 'chrome://resources/js/cr/ui/focus_without_ink.m.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+import {afterNextRender, html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {ItemDelegate} from './item.js';
+import {ItemBehavior} from './item_behavior.js';
+import {computeInspectableViewLabel, getItemSource, getItemSourceString, isControlled, isEnabled, userCanChangeEnablement} from './item_util.js';
+import {navigation, Page} from './navigation_helper.js';
+
+Polymer({
+ is: 'extensions-detail-view',
+
+ _template: html`{__html_template__}`,
+
+ behaviors: [
+ CrContainerShadowBehavior,
+ ItemBehavior,
+ ],
+
+ properties: {
/**
- * @param {string} description
- * @param {string} fallback
- * @return {string}
- * @private
+ * The underlying ExtensionInfo for the details being displayed.
+ * @type {!chrome.developerPrivate.ExtensionInfo}
*/
- getDescription_: function(description, fallback) {
- return description || fallback;
- },
+ data: Object,
/** @private */
- onCloseButtonTap_: function() {
- extensions.navigation.navigateTo({page: extensions.Page.LIST});
- },
-
- /**
- * @return {boolean}
- * @private
- */
- isControlled_: function() {
- return extensions.isControlled(this.data);
- },
-
- /**
- * @return {boolean}
- * @private
- */
- isEnabled_: function() {
- return extensions.isEnabled(this.data.state);
- },
-
- /**
- * @return {boolean}
- * @private
- */
- isEnableToggleEnabled_: function() {
- return extensions.userCanChangeEnablement(this.data);
- },
-
- /**
- * Returns true if the extension is in the terminated state.
- * @return {boolean}
- * @private
- */
- isTerminated_: function() {
- return this.data.state ==
- chrome.developerPrivate.ExtensionState.TERMINATED;
- },
-
- /**
- * @return {boolean}
- * @private
- */
- hasDependentExtensions_: function() {
- return this.data.dependentExtensions.length > 0;
- },
-
- /**
- * @return {boolean}
- * @private
- */
- hasWarnings_: function() {
- return this.data.disableReasons.corruptInstall ||
- this.data.disableReasons.suspiciousInstall ||
- this.data.disableReasons.updateRequired ||
- !!this.data.blacklistText || this.data.runtimeWarnings.length > 0;
- },
-
- /**
- * @return {string}
- * @private
- */
- computeEnabledStyle_: function() {
- return this.isEnabled_() ? 'enabled-text' : '';
- },
-
- /**
- * @param {!chrome.developerPrivate.ExtensionState} state
- * @param {string} onText
- * @param {string} offText
- * @return {string}
- * @private
- */
- computeEnabledText_: function(state, onText, offText) {
- // TODO(devlin): Get the full spectrum of these strings from bettes.
- return extensions.isEnabled(state) ? onText : offText;
- },
-
- /**
- * @param {!chrome.developerPrivate.ExtensionView} view
- * @return {string}
- * @private
- */
- computeInspectLabel_: function(view) {
- return extensions.computeInspectableViewLabel(view);
- },
-
- /**
- * @return {boolean}
- * @private
- */
- shouldShowOptionsLink_: function() {
- return !!this.data.optionsPage;
- },
-
- /**
- * @return {boolean}
- * @private
- */
- shouldShowOptionsSection_: function() {
- return this.data.incognitoAccess.isEnabled ||
- this.data.fileAccess.isEnabled || this.data.errorCollection.isEnabled;
- },
-
- /**
- * @return {boolean}
- * @private
- */
- shouldShowIncognitoOption_: function() {
- return this.data.incognitoAccess.isEnabled && this.incognitoAvailable;
- },
-
- /** @private */
- onEnableChange_: function() {
- this.delegate.setItemEnabled(
- this.data.id, this.$['enable-toggle'].checked);
- },
-
- /**
- * @param {!{model: !{item: !chrome.developerPrivate.ExtensionView}}} e
- * @private
- */
- onInspectTap_: function(e) {
- this.delegate.inspectItemView(this.data.id, e.model.item);
- },
-
- /** @private */
- onExtensionOptionsTap_: function() {
- this.delegate.showItemOptionsPage(this.data);
- },
-
- /** @private */
- onReloadTap_: function() {
- this.delegate.reloadItem(this.data.id).catch(loadError => {
- this.fire('load-error', loadError);
- });
- },
-
- /** @private */
- onRemoveTap_: function() {
- this.delegate.deleteItem(this.data.id);
- },
-
- /** @private */
- onRepairTap_: function() {
- this.delegate.repairItem(this.data.id);
- },
-
- /** @private */
- onLoadPathTap_: function() {
- this.delegate.showInFolder(this.data.id);
- },
-
- /** @private */
- onAllowIncognitoChange_: function() {
- this.delegate.setItemAllowedIncognito(
- this.data.id, this.$$('#allow-incognito').checked);
- },
-
- /** @private */
- onAllowOnFileUrlsChange_: function() {
- this.delegate.setItemAllowedOnFileUrls(
- this.data.id, this.$$('#allow-on-file-urls').checked);
- },
-
- /** @private */
- onCollectErrorsChange_: function() {
- this.delegate.setItemCollectsErrors(
- this.data.id, this.$$('#collect-errors').checked);
- },
-
- /** @private */
- onExtensionWebSiteTap_: function() {
- this.delegate.openUrl(this.data.manifestHomePageUrl);
- },
-
- /** @private */
- onViewInStoreTap_: function() {
- this.delegate.openUrl(this.data.webStoreUrl);
- },
-
- /**
- * @param {!chrome.developerPrivate.DependentExtension} item
- * @return {string}
- * @private
- */
- computeDependentEntry_: function(item) {
- return loadTimeData.getStringF('itemDependentEntry', item.name, item.id);
- },
-
- /**
- * @return {string}
- * @private
- */
- computeSourceString_: function() {
- return this.data.locationText ||
- extensions.getItemSourceString(extensions.getItemSource(this.data));
- },
-
- /**
- * @param {chrome.developerPrivate.ControllerType} type
- * @return {string}
- * @private
- */
- getIndicatorIcon_: function(type) {
- switch (type) {
- case 'POLICY':
- return 'cr20:domain';
- case 'CHILD_CUSTODIAN':
- return 'cr:account-child-invert';
- case 'SUPERVISED_USER_CUSTODIAN':
- return 'cr:supervisor-account';
- default:
- return '';
- }
- },
-
- /**
- * @return {boolean}
- * @private
- */
- hasPermissions_: function() {
- return this.data.permissions.simplePermissions.length > 0 ||
- this.hasRuntimeHostPermissions_();
- },
-
- /**
- * @return {boolean}
- * @private
- */
- hasRuntimeHostPermissions_: function() {
- return !!this.data.permissions.runtimeHostPermissions;
- },
-
- /**
- * @return {boolean}
- * @private
- */
- showSiteAccessContent_: function() {
- return this.showFreeformRuntimeHostPermissions_() ||
- this.showHostPermissionsToggleList_();
- },
-
- /**
- * @return {boolean}
- * @private
- */
- showFreeformRuntimeHostPermissions_: function() {
- return this.hasRuntimeHostPermissions_() &&
- this.data.permissions.runtimeHostPermissions.hasAllHosts;
- },
-
- /**
- * @return {boolean}
- * @private
- */
- showHostPermissionsToggleList_: function() {
- return this.hasRuntimeHostPermissions_() &&
- !this.data.permissions.runtimeHostPermissions.hasAllHosts;
- },
- });
-
- return {DetailView: DetailView};
+ size_: String,
+
+ /** @type {!ItemDelegate} */
+ delegate: Object,
+
+ /** Whether the user has enabled the UI's developer mode. */
+ inDevMode: Boolean,
+
+ /** Whether "allow in incognito" option should be shown. */
+ incognitoAvailable: Boolean,
+
+ /** Whether "View Activity Log" link should be shown. */
+ showActivityLog: Boolean,
+
+ /** Whether the user navigated to this page from the activity log page. */
+ fromActivityLog: Boolean,
+ },
+
+ observers: [
+ 'onItemIdChanged_(data.id, delegate)',
+ ],
+
+ listeners: {
+ 'view-enter-start': 'onViewEnterStart_',
+ },
+
+ /**
+ * Focuses the extensions options button. This should be used after the
+ * dialog closes.
+ */
+ focusOptionsButton: function() {
+ this.$$('#extensions-options').focus();
+ },
+
+ /**
+ * Focuses the back button when page is loaded.
+ * @private
+ */
+ onViewEnterStart_: function() {
+ const elementToFocus = this.fromActivityLog ?
+ this.$.extensionsActivityLogLink :
+ this.$.closeButton;
+
+ afterNextRender(this, () => focusWithoutInk(elementToFocus));
+ },
+
+ /** @private */
+ onItemIdChanged_: function() {
+ // Clear the size, since this view is reused, such that no obsolete size
+ // is displayed.:
+ this.size_ = '';
+ this.delegate.getExtensionSize(this.data.id).then(size => {
+ this.size_ = size;
+ });
+ },
+
+ /** @private */
+ onActivityLogTap_: function() {
+ navigation.navigateTo({page: Page.ACTIVITY_LOG, extensionId: this.data.id});
+ },
+
+ /**
+ * @param {string} description
+ * @param {string} fallback
+ * @return {string}
+ * @private
+ */
+ getDescription_: function(description, fallback) {
+ return description || fallback;
+ },
+
+ /** @private */
+ onCloseButtonTap_: function() {
+ navigation.navigateTo({page: Page.LIST});
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ isControlled_: function() {
+ return isControlled(this.data);
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ isEnabled_: function() {
+ return isEnabled(this.data.state);
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ isEnableToggleEnabled_: function() {
+ return userCanChangeEnablement(this.data);
+ },
+
+ /**
+ * Returns true if the extension is in the terminated state.
+ * @return {boolean}
+ * @private
+ */
+ isTerminated_: function() {
+ return this.data.state == chrome.developerPrivate.ExtensionState.TERMINATED;
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ hasDependentExtensions_: function() {
+ return this.data.dependentExtensions.length > 0;
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ hasWarnings_: function() {
+ return this.data.disableReasons.corruptInstall ||
+ this.data.disableReasons.suspiciousInstall ||
+ this.data.disableReasons.updateRequired || !!this.data.blacklistText ||
+ this.data.runtimeWarnings.length > 0;
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ computeEnabledStyle_: function() {
+ return this.isEnabled_() ? 'enabled-text' : '';
+ },
+
+ /**
+ * @param {!chrome.developerPrivate.ExtensionState} state
+ * @param {string} onText
+ * @param {string} offText
+ * @return {string}
+ * @private
+ */
+ computeEnabledText_: function(state, onText, offText) {
+ // TODO(devlin): Get the full spectrum of these strings from bettes.
+ return isEnabled(state) ? onText : offText;
+ },
+
+ /**
+ * @param {!chrome.developerPrivate.ExtensionView} view
+ * @return {string}
+ * @private
+ */
+ computeInspectLabel_: function(view) {
+ return computeInspectableViewLabel(view);
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ shouldShowOptionsLink_: function() {
+ return !!this.data.optionsPage;
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ shouldShowOptionsSection_: function() {
+ return this.data.incognitoAccess.isEnabled ||
+ this.data.fileAccess.isEnabled || this.data.errorCollection.isEnabled;
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ shouldShowIncognitoOption_: function() {
+ return this.data.incognitoAccess.isEnabled && this.incognitoAvailable;
+ },
+
+ /** @private */
+ onEnableChange_: function() {
+ this.delegate.setItemEnabled(this.data.id, this.$['enable-toggle'].checked);
+ },
+
+ /**
+ * @param {!{model: !{item: !chrome.developerPrivate.ExtensionView}}} e
+ * @private
+ */
+ onInspectTap_: function(e) {
+ this.delegate.inspectItemView(this.data.id, e.model.item);
+ },
+
+ /** @private */
+ onExtensionOptionsTap_: function() {
+ this.delegate.showItemOptionsPage(this.data);
+ },
+
+ /** @private */
+ onReloadTap_: function() {
+ this.delegate.reloadItem(this.data.id).catch(loadError => {
+ this.fire('load-error', loadError);
+ });
+ },
+
+ /** @private */
+ onRemoveTap_: function() {
+ this.delegate.deleteItem(this.data.id);
+ },
+
+ /** @private */
+ onRepairTap_: function() {
+ this.delegate.repairItem(this.data.id);
+ },
+
+ /** @private */
+ onLoadPathTap_: function() {
+ this.delegate.showInFolder(this.data.id);
+ },
+
+ /** @private */
+ onAllowIncognitoChange_: function() {
+ this.delegate.setItemAllowedIncognito(
+ this.data.id, this.$$('#allow-incognito').checked);
+ },
+
+ /** @private */
+ onAllowOnFileUrlsChange_: function() {
+ this.delegate.setItemAllowedOnFileUrls(
+ this.data.id, this.$$('#allow-on-file-urls').checked);
+ },
+
+ /** @private */
+ onCollectErrorsChange_: function() {
+ this.delegate.setItemCollectsErrors(
+ this.data.id, this.$$('#collect-errors').checked);
+ },
+
+ /** @private */
+ onExtensionWebSiteTap_: function() {
+ this.delegate.openUrl(this.data.manifestHomePageUrl);
+ },
+
+ /** @private */
+ onViewInStoreTap_: function() {
+ this.delegate.openUrl(this.data.webStoreUrl);
+ },
+
+ /**
+ * @param {!chrome.developerPrivate.DependentExtension} item
+ * @return {string}
+ * @private
+ */
+ computeDependentEntry_: function(item) {
+ return loadTimeData.getStringF('itemDependentEntry', item.name, item.id);
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ computeSourceString_: function() {
+ return this.data.locationText ||
+ getItemSourceString(getItemSource(this.data));
+ },
+
+ /**
+ * @param {chrome.developerPrivate.ControllerType} type
+ * @return {string}
+ * @private
+ */
+ getIndicatorIcon_: function(type) {
+ switch (type) {
+ case 'POLICY':
+ return 'cr20:domain';
+ case 'SUPERVISED_USER_CUSTODIAN':
+ return 'cr:supervisor-account';
+ default:
+ return '';
+ }
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ hasPermissions_: function() {
+ return this.data.permissions.simplePermissions.length > 0 ||
+ this.hasRuntimeHostPermissions_();
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ hasRuntimeHostPermissions_: function() {
+ return !!this.data.permissions.runtimeHostPermissions;
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ showSiteAccessContent_: function() {
+ return this.showFreeformRuntimeHostPermissions_() ||
+ this.showHostPermissionsToggleList_();
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ showFreeformRuntimeHostPermissions_: function() {
+ return this.hasRuntimeHostPermissions_() &&
+ this.data.permissions.runtimeHostPermissions.hasAllHosts;
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ showHostPermissionsToggleList_: function() {
+ return this.hasRuntimeHostPermissions_() &&
+ !this.data.permissions.runtimeHostPermissions.hasAllHosts;
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/drag_and_drop_handler.html b/chromium/chrome/browser/resources/extensions/drag_and_drop_handler.html
deleted file mode 100644
index 5e959f2d095..00000000000
--- a/chromium/chrome/browser/resources/extensions/drag_and_drop_handler.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="service.html">
-<script src="drag_and_drop_handler.js"></script>
diff --git a/chromium/chrome/browser/resources/extensions/drag_and_drop_handler.js b/chromium/chrome/browser/resources/extensions/drag_and_drop_handler.js
index 15324adb0ef..a6bfab31897 100644
--- a/chromium/chrome/browser/resources/extensions/drag_and_drop_handler.js
+++ b/chromium/chrome/browser/resources/extensions/drag_and_drop_handler.js
@@ -2,109 +2,103 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
-
- /** @implements cr.ui.DragWrapperDelegate */
- class DragAndDropHandler {
- /**
- * @param {boolean} dragEnabled
- * @param {!EventTarget} target
- */
- constructor(dragEnabled, target) {
- this.dragEnabled = dragEnabled;
-
- /** @private {!EventTarget} */
- this.eventTarget_ = target;
- }
+import {DragWrapperDelegate} from 'chrome://resources/js/cr/ui/drag_wrapper.m.js';
- /** @override */
- shouldAcceptDrag(e) {
- // External Extension installation can be disabled globally, e.g. while a
- // different overlay is already showing.
- if (!this.dragEnabled) {
- return false;
- }
-
- // We can't access filenames during the 'dragenter' event, so we have to
- // wait until 'drop' to decide whether to do something with the file or
- // not.
- // See: http://www.w3.org/TR/2011/WD-html5-20110113/dnd.html#concept-dnd-p
- return !!e.dataTransfer.types &&
- e.dataTransfer.types.indexOf('Files') > -1;
- }
+import {Service} from './service.js';
- /** @override */
- doDragEnter() {
- extensions.Service.getInstance().notifyDragInstallInProgress();
- this.eventTarget_.dispatchEvent(
- new CustomEvent('extension-drag-started'));
- }
- /** @override */
- doDragLeave() {
- this.fireDragEnded_();
- }
+/** @implements DragWrapperDelegate */
+export class DragAndDropHandler {
+ /**
+ * @param {boolean} dragEnabled
+ * @param {!EventTarget} target
+ */
+ constructor(dragEnabled, target) {
+ this.dragEnabled = dragEnabled;
- /** @override */
- doDragOver(e) {
- e.preventDefault();
- }
+ /** @private {!EventTarget} */
+ this.eventTarget_ = target;
+ }
- /** @override */
- doDrop(e) {
- this.fireDragEnded_();
- if (e.dataTransfer.files.length != 1) {
- return;
- }
-
- let handled = false;
-
- // Files lack a check if they're a directory, but we can find out through
- // its item entry.
- const item = e.dataTransfer.items[0];
- if (item.kind === 'file' && item.webkitGetAsEntry().isDirectory) {
- handled = true;
- this.handleDirectoryDrop_();
- } else if (/\.(crx|user\.js|zip)$/i.test(e.dataTransfer.files[0].name)) {
- // Only process files that look like extensions. Other files should
- // navigate the browser normally.
- handled = true;
- this.handleFileDrop_();
- }
-
- if (handled) {
- e.preventDefault();
- }
+ /** @override */
+ shouldAcceptDrag(e) {
+ // External Extension installation can be disabled globally, e.g. while a
+ // different overlay is already showing.
+ if (!this.dragEnabled) {
+ return false;
}
- /**
- * Handles a dropped file.
- * @private
- */
- handleFileDrop_() {
- extensions.Service.getInstance().installDroppedFile();
+ // We can't access filenames during the 'dragenter' event, so we have to
+ // wait until 'drop' to decide whether to do something with the file or
+ // not.
+ // See: http://www.w3.org/TR/2011/WD-html5-20110113/dnd.html#concept-dnd-p
+ return !!e.dataTransfer.types && e.dataTransfer.types.indexOf('Files') > -1;
+ }
+
+ /** @override */
+ doDragEnter() {
+ Service.getInstance().notifyDragInstallInProgress();
+ this.eventTarget_.dispatchEvent(new CustomEvent('extension-drag-started'));
+ }
+
+ /** @override */
+ doDragLeave() {
+ this.fireDragEnded_();
+ }
+
+ /** @override */
+ doDragOver(e) {
+ e.preventDefault();
+ }
+
+ /** @override */
+ doDrop(e) {
+ this.fireDragEnded_();
+ if (e.dataTransfer.files.length != 1) {
+ return;
}
- /**
- * Handles a dropped directory.
- * @private
- */
- handleDirectoryDrop_() {
- extensions.Service.getInstance().loadUnpackedFromDrag().catch(
- loadError => {
- this.eventTarget_.dispatchEvent(new CustomEvent(
- 'drag-and-drop-load-error', {detail: loadError}));
- });
+ let handled = false;
+
+ // Files lack a check if they're a directory, but we can find out through
+ // its item entry.
+ const item = e.dataTransfer.items[0];
+ if (item.kind === 'file' && item.webkitGetAsEntry().isDirectory) {
+ handled = true;
+ this.handleDirectoryDrop_();
+ } else if (/\.(crx|user\.js|zip)$/i.test(e.dataTransfer.files[0].name)) {
+ // Only process files that look like extensions. Other files should
+ // navigate the browser normally.
+ handled = true;
+ this.handleFileDrop_();
}
- /** @private */
- fireDragEnded_() {
- this.eventTarget_.dispatchEvent(new CustomEvent('extension-drag-ended'));
+ if (handled) {
+ e.preventDefault();
}
}
- return {
- DragAndDropHandler: DragAndDropHandler,
- };
-});
+ /**
+ * Handles a dropped file.
+ * @private
+ */
+ handleFileDrop_() {
+ Service.getInstance().installDroppedFile();
+ }
+
+ /**
+ * Handles a dropped directory.
+ * @private
+ */
+ handleDirectoryDrop_() {
+ Service.getInstance().loadUnpackedFromDrag().catch(loadError => {
+ this.eventTarget_.dispatchEvent(
+ new CustomEvent('drag-and-drop-load-error', {detail: loadError}));
+ });
+ }
+
+ /** @private */
+ fireDragEnded_() {
+ this.eventTarget_.dispatchEvent(new CustomEvent('extension-drag-ended'));
+ }
+}
diff --git a/chromium/chrome/browser/resources/extensions/drop_overlay.html b/chromium/chrome/browser/resources/extensions/drop_overlay.html
index b3209817520..beedbf81ab2 100644
--- a/chromium/chrome/browser/resources/extensions/drop_overlay.html
+++ b/chromium/chrome/browser/resources/extensions/drop_overlay.html
@@ -1,57 +1,42 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="cr-hidden-style">
+ :host {
+ align-items: center;
+ background-color: rgba(241, 241, 241, .9);
+ color: var(--cr-secondary-text-color);
+ display: flex;
+ height: 100%;
+ justify-content: center;
+ position: absolute;
+ width: 100%;
+ z-index: 10;
+ }
-<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
-<link rel="import" href="chrome://resources/cr_elements/icons.html">
-<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/html/cr/ui/drag_wrapper.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
-<link rel="import" href="drag_and_drop_handler.html">
+ @media (prefers-color-scheme: dark) {
+ :host {
+ /* TODO(dbeam): share with cr-dialog dialog::backdrop? */
+ background-color: rgba(0, 0, 0, .6);
+ }
+ }
-<dom-module id="extensions-drop-overlay">
- <template>
- <style include="cr-hidden-style">
- :host {
- align-items: center;
- background-color: rgba(241, 241, 241, .9);
- color: var(--cr-secondary-text-color);
- display: flex;
- height: 100%;
- justify-content: center;
- position: absolute;
- width: 100%;
- z-index: 10;
- }
+ #container {
+ align-items: center;
+ display: flex;
+ flex-direction: column;
+ }
- @media (prefers-color-scheme: dark) {
- :host {
- /* TODO(dbeam): share with cr-dialog dialog::backdrop? */
- background-color: rgba(0, 0, 0, .6);
- }
- }
+ iron-icon {
+ height: 64px;
+ margin-bottom: 16px;
+ width: 64px;
+ }
- #container {
- align-items: center;
- display: flex;
- flex-direction: column;
- }
-
- iron-icon {
- height: 64px;
- margin-bottom: 16px;
- width: 64px;
- }
-
- #text {
- color: #6e6e6e;
- font-size: 123.1%;
- font-weight: 500;
- }
- </style>
- <div id="container">
- <iron-icon icon="cr:extension"></iron-icon>
- <div id="text">$i18n{dropToInstall}</div>
- </div>
- </template>
- <script src="drop_overlay.js"></script>
-</dom-module>
+ #text {
+ color: #6e6e6e;
+ font-size: 123.1%;
+ font-weight: 500;
+ }
+</style>
+<div id="container">
+ <iron-icon icon="cr:extension"></iron-icon>
+ <div id="text">$i18n{dropToInstall}</div>
+</div>
diff --git a/chromium/chrome/browser/resources/extensions/drop_overlay.js b/chromium/chrome/browser/resources/extensions/drop_overlay.js
index 913d7186a84..2a627f85c7a 100644
--- a/chromium/chrome/browser/resources/extensions/drop_overlay.js
+++ b/chromium/chrome/browser/resources/extensions/drop_overlay.js
@@ -2,12 +2,21 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-(function() {
-'use strict';
+import 'chrome://resources/cr_elements/hidden_style_css.m.js';
+import 'chrome://resources/cr_elements/icons.m.js';
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
+
+import {DragWrapper} from 'chrome://resources/js/cr/ui/drag_wrapper.m.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {DragAndDropHandler} from './drag_and_drop_handler.js';
Polymer({
is: 'extensions-drop-overlay',
+ _template: html`{__html_template__}`,
+
properties: {
/** @private {boolean} */
dragEnabled: {
@@ -20,8 +29,7 @@ Polymer({
created: function() {
this.hidden = true;
const dragTarget = document.documentElement;
- this.dragWrapperHandler_ =
- new extensions.DragAndDropHandler(true, dragTarget);
+ this.dragWrapperHandler_ = new DragAndDropHandler(true, dragTarget);
// TODO(devlin): All these dragTarget listeners leak (they aren't removed
// when the element is). This only matters in tests at the moment, but would
// be good to fix.
@@ -34,8 +42,7 @@ Polymer({
dragTarget.addEventListener('drag-and-drop-load-error', (e) => {
this.fire('load-error', e.detail);
});
- this.dragWrapper_ =
- new cr.ui.DragWrapper(dragTarget, this.dragWrapperHandler_);
+ this.dragWrapper_ = new DragWrapper(dragTarget, this.dragWrapperHandler_);
},
/**
@@ -46,4 +53,3 @@ Polymer({
this.dragWrapperHandler_.dragEnabled = dragEnabled;
},
});
-})();
diff --git a/chromium/chrome/browser/resources/extensions/error_page.html b/chromium/chrome/browser/resources/extensions/error_page.html
index 4e0e4784985..5f67a455dd8 100644
--- a/chromium/chrome/browser/resources/extensions/error_page.html
+++ b/chromium/chrome/browser/resources/extensions/error_page.html
@@ -1,215 +1,192 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
-
-<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_container_shadow_behavior.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
-<link rel="import" href="chrome://resources/cr_elements/icons.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">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/html/cr/ui/focus_outline_manager.html">
-<link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.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-styles/color.html">
-<link rel="import" href="code_section.html">
-<link rel="import" href="item_util.html">
-<link rel="import" href="navigation_helper.html">
-<link rel="import" href="shared_style.html">
-
-<dom-module id="extensions-error-page">
- <template>
- <style include="cr-icons cr-shared-style shared-style">
- :host {
- display: block;
- height: 100%;
- }
-
- iron-icon {
- --iron-icon-fill-color: var(--google-grey-refresh-700);
- @apply --cr-icon-height-width;
- flex-shrink: 0;
- }
-
- iron-icon[icon='cr:warning'] {
- /* TODO(dbeam): find dark mode equivalent for this orange. */
- --iron-icon-fill-color: var(--paper-orange-500);
- }
-
- iron-icon[icon='cr:error'] {
- --iron-icon-fill-color: var(--error-color);
- }
-
- .section {
- padding: 0 var(--cr-section-padding);
- }
-
- #heading {
- align-items: center;
- display: flex;
- height: 40px;
- margin-bottom: 30px;
- padding: 8px 12px 0;
- }
-
- #heading span {
- flex: 1;
- margin: 0 10px;
- }
-
- #errorsList {
- min-height: 100px;
- }
-
- .error-item {
- @apply --cr-section;
- padding-inline-start: 0;
- }
-
- .error-item cr-icon-button {
- margin: 0;
- }
-
- .error-item.selected {
- background-color: rgba(0, 0, 0, 0.08);
- }
-
- .error-item .start {
- align-items: center;
- align-self: stretch; /* Makes the tappable area fill its parent. */
- display: flex;
- flex: 1;
- padding: 0 var(--cr-section-padding);
- }
-
- .error-message {
- flex-grow: 1;
- margin-inline-start: 10px;
- word-break: break-word;
- }
-
- .devtools-controls {
- padding: 0 var(--cr-section-padding);
- }
-
- .details-heading {
- align-items: center;
- display: flex;
- height: var(--cr-section-min-height);
- }
-
- .stack-trace-container {
- list-style: none;
- margin-top: 0;
- padding: 0;
- }
-
- .stack-trace-container li {
- cursor: pointer;
- font-family: monospace;
- padding: 4px;
- }
-
- .stack-trace-container li.selected,
- .stack-trace-container li:hover {
- background: var(--google-blue-100);
- color: var(--google-grey-900); /* Same in light & dark modes. */
- }
-
- extensions-code-section {
- height: 200px;
- margin-bottom: 20px;
- }
-
- :host-context(.focus-outline-visible) .start:focus {
- outline: -webkit-focus-ring-color auto 5px;
- }
-
- .start:focus {
- outline: none;
- }
-
- .context-url {
- word-wrap: break-word;
- }
- </style>
- <div class="page-container" id="container">
- <div class="page-content">
- <div id="heading" class="cr-title-text">
- <cr-icon-button class="icon-arrow-back no-overlap" id="closeButton"
- aria-label="$i18n{back}" on-click="onCloseButtonTap_">
- </cr-icon-button>
- <span>$i18n{errorsPageHeading}</span>
- <cr-button on-click="onClearAllTap_" hidden="[[!entries_.length]]">
- $i18n{clearAll}
- </cr-button>
- </div>
- <div class="section">
- <div id="errorsList">
- <template is="dom-repeat" items="[[entries_]]">
- <div class="item-container">
- <div class$="error-item
- [[computeErrorClass_(item, selectedEntry_)]]">
- <div actionable class="start" on-click="onErrorItemAction_"
- on-keydown="onErrorItemAction_" tabindex="0"
- role="button" aria-expanded$="[[isAriaExpanded_(
- index, selectedEntry_)]]">
- <iron-icon icon$="cr:[[computeErrorIcon_(item)]]"
- title$="[[computeErrorTypeLabel_(item)]]">
- </iron-icon>
- <div id$="[[item.id]]" class="error-message">
- [[item.message]]
- </div>
- <div class$="cr-icon [[iconName_(index, selectedEntry_)]]">
- </div>
- </div>
- <div class="separator"></div>
- <cr-icon-button class="icon-delete-gray"
- on-click="onDeleteErrorAction_"
- aria-describedby$="[[item.id]]"
- aria-label="$i18n{clearEntry}"></cr-icon-button>
+<style include="cr-icons cr-shared-style shared-style">
+ :host {
+ display: block;
+ height: 100%;
+ }
+
+ iron-icon {
+ --iron-icon-fill-color: var(--google-grey-refresh-700);
+ @apply --cr-icon-height-width;
+ flex-shrink: 0;
+ }
+
+ iron-icon[icon='cr:warning'] {
+ /* TODO(dbeam): find dark mode equivalent for this orange. */
+ --iron-icon-fill-color: var(--paper-orange-500);
+ }
+
+ iron-icon[icon='cr:error'] {
+ --iron-icon-fill-color: var(--error-color);
+ }
+
+ .section {
+ padding: 0 var(--cr-section-padding);
+ }
+
+ #heading {
+ align-items: center;
+ display: flex;
+ height: 40px;
+ margin-bottom: 30px;
+ padding: 8px 12px 0;
+ }
+
+ #heading span {
+ flex: 1;
+ margin: 0 10px;
+ }
+
+ #errorsList {
+ min-height: 100px;
+ }
+
+ .error-item {
+ @apply --cr-section;
+ padding-inline-start: 0;
+ }
+
+ .error-item cr-icon-button {
+ margin: 0;
+ }
+
+ .error-item.selected {
+ background-color: rgba(0, 0, 0, 0.08);
+ }
+
+ .error-item .start {
+ align-items: center;
+ align-self: stretch; /* Makes the tappable area fill its parent. */
+ display: flex;
+ flex: 1;
+ padding: 0 var(--cr-section-padding);
+ }
+
+ .error-message {
+ flex-grow: 1;
+ margin-inline-start: 10px;
+ word-break: break-word;
+ }
+
+ .devtools-controls {
+ padding: 0 var(--cr-section-padding);
+ }
+
+ .details-heading {
+ align-items: center;
+ display: flex;
+ height: var(--cr-section-min-height);
+ }
+
+ .stack-trace-container {
+ list-style: none;
+ margin-top: 0;
+ padding: 0;
+ }
+
+ .stack-trace-container li {
+ cursor: pointer;
+ font-family: monospace;
+ padding: 4px;
+ }
+
+ .stack-trace-container li.selected,
+ .stack-trace-container li:hover {
+ background: var(--google-blue-100);
+ color: var(--google-grey-900); /* Same in light & dark modes. */
+ }
+
+ extensions-code-section {
+ height: 200px;
+ margin-bottom: 20px;
+ }
+
+ :host-context(.focus-outline-visible) .start:focus {
+ outline: -webkit-focus-ring-color auto 5px;
+ }
+
+ .start:focus {
+ outline: none;
+ }
+
+ .context-url {
+ word-wrap: break-word;
+ }
+</style>
+<div class="page-container" id="container">
+ <div class="page-content">
+ <div id="heading" class="cr-title-text">
+ <cr-icon-button class="icon-arrow-back no-overlap" id="closeButton"
+ aria-label="$i18n{back}" on-click="onCloseButtonTap_">
+ </cr-icon-button>
+ <span role="heading" aria-level="2">$i18n{errorsPageHeading}</span>
+ <cr-button on-click="onClearAllTap_" hidden="[[!entries_.length]]">
+ $i18n{clearAll}
+ </cr-button>
+ </div>
+ <div class="section">
+ <div id="errorsList">
+ <template is="dom-repeat" items="[[entries_]]">
+ <div class="item-container">
+ <div class$="error-item
+ [[computeErrorClass_(item, selectedEntry_)]]">
+ <div actionable class="start" on-click="onErrorItemAction_"
+ on-keydown="onErrorItemAction_" tabindex="0"
+ role="button" aria-expanded$="[[isAriaExpanded_(
+ index, selectedEntry_)]]">
+ <iron-icon icon$="cr:[[computeErrorIcon_(item)]]"
+ title$="[[computeErrorTypeLabel_(item)]]">
+ </iron-icon>
+ <div id$="[[item.id]]" class="error-message">
+ [[item.message]]
</div>
- <iron-collapse opened="[[isOpened_(index, selectedEntry_)]]">
- <div class="devtools-controls">
- <template is="dom-if"
- if="[[computeIsRuntimeError_(item)]]">
- <div class="details-heading cr-title-text">
- $i18n{errorContext}
- </div>
- <span class="context-url">
- [[getContextUrl_(
- item, '$i18nPolymer{errorContextUnknown}')]]
- </span>
- <div class="details-heading cr-title-text">
- $i18n{stackTrace}
- </div>
- <ul class="stack-trace-container"
- on-keydown="onStackKeydown_">
- <template is="dom-repeat" items="[[item.stackTrace]]">
- <li on-click="onStackFrameTap_"
- tabindex$="[[getStackFrameTabIndex_(item,
- selectedStackFrame_)]]"
- hidden="[[!shouldDisplayFrame_(item.url)]]"
- class$="[[getStackFrameClass_(item,
- selectedStackFrame_)]]">
- [[getStackTraceLabel_(item)]]
- </li>
- </template>
- </ul>
- </template>
- <extensions-code-section code="[[code_]]"
- is-active="[[isOpened_(index, selectedEntry_)]]"
- could-not-display-code="$i18n{noErrorsToShow}">
- </extensions-code-section>
+ <div class$="cr-icon [[iconName_(index, selectedEntry_)]]">
+ </div>
+ </div>
+ <div class="separator"></div>
+ <cr-icon-button class="icon-delete-gray"
+ on-click="onDeleteErrorAction_"
+ aria-describedby$="[[item.id]]"
+ aria-label="$i18n{clearEntry}"></cr-icon-button>
+ </div>
+ <iron-collapse opened="[[isOpened_(index, selectedEntry_)]]">
+ <div class="devtools-controls">
+ <template is="dom-if"
+ if="[[computeIsRuntimeError_(item)]]">
+ <div class="details-heading cr-title-text" role="heading"
+ aria-level="3">
+ $i18n{errorContext}
+ </div>
+ <span class="context-url">
+ [[getContextUrl_(
+ item, '$i18nPolymer{errorContextUnknown}')]]
+ </span>
+ <div class="details-heading cr-title-text" role="heading"
+ aria-level="3">
+ $i18n{stackTrace}
</div>
- </iron-collapse>
+ <ul class="stack-trace-container"
+ on-keydown="onStackKeydown_">
+ <template is="dom-repeat" items="[[item.stackTrace]]">
+ <li on-click="onStackFrameTap_"
+ tabindex$="[[getStackFrameTabIndex_(item,
+ selectedStackFrame_)]]"
+ hidden="[[!shouldDisplayFrame_(item.url)]]"
+ class$="[[getStackFrameClass_(item,
+ selectedStackFrame_)]]">
+ [[getStackTraceLabel_(item)]]
+ </li>
+ </template>
+ </ul>
+ </template>
+ <extensions-code-section code="[[code_]]"
+ is-active="[[isOpened_(index, selectedEntry_)]]"
+ could-not-display-code="$i18n{noErrorsToShow}">
+ </extensions-code-section>
</div>
- </template>
+ </iron-collapse>
</div>
- </div>
+ </template>
</div>
</div>
- </template>
- <script src="error_page.js"></script>
-</dom-module>
+ </div>
+</div>
diff --git a/chromium/chrome/browser/resources/extensions/error_page.js b/chromium/chrome/browser/resources/extensions/error_page.js
index fea88babb4a..1da980e9a85 100644
--- a/chromium/chrome/browser/resources/extensions/error_page.js
+++ b/chromium/chrome/browser/resources/extensions/error_page.js
@@ -2,428 +2,440 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
+import 'chrome://resources/cr_elements/cr_icons_css.m.js';
+import 'chrome://resources/cr_elements/icons.m.js';
+import 'chrome://resources/cr_elements/shared_style_css.m.js';
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+import 'chrome://resources/polymer/v3_0/iron-collapse/iron-collapse.js';
+import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
+import 'chrome://resources/polymer/v3_0/paper-styles/color.js';
+import './code_section.js';
+import './shared_style.js';
+
+import {CrContainerShadowBehavior} from 'chrome://resources/cr_elements/cr_container_shadow_behavior.m.js';
+import {assert, assertNotReached} from 'chrome://resources/js/assert.m.js';
+import {FocusOutlineManager} from 'chrome://resources/js/cr/ui/focus_outline_manager.m.js';
+import {focusWithoutInk} from 'chrome://resources/js/cr/ui/focus_without_ink.m.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+import {afterNextRender, html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {navigation, Page} from './navigation_helper.js';
+
/** @typedef {chrome.developerPrivate.ManifestError} */
let ManifestError;
/** @typedef {chrome.developerPrivate.RuntimeError} */
let RuntimeError;
-cr.define('extensions', function() {
- 'use strict';
-
- /** @interface */
- class ErrorPageDelegate {
- /**
- * @param {string} extensionId
- * @param {!Array<number>=} errorIds
- * @param {chrome.developerPrivate.ErrorType=} type
- */
- deleteErrors(extensionId, errorIds, type) {}
-
- /**
- * @param {chrome.developerPrivate.RequestFileSourceProperties} args
- * @return {!Promise<!chrome.developerPrivate.RequestFileSourceResponse>}
- */
- requestFileSource(args) {}
- }
-
+/** @interface */
+export class ErrorPageDelegate {
/**
- * Get the URL relative to the main extension url. If the url is
- * unassociated with the extension, this will be the full url.
- * @param {string} url
- * @param {?(ManifestError|RuntimeError)} error
- * @return {string}
+ * @param {string} extensionId
+ * @param {!Array<number>=} errorIds
+ * @param {chrome.developerPrivate.ErrorType=} type
*/
- function getRelativeUrl(url, error) {
- const fullUrl = 'chrome-extension://' + error.extensionId + '/';
- return url.startsWith(fullUrl) ? url.substring(fullUrl.length) : url;
- }
+ deleteErrors(extensionId, errorIds, type) {}
/**
- * Given 3 strings, this function returns the correct one for the type of
- * error that |item| is.
- * @param {!ManifestError|!RuntimeError} item
- * @param {string} log
- * @param {string} warn
- * @param {string} error
- * @return {string}
- * @private
+ * @param {chrome.developerPrivate.RequestFileSourceProperties} args
+ * @return {!Promise<!chrome.developerPrivate.RequestFileSourceResponse>}
*/
- function getErrorSeverityText_(item, log, warn, error) {
- if (item.type == chrome.developerPrivate.ErrorType.RUNTIME) {
- switch (item.severity) {
- case chrome.developerPrivate.ErrorLevel.LOG:
- return log;
- case chrome.developerPrivate.ErrorLevel.WARN:
- return warn;
- case chrome.developerPrivate.ErrorLevel.ERROR:
- return error;
- }
- assertNotReached();
+ requestFileSource(args) {}
+}
+
+/**
+ * Get the URL relative to the main extension url. If the url is
+ * unassociated with the extension, this will be the full url.
+ * @param {string} url
+ * @param {?(ManifestError|RuntimeError)} error
+ * @return {string}
+ */
+function getRelativeUrl(url, error) {
+ const fullUrl = 'chrome-extension://' + error.extensionId + '/';
+ return url.startsWith(fullUrl) ? url.substring(fullUrl.length) : url;
+}
+
+/**
+ * Given 3 strings, this function returns the correct one for the type of
+ * error that |item| is.
+ * @param {!ManifestError|!RuntimeError} item
+ * @param {string} log
+ * @param {string} warn
+ * @param {string} error
+ * @return {string}
+ * @private
+ */
+function getErrorSeverityText_(item, log, warn, error) {
+ if (item.type == chrome.developerPrivate.ErrorType.RUNTIME) {
+ switch (item.severity) {
+ case chrome.developerPrivate.ErrorLevel.LOG:
+ return log;
+ case chrome.developerPrivate.ErrorLevel.WARN:
+ return warn;
+ case chrome.developerPrivate.ErrorLevel.ERROR:
+ return error;
}
- assert(item.type == chrome.developerPrivate.ErrorType.MANIFEST);
- return warn;
+ assertNotReached();
}
+ assert(item.type == chrome.developerPrivate.ErrorType.MANIFEST);
+ return warn;
+}
- const ErrorPage = Polymer({
- is: 'extensions-error-page',
-
- behaviors: [CrContainerShadowBehavior],
-
- properties: {
- /** @type {!chrome.developerPrivate.ExtensionInfo|undefined} */
- data: Object,
-
- /** @type {!extensions.ErrorPageDelegate|undefined} */
- delegate: Object,
+Polymer({
+ is: 'extensions-error-page',
- // Whether or not dev mode is enabled.
- inDevMode: {
- type: Boolean,
- value: false,
- observer: 'onInDevModeChanged_',
- },
-
- /** @private {!Array<!(ManifestError|RuntimeError)>} */
- entries_: Array,
-
- /** @private {?chrome.developerPrivate.RequestFileSourceResponse} */
- code_: Object,
+ _template: html`{__html_template__}`,
- /**
- * Index into |entries_|.
- * @private
- */
- selectedEntry_: {
- type: Number,
- observer: 'onSelectedErrorChanged_',
- },
-
- /** @private {?chrome.developerPrivate.StackFrame}*/
- selectedStackFrame_: {
- type: Object,
- value: function() {
- return null;
- },
- },
- },
+ behaviors: [CrContainerShadowBehavior],
- observers: [
- 'observeDataChanges_(data.*)',
- ],
+ properties: {
+ /** @type {!chrome.developerPrivate.ExtensionInfo|undefined} */
+ data: Object,
- listeners: {
- 'view-enter-start': 'onViewEnterStart_',
- },
+ /** @type {!ErrorPageDelegate|undefined} */
+ delegate: Object,
- /** @override */
- ready: function() {
- cr.ui.FocusOutlineManager.forDocument(document);
+ // Whether or not dev mode is enabled.
+ inDevMode: {
+ type: Boolean,
+ value: false,
+ observer: 'onInDevModeChanged_',
},
- /** @return {!ManifestError|!RuntimeError} */
- getSelectedError: function() {
- return this.entries_[this.selectedEntry_];
- },
+ /** @private {!Array<!(ManifestError|RuntimeError)>} */
+ entries_: Array,
- /**
- * Focuses the back button when page is loaded.
- * @private
- */
- onViewEnterStart_: function() {
- Polymer.RenderStatus.afterNextRender(
- this, () => cr.ui.focusWithoutInk(this.$.closeButton));
- chrome.metricsPrivate.recordUserAction('Options_ViewExtensionErrors');
- },
+ /** @private {?chrome.developerPrivate.RequestFileSourceResponse} */
+ code_: Object,
/**
- * @param {!ManifestError|!RuntimeError} error
- * @param {string} unknown
- * @return {string}
+ * Index into |entries_|.
* @private
*/
- getContextUrl_: function(error, unknown) {
- return error.contextUrl ? getRelativeUrl(error.contextUrl, error) :
- unknown;
+ selectedEntry_: {
+ type: Number,
+ observer: 'onSelectedErrorChanged_',
},
- /**
- * Watches for changes to |data| in order to fetch the corresponding
- * file source.
- * @private
- */
- observeDataChanges_: function() {
- const errors = this.data.manifestErrors.concat(this.data.runtimeErrors);
- this.entries_ = errors;
- this.selectedEntry_ = -1; // This also help reset code-section content.
- if (this.entries_.length) {
- this.selectedEntry_ = 0;
- }
+ /** @private {?chrome.developerPrivate.StackFrame}*/
+ selectedStackFrame_: {
+ type: Object,
+ value: function() {
+ return null;
+ },
},
+ },
- /** @private */
- onCloseButtonTap_: function() {
- extensions.navigation.navigateTo({page: extensions.Page.LIST});
- },
+ observers: [
+ 'observeDataChanges_(data.*)',
+ ],
- /** @private */
- onClearAllTap_: function() {
- const ids = this.entries_.map(entry => entry.id);
- this.delegate.deleteErrors(this.data.id, ids);
- },
+ listeners: {
+ 'view-enter-start': 'onViewEnterStart_',
+ },
- /**
- * @param {!ManifestError|!RuntimeError} error
- * @return {string}
- * @private
- */
- computeErrorIcon_: function(error) {
- // Do not i18n these strings, they're CSS classes.
- return getErrorSeverityText_(error, 'info', 'warning', 'error');
- },
+ /** @override */
+ ready: function() {
+ FocusOutlineManager.forDocument(document);
+ },
- /**
- * @param {!ManifestError|!RuntimeError} error
- * @return {string}
- * @private
- */
- computeErrorTypeLabel_: function(error) {
- return getErrorSeverityText_(
- error, loadTimeData.getString('logLevel'),
- loadTimeData.getString('warnLevel'),
- loadTimeData.getString('errorLevel'));
- },
+ /** @return {!ManifestError|!RuntimeError} */
+ getSelectedError: function() {
+ return this.entries_[this.selectedEntry_];
+ },
- /**
- * @param {!Event} e
- * @private
- */
- onDeleteErrorAction_: function(e) {
- this.delegate.deleteErrors(
- this.data.id, [(/** @type {!{model:Object}} */ (e)).model.item.id]);
- e.stopPropagation();
- },
+ /**
+ * Focuses the back button when page is loaded.
+ * @private
+ */
+ onViewEnterStart_: function() {
+ afterNextRender(this, () => focusWithoutInk(this.$.closeButton));
+ chrome.metricsPrivate.recordUserAction('Options_ViewExtensionErrors');
+ },
- /** private */
- onInDevModeChanged_: function() {
- if (!this.inDevMode) {
- // Wait until next render cycle in case error page is loading.
- this.async(() => {
- this.onCloseButtonTap_();
- });
- }
- },
+ /**
+ * @param {!ManifestError|!RuntimeError} error
+ * @param {string} unknown
+ * @return {string}
+ * @private
+ */
+ getContextUrl_: function(error, unknown) {
+ return error.contextUrl ? getRelativeUrl(error.contextUrl, error) : unknown;
+ },
- /**
- * Fetches the source for the selected error and populates the code section.
- * @private
- */
- onSelectedErrorChanged_: function() {
- this.code_ = null;
+ /**
+ * Watches for changes to |data| in order to fetch the corresponding
+ * file source.
+ * @private
+ */
+ observeDataChanges_: function() {
+ const errors = this.data.manifestErrors.concat(this.data.runtimeErrors);
+ this.entries_ = errors;
+ this.selectedEntry_ = -1; // This also help reset code-section content.
+ if (this.entries_.length) {
+ this.selectedEntry_ = 0;
+ }
+ },
- if (this.selectedEntry_ < 0) {
- return;
- }
+ /** @private */
+ onCloseButtonTap_: function() {
+ navigation.navigateTo({page: Page.LIST});
+ },
- const error = this.getSelectedError();
- const args = {
- extensionId: error.extensionId,
- message: error.message,
- };
- switch (error.type) {
- case chrome.developerPrivate.ErrorType.MANIFEST:
- args.pathSuffix = error.source;
- args.manifestKey = error.manifestKey;
- args.manifestSpecific = error.manifestSpecific;
- break;
- case chrome.developerPrivate.ErrorType.RUNTIME:
- // slice(1) because pathname starts with a /.
- args.pathSuffix = new URL(error.source).pathname.slice(1);
- args.lineNumber = error.stackTrace && error.stackTrace[0] ?
- error.stackTrace[0].lineNumber :
- 0;
- this.selectedStackFrame_ = error.stackTrace && error.stackTrace[0] ?
- error.stackTrace[0] :
- null;
- break;
- }
- this.delegate.requestFileSource(args).then(code => this.code_ = code);
- },
+ /** @private */
+ onClearAllTap_: function() {
+ const ids = this.entries_.map(entry => entry.id);
+ this.delegate.deleteErrors(this.data.id, ids);
+ },
- /**
- * @return {boolean}
- * @private
- */
- computeIsRuntimeError_: function(item) {
- return item.type == chrome.developerPrivate.ErrorType.RUNTIME;
- },
+ /**
+ * @param {!ManifestError|!RuntimeError} error
+ * @return {string}
+ * @private
+ */
+ computeErrorIcon_: function(error) {
+ // Do not i18n these strings, they're CSS classes.
+ return getErrorSeverityText_(error, 'info', 'warning', 'error');
+ },
- /**
- * The description is a human-readable summation of the frame, in the
- * form "<relative_url>:<line_number> (function)", e.g.
- * "myfile.js:25 (myFunction)".
- * @param {!chrome.developerPrivate.StackFrame} frame
- * @return {string}
- * @private
- */
- getStackTraceLabel_: function(frame) {
- let description = getRelativeUrl(frame.url, this.getSelectedError()) +
- ':' + frame.lineNumber;
-
- if (frame.functionName) {
- const functionName = frame.functionName == '(anonymous function)' ?
- loadTimeData.getString('anonymousFunction') :
- frame.functionName;
- description += ' (' + functionName + ')';
- }
+ /**
+ * @param {!ManifestError|!RuntimeError} error
+ * @return {string}
+ * @private
+ */
+ computeErrorTypeLabel_: function(error) {
+ return getErrorSeverityText_(
+ error, loadTimeData.getString('logLevel'),
+ loadTimeData.getString('warnLevel'),
+ loadTimeData.getString('errorLevel'));
+ },
- return description;
- },
+ /**
+ * @param {!Event} e
+ * @private
+ */
+ onDeleteErrorAction_: function(e) {
+ this.delegate.deleteErrors(
+ this.data.id, [(/** @type {!{model:Object}} */ (e)).model.item.id]);
+ e.stopPropagation();
+ },
+
+ /** private */
+ onInDevModeChanged_: function() {
+ if (!this.inDevMode) {
+ // Wait until next render cycle in case error page is loading.
+ this.async(() => {
+ this.onCloseButtonTap_();
+ });
+ }
+ },
- /**
- * @param {chrome.developerPrivate.StackFrame} frame
- * @return {string}
- * @private
- */
- getStackFrameClass_: function(frame) {
- return frame == this.selectedStackFrame_ ? 'selected' : '';
- },
+ /**
+ * Fetches the source for the selected error and populates the code section.
+ * @private
+ */
+ onSelectedErrorChanged_: function() {
+ this.code_ = null;
- /**
- * @param {!chrome.developerPrivate.StackFrame} frame
- * @return {number}
- * @private
- */
- getStackFrameTabIndex_: function(frame) {
- return frame == this.selectedStackFrame_ ? 0 : -1;
- },
+ if (this.selectedEntry_ < 0) {
+ return;
+ }
- /**
- * This function is used to determine whether or not we want to show a
- * stack frame. We don't want to show code from internal scripts.
- * @param {string} url
- * @return {boolean}
- * @private
- */
- shouldDisplayFrame_: function(url) {
- // All our internal scripts are in the 'extensions::' namespace.
- return !/^extensions::/.test(url);
- },
+ const error = this.getSelectedError();
+ const args = {
+ extensionId: error.extensionId,
+ message: error.message,
+ };
+ switch (error.type) {
+ case chrome.developerPrivate.ErrorType.MANIFEST:
+ args.pathSuffix = error.source;
+ args.manifestKey = error.manifestKey;
+ args.manifestSpecific = error.manifestSpecific;
+ break;
+ case chrome.developerPrivate.ErrorType.RUNTIME:
+ // slice(1) because pathname starts with a /.
+ args.pathSuffix = new URL(error.source).pathname.slice(1);
+ args.lineNumber = error.stackTrace && error.stackTrace[0] ?
+ error.stackTrace[0].lineNumber :
+ 0;
+ this.selectedStackFrame_ = error.stackTrace && error.stackTrace[0] ?
+ error.stackTrace[0] :
+ null;
+ break;
+ }
+ this.delegate.requestFileSource(args).then(code => this.code_ = code);
+ },
- /**
- * @param {!chrome.developerPrivate.StackFrame} frame
- * @private
- */
- updateSelected_: function(frame) {
- this.selectedStackFrame_ = assert(frame);
-
- const selectedError = this.getSelectedError();
- this.delegate
- .requestFileSource({
- extensionId: selectedError.extensionId,
- message: selectedError.message,
- pathSuffix: getRelativeUrl(frame.url, selectedError),
- lineNumber: frame.lineNumber,
- })
- .then(code => this.code_ = code);
- },
+ /**
+ * @return {boolean}
+ * @private
+ */
+ computeIsRuntimeError_: function(item) {
+ return item.type == chrome.developerPrivate.ErrorType.RUNTIME;
+ },
- /**
- * @param {!Event} e
- * @private
- */
- onStackFrameTap_: function(e) {
- const frame = /** @type {!{model:Object}} */ (e).model.item;
- this.updateSelected_(frame);
- },
+ /**
+ * The description is a human-readable summation of the frame, in the
+ * form "<relative_url>:<line_number> (function)", e.g.
+ * "myfile.js:25 (myFunction)".
+ * @param {!chrome.developerPrivate.StackFrame} frame
+ * @return {string}
+ * @private
+ */
+ getStackTraceLabel_: function(frame) {
+ let description = getRelativeUrl(frame.url, this.getSelectedError()) + ':' +
+ frame.lineNumber;
+
+ if (frame.functionName) {
+ const functionName = frame.functionName == '(anonymous function)' ?
+ loadTimeData.getString('anonymousFunction') :
+ frame.functionName;
+ description += ' (' + functionName + ')';
+ }
- /**
- * @param {!Event} e
- * @private
- */
- onStackKeydown_: function(e) {
- let direction = 0;
-
- if (e.key == 'ArrowDown') {
- direction = 1;
- } else if (e.key == 'ArrowUp') {
- direction = -1;
- } else {
- return;
- }
+ return description;
+ },
- e.preventDefault();
+ /**
+ * @param {chrome.developerPrivate.StackFrame} frame
+ * @return {string}
+ * @private
+ */
+ getStackFrameClass_: function(frame) {
+ return frame == this.selectedStackFrame_ ? 'selected' : '';
+ },
- const list = e.target.parentElement.querySelectorAll('li');
+ /**
+ * @param {!chrome.developerPrivate.StackFrame} frame
+ * @return {number}
+ * @private
+ */
+ getStackFrameTabIndex_: function(frame) {
+ return frame == this.selectedStackFrame_ ? 0 : -1;
+ },
- for (let i = 0; i < list.length; ++i) {
- if (list[i].classList.contains('selected')) {
- const polymerEvent = /** @type {!{model: !Object}} */ (e);
- const frame = polymerEvent.model.item.stackTrace[i + direction];
- if (frame) {
- this.updateSelected_(frame);
- list[i + direction].focus(); // Preserve focus.
- }
- return;
- }
- }
- },
+ /**
+ * This function is used to determine whether or not we want to show a
+ * stack frame. We don't want to show code from internal scripts.
+ * @param {string} url
+ * @return {boolean}
+ * @private
+ */
+ shouldDisplayFrame_: function(url) {
+ // All our internal scripts are in the 'extensions::' namespace.
+ return !/^extensions::/.test(url);
+ },
- /**
- * Computes the class name for the error item depending on whether its
- * the currently selected error.
- * @param {number} index
- * @return {string}
- * @private
- */
- computeErrorClass_: function(index) {
- return index == this.selectedEntry_ ? 'selected' : '';
- },
+ /**
+ * @param {!chrome.developerPrivate.StackFrame} frame
+ * @private
+ */
+ updateSelected_: function(frame) {
+ this.selectedStackFrame_ = assert(frame);
+
+ const selectedError = this.getSelectedError();
+ this.delegate
+ .requestFileSource({
+ extensionId: selectedError.extensionId,
+ message: selectedError.message,
+ pathSuffix: getRelativeUrl(frame.url, selectedError),
+ lineNumber: frame.lineNumber,
+ })
+ .then(code => this.code_ = code);
+ },
- /** @private */
- iconName_: function(index) {
- return index == this.selectedEntry_ ? 'icon-expand-less' :
- 'icon-expand-more';
- },
+ /**
+ * @param {!Event} e
+ * @private
+ */
+ onStackFrameTap_: function(e) {
+ const frame = /** @type {!{model:Object}} */ (e).model.item;
+ this.updateSelected_(frame);
+ },
- /**
- * Determine if the iron-collapse should be opened (expanded).
- * @param {number} index
- * @return {boolean}
- * @private
- */
- isOpened_: function(index) {
- return index == this.selectedEntry_;
- },
+ /**
+ * @param {!Event} e
+ * @private
+ */
+ onStackKeydown_: function(e) {
+ let direction = 0;
+
+ if (e.key == 'ArrowDown') {
+ direction = 1;
+ } else if (e.key == 'ArrowUp') {
+ direction = -1;
+ } else {
+ return;
+ }
+ e.preventDefault();
- /**
- * @param {number} index
- * @return {string} The aria-expanded value as a string.
- * @private
- */
- isAriaExpanded_: function(index) {
- return this.isOpened_(index).toString();
- },
+ const list = e.target.parentElement.querySelectorAll('li');
- /**
- * @param {!{type: string, code: string, model: !{index: number}}} e
- * @private
- */
- onErrorItemAction_: function(e) {
- if (e.type == 'keydown' && !((e.code == 'Space' || e.code == 'Enter'))) {
+ for (let i = 0; i < list.length; ++i) {
+ if (list[i].classList.contains('selected')) {
+ const polymerEvent = /** @type {!{model: !Object}} */ (e);
+ const frame = polymerEvent.model.item.stackTrace[i + direction];
+ if (frame) {
+ this.updateSelected_(frame);
+ list[i + direction].focus(); // Preserve focus.
+ }
return;
}
+ }
+ },
- // Call preventDefault() to avoid the browser scrolling when the space key
- // is pressed.
- e.preventDefault();
- this.selectedEntry_ =
- this.selectedEntry_ == e.model.index ? -1 : e.model.index;
- },
- });
+ /**
+ * Computes the class name for the error item depending on whether its
+ * the currently selected error.
+ * @param {number} index
+ * @return {string}
+ * @private
+ */
+ computeErrorClass_: function(index) {
+ return index == this.selectedEntry_ ? 'selected' : '';
+ },
+
+ /** @private */
+ iconName_: function(index) {
+ return index == this.selectedEntry_ ? 'icon-expand-less' :
+ 'icon-expand-more';
+ },
+
+ /**
+ * Determine if the iron-collapse should be opened (expanded).
+ * @param {number} index
+ * @return {boolean}
+ * @private
+ */
+ isOpened_: function(index) {
+ return index == this.selectedEntry_;
+ },
+
+
+ /**
+ * @param {number} index
+ * @return {string} The aria-expanded value as a string.
+ * @private
+ */
+ isAriaExpanded_: function(index) {
+ return this.isOpened_(index).toString();
+ },
+
+ /**
+ * @param {!{type: string, code: string, model: !{index: number}}} e
+ * @private
+ */
+ onErrorItemAction_: function(e) {
+ if (e.type == 'keydown' && !((e.code == 'Space' || e.code == 'Enter'))) {
+ return;
+ }
- return {
- ErrorPage: ErrorPage,
- ErrorPageDelegate: ErrorPageDelegate,
- };
+ // Call preventDefault() to avoid the browser scrolling when the space key
+ // is pressed.
+ e.preventDefault();
+ this.selectedEntry_ =
+ this.selectedEntry_ == e.model.index ? -1 : e.model.index;
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/extensions.html b/chromium/chrome/browser/resources/extensions/extensions.html
index 832434023d9..087a92fd887 100644
--- a/chromium/chrome/browser/resources/extensions/extensions.html
+++ b/chromium/chrome/browser/resources/extensions/extensions.html
@@ -1,12 +1,10 @@
<!doctype html>
<html dir="$i18n{textdirection}" lang="$i18n{language}"
- class="loading $i18n{loadTimeClasses}">
+ class="loading $i18n{loadTimeClasses}" $i18n{a11yenhanced}>
<head>
<meta charset="utf8">
<title>$i18n{title}</title>
-<if expr="not optimize_webui">
<base href="chrome://extensions">
-</if>
<link rel="stylesheet" href="chrome://resources/css/md_colors.css">
<style>
html {
@@ -55,12 +53,10 @@
width: 100%;
}
</style>
+ <script type="module" src="extensions.js"></script>
</head>
<body>
- <script src="chrome://resources/polymer/v1_0/html-imports/html-imports.min.js">
- </script>
<extensions-manager></extensions-manager>
<link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
- <link rel="import" href="manager.html">
</body>
</html>
diff --git a/chromium/chrome/browser/resources/extensions/extensions.js b/chromium/chrome/browser/resources/extensions/extensions.js
new file mode 100644
index 00000000000..289f30d6bb9
--- /dev/null
+++ b/chromium/chrome/browser/resources/extensions/extensions.js
@@ -0,0 +1,17 @@
+// 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.
+
+import './manager.js';
+
+export {getToastManager} from 'chrome://resources/cr_elements/cr_toast/cr_toast_manager.m.js';
+export {ActivityLogPageState} from './activity_log/activity_log_history.js';
+export {ARG_URL_PLACEHOLDER} from './activity_log/activity_log_stream_item.js';
+// <if expr="chromeos">
+export {KioskBrowserProxyImpl} from './kiosk_browser_proxy.js';
+// </if>
+export {Dialog, navigation, NavigationHelper, Page} from './navigation_helper.js';
+export {OptionsDialogMaxHeight, OptionsDialogMinWidth} from './options_dialog.js';
+export {getPatternFromSite} from './runtime_hosts_dialog.js';
+export {Service} from './service.js';
+export {isValidKeyCode, Key, keystrokeToString} from './shortcut_util.js';
diff --git a/chromium/chrome/browser/resources/extensions/extensions_resources.grd b/chromium/chrome/browser/resources/extensions/extensions_resources.grd
index 9201c338087..a98ad371e92 100644
--- a/chromium/chrome/browser/resources/extensions/extensions_resources.grd
+++ b/chromium/chrome/browser/resources/extensions/extensions_resources.grd
@@ -11,238 +11,136 @@
<output filename="extensions_resources.pak" type="data_package" />
</outputs>
<release seq="1">
+ <includes>
+ <include name="IDR_EXTENSIONS_CODE_SECTION_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/code_section.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/activity_log/activity_log.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_HISTORY_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/activity_log/activity_log_history.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_HISTORY_ITEM_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/activity_log/activity_log_history_item.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_STREAM_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/activity_log/activity_log_stream.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_STREAM_ITEM_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/activity_log/activity_log_stream_item.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_DETAIL_VIEW_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/detail_view.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_DROP_OVERLAY_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/drop_overlay.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_ERROR_PAGE_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/error_page.js"
+ use_base_dir="false" type ="BINDATA" flattenhtml="true" />
+ <include name="IDR_EXTENSIONS_KEYBOARD_SHORTCUTS_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/keyboard_shortcuts.js"
+ use_base_dir="false" type ="BINDATA" />
+ <if expr="chromeos">
+ <include name="IDR_EXTENSIONS_KIOSK_DIALOG_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/kiosk_dialog.js"
+ use_base_dir="false" type ="BINDATA" />
+ </if>
+ <include name="IDR_EXTENSIONS_MANAGER_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/manager.js"
+ use_base_dir="false" type ="BINDATA" flattenhtml="true" />
+ <include name="IDR_EXTENSIONS_ICONS_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/icons.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_INSTALL_WARNINGS_DIALOG_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/install_warnings_dialog.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_ITEM_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/item.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_ITEM_LIST_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/item_list.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_LOAD_ERROR_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/load_error.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_HOST_PERMISSIONS_TOGGLE_LIST_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/host_permissions_toggle_list.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_OPTIONS_DIALOG_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/options_dialog.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_PACK_DIALOG_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/pack_dialog.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_PACK_DIALOG_ALERT_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/pack_dialog_alert.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_RUNTIME_HOST_PERMISSIONS_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/runtime_host_permissions.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_RUNTIME_HOSTS_DIALOG_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/runtime_hosts_dialog.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_SHARED_STYLE_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/shared_style.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_SHARED_VARS_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/shared_vars.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_SHORTCUT_INPUT_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/shortcut_input.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_SIDEBAR_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/sidebar.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_TOGGLE_ROW_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/toggle_row.js"
+ use_base_dir="false" type ="BINDATA" />
+ <include name="IDR_EXTENSIONS_TOOLBAR_JS"
+ file="${root_gen_dir}/chrome/browser/resources/extensions/toolbar.js"
+ use_base_dir="false" type ="BINDATA" flattenhtml="true" />
+ <include name="IDR_WEBUI_IMAGES_CHECKUP_IMAGE"
+ file="checkup_image.svg" type="BINDATA" compress="gzip" />
+ <include name="IDR_WEBUI_IMAGES_CHECKUP_IMAGE_DARKMODE"
+ file="checkup_image_dark.svg" type="BINDATA"
+ compress="gzip" />
+ </includes>
<structures>
- <structure name="IDR_EXTENSIONS_ITEM_BEHAVIOR_HTML"
- file="item_behavior.html"
- type="chrome_html" />
<structure name="IDR_EXTENSIONS_ITEM_BEHAVIOR_JS"
file="item_behavior.js"
type="chrome_html" />
<structure name="IDR_EXTENSIONS_EXTENSIONS_HTML"
file="extensions.html"
- flattenhtml="true"
- allowexternalscript="true"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_CODE_SECTION_HTML"
- file="code_section.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_CODE_SECTION_JS"
- file="code_section.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_HTML"
- file="activity_log/activity_log.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_JS"
- file="activity_log/activity_log.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_HISTORY_HTML"
- file="activity_log/activity_log_history.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_HISTORY_JS"
- file="activity_log/activity_log_history.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_HISTORY_ITEM_HTML"
- file="activity_log/activity_log_history_item.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_HISTORY_ITEM_JS"
- file="activity_log/activity_log_history_item.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_STREAM_HTML"
- file="activity_log/activity_log_stream.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_STREAM_JS"
- file="activity_log/activity_log_stream.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_STREAM_ITEM_HTML"
- file="activity_log/activity_log_stream_item.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_ACTIVITY_LOG_ACTIVITY_LOG_STREAM_ITEM_JS"
- file="activity_log/activity_log_stream_item.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_DETAIL_VIEW_HTML"
- file="detail_view.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_DETAIL_VIEW_JS"
- file="detail_view.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_DRAG_AND_DROP_HANDLER_HTML"
- file="drag_and_drop_handler.html"
type="chrome_html" />
<structure name="IDR_EXTENSIONS_DRAG_AND_DROP_HANDLER_JS"
file="drag_and_drop_handler.js"
type="chrome_html" />
- <structure name="IDR_EXTENSIONS_DROP_OVERLAY_HTML"
- file="drop_overlay.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_DROP_OVERLAY_JS"
- file="drop_overlay.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_ERROR_PAGE_HTML"
- file="error_page.html"
- flattenhtml="true"
- allowexternalscript="true"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_ERROR_PAGE_JS"
- file="error_page.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_KEYBOARD_SHORTCUT_DELEGATE_HTML"
- file="keyboard_shortcut_delegate.html"
+ <structure name="IDR_EXTENSIONS_EXTENSIONS_JS"
+ file="extensions.js"
+ preprocess="true"
type="chrome_html" />
<structure name="IDR_EXTENSIONS_KEYBOARD_SHORTCUT_DELEGATE_JS"
file="keyboard_shortcut_delegate.js"
type="chrome_html" />
- <structure name="IDR_EXTENSIONS_KEYBOARD_SHORTCUTS_HTML"
- file="keyboard_shortcuts.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_KEYBOARD_SHORTCUTS_JS"
- file="keyboard_shortcuts.js"
- type="chrome_html" />
<if expr="chromeos">
- <structure name="IDR_EXTENSIONS_KIOSK_BROWSER_PROXY_HTML"
- file="kiosk_browser_proxy.html"
- type="chrome_html" />
<structure name="IDR_EXTENSIONS_KIOSK_BROWSER_PROXY_JS"
file="kiosk_browser_proxy.js"
type="chrome_html" />
- <structure name="IDR_EXTENSIONS_KIOSK_DIALOG_HTML"
- file="kiosk_dialog.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_KIOSK_DIALOG_JS"
- file="kiosk_dialog.js"
- type="chrome_html" />
</if>
- <structure name="IDR_EXTENSIONS_MANAGER_HTML"
- file="manager.html"
- type="chrome_html"
- flattenhtml="true"
- allowexternalscript="true" />
- <structure name="IDR_EXTENSIONS_MANAGER_JS"
- file="manager.js"
- type="chrome_html"
- flattenhtml="true" />
- <structure name="IDR_EXTENSIONS_ICONS_HTML"
- file="icons.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_INSTALL_WARNINGS_DIALOG_HTML"
- file="install_warnings_dialog.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_INSTALL_WARNINGS_DIALOG_JS"
- file="install_warnings_dialog.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_ITEM_HTML"
- file="item.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_ITEM_JS"
- file="item.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_ITEM_LIST_HTML"
- file="item_list.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_ITEM_LIST_JS"
- file="item_list.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_ITEM_UTIL_HTML"
- file="item_util.html"
- type="chrome_html" />
<structure name="IDR_EXTENSIONS_ITEM_UTIL_JS"
file="item_util.js"
type="chrome_html" />
- <structure name="IDR_EXTENSIONS_LOAD_ERROR_HTML"
- file="load_error.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_LOAD_ERROR_JS"
- file="load_error.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_HOST_PERMISSIONS_TOGGLE_LIST_HMTL"
- file="host_permissions_toggle_list.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_HOST_PERMISSIONS_TOGGLE_LIST_JS"
- file="host_permissions_toggle_list.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_NAVIGATION_HELPER_HTML"
- file="navigation_helper.html"
- type="chrome_html" />
<structure name="IDR_EXTENSIONS_NAVIGATION_HELPER_JS"
file="navigation_helper.js"
type="chrome_html" />
- <structure name="IDR_EXTENSIONS_OPTIONS_DIALOG_HTML"
- file="options_dialog.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_OPTIONS_DIALOG_JS"
- file="options_dialog.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_PACK_DIALOG_HTML"
- file="pack_dialog.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_PACK_DIALOG_JS"
- file="pack_dialog.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_PACK_DIALOG_ALERT_HTML"
- file="pack_dialog_alert.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_PACK_DIALOG_ALERT_JS"
- file="pack_dialog_alert.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_RUNTIME_HOST_PERMISSIONS_HMTL"
- file="runtime_host_permissions.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_RUNTIME_HOST_PERMISSIONS_JS"
- file="runtime_host_permissions.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_RUNTIME_HOSTS_DIALOG_HTML"
- file="runtime_hosts_dialog.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_RUNTIME_HOSTS_DIALOG_JS"
- file="runtime_hosts_dialog.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_SERVICE_HTML"
- file="service.html"
- type="chrome_html" />
<structure name="IDR_EXTENSIONS_SERVICE_JS"
file="service.js"
type="chrome_html" />
- <structure name="IDR_EXTENSIONS_SHARED_STYLE_HTML"
- file="shared_style.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_SHARED_VARS_HTML"
- file="shared_vars.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_SHORTCUT_INPUT_HTML"
- file="shortcut_input.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_SHORTCUT_INPUT_JS"
- file="shortcut_input.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_SHORTCUT_UTIL_HTML"
- file="shortcut_util.html"
- type="chrome_html" />
<structure name="IDR_EXTENSIONS_SHORTCUT_UTIL_JS"
file="shortcut_util.js"
type="chrome_html" />
- <structure name="IDR_EXTENSIONS_SIDEBAR_HTML"
- file="sidebar.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_SIDEBAR_JS"
- file="sidebar.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_TOGGLE_ROW_HTML"
- file="toggle_row.html"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_TOGGLE_ROW_JS"
- file="toggle_row.js"
- type="chrome_html" />
- <structure name="IDR_EXTENSIONS_TOOLBAR_HTML"
- file="toolbar.html"
- type="chrome_html"
- flattenhtml="true"
- allowexternalscript="true" />
- <structure name="IDR_EXTENSIONS_TOOLBAR_JS"
- file="toolbar.js"
- type="chrome_html"
- flattenhtml="true" />
- <structure name="IDR_EXTENSIONS_STRINGS_HTML"
- file="strings.html"
- type="chrome_html" />
</structures>
</release>
</grit>
diff --git a/chromium/chrome/browser/resources/extensions/extensions_resources_vulcanized.grd b/chromium/chrome/browser/resources/extensions/extensions_resources_vulcanized.grd
index 2a3c0c6c403..d8aec253a44 100644
--- a/chromium/chrome/browser/resources/extensions/extensions_resources_vulcanized.grd
+++ b/chromium/chrome/browser/resources/extensions/extensions_resources_vulcanized.grd
@@ -12,17 +12,14 @@
</outputs>
<release seq="1">
<includes>
- <include name="IDR_EXTENSIONS_VULCANIZED_HTML"
- file="${root_gen_dir}\chrome\browser\resources\extensions\vulcanized.html"
- use_base_dir="false"
- flattenhtml="true"
- allowexternalscript="true"
- type="BINDATA"
+ <include name="IDR_EXTENSIONS_EXTENSIONS_HTML"
+ file="extensions.html"
+ type="chrome_html"
compress="gzip" />
- <include name="IDR_EXTENSIONS_CRISPER_JS"
- file="${root_gen_dir}\chrome\browser\resources\extensions\crisper.js"
+ <include name="IDR_EXTENSIONS_EXTENSIONS_ROLLUP_JS"
+ file="${root_gen_dir}\chrome\browser\resources\extensions\extensions.rollup.js"
use_base_dir="false"
- flattenhtml="true"
+ preprocess="true"
type="BINDATA"
compress="gzip" />
</includes>
diff --git a/chromium/chrome/browser/resources/extensions/host_permissions_toggle_list.html b/chromium/chrome/browser/resources/extensions/host_permissions_toggle_list.html
index 4094ed0a0cc..385b9297aad 100644
--- a/chromium/chrome/browser/resources/extensions/host_permissions_toggle_list.html
+++ b/chromium/chrome/browser/resources/extensions/host_permissions_toggle_list.html
@@ -1,67 +1,51 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="cr-shared-style shared-style">
+ iron-icon {
+ --iron-icon-height: var(--cr-icon-size);
+ --iron-icon-width: var(--cr-icon-size);
+ }
-<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
-<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
-<link rel="import" href="chrome://resources/cr_elements/icons.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
-<link rel="import" href="toggle_row.html">
-<link rel="import" href="shared_style.html">
-<link rel="import" href="strings.html">
+ #section-heading {
+ align-items: center;
+ color: var(--cr-primary-text-color);
+ display: flex;
+ justify-content: space-between;
+ margin-top: 12px;
+ }
-<dom-module id="extensions-host-permissions-toggle-list">
- <template>
- <style include="cr-shared-style shared-style">
- iron-icon {
- --iron-icon-height: var(--cr-icon-size);
- --iron-icon-width: var(--cr-icon-size);
- }
+ .toggle-section {
+ display: flex;
+ flex-direction: column;
+ justify-content: center;
+ min-height: var(--cr-section-min-height);
+ }
- #section-heading {
- align-items: center;
- color: var(--cr-primary-text-color);
- display: flex;
- justify-content: space-between;
- margin-top: 12px;
- }
-
- .toggle-section {
- display: flex;
- flex-direction: column;
- justify-content: center;
- min-height: var(--cr-section-min-height);
- }
-
- .site-toggle {
- border-top: var(--cr-separator-line);
- margin-inline-start: var(--cr-section-indent-width);
- }
- </style>
- <div id="section-heading">
- <span>$i18n{hostPermissionsDescription}</span>
- <a id="link-icon-button" aria-label="$i18n{learnMore}"
- href="$i18n{hostPermissionsLearnMoreLink}" target="_blank">
- <iron-icon icon="cr:help-outline"></iron-icon>
- </a>
- </div>
- <div class="toggle-section">
- <extensions-toggle-row checked="[[allowedOnAllHosts_(permissions.*)]]"
- id="allHostsToggle"
- on-change="onAllHostsToggleChanged_">
- <span>$i18n{itemAllowOnFollowingSites}</span>
- </extensions-toggle-row>
- </div>
- <template is="dom-repeat" items="[[getSortedHosts_(permissions.*)]]">
- <div class="toggle-section site-toggle">
- <extensions-toggle-row checked="[[item.granted]]"
- class="host-toggle no-end-padding"
- disabled="[[allowedOnAllHosts_(permissions.*)]]"
- host="[[item.host]]"
- on-change="onHostAccessChanged_">
- <span>[[item.host]]</span>
- </extensions-toggle-row>
- </div>
- </template>
- </template>
- <script src="host_permissions_toggle_list.js"></script>
-</dom-module>
+ .site-toggle {
+ border-top: var(--cr-separator-line);
+ margin-inline-start: var(--cr-section-indent-width);
+ }
+</style>
+<div id="section-heading">
+ <span>$i18n{hostPermissionsDescription}</span>
+ <a id="link-icon-button" aria-label="$i18n{learnMore}"
+ href="$i18n{hostPermissionsLearnMoreLink}" target="_blank">
+ <iron-icon icon="cr:help-outline"></iron-icon>
+ </a>
+</div>
+<div class="toggle-section">
+ <extensions-toggle-row checked="[[allowedOnAllHosts_(permissions.*)]]"
+ id="allHostsToggle"
+ on-change="onAllHostsToggleChanged_">
+ <span>$i18n{itemAllowOnFollowingSites}</span>
+ </extensions-toggle-row>
+</div>
+<template is="dom-repeat" items="[[getSortedHosts_(permissions.*)]]">
+ <div class="toggle-section site-toggle">
+ <extensions-toggle-row checked="[[item.granted]]"
+ class="host-toggle no-end-padding"
+ disabled="[[allowedOnAllHosts_(permissions.*)]]"
+ host="[[item.host]]"
+ on-change="onHostAccessChanged_">
+ <span>[[item.host]]</span>
+ </extensions-toggle-row>
+ </div>
+</template>
diff --git a/chromium/chrome/browser/resources/extensions/host_permissions_toggle_list.js b/chromium/chrome/browser/resources/extensions/host_permissions_toggle_list.js
index 6ca93aeab16..b8a3e492161 100644
--- a/chromium/chrome/browser/resources/extensions/host_permissions_toggle_list.js
+++ b/chromium/chrome/browser/resources/extensions/host_permissions_toggle_list.js
@@ -2,82 +2,90 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
+import 'chrome://resources/cr_elements/shared_style_css.m.js';
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+import 'chrome://resources/cr_elements/icons.m.js';
+import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
+import './toggle_row.js';
+import './shared_style.js';
+import './strings.m.js';
- const HostPermissionsToggleList = Polymer({
- is: 'extensions-host-permissions-toggle-list',
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
- properties: {
- /**
- * The underlying permissions data.
- * @type {chrome.developerPrivate.RuntimeHostPermissions}
- */
- permissions: Object,
+import {ItemDelegate} from './item.js';
- /** @private */
- itemId: String,
+Polymer({
+ is: 'extensions-host-permissions-toggle-list',
- /** @type {!extensions.ItemDelegate} */
- delegate: Object,
- },
+ _template: html`{__html_template__}`,
+ properties: {
/**
- * @return {boolean} Whether the item is allowed to execute on all of its
- * requested sites.
- * @private
+ * The underlying permissions data.
+ * @type {chrome.developerPrivate.RuntimeHostPermissions}
*/
- allowedOnAllHosts_: function() {
- return this.permissions.hostAccess ==
- chrome.developerPrivate.HostAccess.ON_ALL_SITES;
- },
-
- /**
- * Returns a lexicographically-sorted list of the hosts associated with this
- * item.
- * @return {!Array<!chrome.developerPrivate.SiteControl>}
- * @private
- */
- getSortedHosts_: function() {
- return this.permissions.hosts.sort((a, b) => {
- if (a.host < b.host) {
- return -1;
- }
- if (a.host > b.host) {
- return 1;
- }
- return 0;
- });
- },
+ permissions: Object,
/** @private */
- onAllHostsToggleChanged_: function() {
- // TODO(devlin): In the case of going from all sites to specific sites,
- // we'll withhold all sites (i.e., all specific site toggles will move to
- // unchecked, and the user can check them individually). This is slightly
- // different than the sync page, where disabling the "sync everything"
- // switch leaves everything synced, and user can uncheck them
- // individually. It could be nice to align on behavior, but probably not
- // super high priority.
- this.delegate.setItemHostAccess(
- this.itemId,
- this.$.allHostsToggle.checked ?
- chrome.developerPrivate.HostAccess.ON_ALL_SITES :
- chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES);
- },
+ itemId: String,
- /** @private */
- onHostAccessChanged_: function(e) {
- const host = e.target.host;
- const checked = e.target.checked;
+ /** @type {!ItemDelegate} */
+ delegate: Object,
+ },
- if (checked) {
- this.delegate.addRuntimeHostPermission(this.itemId, host);
- } else {
- this.delegate.removeRuntimeHostPermission(this.itemId, host);
+ /**
+ * @return {boolean} Whether the item is allowed to execute on all of its
+ * requested sites.
+ * @private
+ */
+ allowedOnAllHosts_: function() {
+ return this.permissions.hostAccess ==
+ chrome.developerPrivate.HostAccess.ON_ALL_SITES;
+ },
+
+ /**
+ * Returns a lexicographically-sorted list of the hosts associated with this
+ * item.
+ * @return {!Array<!chrome.developerPrivate.SiteControl>}
+ * @private
+ */
+ getSortedHosts_: function() {
+ return this.permissions.hosts.sort((a, b) => {
+ if (a.host < b.host) {
+ return -1;
+ }
+ if (a.host > b.host) {
+ return 1;
}
- },
- });
+ return 0;
+ });
+ },
+
+ /** @private */
+ onAllHostsToggleChanged_: function() {
+ // TODO(devlin): In the case of going from all sites to specific sites,
+ // we'll withhold all sites (i.e., all specific site toggles will move to
+ // unchecked, and the user can check them individually). This is slightly
+ // different than the sync page, where disabling the "sync everything"
+ // switch leaves everything synced, and user can uncheck them
+ // individually. It could be nice to align on behavior, but probably not
+ // super high priority.
+ this.delegate.setItemHostAccess(
+ this.itemId,
+ this.$.allHostsToggle.checked ?
+ chrome.developerPrivate.HostAccess.ON_ALL_SITES :
+ chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES);
+ },
+
+ /** @private */
+ onHostAccessChanged_: function(e) {
+ const host = e.target.host;
+ const checked = e.target.checked;
- return {HostPermissionsToggleList: HostPermissionsToggleList};
+ if (checked) {
+ this.delegate.addRuntimeHostPermission(this.itemId, host);
+ } else {
+ this.delegate.removeRuntimeHostPermission(this.itemId, host);
+ }
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/icons.html b/chromium/chrome/browser/resources/extensions/icons.html
index 765f9bf400a..925e4108ec3 100644
--- a/chromium/chrome/browser/resources/extensions/icons.html
+++ b/chromium/chrome/browser/resources/extensions/icons.html
@@ -1,6 +1,3 @@
-<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">
-
<iron-iconset-svg name="extensions-icons" size="24">
<svg>
<defs>
diff --git a/chromium/chrome/browser/resources/extensions/icons.js b/chromium/chrome/browser/resources/extensions/icons.js
new file mode 100644
index 00000000000..531c5e73112
--- /dev/null
+++ b/chromium/chrome/browser/resources/extensions/icons.js
@@ -0,0 +1,9 @@
+// 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.
+
+import 'chrome://resources/polymer/v3_0/iron-iconset-svg/iron-iconset-svg.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+const template = html`{__html_template__}`;
+document.head.appendChild(template.content);
diff --git a/chromium/chrome/browser/resources/extensions/install_warnings_dialog.html b/chromium/chrome/browser/resources/extensions/install_warnings_dialog.html
index 760a8a40ae6..abd531cd53d 100644
--- a/chromium/chrome/browser/resources/extensions/install_warnings_dialog.html
+++ b/chromium/chrome/browser/resources/extensions/install_warnings_dialog.html
@@ -1,47 +1,32 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="cr-shared-style">
+ div[slot='body'] ul {
+ background-color: var(--paper-red-50);
+ margin: 0;
+ padding-bottom: 10px;
+ padding-inline-end: 10px;
+ padding-top: 10px;
+ }
-<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
-<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
-<link rel="import" href="chrome://resources/html/assert.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
-<link rel="import" href="code_section.html">
-
-<dom-module id="extensions-install-warnings-dialog">
- <template>
- <style include="cr-shared-style">
- div[slot='body'] ul {
- background-color: var(--paper-red-50);
- margin: 0;
- padding-bottom: 10px;
- padding-inline-end: 10px;
- padding-top: 10px;
- }
-
- @media (prefers-color-scheme: dark) {
- div[slot='body'] ul {
- /* TODO(dbeam): merge with --cr-input-background-color? */
- background-color: rgba(0, 0, 0, .3);
- color: var(--error-color);
- }
- }
- </style>
- <cr-dialog id="dialog" close-text="$i18n{close}">
- <div slot="title">$i18n{installWarnings}</div>
- <div slot="body">
- <ul>
- <template is="dom-repeat" items="[[installWarnings]]">
- <li>[[item]]</li>
- </template>
- </ul>
- </div>
- <div slot="button-container">
- <cr-button class="action-button" on-click="onOkTap_">
- $i18n{ok}
- </cr-button>
- </div>
- </cr-dialog>
- </template>
- <script src="install_warnings_dialog.js"></script>
-</dom-module>
+ @media (prefers-color-scheme: dark) {
+ div[slot='body'] ul {
+ /* TODO(dbeam): merge with --cr-input-background-color? */
+ background-color: rgba(0, 0, 0, .3);
+ color: var(--error-color);
+ }
+ }
+</style>
+<cr-dialog id="dialog" close-text="$i18n{close}">
+ <div slot="title">$i18n{installWarnings}</div>
+ <div slot="body">
+ <ul>
+ <template is="dom-repeat" items="[[installWarnings]]">
+ <li>[[item]]</li>
+ </template>
+ </ul>
+ </div>
+ <div slot="button-container">
+ <cr-button class="action-button" on-click="onOkTap_">
+ $i18n{ok}
+ </cr-button>
+ </div>
+</cr-dialog>
diff --git a/chromium/chrome/browser/resources/extensions/install_warnings_dialog.js b/chromium/chrome/browser/resources/extensions/install_warnings_dialog.js
index 5417428c937..b333dca3db5 100644
--- a/chromium/chrome/browser/resources/extensions/install_warnings_dialog.js
+++ b/chromium/chrome/browser/resources/extensions/install_warnings_dialog.js
@@ -2,27 +2,31 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
+import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
+import 'chrome://resources/cr_elements/shared_style_css.m.js';
+import 'chrome://resources/polymer/v3_0/paper-styles/color.js';
+import './code_section.js';
- const InstallWarningsDialog = Polymer({
- is: 'extensions-install-warnings-dialog',
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
- properties: {
- /** @type {!Array<string>} */
- installWarnings: Array,
- },
+Polymer({
+ is: 'extensions-install-warnings-dialog',
- /** @override */
- attached: function() {
- this.$.dialog.showModal();
- },
+ _template: html`{__html_template__}`,
- /** @private */
- onOkTap_: function() {
- this.$.dialog.close();
- },
- });
+ properties: {
+ /** @type {!Array<string>} */
+ installWarnings: Array,
+ },
- return {InstallWarningsDialog: InstallWarningsDialog};
+ /** @override */
+ attached: function() {
+ this.$.dialog.showModal();
+ },
+
+ /** @private */
+ onOkTap_: function() {
+ this.$.dialog.close();
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/item.html b/chromium/chrome/browser/resources/extensions/item.html
index a69c6b4c656..b70ec925b38 100644
--- a/chromium/chrome/browser/resources/extensions/item.html
+++ b/chromium/chrome/browser/resources/extensions/item.html
@@ -1,356 +1,325 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="iron-flex cr-hidden-style cr-icons action-link
+ shared-style">
+ .bounded-text,
+ .multiline-clippable-text,
+ .clippable-flex-text {
+ /** Ensure that the text does not overflow its container. */
+ overflow: hidden;
+ text-overflow: ellipsis;
+ }
-<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_toast/cr_toast_manager.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
-<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
-<link rel="import" href="chrome://resources/cr_elements/icons.html">
-<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
-<link rel="import" href="chrome://resources/html/action_link.html">
-<link rel="import" href="chrome://resources/cr_elements/action_link_css.html">
-<link rel="import" href="chrome://resources/html/assert.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/html/i18n_behavior.html">
-<link rel="import" href="icons.html">
-<link rel="import" href="item_behavior.html">
-<link rel="import" href="item_util.html">
-<link rel="import" href="shared_style.html">
-<link rel="import" href="shared_vars.html">
-<link rel="import" href="strings.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-tooltip/paper-tooltip.html">
-<link rel="import" href="navigation_helper.html">
+ .bounded-text,
+ .clippable-flex-text {
+ white-space: nowrap;
+ }
-<dom-module id="extensions-item">
- <template>
- <style include="iron-flex cr-hidden-style cr-icons action-link
- shared-style">
- .bounded-text,
- .multiline-clippable-text,
- .clippable-flex-text {
- /** Ensure that the text does not overflow its container. */
- overflow: hidden;
- text-overflow: ellipsis;
- }
+ .clippable-flex-text {
+ /**
+ * These labels can be arbitrarily long. We want to ensure that these
+ * shrink, rather than the neighboring content.
+ */
+ flex-shrink: 1;
+ }
- .bounded-text,
- .clippable-flex-text {
- white-space: nowrap;
- }
+ #icon-wrapper {
+ align-self: flex-start;
+ display: flex;
+ padding: 6px;
+ position: relative;
+ }
- .clippable-flex-text {
- /**
- * These labels can be arbitrarily long. We want to ensure that these
- * shrink, rather than the neighboring content.
- */
- flex-shrink: 1;
- }
+ #icon {
+ height: 36px;
+ width: 36px;
+ }
- #icon-wrapper {
- align-self: flex-start;
- display: flex;
- padding: 6px;
- position: relative;
- }
+ #card {
+ @apply --cr-card-elevation;
+ background-color: var(--cr-card-background-color);
+ border-radius: var(--cr-card-border-radius);
+ display: flex;
+ flex-direction: column;
+ height: 160px;
+ /* Duration matches --drawer-transition from toolbar.html. */
+ transition: height 300ms cubic-bezier(.25, .1, .25, 1);
+ }
- #icon {
- height: 36px;
- width: 36px;
- }
+ #card.dev-mode {
+ height: 208px;
+ }
- #card {
- @apply --cr-card-elevation;
- background-color: var(--cr-card-background-color);
- border-radius: var(--cr-card-border-radius);
- display: flex;
- flex-direction: column;
- height: 160px;
- /* Duration matches --drawer-transition from toolbar.html. */
- transition: height 300ms cubic-bezier(.25, .1, .25, 1);
- }
+ #main {
+ display: flex;
+ flex: 1;
+ min-height: 0;
+ padding: 16px 20px;
+ }
- #card.dev-mode {
- height: 208px;
- }
+ #content {
+ display: flex;
+ flex: 1;
+ flex-direction: column;
+ margin-inline-start: 24px;
+ overflow: hidden;
+ }
- #main {
- display: flex;
- flex: 1;
- min-height: 0;
- padding: 16px 20px;
- }
+ #name-and-version {
+ color: var(--cr-primary-text-color);
+ margin-bottom: 4px;
+ }
- #content {
- display: flex;
- flex: 1;
- flex-direction: column;
- margin-inline-start: 24px;
- overflow: hidden;
- }
+ #name {
+ margin-inline-end: 8px;
+ }
- #name-and-version {
- color: var(--cr-primary-text-color);
- margin-bottom: 4px;
- }
+ #description {
+ flex: 1;
+ }
- #name {
- margin-inline-end: 8px;
- }
+ #warnings {
+ color: var(--error-color);
+ flex: 1;
+ margin-bottom: 8px;
+ }
- #description {
- flex: 1;
- }
+ #error-icon {
+ --iron-icon-fill-color: var(--error-color);
+ height: 18px;
+ margin-inline-end: 4px;
+ width: 18px;
+ }
- #warnings {
- color: var(--error-color);
- flex: 1;
- margin-bottom: 8px;
- }
+ #description,
+ #version,
+ #extension-id,
+ #inspect-views,
+ #button-strip {
+ @apply --cr-secondary-text;
+ }
- #error-icon {
- --iron-icon-fill-color: var(--error-color);
- height: 18px;
- margin-inline-end: 4px;
- width: 18px;
- }
+ #extension-id {
+ flex-shrink: 0;
+ }
- #description,
- #version,
- #extension-id,
- #inspect-views,
- #button-strip {
- @apply --cr-secondary-text;
- }
+ #inspect-views {
+ display: flex;
+ white-space: nowrap;
+ }
- #extension-id {
- flex-shrink: 0;
- }
+ #inspect-views > span {
+ margin-inline-end: 4px;
+ }
- #inspect-views {
- display: flex;
- white-space: nowrap;
- }
+ #button-strip {
+ box-sizing: border-box;
+ flex-shrink: 0;
+ height: var(--cr-section-min-height);
+ padding-bottom: 8px;
+ padding-inline-end: 20px;
+ padding-top: 8px;
+ }
- #inspect-views > span {
- margin-inline-end: 4px;
- }
+ #button-strip cr-button {
+ margin-inline-start: 8px;
+ }
- #button-strip {
- box-sizing: border-box;
- flex-shrink: 0;
- height: var(--cr-section-min-height);
- padding-bottom: 8px;
- padding-inline-end: 20px;
- padding-top: 8px;
- }
+ #source-indicator {
+ margin-inline-start: 24px;
+ margin-top: 24px;
+ position: absolute;
+ }
- #button-strip cr-button {
- margin-inline-start: 8px;
- }
+ .source-icon-wrapper {
+ align-items: center;
+ background: rgb(241, 89, 43); /* Same in light & dark modes. */
+ border-radius: 50%; /* 50% border radius == a circle */
+ box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.22),
+ 0 2px 2px 0 rgba(0, 0, 0, 0.12);
+ display: flex;
+ height: 22px;
+ justify-content: center;
+ width: 22px;
+ }
- #source-indicator {
- margin-inline-start: 24px;
- margin-top: 24px;
- position: absolute;
- }
+ #source-indicator iron-icon {
+ color: white;
+ height: 16px;
+ width: 16px;
+ }
- .source-icon-wrapper {
- align-items: center;
- background: rgb(241, 89, 43); /* Same in light & dark modes. */
- border-radius: 50%; /* 50% border radius == a circle */
- box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.22),
- 0 2px 2px 0 rgba(0, 0, 0, 0.12);
- display: flex;
- height: 22px;
- justify-content: center;
- width: 22px;
- }
+ paper-tooltip {
+ --paper-tooltip: {
+ @apply --cr-tooltip;
+ min-width: 0;
+ };
+ }
- #source-indicator iron-icon {
- color: white;
- height: 16px;
- width: 16px;
- }
+ #errors-button {
+ color: var(--error-color);
+ }
- paper-tooltip {
- --paper-tooltip: {
- @apply --cr-tooltip;
- min-width: 0;
- };
- }
+ #dev-reload-button {
+ margin-inline-end: 12px;
+ }
- #errors-button {
- color: var(--error-color);
- }
+ #blacklisted-warning:empty {
+ display: none;
+ }
- #dev-reload-button {
- margin-inline-end: 12px;
- }
-
- #blacklisted-warning:empty {
- display: none;
- }
-
- #a11yAssociation {
- height: 0;
- overflow: hidden;
- }
- </style>
- <!-- Invisible instead of hidden because VoiceOver refuses to read text of
- element that's hidden when referenced by an aria label. Unfortunately,
- this text can be found by Ctrl + F because it isn't hidden. -->
- <div id="a11yAssociation" aria-hidden="true">
- [[a11yAssociation_(data.name)]]
- </div>
- <div id="card" class$="[[computeClasses_(data.state, inDevMode)]]">
- <div id="main">
- <div id="icon-wrapper">
- <img id="icon" src="[[data.iconUrl]]"
+ #a11yAssociation {
+ height: 0;
+ overflow: hidden;
+ }
+</style>
+<!-- Invisible instead of hidden because VoiceOver refuses to read text of
+ element that's hidden when referenced by an aria label. Unfortunately,
+ this text can be found by Ctrl + F because it isn't hidden. -->
+<div id="a11yAssociation" aria-hidden="true">
+ [[a11yAssociation_(data.name)]]
+</div>
+<div id="card" class$="[[computeClasses_(data.state, inDevMode)]]">
+ <div id="main">
+ <div id="icon-wrapper">
+ <img id="icon" src="[[data.iconUrl]]"
+ aria-describedby="a11yAssociation"
+ alt$="[[appOrExtension(
+ data.type,
+ '$i18nPolymer{appIcon}',
+ '$i18nPolymer{extensionIcon}')]]">
+ <template is="dom-if"
+ if="[[computeSourceIndicatorIcon_(data.*)]]">
+ <div id="source-indicator">
+ <div class="source-icon-wrapper" role="img"
aria-describedby="a11yAssociation"
- alt$="[[appOrExtension(
- data.type,
- '$i18nPolymer{appIcon}',
- '$i18nPolymer{extensionIcon}')]]">
- <template is="dom-if"
- if="[[computeSourceIndicatorIcon_(data.*)]]">
- <div id="source-indicator">
- <div class="source-icon-wrapper" role="img"
- aria-describedby="a11yAssociation"
- aria-label$="[[computeSourceIndicatorText_(data.*)]]">
- <iron-icon icon="[[computeSourceIndicatorIcon_(data.*)]]">
- </iron-icon>
- </div>
- </div>
- </template>
+ aria-label$="[[computeSourceIndicatorText_(data.*)]]">
+ <iron-icon icon="[[computeSourceIndicatorIcon_(data.*)]]">
+ </iron-icon>
+ </div>
+ </div>
+ </template>
+ </div>
+ <!-- This needs to be separate from the source-indicator since it can't
+ be contained inside of a position:relative parent element. -->
+ <template is="dom-if"
+ if="[[computeSourceIndicatorIcon_(data.*)]]">
+ <paper-tooltip id="source-indicator-text" for="source-indicator"
+ position="top" fit-to-visible-bounds aria-hidden="true">
+ [[computeSourceIndicatorText_(data.*)]]
+ </paper-tooltip>
+ </template>
+ <div id="content">
+ <!--Note: We wrap inspect-views in a div so that the outer div
+ doesn't shrink (because it's not display: flex).-->
+ <div>
+ <div id="name-and-version" class="layout horizontal center">
+ <div id="name" role="heading" aria-level="3"
+ class="clippable-flex-text">[[data.name]]</div>
+ <span id="version" hidden$="[[!inDevMode]]">
+ [[data.version]]
+ </span>
</div>
- <!-- This needs to be separate from the source-indicator since it can't
- be contained inside of a position:relative parent element. -->
+ </div>
+ <div id="description" class="multiline-clippable-text"
+ hidden$="[[hasWarnings_(data.disableReasons.*, data.*)]]">
+ [[data.description]]
+ </div>
+ <template is="dom-if"
+ if="[[hasWarnings_(data.disableReasons.*, data.*)]]">
+ <div id="warnings">
+ <iron-icon id="error-icon" icon="cr:error"></iron-icon>
+ <span id="runtime-warnings" aria-describedby="a11yAssociation"
+ hidden$="[[!data.runtimeWarnings.length]]">
+ <template is="dom-repeat" items="[[data.runtimeWarnings]]">
+ [[item]]
+ </template>
+ </span>
+ <span id="suspicious-warning" aria-describedby="a11yAssociation"
+ hidden$="[[!data.disableReasons.suspiciousInstall]]">
+ $i18n{itemSuspiciousInstall}
+ <a target="_blank" href="$i18n{suspiciousInstallHelpUrl}">
+ $i18n{learnMore}
+ </a>
+ </span>
+ <span id="corrupted-warning" aria-describedby="a11yAssociation"
+ hidden$="[[!data.disableReasons.corruptInstall]]">
+ $i18n{itemCorruptInstall}
+ </span>
+ <span id="blacklisted-warning"><!-- No whitespace
+ -->[[data.blacklistText]]<!-- so we can use :empty in css.
+ --></span>
+ </div>
+ </template>
+ <template is="dom-if" if="[[inDevMode]]">
+ <div id="extension-id" class="bounded-text">[[data.id]]</div>
<template is="dom-if"
- if="[[computeSourceIndicatorIcon_(data.*)]]">
- <paper-tooltip id="source-indicator-text" for="source-indicator"
- position="top" fit-to-visible-bounds aria-hidden="true">
- [[computeSourceIndicatorText_(data.*)]]
- </paper-tooltip>
- </template>
- <div id="content">
+ if="[[!computeInspectViewsHidden_(data.views)]]">
<!--Note: We wrap inspect-views in a div so that the outer div
doesn't shrink (because it's not display: flex).-->
<div>
- <div id="name-and-version" class="layout horizontal center">
- <div id="name" role="heading" aria-level="3"
- class="clippable-flex-text">[[data.name]]</div>
- <span id="version" hidden$="[[!inDevMode]]">
- [[data.version]]
+ <div id="inspect-views">
+ <span aria-describedby="a11yAssociation">
+ $i18n{itemInspectViews}
</span>
+ <a class="clippable-flex-text" is="action-link"
+ title="[[computeFirstInspectTitle_(data.views)]]"
+ on-click="onInspectTap_">
+ [[computeFirstInspectLabel_(data.views)]]
+ </a>
+ <a is="action-link"
+ hidden$="[[computeExtraViewsHidden_(data.views)]]"
+ on-click="onExtraInspectTap_">
+ [[computeExtraInspectLabel_(data.views)]]
+ </a>
</div>
</div>
- <div id="description" class="multiline-clippable-text"
- hidden$="[[hasWarnings_(data.disableReasons.*, data.*)]]">
- [[data.description]]
- </div>
- <template is="dom-if"
- if="[[hasWarnings_(data.disableReasons.*, data.*)]]">
- <div id="warnings">
- <iron-icon id="error-icon" icon="cr:error"></iron-icon>
- <span id="runtime-warnings" aria-describedby="a11yAssociation"
- hidden$="[[!data.runtimeWarnings.length]]">
- <template is="dom-repeat" items="[[data.runtimeWarnings]]">
- [[item]]
- </template>
- </span>
- <span id="suspicious-warning" aria-describedby="a11yAssociation"
- hidden$="[[!data.disableReasons.suspiciousInstall]]">
- $i18n{itemSuspiciousInstall}
- <a target="_blank" href="$i18n{suspiciousInstallHelpUrl}">
- $i18n{learnMore}
- </a>
- </span>
- <span id="corrupted-warning" aria-describedby="a11yAssociation"
- hidden$="[[!data.disableReasons.corruptInstall]]">
- $i18n{itemCorruptInstall}
- </span>
- <span id="blacklisted-warning"><!-- No whitespace
- -->[[data.blacklistText]]<!-- so we can use :empty in css.
- --></span>
- </div>
- </template>
- <template is="dom-if" if="[[inDevMode]]">
- <div id="extension-id" class="bounded-text">[[data.id]]</div>
- <template is="dom-if"
- if="[[!computeInspectViewsHidden_(data.views)]]">
- <!--Note: We wrap inspect-views in a div so that the outer div
- doesn't shrink (because it's not display: flex).-->
- <div>
- <div id="inspect-views">
- <span aria-describedby="a11yAssociation">
- $i18n{itemInspectViews}
- </span>
- <a class="clippable-flex-text" is="action-link"
- title="[[computeFirstInspectTitle_(data.views)]]"
- on-click="onInspectTap_">
- [[computeFirstInspectLabel_(data.views)]]
- </a>
- <a is="action-link"
- hidden$="[[computeExtraViewsHidden_(data.views)]]"
- on-click="onExtraInspectTap_">
- [[computeExtraInspectLabel_(data.views)]]
- </a>
- </div>
- </div>
- </template>
- </template>
- </div>
- </div>
- <div id="button-strip" class="layout horizontal center">
- <div class="layout flex horizontal center">
- <cr-button id="detailsButton" on-click="onDetailsTap_"
- aria-describedby="a11yAssociation">
- $i18n{itemDetails}
- </cr-button>
- <cr-button id="remove-button" on-click="onRemoveTap_"
- aria-describedby="a11yAssociation"
- hidden="[[isControlled_(data.controlledInfo)]]">
- $i18n{remove}
- </cr-button>
- <template is="dom-if" if="[[shouldShowErrorsButton_(data.*)]]">
- <cr-button id="errors-button" on-click="onErrorsTap_"
- aria-describedby="a11yAssociation">
- $i18n{itemErrors}
- </cr-button>
- </template>
- </div>
- <template is="dom-if" if="[[!computeDevReloadButtonHidden_(data.*)]]">
- <cr-icon-button id="dev-reload-button" class="icon-refresh no-overlap"
- aria-label="$i18n{itemReload}" aria-describedby="a11yAssociation"
- on-click="onReloadTap_"></cr-icon-button>
- </template>
- <template is="dom-if" if="[[data.disableReasons.corruptInstall]]">
- <cr-button id="repair-button" class="action-button"
- aria-describedby="a11yAssociation" on-click="onRepairTap_">
- $i18n{itemRepair}
- </cr-button>
</template>
- <template is="dom-if" if="[[isTerminated_(data.state)]]">
- <cr-button id="terminated-reload-button" on-click="onReloadTap_"
- aria-describedby="a11yAssociation" class="action-button">
- $i18n{itemReload}
- </cr-button>
- </template>
- <cr-toggle id="enable-toggle"
- aria-label$="[[appOrExtension(
- data.type,
- '$i18nPolymer{appEnabled}',
- '$i18nPolymer{extensionEnabled}')]]"
- aria-describedby="a11yAssociation"
- checked="[[isEnabled_(data.state)]]" on-change="onEnableChange_"
- disabled="[[!isEnableToggleEnabled_(data.*)]]"
- hidden$="[[!showEnableToggle_(data.*)]]">
- </cr-toggle>
- </div>
+ </template>
+ </div>
+ </div>
+ <div id="button-strip" class="layout horizontal center">
+ <div class="layout flex horizontal center">
+ <cr-button id="detailsButton" on-click="onDetailsTap_"
+ aria-describedby="a11yAssociation">
+ $i18n{itemDetails}
+ </cr-button>
+ <cr-button id="remove-button" on-click="onRemoveTap_"
+ aria-describedby="a11yAssociation"
+ hidden="[[isControlled_(data.controlledInfo)]]">
+ $i18n{remove}
+ </cr-button>
+ <template is="dom-if" if="[[shouldShowErrorsButton_(data.*)]]">
+ <cr-button id="errors-button" on-click="onErrorsTap_"
+ aria-describedby="a11yAssociation">
+ $i18n{itemErrors}
+ </cr-button>
+ </template>
</div>
- </template>
- <script src="item.js"></script>
-</dom-module>
+ <template is="dom-if" if="[[!computeDevReloadButtonHidden_(data.*)]]">
+ <cr-icon-button id="dev-reload-button" class="icon-refresh no-overlap"
+ aria-label="$i18n{itemReload}" aria-describedby="a11yAssociation"
+ on-click="onReloadTap_"></cr-icon-button>
+ </template>
+ <template is="dom-if" if="[[data.disableReasons.corruptInstall]]">
+ <cr-button id="repair-button" class="action-button"
+ aria-describedby="a11yAssociation" on-click="onRepairTap_">
+ $i18n{itemRepair}
+ </cr-button>
+ </template>
+ <template is="dom-if" if="[[isTerminated_(data.state)]]">
+ <cr-button id="terminated-reload-button" on-click="onReloadTap_"
+ aria-describedby="a11yAssociation" class="action-button">
+ $i18n{itemReload}
+ </cr-button>
+ </template>
+ <cr-toggle id="enable-toggle"
+ aria-label$="[[appOrExtension(
+ data.type,
+ '$i18nPolymer{appEnabled}',
+ '$i18nPolymer{extensionEnabled}')]]"
+ aria-describedby="a11yAssociation"
+ checked="[[isEnabled_(data.state)]]" on-change="onEnableChange_"
+ disabled="[[!isEnableToggleEnabled_(data.*)]]"
+ hidden$="[[!showEnableToggle_(data.*)]]">
+ </cr-toggle>
+ </div>
+</div>
diff --git a/chromium/chrome/browser/resources/extensions/item.js b/chromium/chrome/browser/resources/extensions/item.js
index d1fc8e973ab..7973811c58e 100644
--- a/chromium/chrome/browser/resources/extensions/item.js
+++ b/chromium/chrome/browser/resources/extensions/item.js
@@ -2,426 +2,441 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- /** @interface */
- class ItemDelegate {
- /** @param {string} id */
- deleteItem(id) {}
-
- /**
- * @param {string} id
- * @param {boolean} isEnabled
- */
- setItemEnabled(id, isEnabled) {}
-
- /**
- * @param {string} id
- * @param {boolean} isAllowedIncognito
- */
- setItemAllowedIncognito(id, isAllowedIncognito) {}
-
- /**
- * @param {string} id
- * @param {boolean} isAllowedOnFileUrls
- */
- setItemAllowedOnFileUrls(id, isAllowedOnFileUrls) {}
-
- /**
- * @param {string} id
- * @param {!chrome.developerPrivate.HostAccess} hostAccess
- */
- setItemHostAccess(id, hostAccess) {}
-
- /**
- * @param {string} id
- * @param {boolean} collectsErrors
- */
- setItemCollectsErrors(id, collectsErrors) {}
-
- /**
- * @param {string} id
- * @param {chrome.developerPrivate.ExtensionView} view
- */
- inspectItemView(id, view) {}
-
- /**
- * @param {string} url
- */
- openUrl(url) {}
-
- /**
- * @param {string} id
- * @return {!Promise}
- */
- reloadItem(id) {}
-
- /** @param {string} id */
- repairItem(id) {}
-
- /** @param {!chrome.developerPrivate.ExtensionInfo} extension */
- showItemOptionsPage(extension) {}
-
- /** @param {string} id */
- showInFolder(id) {}
-
- /**
- * @param {string} id
- * @return {!Promise<string>}
- */
- getExtensionSize(id) {}
-
- /**
- * @param {string} id
- * @param {string} host
- * @return {!Promise<void>}
- */
- addRuntimeHostPermission(id, host) {}
-
- /**
- * @param {string} id
- * @param {string} host
- * @return {!Promise<void>}
- */
- removeRuntimeHostPermission(id, host) {}
- }
-
- const Item = Polymer({
- is: 'extensions-item',
-
- behaviors: [I18nBehavior, extensions.ItemBehavior],
-
- properties: {
- // The item's delegate, or null.
- delegate: {
- type: Object,
- },
-
- // Whether or not dev mode is enabled.
- inDevMode: {
- type: Boolean,
- value: false,
- },
-
- // The underlying ExtensionInfo itself. Public for use in declarative
- // bindings.
- /** @type {chrome.developerPrivate.ExtensionInfo} */
- data: {
- type: Object,
- },
-
- // Whether or not the expanded view of the item is shown.
- /** @private */
- showingDetails_: {
- type: Boolean,
- value: false,
- },
+import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
+import 'chrome://resources/cr_elements/cr_icons_css.m.js';
+import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.m.js';
+import 'chrome://resources/cr_elements/hidden_style_css.m.js';
+import 'chrome://resources/cr_elements/icons.m.js';
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+import 'chrome://resources/js/action_link.js';
+import 'chrome://resources/cr_elements/action_link_css.m.js';
+import './icons.js';
+import './shared_style.js';
+import './shared_vars.js';
+import './strings.m.js';
+import 'chrome://resources/polymer/v3_0/iron-flex-layout/iron-flex-layout-classes.js';
+import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
+import 'chrome://resources/polymer/v3_0/paper-tooltip/paper-tooltip.js';
+
+import {getToastManager} from 'chrome://resources/cr_elements/cr_toast/cr_toast_manager.m.js';
+import {assert, assertNotReached} from 'chrome://resources/js/assert.m.js';
+import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+import {flush, html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {ItemBehavior} from './item_behavior.js';
+import {computeInspectableViewLabel, getItemSource, getItemSourceString, isControlled, isEnabled, SourceType, userCanChangeEnablement} from './item_util.js';
+import {navigation, Page} from './navigation_helper.js';
+
+/** @interface */
+export class ItemDelegate {
+ /** @param {string} id */
+ deleteItem(id) {}
+
+ /**
+ * @param {string} id
+ * @param {boolean} isEnabled
+ */
+ setItemEnabled(id, isEnabled) {}
+
+ /**
+ * @param {string} id
+ * @param {boolean} isAllowedIncognito
+ */
+ setItemAllowedIncognito(id, isAllowedIncognito) {}
+
+ /**
+ * @param {string} id
+ * @param {boolean} isAllowedOnFileUrls
+ */
+ setItemAllowedOnFileUrls(id, isAllowedOnFileUrls) {}
+
+ /**
+ * @param {string} id
+ * @param {!chrome.developerPrivate.HostAccess} hostAccess
+ */
+ setItemHostAccess(id, hostAccess) {}
+
+ /**
+ * @param {string} id
+ * @param {boolean} collectsErrors
+ */
+ setItemCollectsErrors(id, collectsErrors) {}
+
+ /**
+ * @param {string} id
+ * @param {chrome.developerPrivate.ExtensionView} view
+ */
+ inspectItemView(id, view) {}
+
+ /**
+ * @param {string} url
+ */
+ openUrl(url) {}
+
+ /**
+ * @param {string} id
+ * @return {!Promise}
+ */
+ reloadItem(id) {}
+
+ /** @param {string} id */
+ repairItem(id) {}
+
+ /** @param {!chrome.developerPrivate.ExtensionInfo} extension */
+ showItemOptionsPage(extension) {}
+
+ /** @param {string} id */
+ showInFolder(id) {}
+
+ /**
+ * @param {string} id
+ * @return {!Promise<string>}
+ */
+ getExtensionSize(id) {}
+
+ /**
+ * @param {string} id
+ * @param {string} host
+ * @return {!Promise<void>}
+ */
+ addRuntimeHostPermission(id, host) {}
+
+ /**
+ * @param {string} id
+ * @param {string} host
+ * @return {!Promise<void>}
+ */
+ removeRuntimeHostPermission(id, host) {}
+}
+
+Polymer({
+ is: 'extensions-item',
+
+ _template: html`{__html_template__}`,
+
+ behaviors: [I18nBehavior, ItemBehavior],
+
+ properties: {
+ // The item's delegate, or null.
+ delegate: {
+ type: Object,
},
- /** Prevents reloading the same item while it's already being reloaded. */
- isReloading_: false,
-
- observers: [
- 'observeIdVisibility_(inDevMode, showingDetails_, data.id)',
- ],
-
- /** @return {!HTMLElement} The "Details" button. */
- getDetailsButton: function() {
- return this.$.detailsButton;
- },
-
- /** @return {?HTMLElement} The "Errors" button, if it exists. */
- getErrorsButton: function() {
- return /** @type {?HTMLElement} */ (this.$$('#errors-button'));
- },
-
- /** @private string */
- a11yAssociation_: function() {
- // Don't use I18nBehavior.i18n because of additional checks it performs.
- // Polymer ensures that this string is not stamped into arbitrary HTML.
- // |this.data.name| can contain any data including html tags.
- // ex: "My <video> download extension!"
- return loadTimeData.getStringF(
- 'extensionA11yAssociation', this.data.name);
- },
-
- /** @private */
- observeIdVisibility_: function(inDevMode, showingDetails, id) {
- Polymer.dom.flush();
- const idElement = this.$$('#extension-id');
- if (idElement) {
- assert(this.data);
- idElement.innerHTML = this.i18n('itemId', this.data.id);
- }
- },
-
- /**
- * @return {boolean}
- * @private
- */
- shouldShowErrorsButton_: function() {
- // When the error console is disabled (happens when
- // --disable-error-console command line flag is used or when in the
- // Stable/Beta channel), |installWarnings| is populated.
- if (this.data.installWarnings && this.data.installWarnings.length > 0) {
- return true;
- }
-
- // When error console is enabled |installedWarnings| is not populated.
- // Instead |manifestErrors| and |runtimeErrors| are used.
- return this.data.manifestErrors.length > 0 ||
- this.data.runtimeErrors.length > 0;
- },
-
- /** @private */
- onRemoveTap_: function() {
- this.delegate.deleteItem(this.data.id);
+ // Whether or not dev mode is enabled.
+ inDevMode: {
+ type: Boolean,
+ value: false,
},
- /** @private */
- onEnableChange_: function() {
- this.delegate.setItemEnabled(
- this.data.id, this.$['enable-toggle'].checked);
+ // The underlying ExtensionInfo itself. Public for use in declarative
+ // bindings.
+ /** @type {chrome.developerPrivate.ExtensionInfo} */
+ data: {
+ type: Object,
},
+ // Whether or not the expanded view of the item is shown.
/** @private */
- onErrorsTap_: function() {
- if (this.data.installWarnings && this.data.installWarnings.length > 0) {
- this.fire('show-install-warnings', this.data.installWarnings);
- return;
- }
-
- extensions.navigation.navigateTo(
- {page: extensions.Page.ERRORS, extensionId: this.data.id});
- },
-
- /** @private */
- onDetailsTap_: function() {
- extensions.navigation.navigateTo(
- {page: extensions.Page.DETAILS, extensionId: this.data.id});
- },
-
- /**
- * @param {!{model: !{item: !chrome.developerPrivate.ExtensionView}}} e
- * @private
- */
- onInspectTap_: function(e) {
- this.delegate.inspectItemView(this.data.id, this.data.views[0]);
- },
-
- /** @private */
- onExtraInspectTap_: function() {
- extensions.navigation.navigateTo(
- {page: extensions.Page.DETAILS, extensionId: this.data.id});
- },
-
- /** @private */
- onReloadTap_: function() {
- // Don't reload if in the middle of an update.
- if (this.isReloading_) {
- return;
- }
-
- this.isReloading_ = true;
-
- const toastManager = cr.toastManager.getInstance();
- // Keep the toast open indefinitely.
- toastManager.duration = 0;
- toastManager.show(this.i18n('itemReloading'), false);
- this.delegate.reloadItem(this.data.id)
- .then(
- () => {
- toastManager.hide();
- toastManager.duration = 3000;
- toastManager.show(this.i18n('itemReloaded'), false);
- this.isReloading_ = false;
- },
- loadError => {
- this.fire('load-error', loadError);
- toastManager.hide();
- this.isReloading_ = false;
- });
- },
-
- /** @private */
- onRepairTap_: function() {
- this.delegate.repairItem(this.data.id);
- },
-
- /**
- * @return {boolean}
- * @private
- */
- isControlled_: function() {
- return extensions.isControlled(this.data);
+ showingDetails_: {
+ type: Boolean,
+ value: false,
},
-
- /**
- * @return {boolean}
- * @private
- */
- isEnabled_: function() {
- return extensions.isEnabled(this.data.state);
- },
-
- /**
- * @return {boolean}
- * @private
- */
- isEnableToggleEnabled_: function() {
- return extensions.userCanChangeEnablement(this.data);
- },
-
- /**
- * Returns true if the enable toggle should be shown.
- * @return {boolean}
- * @private
- */
- showEnableToggle_: function() {
- return !this.isTerminated_() && !this.data.disableReasons.corruptInstall;
- },
-
- /**
- * Returns true if the extension is in the terminated state.
- * @return {boolean}
- * @private
- */
- isTerminated_: function() {
- return this.data.state ==
- chrome.developerPrivate.ExtensionState.TERMINATED;
- },
-
- /**
- * return {string}
- * @private
- */
- computeClasses_: function() {
- let classes = this.isEnabled_() ? 'enabled' : 'disabled';
- if (this.inDevMode) {
- classes += ' dev-mode';
- }
- return classes;
- },
-
- /**
- * @return {string}
- * @private
- */
- computeSourceIndicatorIcon_: function() {
- switch (extensions.getItemSource(this.data)) {
- case SourceType.POLICY:
- return 'extensions-icons:business';
- case SourceType.SIDELOADED:
- return 'extensions-icons:input';
- case SourceType.UNKNOWN:
- // TODO(dpapad): Ask UX for a better icon for this case.
- return 'extensions-icons:input';
- case SourceType.UNPACKED:
- return 'extensions-icons:unpacked';
- case SourceType.WEBSTORE:
- return '';
- }
- assertNotReached();
- },
-
- /**
- * @return {string}
- * @private
- */
- computeSourceIndicatorText_: function() {
- if (this.data.locationText) {
- return this.data.locationText;
- }
-
- const sourceType = extensions.getItemSource(this.data);
- return sourceType == SourceType.WEBSTORE ?
- '' :
- extensions.getItemSourceString(sourceType);
- },
-
- /**
- * @return {boolean}
- * @private
- */
- computeInspectViewsHidden_: function() {
- return !this.data.views || this.data.views.length == 0;
- },
-
- /**
- * @return {string}
- * @private
- */
- computeFirstInspectTitle_: function() {
- // Note: theoretically, this wouldn't be called without any inspectable
- // views (because it's in a dom-if="!computeInspectViewsHidden_()").
- // However, due to the recycling behavior of iron list, it seems that
- // sometimes it can. Even when it is, the UI behaves properly, but we
- // need to handle the case gracefully.
- return this.data.views.length > 0 ?
- extensions.computeInspectableViewLabel(this.data.views[0]) :
- '';
- },
-
- /**
- * @return {string}
- * @private
- */
- computeFirstInspectLabel_: function() {
- const label = this.computeFirstInspectTitle_();
- return label && this.data.views.length > 1 ? label + ',' : label;
- },
-
- /**
- * @return {boolean}
- * @private
- */
- computeExtraViewsHidden_: function() {
- return this.data.views.length <= 1;
- },
-
- /**
- * @return {boolean}
- * @private
- */
- computeDevReloadButtonHidden_: function() {
- // Only display the reload spinner if the extension is unpacked and
- // enabled. There's no point in reloading a disabled extension, and we'll
- // show a crashed reload buton if it's terminated.
- const showIcon =
- this.data.location == chrome.developerPrivate.Location.UNPACKED &&
- this.data.state == chrome.developerPrivate.ExtensionState.ENABLED;
- return !showIcon;
- },
-
- /**
- * @return {string}
- * @private
- */
- computeExtraInspectLabel_: function() {
- return this.i18n(
- 'itemInspectViewsExtra', (this.data.views.length - 1).toString());
- },
-
- /**
- * @return {boolean}
- * @private
- */
- hasWarnings_: function() {
- return this.data.disableReasons.corruptInstall ||
- this.data.disableReasons.suspiciousInstall ||
- this.data.runtimeWarnings.length > 0 || !!this.data.blacklistText;
- },
-
- /**
- * @return {string}
- * @private
- */
- computeWarningsClasses_: function() {
- return this.data.blacklistText ? 'severe' : 'mild';
- },
- });
-
- return {
- Item: Item,
- ItemDelegate: ItemDelegate,
- };
+ },
+
+ /** Prevents reloading the same item while it's already being reloaded. */
+ isReloading_: false,
+
+ observers: [
+ 'observeIdVisibility_(inDevMode, showingDetails_, data.id)',
+ ],
+
+ /** @return {!HTMLElement} The "Details" button. */
+ getDetailsButton: function() {
+ return /** @type {!HTMLElement} */ (this.$.detailsButton);
+ },
+
+ /** @return {?HTMLElement} The "Errors" button, if it exists. */
+ getErrorsButton: function() {
+ return /** @type {?HTMLElement} */ (this.$$('#errors-button'));
+ },
+
+ /** @private string */
+ a11yAssociation_: function() {
+ // Don't use I18nBehavior.i18n because of additional checks it performs.
+ // Polymer ensures that this string is not stamped into arbitrary HTML.
+ // |this.data.name| can contain any data including html tags.
+ // ex: "My <video> download extension!"
+ return loadTimeData.getStringF('extensionA11yAssociation', this.data.name);
+ },
+
+ /** @private */
+ observeIdVisibility_: function(inDevMode, showingDetails, id) {
+ flush();
+ const idElement = this.$$('#extension-id');
+ if (idElement) {
+ assert(this.data);
+ idElement.innerHTML = this.i18n('itemId', this.data.id);
+ }
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ shouldShowErrorsButton_: function() {
+ // When the error console is disabled (happens when
+ // --disable-error-console command line flag is used or when in the
+ // Stable/Beta channel), |installWarnings| is populated.
+ if (this.data.installWarnings && this.data.installWarnings.length > 0) {
+ return true;
+ }
+
+ // When error console is enabled |installedWarnings| is not populated.
+ // Instead |manifestErrors| and |runtimeErrors| are used.
+ return this.data.manifestErrors.length > 0 ||
+ this.data.runtimeErrors.length > 0;
+ },
+
+ /** @private */
+ onRemoveTap_: function() {
+ this.delegate.deleteItem(this.data.id);
+ },
+
+ /** @private */
+ onEnableChange_: function() {
+ this.delegate.setItemEnabled(this.data.id, this.$['enable-toggle'].checked);
+ },
+
+ /** @private */
+ onErrorsTap_: function() {
+ if (this.data.installWarnings && this.data.installWarnings.length > 0) {
+ this.fire('show-install-warnings', this.data.installWarnings);
+ return;
+ }
+
+ navigation.navigateTo({page: Page.ERRORS, extensionId: this.data.id});
+ },
+
+ /** @private */
+ onDetailsTap_: function() {
+ navigation.navigateTo({page: Page.DETAILS, extensionId: this.data.id});
+ },
+
+ /**
+ * @param {!{model: !{item: !chrome.developerPrivate.ExtensionView}}} e
+ * @private
+ */
+ onInspectTap_: function(e) {
+ this.delegate.inspectItemView(this.data.id, this.data.views[0]);
+ },
+
+ /** @private */
+ onExtraInspectTap_: function() {
+ navigation.navigateTo({page: Page.DETAILS, extensionId: this.data.id});
+ },
+
+ /** @private */
+ onReloadTap_: function() {
+ // Don't reload if in the middle of an update.
+ if (this.isReloading_) {
+ return;
+ }
+
+ this.isReloading_ = true;
+
+ const toastManager = getToastManager();
+ // Keep the toast open indefinitely.
+ toastManager.duration = 0;
+ toastManager.show(this.i18n('itemReloading'));
+ this.delegate.reloadItem(this.data.id)
+ .then(
+ () => {
+ toastManager.hide();
+ toastManager.duration = 3000;
+ toastManager.show(this.i18n('itemReloaded'));
+ this.isReloading_ = false;
+ },
+ loadError => {
+ this.fire('load-error', loadError);
+ toastManager.hide();
+ this.isReloading_ = false;
+ });
+ },
+
+ /** @private */
+ onRepairTap_: function() {
+ this.delegate.repairItem(this.data.id);
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ isControlled_: function() {
+ return isControlled(this.data);
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ isEnabled_: function() {
+ return isEnabled(this.data.state);
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ isEnableToggleEnabled_: function() {
+ return userCanChangeEnablement(this.data);
+ },
+
+ /**
+ * Returns true if the enable toggle should be shown.
+ * @return {boolean}
+ * @private
+ */
+ showEnableToggle_: function() {
+ return !this.isTerminated_() && !this.data.disableReasons.corruptInstall;
+ },
+
+ /**
+ * Returns true if the extension is in the terminated state.
+ * @return {boolean}
+ * @private
+ */
+ isTerminated_: function() {
+ return this.data.state == chrome.developerPrivate.ExtensionState.TERMINATED;
+ },
+
+ /**
+ * return {string}
+ * @private
+ */
+ computeClasses_: function() {
+ let classes = this.isEnabled_() ? 'enabled' : 'disabled';
+ if (this.inDevMode) {
+ classes += ' dev-mode';
+ }
+ return classes;
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ computeSourceIndicatorIcon_: function() {
+ switch (getItemSource(this.data)) {
+ case SourceType.POLICY:
+ return 'extensions-icons:business';
+ case SourceType.SIDELOADED:
+ return 'extensions-icons:input';
+ case SourceType.UNKNOWN:
+ // TODO(dpapad): Ask UX for a better icon for this case.
+ return 'extensions-icons:input';
+ case SourceType.UNPACKED:
+ return 'extensions-icons:unpacked';
+ case SourceType.WEBSTORE:
+ return '';
+ }
+ assertNotReached();
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ computeSourceIndicatorText_: function() {
+ if (this.data.locationText) {
+ return this.data.locationText;
+ }
+
+ const sourceType = getItemSource(this.data);
+ return sourceType == SourceType.WEBSTORE ? '' :
+ getItemSourceString(sourceType);
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ computeInspectViewsHidden_: function() {
+ return !this.data.views || this.data.views.length == 0;
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ computeFirstInspectTitle_: function() {
+ // Note: theoretically, this wouldn't be called without any inspectable
+ // views (because it's in a dom-if="!computeInspectViewsHidden_()").
+ // However, due to the recycling behavior of iron list, it seems that
+ // sometimes it can. Even when it is, the UI behaves properly, but we
+ // need to handle the case gracefully.
+ return this.data.views.length > 0 ?
+ computeInspectableViewLabel(this.data.views[0]) :
+ '';
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ computeFirstInspectLabel_: function() {
+ const label = this.computeFirstInspectTitle_();
+ return label && this.data.views.length > 1 ? label + ',' : label;
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ computeExtraViewsHidden_: function() {
+ return this.data.views.length <= 1;
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ computeDevReloadButtonHidden_: function() {
+ // Only display the reload spinner if the extension is unpacked and
+ // enabled. There's no point in reloading a disabled extension, and we'll
+ // show a crashed reload button if it's terminated.
+ const showIcon =
+ this.data.location == chrome.developerPrivate.Location.UNPACKED &&
+ this.data.state == chrome.developerPrivate.ExtensionState.ENABLED;
+ return !showIcon;
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ computeExtraInspectLabel_: function() {
+ return this.i18n(
+ 'itemInspectViewsExtra', (this.data.views.length - 1).toString());
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ hasWarnings_: function() {
+ return this.data.disableReasons.corruptInstall ||
+ this.data.disableReasons.suspiciousInstall ||
+ this.data.runtimeWarnings.length > 0 || !!this.data.blacklistText;
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ computeWarningsClasses_: function() {
+ return this.data.blacklistText ? 'severe' : 'mild';
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/item_behavior.html b/chromium/chrome/browser/resources/extensions/item_behavior.html
deleted file mode 100644
index b0369e6dc6d..00000000000
--- a/chromium/chrome/browser/resources/extensions/item_behavior.html
+++ /dev/null
@@ -1 +0,0 @@
-<script src="item_behavior.js"></script>
diff --git a/chromium/chrome/browser/resources/extensions/item_behavior.js b/chromium/chrome/browser/resources/extensions/item_behavior.js
index 40241f5eb2d..c1e368a4368 100644
--- a/chromium/chrome/browser/resources/extensions/item_behavior.js
+++ b/chromium/chrome/browser/resources/extensions/item_behavior.js
@@ -2,29 +2,27 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- /** @polymerBehavior */
- const ItemBehavior = {
- /**
- * @param {chrome.developerPrivate.ExtensionType} type
- * @param {string} appLabel
- * @param {string} extensionLabel
- * @return {string} The app or extension label depending on |type|.
- */
- appOrExtension: function(type, appLabel, extensionLabel) {
- const ExtensionType = chrome.developerPrivate.ExtensionType;
- switch (type) {
- case ExtensionType.HOSTED_APP:
- case ExtensionType.LEGACY_PACKAGED_APP:
- case ExtensionType.PLATFORM_APP:
- return appLabel;
- case ExtensionType.EXTENSION:
- case ExtensionType.SHARED_MODULE:
- return extensionLabel;
- }
- assertNotReached('Item type is not App or Extension.');
- },
- };
+import {assertNotReached} from 'chrome://resources/js/assert.m.js';
- return {ItemBehavior: ItemBehavior};
-});
+/** @polymerBehavior */
+export const ItemBehavior = {
+ /**
+ * @param {chrome.developerPrivate.ExtensionType} type
+ * @param {string} appLabel
+ * @param {string} extensionLabel
+ * @return {string} The app or extension label depending on |type|.
+ */
+ appOrExtension: function(type, appLabel, extensionLabel) {
+ const ExtensionType = chrome.developerPrivate.ExtensionType;
+ switch (type) {
+ case ExtensionType.HOSTED_APP:
+ case ExtensionType.LEGACY_PACKAGED_APP:
+ case ExtensionType.PLATFORM_APP:
+ return appLabel;
+ case ExtensionType.EXTENSION:
+ case ExtensionType.SHARED_MODULE:
+ return extensionLabel;
+ }
+ assertNotReached('Item type is not App or Extension.');
+ },
+};
diff --git a/chromium/chrome/browser/resources/extensions/item_list.html b/chromium/chrome/browser/resources/extensions/item_list.html
index 339e774de80..2ea1c0f87ae 100644
--- a/chromium/chrome/browser/resources/extensions/item_list.html
+++ b/chromium/chrome/browser/resources/extensions/item_list.html
@@ -1,133 +1,118 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="shared-style">
+ .items-container,
+ #content-wrapper {
+ --extensions-card-width: 400px;
+ }
-<link rel="import" href="chrome://resources/cr_components/managed_footnote/managed_footnote.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_container_shadow_behavior.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/html/i18n_behavior.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-announcer/iron-a11y-announcer.html">
-<link rel="import" href="item.html">
-<link rel="import" href="shared_style.html">
+ #container {
+ box-sizing: border-box;
+ height: 100%;
+ overflow: overlay;
+ }
-<dom-module id="extensions-item-list">
- <template>
- <style include="shared-style">
- .items-container,
- #content-wrapper {
- --extensions-card-width: 400px;
- }
+ #content-wrapper {
+ min-width: var(--extensions-card-width);
+ padding: 24px 60px 64px;
+ }
- #container {
- box-sizing: border-box;
- height: 100%;
- overflow: overlay;
- }
+ .empty-list-message {
+ color: #6e6e6e;
+ font-size: 123%; /* Should be 16px when 100% is 13px. */
+ font-weight: 500;
+ margin-top: 80px;
+ text-align: center;
+ }
- #content-wrapper {
- min-width: var(--extensions-card-width);
- padding: 24px 60px 64px;
- }
+ @media (prefers-color-scheme: dark) {
+ .empty-list-message {
+ color: var(--cr-secondary-text-color);
+ }
+ }
- .empty-list-message {
- color: #6e6e6e;
- font-size: 123%; /* Should be 16px when 100% is 13px. */
- font-weight: 500;
- margin-top: 80px;
- text-align: center;
- }
+ .items-container {
+ --grid-gutter: 12px;
+ --max-columns: 3;
+ display: grid;
+ grid-column-gap: var(--grid-gutter);
+ grid-row-gap: var(--grid-gutter);
+ grid-template-columns: repeat(auto-fill, var(--extensions-card-width));
+ justify-content: center;
+ margin: auto;
+ max-width: calc(var(--extensions-card-width) * var(--max-columns) +
+ var(--grid-gutter) * var(--max-columns));
+ }
- @media (prefers-color-scheme: dark) {
- .empty-list-message {
- color: var(--cr-secondary-text-color);
- }
- }
+ extensions-item {
+ grid-column-start: auto;
+ grid-row-start: auto;
+ }
- .items-container {
- --grid-gutter: 12px;
- --max-columns: 3;
- display: grid;
- grid-column-gap: var(--grid-gutter);
- grid-row-gap: var(--grid-gutter);
- grid-template-columns: repeat(auto-fill, var(--extensions-card-width));
- justify-content: center;
- margin: auto;
- max-width: calc(var(--extensions-card-width) * var(--max-columns) +
- var(--grid-gutter) * var(--max-columns));
- }
+ #app-title {
+ color: var(--cr-primary-text-color);
+ font-size: 123%;
+ font-weight: 400;
+ letter-spacing: .25px;
+ margin-bottom: 12px;
+ margin-top: 21px;
+ padding-bottom: 4px;
+ padding-top: 8px;
+ }
- extensions-item {
- grid-column-start: auto;
- grid-row-start: auto;
- }
-
- #app-title {
- color: var(--cr-primary-text-color);
- font-size: 123%;
- font-weight: 400;
- letter-spacing: .25px;
- margin-bottom: 12px;
- margin-top: 21px;
- padding-bottom: 4px;
- padding-top: 8px;
- }
-
- managed-footnote {
- border-top: none;
- /* #content-wrapper has a 24px margin-top. This overrides that
- * margin-top, so the only space left is this element's 12px
- * padding-bottom.
- */
- margin-bottom: -24px;
- padding-bottom: 12px;
- padding-top: 12px;
- /* The next element spills over this element. This ensures the link
- * is clickable. */
- z-index: 1;
- }
- </style>
- <div id="container">
- <managed-footnote hidden="[[filter]]"></managed-footnote>
- <div id="content-wrapper">
- <div id="no-items" class="empty-list-message"
- hidden$="[[!shouldShowEmptyItemsMessage_(
- apps.length, extensions.length)]]">
- <span on-click="onNoExtensionsTap_">
- $i18nRaw{noExtensionsOrApps}
- </span>
- </div>
- <div id="no-search-results" class="empty-list-message"
- hidden$="[[!shouldShowEmptySearchMessage_(
- shownAppsCount_, shownExtensionsCount_, apps, extensions)]]">
- <span>$i18n{noSearchResults}</span>
- </div>
- <div class="items-container" hidden="[[!shownExtensionsCount_]]">
- <!-- Render only a few items first, to improve initial render time,
- then render the remaining items on a different frame. Value of 3
- was chosen by experimentation, and it is a good trade-off between
- initial render time and total render time. -->
- <template is="dom-repeat" items="[[extensions]]" initial-count="3"
- filter="[[computedFilter_]]"
- rendered-item-count="{{shownExtensionsCount_::dom-change}}">
- <extensions-item id="[[item.id]]" data="[[item]]"
- delegate="[[delegate]]" in-dev-mode="[[inDevMode]]">
- </extensions-item>
- </template>
- </div>
- <div hidden="[[!shownAppsCount_]]">
- <!-- app-title needs to left-align with the grid content below, and
- the easiest way to achieve this is to make it a grid as well. -->
- <h2 id="app-title" class="items-container">$i18n{appsTitle}</h2>
- <div class="items-container">
- <template is="dom-repeat" items="[[apps]]" initial-count="3"
- filter="[[computedFilter_]]"
- rendered-item-count="{{shownAppsCount_::dom-change}}">
- <extensions-item id="[[item.id]]" data="[[item]]"
- delegate="[[delegate]]" in-dev-mode="[[inDevMode]]">
- </extensions-item>
- </template>
- </div>
- </div>
+ managed-footnote {
+ border-top: none;
+ /* #content-wrapper has a 24px margin-top. This overrides that
+ * margin-top, so the only space left is this element's 12px
+ * padding-bottom.
+ */
+ margin-bottom: -24px;
+ padding-bottom: 12px;
+ padding-top: 12px;
+ /* The next element spills over this element. This ensures the link
+ * is clickable. */
+ z-index: 1;
+ }
+</style>
+<div id="container">
+ <managed-footnote hidden="[[filter]]"></managed-footnote>
+ <div id="content-wrapper">
+ <div id="no-items" class="empty-list-message"
+ hidden$="[[!shouldShowEmptyItemsMessage_(
+ apps.length, extensions.length)]]">
+ <span on-click="onNoExtensionsTap_">
+ $i18nRaw{noExtensionsOrApps}
+ </span>
+ </div>
+ <div id="no-search-results" class="empty-list-message"
+ hidden$="[[!shouldShowEmptySearchMessage_(
+ shownAppsCount_, shownExtensionsCount_, apps, extensions)]]">
+ <span>$i18n{noSearchResults}</span>
+ </div>
+ <div class="items-container" hidden="[[!shownExtensionsCount_]]">
+ <!-- Render only a few items first, to improve initial render time,
+ then render the remaining items on a different frame. Value of 3
+ was chosen by experimentation, and it is a good trade-off between
+ initial render time and total render time. -->
+ <template is="dom-repeat" items="[[extensions]]" initial-count="3"
+ filter="[[computedFilter_]]"
+ rendered-item-count="{{shownExtensionsCount_::dom-change}}">
+ <extensions-item id="[[item.id]]" data="[[item]]"
+ delegate="[[delegate]]" in-dev-mode="[[inDevMode]]">
+ </extensions-item>
+ </template>
+ </div>
+ <div hidden="[[!shownAppsCount_]]">
+ <!-- app-title needs to left-align with the grid content below, and
+ the easiest way to achieve this is to make it a grid as well. -->
+ <h2 id="app-title" class="items-container">$i18n{appsTitle}</h2>
+ <div class="items-container">
+ <template is="dom-repeat" items="[[apps]]" initial-count="3"
+ filter="[[computedFilter_]]"
+ rendered-item-count="{{shownAppsCount_::dom-change}}">
+ <extensions-item id="[[item.id]]" data="[[item]]"
+ delegate="[[delegate]]" in-dev-mode="[[inDevMode]]">
+ </extensions-item>
+ </template>
</div>
</div>
- </template>
- <script src="item_list.js"></script>
-</dom-module>
+ </div>
+</div>
diff --git a/chromium/chrome/browser/resources/extensions/item_list.js b/chromium/chrome/browser/resources/extensions/item_list.js
index 04f8df0dfd5..f24ce184d71 100644
--- a/chromium/chrome/browser/resources/extensions/item_list.js
+++ b/chromium/chrome/browser/resources/extensions/item_list.js
@@ -2,125 +2,131 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- const ItemList = Polymer({
- is: 'extensions-item-list',
-
- behaviors: [CrContainerShadowBehavior, I18nBehavior],
-
- properties: {
- /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */
- apps: Array,
-
- /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */
- extensions: Array,
-
- /** @type {extensions.ItemDelegate} */
- delegate: Object,
-
- inDevMode: {
- type: Boolean,
- value: false,
- },
-
- filter: {
- type: String,
- },
-
- /** @private */
- computedFilter_: {
- type: String,
- computed: 'computeFilter_(filter)',
- observer: 'announceSearchResults_',
- },
-
- /** @private */
- shownExtensionsCount_: {
- type: Number,
- value: 0,
- },
-
- /** @private */
- shownAppsCount_: {
- type: Number,
- value: 0,
- },
- },
+import 'chrome://resources/cr_components/managed_footnote/managed_footnote.m.js';
+import './shared_style.js';
- /**
- * @param {string} id
- * @return {?Element}
- */
- getDetailsButton: function(id) {
- const item = this.$$(`#${id}`);
- return item && item.getDetailsButton();
- },
+import {CrContainerShadowBehavior} from 'chrome://resources/cr_elements/cr_container_shadow_behavior.m.js';
+import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
+import {IronA11yAnnouncer} from 'chrome://resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
- /**
- * @param {string} id
- * @return {?Element}
- */
- getErrorsButton: function(id) {
- const item = this.$$(`#${id}`);
- return item && item.getErrorsButton();
- },
+import {ItemDelegate} from './item.js';
- /**
- * Computes the filter function to be used for determining which items
- * should be shown. A |null| value indicates that everything should be
- * shown.
- * return {?Function}
- * @private
- */
- computeFilter_: function() {
- const formattedFilter = this.filter.trim().toLowerCase();
- return formattedFilter ?
- i => i.name.toLowerCase().includes(formattedFilter) :
- null;
- },
+Polymer({
+ is: 'extensions-item-list',
- /** @private */
- shouldShowEmptyItemsMessage_: function() {
- if (!this.apps || !this.extensions) {
- return;
- }
+ _template: html`{__html_template__}`,
+
+ behaviors: [CrContainerShadowBehavior, I18nBehavior],
+
+ properties: {
+ /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */
+ apps: Array,
- return this.apps.length === 0 && this.extensions.length === 0;
+ /** @type {!Array<!chrome.developerPrivate.ExtensionInfo>} */
+ extensions: Array,
+
+ /** @type {ItemDelegate} */
+ delegate: Object,
+
+ inDevMode: {
+ type: Boolean,
+ value: false,
},
- /** @private */
- shouldShowEmptySearchMessage_: function() {
- return !this.shouldShowEmptyItemsMessage_() &&
- this.shownAppsCount_ === 0 && this.shownExtensionsCount_ === 0;
+ filter: {
+ type: String,
},
/** @private */
- onNoExtensionsTap_: function(e) {
- if (e.target.tagName == 'A') {
- chrome.metricsPrivate.recordUserAction('Options_GetMoreExtensions');
- }
+ computedFilter_: {
+ type: String,
+ computed: 'computeFilter_(filter)',
+ observer: 'announceSearchResults_',
},
/** @private */
- announceSearchResults_: function() {
- if (this.computedFilter_) {
- Polymer.IronA11yAnnouncer.requestAvailability();
- this.async(() => { // Async to allow list to update.
- const total = this.shownAppsCount_ + this.shownExtensionsCount_;
- this.fire('iron-announce', {
- text: this.shouldShowEmptySearchMessage_() ?
- this.i18n('noSearchResults') :
- (total == 1 ?
- this.i18n('searchResultsSingular', this.filter) :
- this.i18n(
- 'searchResultsPlural', total.toString(), this.filter)),
- });
- });
- }
+ shownExtensionsCount_: {
+ type: Number,
+ value: 0,
},
- });
- return {
- ItemList: ItemList,
- };
+ /** @private */
+ shownAppsCount_: {
+ type: Number,
+ value: 0,
+ },
+ },
+
+ /**
+ * @param {string} id
+ * @return {?Element}
+ */
+ getDetailsButton: function(id) {
+ const item = this.$$(`#${id}`);
+ return item && item.getDetailsButton();
+ },
+
+ /**
+ * @param {string} id
+ * @return {?Element}
+ */
+ getErrorsButton: function(id) {
+ const item = this.$$(`#${id}`);
+ return item && item.getErrorsButton();
+ },
+
+ /**
+ * Computes the filter function to be used for determining which items
+ * should be shown. A |null| value indicates that everything should be
+ * shown.
+ * return {?Function}
+ * @private
+ */
+ computeFilter_: function() {
+ const formattedFilter = this.filter.trim().toLowerCase();
+ return formattedFilter ?
+ i => i.name.toLowerCase().includes(formattedFilter) :
+ null;
+ },
+
+ /** @private */
+ shouldShowEmptyItemsMessage_: function() {
+ if (!this.apps || !this.extensions) {
+ return;
+ }
+
+ return this.apps.length === 0 && this.extensions.length === 0;
+ },
+
+ /** @private */
+ shouldShowEmptySearchMessage_: function() {
+ return !this.shouldShowEmptyItemsMessage_() && this.shownAppsCount_ === 0 &&
+ this.shownExtensionsCount_ === 0;
+ },
+
+ /** @private */
+ onNoExtensionsTap_: function(e) {
+ if (e.target.tagName == 'A') {
+ chrome.metricsPrivate.recordUserAction('Options_GetMoreExtensions');
+ }
+ },
+
+ /** @private */
+ announceSearchResults_: function() {
+ if (this.computedFilter_) {
+ IronA11yAnnouncer.requestAvailability();
+ this.async(() => { // Async to allow list to update.
+ const total = this.shownAppsCount_ + this.shownExtensionsCount_;
+ this.fire('iron-announce', {
+ text: this.shouldShowEmptySearchMessage_() ?
+ this.i18n('noSearchResults') :
+ (total == 1 ?
+ this.i18n('searchResultsSingular', this.filter) :
+ this.i18n(
+ 'searchResultsPlural', total.toString(), this.filter)),
+ });
+ });
+ }
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/item_util.html b/chromium/chrome/browser/resources/extensions/item_util.html
deleted file mode 100644
index 8836ce076d2..00000000000
--- a/chromium/chrome/browser/resources/extensions/item_util.html
+++ /dev/null
@@ -1,4 +0,0 @@
-<link rel="import" href="chrome://resources/html/assert.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="strings.html">
-<script src="item_util.js"></script>
diff --git a/chromium/chrome/browser/resources/extensions/item_util.js b/chromium/chrome/browser/resources/extensions/item_util.js
index b619d2cdb8e..b137f5d8438 100644
--- a/chromium/chrome/browser/resources/extensions/item_util.js
+++ b/chromium/chrome/browser/resources/extensions/item_util.js
@@ -2,9 +2,15 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import './strings.m.js';
+
+import {assertNotReached} from 'chrome://resources/js/assert.m.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+
+
// Closure compiler won't let this be declared inside cr.define().
/** @enum {string} */
-const SourceType = {
+export const SourceType = {
WEBSTORE: 'webstore',
POLICY: 'policy',
SIDELOADED: 'sideloaded',
@@ -12,145 +18,134 @@ const SourceType = {
UNKNOWN: 'unknown',
};
-cr.define('extensions', function() {
- /**
- * Returns true if the extension is enabled, including terminated
- * extensions.
- * @param {!chrome.developerPrivate.ExtensionState} state
- * @return {boolean}
- */
- function isEnabled(state) {
- switch (state) {
- case chrome.developerPrivate.ExtensionState.ENABLED:
- case chrome.developerPrivate.ExtensionState.TERMINATED:
- return true;
- case chrome.developerPrivate.ExtensionState.BLACKLISTED:
- case chrome.developerPrivate.ExtensionState.DISABLED:
- return false;
- }
- assertNotReached();
+/**
+ * Returns true if the extension is enabled, including terminated
+ * extensions.
+ * @param {!chrome.developerPrivate.ExtensionState} state
+ * @return {boolean}
+ */
+export function isEnabled(state) {
+ switch (state) {
+ case chrome.developerPrivate.ExtensionState.ENABLED:
+ case chrome.developerPrivate.ExtensionState.TERMINATED:
+ return true;
+ case chrome.developerPrivate.ExtensionState.BLACKLISTED:
+ case chrome.developerPrivate.ExtensionState.DISABLED:
+ return false;
}
+ assertNotReached();
+}
+
+/**
+ * @param {!chrome.developerPrivate.ExtensionInfo} extensionInfo
+ * @return {boolean} Whether the extension is controlled.
+ */
+export function isControlled(extensionInfo) {
+ return !!extensionInfo.controlledInfo;
+}
- /**
- * @param {!chrome.developerPrivate.ExtensionInfo} extensionInfo
- * @return {boolean} Whether the extension is controlled.
- */
- function isControlled(extensionInfo) {
- return !!extensionInfo.controlledInfo;
+/**
+ * Returns true if the user can change whether or not the extension is
+ * enabled.
+ * @param {!chrome.developerPrivate.ExtensionInfo} item
+ * @return {boolean}
+ */
+export function userCanChangeEnablement(item) {
+ // User doesn't have permission.
+ if (!item.userMayModify) {
+ return false;
+ }
+ // Item is forcefully disabled.
+ if (item.disableReasons.corruptInstall ||
+ item.disableReasons.suspiciousInstall ||
+ item.disableReasons.updateRequired) {
+ return false;
+ }
+ // An item with dependent extensions can't be disabled (it would bork the
+ // dependents).
+ if (item.dependentExtensions.length > 0) {
+ return false;
+ }
+ // Blacklisted can't be enabled, either.
+ if (item.state == chrome.developerPrivate.ExtensionState.BLACKLISTED) {
+ return false;
}
- /**
- * Returns true if the user can change whether or not the extension is
- * enabled.
- * @param {!chrome.developerPrivate.ExtensionInfo} item
- * @return {boolean}
- */
- function userCanChangeEnablement(item) {
- // User doesn't have permission.
- if (!item.userMayModify) {
- return false;
- }
- // Item is forcefully disabled.
- if (item.disableReasons.corruptInstall ||
- item.disableReasons.suspiciousInstall ||
- item.disableReasons.updateRequired) {
- return false;
- }
- // An item with dependent extensions can't be disabled (it would bork the
- // dependents).
- if (item.dependentExtensions.length > 0) {
- return false;
- }
- // Blacklisted can't be enabled, either.
- if (item.state == chrome.developerPrivate.ExtensionState.BLACKLISTED) {
- return false;
- }
+ return true;
+}
- return true;
+/**
+ * @param {!chrome.developerPrivate.ExtensionInfo} item
+ * @return {SourceType}
+ */
+export function getItemSource(item) {
+ if (item.controlledInfo &&
+ item.controlledInfo.type ==
+ chrome.developerPrivate.ControllerType.POLICY) {
+ return SourceType.POLICY;
}
- /**
- * @param {!chrome.developerPrivate.ExtensionInfo} item
- * @return {SourceType}
- */
- function getItemSource(item) {
- if (item.controlledInfo &&
- item.controlledInfo.type ==
- chrome.developerPrivate.ControllerType.POLICY) {
- return SourceType.POLICY;
- }
+ switch (item.location) {
+ case chrome.developerPrivate.Location.THIRD_PARTY:
+ return SourceType.SIDELOADED;
+ case chrome.developerPrivate.Location.UNPACKED:
+ return SourceType.UNPACKED;
+ case chrome.developerPrivate.Location.UNKNOWN:
+ return SourceType.UNKNOWN;
+ case chrome.developerPrivate.Location.FROM_STORE:
+ return SourceType.WEBSTORE;
+ }
- switch (item.location) {
- case chrome.developerPrivate.Location.THIRD_PARTY:
- return SourceType.SIDELOADED;
- case chrome.developerPrivate.Location.UNPACKED:
- return SourceType.UNPACKED;
- case chrome.developerPrivate.Location.UNKNOWN:
- return SourceType.UNKNOWN;
- case chrome.developerPrivate.Location.FROM_STORE:
- return SourceType.WEBSTORE;
- }
+ assertNotReached(item.location);
+}
- assertNotReached(item.location);
+/**
+ * @param {SourceType} source
+ * @return {string}
+ */
+export function getItemSourceString(source) {
+ switch (source) {
+ case SourceType.POLICY:
+ return loadTimeData.getString('itemSourcePolicy');
+ case SourceType.SIDELOADED:
+ return loadTimeData.getString('itemSourceSideloaded');
+ case SourceType.UNPACKED:
+ return loadTimeData.getString('itemSourceUnpacked');
+ case SourceType.WEBSTORE:
+ return loadTimeData.getString('itemSourceWebstore');
+ case SourceType.UNKNOWN:
+ // Nothing to return. Calling code should use
+ // chrome.developerPrivate.ExtensionInfo's |locationText| instead.
+ return '';
}
+ assertNotReached();
+}
- /**
- * @param {SourceType} source
- * @return {string}
- */
- function getItemSourceString(source) {
- switch (source) {
- case SourceType.POLICY:
- return loadTimeData.getString('itemSourcePolicy');
- case SourceType.SIDELOADED:
- return loadTimeData.getString('itemSourceSideloaded');
- case SourceType.UNPACKED:
- return loadTimeData.getString('itemSourceUnpacked');
- case SourceType.WEBSTORE:
- return loadTimeData.getString('itemSourceWebstore');
- case SourceType.UNKNOWN:
- // Nothing to return. Calling code should use
- // chrome.developerPrivate.ExtensionInfo's |locationText| instead.
- return '';
- }
- assertNotReached();
+/**
+ * Computes the human-facing label for the given inspectable view.
+ * @param {!chrome.developerPrivate.ExtensionView} view
+ * @return {string}
+ */
+export function computeInspectableViewLabel(view) {
+ // Trim the "chrome-extension://<id>/".
+ const url = new URL(view.url);
+ let label = view.url;
+ if (url.protocol == 'chrome-extension:') {
+ label = url.pathname.substring(1);
}
-
- /**
- * Computes the human-facing label for the given inspectable view.
- * @param {!chrome.developerPrivate.ExtensionView} view
- * @return {string}
- */
- function computeInspectableViewLabel(view) {
- // Trim the "chrome-extension://<id>/".
- const url = new URL(view.url);
- let label = view.url;
- if (url.protocol == 'chrome-extension:') {
- label = url.pathname.substring(1);
- }
- if (label == '_generated_background_page.html') {
- label = loadTimeData.getString('viewBackgroundPage');
- }
- // Add any qualifiers.
- if (view.incognito) {
- label += ' ' + loadTimeData.getString('viewIncognito');
- }
- if (view.renderProcessId == -1) {
- label += ' ' + loadTimeData.getString('viewInactive');
- }
- if (view.isIframe) {
- label += ' ' + loadTimeData.getString('viewIframe');
- }
-
- return label;
+ if (label == '_generated_background_page.html') {
+ label = loadTimeData.getString('viewBackgroundPage');
+ }
+ // Add any qualifiers.
+ if (view.incognito) {
+ label += ' ' + loadTimeData.getString('viewIncognito');
+ }
+ if (view.renderProcessId == -1) {
+ label += ' ' + loadTimeData.getString('viewInactive');
+ }
+ if (view.isIframe) {
+ label += ' ' + loadTimeData.getString('viewIframe');
}
- return {
- isControlled: isControlled,
- isEnabled: isEnabled,
- userCanChangeEnablement: userCanChangeEnablement,
- getItemSource: getItemSource,
- getItemSourceString: getItemSourceString,
- computeInspectableViewLabel: computeInspectableViewLabel
- };
-});
+ return label;
+}
diff --git a/chromium/chrome/browser/resources/extensions/keyboard_shortcut_delegate.html b/chromium/chrome/browser/resources/extensions/keyboard_shortcut_delegate.html
deleted file mode 100644
index bb851cf9c59..00000000000
--- a/chromium/chrome/browser/resources/extensions/keyboard_shortcut_delegate.html
+++ /dev/null
@@ -1 +0,0 @@
-<script src="keyboard_shortcut_delegate.js"></script>
diff --git a/chromium/chrome/browser/resources/extensions/keyboard_shortcut_delegate.js b/chromium/chrome/browser/resources/extensions/keyboard_shortcut_delegate.js
index d83e47926d3..4281304ea03 100644
--- a/chromium/chrome/browser/resources/extensions/keyboard_shortcut_delegate.js
+++ b/chromium/chrome/browser/resources/extensions/keyboard_shortcut_delegate.js
@@ -1,41 +1,35 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// 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.
-cr.define('extensions', function() {
- 'use strict';
+'use strict';
- /** @interface */
- class KeyboardShortcutDelegate {
- /**
- * Called when shortcut capturing changes in order to suspend or re-enable
- * global shortcut handling. This is important so that the shortcuts aren't
- * processed normally as the user types them.
- * TODO(devlin): From very brief experimentation, it looks like preventing
- * the default handling on the event also does this. Investigate more in the
- * future.
- * @param {boolean} isCapturing
- */
- setShortcutHandlingSuspended(isCapturing) {}
+/** @interface */
+export class KeyboardShortcutDelegate {
+ /**
+ * Called when shortcut capturing changes in order to suspend or re-enable
+ * global shortcut handling. This is important so that the shortcuts aren't
+ * processed normally as the user types them.
+ * TODO(devlin): From very brief experimentation, it looks like preventing
+ * the default handling on the event also does this. Investigate more in the
+ * future.
+ * @param {boolean} isCapturing
+ */
+ setShortcutHandlingSuspended(isCapturing) {}
- /**
- * Updates an extension command's keybinding.
- * @param {string} extensionId
- * @param {string} commandName
- * @param {string} keybinding
- */
- updateExtensionCommandKeybinding(extensionId, commandName, keybinding) {}
+ /**
+ * Updates an extension command's keybinding.
+ * @param {string} extensionId
+ * @param {string} commandName
+ * @param {string} keybinding
+ */
+ updateExtensionCommandKeybinding(extensionId, commandName, keybinding) {}
- /**
- * Updates an extension command's scope.
- * @param {string} extensionId
- * @param {string} commandName
- * @param {chrome.developerPrivate.CommandScope} scope
- */
- updateExtensionCommandScope(extensionId, commandName, scope) {}
- }
-
- return {
- KeyboardShortcutDelegate: KeyboardShortcutDelegate,
- };
-});
+ /**
+ * Updates an extension command's scope.
+ * @param {string} extensionId
+ * @param {string} commandName
+ * @param {chrome.developerPrivate.CommandScope} scope
+ */
+ updateExtensionCommandScope(extensionId, commandName, scope) {}
+}
diff --git a/chromium/chrome/browser/resources/extensions/keyboard_shortcuts.html b/chromium/chrome/browser/resources/extensions/keyboard_shortcuts.html
index cc985093d80..9c8a8638fb3 100644
--- a/chromium/chrome/browser/resources/extensions/keyboard_shortcuts.html
+++ b/chromium/chrome/browser/resources/extensions/keyboard_shortcuts.html
@@ -1,123 +1,106 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="md-select cr-shared-style">
+ :host {
+ height: 100%;
+ }
-<link rel="import" href="chrome://resources/cr_elements/cr_container_shadow_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">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/cr_elements/md_select_css.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
-<link rel="import" href="item_behavior.html">
-<link rel="import" href="keyboard_shortcut_delegate.html">
-<link rel="import" href="shortcut_input.html">
+ .shortcut-card {
+ @apply --cr-card-elevation;
+ background-color: var(--cr-card-background-color);
+ border-radius: var(--cr-card-border-radius);
+ color: var(--cr-primary-text-color);
+ margin: 0 auto 16px auto;
+ padding-bottom: 8px;
+ width: var(--cr-toolbar-field-width);
+ }
-<dom-module id="extensions-keyboard-shortcuts">
- <template>
- <style include="md-select cr-shared-style">
- :host {
- height: 100%;
- }
+ .shortcut-card:last-of-type {
+ margin-bottom: 64px;
+ }
- .shortcut-card {
- @apply --cr-card-elevation;
- background-color: var(--cr-card-background-color);
- border-radius: var(--cr-card-border-radius);
- color: var(--cr-primary-text-color);
- margin: 0 auto 16px auto;
- padding-bottom: 8px;
- width: var(--cr-toolbar-field-width);
- }
+ #container {
+ box-sizing: border-box;
+ height: 100%;
+ overflow: overlay;
+ padding-top: 24px;
+ }
- .shortcut-card:last-of-type {
- margin-bottom: 64px;
- }
+ .command-entry {
+ align-items: start;
+ display: flex;
+ /* Makes top/bottom spacing of each row more even, while leaving
+ space for cr-input error message in between rows. */
+ margin-bottom: -8px;
+ padding-top: 16px;
+ }
- #container {
- box-sizing: border-box;
- height: 100%;
- overflow: overlay;
- padding-top: 24px;
- }
+ .command-name {
+ /* Align with cr-input by matching the field's top padding. */
+ flex: 1;
+ margin-top: 6px;
+ }
- .command-entry {
- align-items: start;
- display: flex;
- /* Makes top/bottom spacing of each row more even, while leaving
- space for cr-input error message in between rows. */
- margin-bottom: -8px;
- padding-top: 16px;
- }
+ .command-entry .md-select {
+ /* TODO(johntlee): line-height needs adjustment to fix large fonts. */
+ line-height: 22px;
+ margin-inline-start: var(--cr-section-padding);
+ }
- .command-name {
- /* Align with cr-input by matching the field's top padding. */
- flex: 1;
- margin-top: 6px;
- }
+ .card-title {
+ align-items: center;
+ border-bottom: var(--cr-separator-line);
+ display: flex;
+ margin-bottom: 9px;
+ padding: 16px var(--cr-section-padding);
+ }
- .command-entry .md-select {
- /* TODO(johntlee): line-height needs adjustment to fix large fonts. */
- line-height: 22px;
- margin-inline-start: var(--cr-section-padding);
- }
+ .icon {
+ height: 20px;
+ margin-inline-end: 20px;
+ width: 20px;
+ }
- .card-title {
- align-items: center;
- border-bottom: var(--cr-separator-line);
- display: flex;
- margin-bottom: 9px;
- padding: 16px var(--cr-section-padding);
- }
-
- .icon {
- height: 20px;
- margin-inline-end: 20px;
- width: 20px;
- }
-
- .card-controls {
- /* We line up the controls with the name, which is after the
- 20px left padding + 20px icon + 20px margin on the icon. */
- margin-inline-end: 20px;
- margin-inline-start: 60px;
- }
- </style>
- <div id="container">
- <template is="dom-repeat" items="[[calculateShownItems_(items.*)]]">
- <div class="shortcut-card">
- <div class="card-title cr-title-text">
- <img class="icon" src="[[item.iconUrl]]"
- alt$="[[appOrExtension(
- item.type,
- '$i18nPolymer{appIcon}',
- '$i18nPolymer{extensionIcon}')]]">
- <span>[[item.name]]</span>
- </div>
- <div class="card-controls">
- <template is="dom-repeat" items="[[item.commands]]" as="command">
- <div class="command-entry" command="[[command]]">
- <span class="command-name">[[command.description]]</span>
- <extensions-shortcut-input delegate="[[delegate]]"
- item="[[item.id]]" shortcut="[[command.keybinding]]"
- command-name="[[command.name]]">
- </extensions-shortcut-input>
- <!-- Binding "value" to triggerScopeChange_ to trigger update
- only after CommandScope_ becomes available. -->
- <select class="md-select" on-change="onScopeChanged_"
- disabled$="[[computeScopeDisabled_(command)]]"
- value="[[
- triggerScopeChange_(command.scope, CommandScope_)]]">
- <option value$="[[CommandScope_.CHROME]]">
- $i18n{shortcutScopeInChrome}
- </option>
- <option value$="[[CommandScope_.GLOBAL]]">
- $i18n{shortcutScopeGlobal}
- </option>
- </select>
- </div>
- </template>
+ .card-controls {
+ /* We line up the controls with the name, which is after the
+ 20px left padding + 20px icon + 20px margin on the icon. */
+ margin-inline-end: 20px;
+ margin-inline-start: 60px;
+ }
+</style>
+<div id="container">
+ <template is="dom-repeat" items="[[calculateShownItems_(items.*)]]">
+ <div class="shortcut-card">
+ <div class="card-title cr-title-text">
+ <img class="icon" src="[[item.iconUrl]]"
+ alt$="[[appOrExtension(
+ item.type,
+ '$i18nPolymer{appIcon}',
+ '$i18nPolymer{extensionIcon}')]]">
+ <span role="heading" aria-level="2">[[item.name]]</span>
+ </div>
+ <div class="card-controls">
+ <template is="dom-repeat" items="[[item.commands]]" as="command">
+ <div class="command-entry" command="[[command]]">
+ <span class="command-name">[[command.description]]</span>
+ <extensions-shortcut-input delegate="[[delegate]]"
+ item="[[item.id]]" shortcut="[[command.keybinding]]"
+ command-name="[[command.name]]">
+ </extensions-shortcut-input>
+ <!-- Binding "value" to triggerScopeChange_ to trigger update
+ only after CommandScope_ becomes available. -->
+ <select class="md-select" on-change="onScopeChanged_"
+ disabled$="[[computeScopeDisabled_(command)]]"
+ value="[[
+ triggerScopeChange_(command.scope, CommandScope_)]]">
+ <option value$="[[CommandScope_.CHROME]]">
+ $i18n{shortcutScopeInChrome}
+ </option>
+ <option value$="[[CommandScope_.GLOBAL]]">
+ $i18n{shortcutScopeGlobal}
+ </option>
+ </select>
</div>
- </div>
- </template>
+ </template>
+ </div>
</div>
</template>
- <script src="keyboard_shortcuts.js"></script>
-</dom-module>
+</div>
diff --git a/chromium/chrome/browser/resources/extensions/keyboard_shortcuts.js b/chromium/chrome/browser/resources/extensions/keyboard_shortcuts.js
index f0716526957..92d8663ffee 100644
--- a/chromium/chrome/browser/resources/extensions/keyboard_shortcuts.js
+++ b/chromium/chrome/browser/resources/extensions/keyboard_shortcuts.js
@@ -2,101 +2,107 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
-
- // The UI to display and manage keyboard shortcuts set for extension commands.
- const KeyboardShortcuts = Polymer({
- is: 'extensions-keyboard-shortcuts',
-
- behaviors: [CrContainerShadowBehavior, extensions.ItemBehavior],
-
- properties: {
- /** @type {!extensions.KeyboardShortcutDelegate} */
- delegate: Object,
-
- /** @type {Array<!chrome.developerPrivate.ExtensionInfo>} */
- items: Array,
-
- /**
- * Proxying the enum to be used easily by the html template.
- * @private
- */
- CommandScope_: {
- type: Object,
- value: chrome.developerPrivate.CommandScope,
- },
- },
+import 'chrome://resources/cr_elements/shared_style_css.m.js';
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+import 'chrome://resources/cr_elements/md_select_css.m.js';
+import 'chrome://resources/polymer/v3_0/paper-styles/color.js';
+import './shortcut_input.js';
- listeners: {
- 'view-enter-start': 'onViewEnter_',
- },
+import {CrContainerShadowBehavior} from 'chrome://resources/cr_elements/cr_container_shadow_behavior.m.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
- /** @private */
- onViewEnter_: function() {
- chrome.metricsPrivate.recordUserAction('Options_ExtensionCommands');
- },
+import {ItemBehavior} from './item_behavior.js';
+import {KeyboardShortcutDelegate} from './keyboard_shortcut_delegate.js';
- /**
- * @return {!Array<!chrome.developerPrivate.ExtensionInfo>}
- * @private
- */
- calculateShownItems_: function() {
- return this.items.filter(function(item) {
- return item.commands.length > 0;
- });
- },
+// The UI to display and manage keyboard shortcuts set for extension commands.
+Polymer({
+ is: 'extensions-keyboard-shortcuts',
- /**
- * A polymer bug doesn't allow for databinding of a string property as a
- * boolean, but it is correctly interpreted from a function.
- * Bug: https://github.com/Polymer/polymer/issues/3669
- * @param {string} keybinding
- * @return {boolean}
- * @private
- */
- hasKeybinding_: function(keybinding) {
- return !!keybinding;
- },
+ _template: html`{__html_template__}`,
- /**
- * Determines whether to disable the dropdown menu for the command's scope.
- * @param {!chrome.developerPrivate.Command} command
- * @return {boolean}
- * @private
- */
- computeScopeDisabled_: function(command) {
- return command.isExtensionAction || !command.isActive;
- },
+ behaviors: [CrContainerShadowBehavior, ItemBehavior],
- /**
- * This function exists to force trigger an update when CommandScope_
- * becomes available.
- * @param {string} scope
- * @return {string}
- */
- triggerScopeChange_: function(scope) {
- return scope;
- },
+ properties: {
+ /** @type {!KeyboardShortcutDelegate} */
+ delegate: Object,
- /** @private */
- onCloseButtonClick_: function() {
- this.fire('close');
- },
+ /** @type {Array<!chrome.developerPrivate.ExtensionInfo>} */
+ items: Array,
/**
- * @param {!{target: HTMLSelectElement, model: Object}} event
+ * Proxying the enum to be used easily by the html template.
* @private
*/
- onScopeChanged_: function(event) {
- this.delegate.updateExtensionCommandScope(
- event.model.get('item.id'), event.model.get('command.name'),
- /** @type {chrome.developerPrivate.CommandScope} */
- (event.target.value));
+ CommandScope_: {
+ type: Object,
+ value: chrome.developerPrivate.CommandScope,
},
- });
+ },
+
+ listeners: {
+ 'view-enter-start': 'onViewEnter_',
+ },
+
+ /** @private */
+ onViewEnter_: function() {
+ chrome.metricsPrivate.recordUserAction('Options_ExtensionCommands');
+ },
+
+ /**
+ * @return {!Array<!chrome.developerPrivate.ExtensionInfo>}
+ * @private
+ */
+ calculateShownItems_: function() {
+ return this.items.filter(function(item) {
+ return item.commands.length > 0;
+ });
+ },
+
+ /**
+ * A polymer bug doesn't allow for databinding of a string property as a
+ * boolean, but it is correctly interpreted from a function.
+ * Bug: https://github.com/Polymer/polymer/issues/3669
+ * @param {string} keybinding
+ * @return {boolean}
+ * @private
+ */
+ hasKeybinding_: function(keybinding) {
+ return !!keybinding;
+ },
+
+ /**
+ * Determines whether to disable the dropdown menu for the command's scope.
+ * @param {!chrome.developerPrivate.Command} command
+ * @return {boolean}
+ * @private
+ */
+ computeScopeDisabled_: function(command) {
+ return command.isExtensionAction || !command.isActive;
+ },
+
+ /**
+ * This function exists to force trigger an update when CommandScope_
+ * becomes available.
+ * @param {string} scope
+ * @return {string}
+ */
+ triggerScopeChange_: function(scope) {
+ return scope;
+ },
+
+ /** @private */
+ onCloseButtonClick_: function() {
+ this.fire('close');
+ },
- return {
- KeyboardShortcuts: KeyboardShortcuts,
- };
+ /**
+ * @param {!{target: HTMLSelectElement, model: Object}} event
+ * @private
+ */
+ onScopeChanged_: function(event) {
+ this.delegate.updateExtensionCommandScope(
+ event.model.get('item.id'), event.model.get('command.name'),
+ /** @type {chrome.developerPrivate.CommandScope} */
+ (event.target.value));
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/kiosk_browser_proxy.html b/chromium/chrome/browser/resources/extensions/kiosk_browser_proxy.html
deleted file mode 100644
index 58f9bb8fe27..00000000000
--- a/chromium/chrome/browser/resources/extensions/kiosk_browser_proxy.html
+++ /dev/null
@@ -1,2 +0,0 @@
-<link rel="import" href="chrome://resources/html/cr.html">
-<script src="kiosk_browser_proxy.js"></script>
diff --git a/chromium/chrome/browser/resources/extensions/kiosk_browser_proxy.js b/chromium/chrome/browser/resources/extensions/kiosk_browser_proxy.js
index 1d0539898b8..2a00b9e63e9 100644
--- a/chromium/chrome/browser/resources/extensions/kiosk_browser_proxy.js
+++ b/chromium/chrome/browser/resources/extensions/kiosk_browser_proxy.js
@@ -7,6 +7,8 @@
* the browser.
*/
+import {addSingletonGetter, sendWithPromise} from 'chrome://resources/js/cr.m.js';
+
/**
* @typedef {{
* kioskEnabled: boolean,
@@ -24,7 +26,7 @@ let KioskSettings;
* isLoading: boolean
* }}
*/
-let KioskApp;
+export let KioskApp;
/**
* @typedef {{
@@ -33,75 +35,68 @@ let KioskApp;
* hasAutoLaunchApp: boolean
* }}
*/
-let KioskAppSettings;
+export let KioskAppSettings;
+
+/** @interface */
+export class KioskBrowserProxy {
+ /** @param {string} appId */
+ addKioskApp(appId) {}
+
+ /** @param {string} appId */
+ disableKioskAutoLaunch(appId) {}
-cr.define('extensions', function() {
- /** @interface */
- class KioskBrowserProxy {
- /** @param {string} appId */
- addKioskApp(appId) {}
+ /** @param {string} appId */
+ enableKioskAutoLaunch(appId) {}
- /** @param {string} appId */
- disableKioskAutoLaunch(appId) {}
+ /** @return {!Promise<!KioskAppSettings>} */
+ getKioskAppSettings() {}
- /** @param {string} appId */
- enableKioskAutoLaunch(appId) {}
+ /** @return {!Promise<!KioskSettings>} */
+ initializeKioskAppSettings() {}
- /** @return {!Promise<!KioskAppSettings>} */
- getKioskAppSettings() {}
+ /** @param {string} appId */
+ removeKioskApp(appId) {}
- /** @return {!Promise<!KioskSettings>} */
- initializeKioskAppSettings() {}
+ /** @param {boolean} disableBailout */
+ setDisableBailoutShortcut(disableBailout) {}
+}
- /** @param {string} appId */
- removeKioskApp(appId) {}
+/** @implements {KioskBrowserProxy} */
+export class KioskBrowserProxyImpl {
+ /** @override */
+ initializeKioskAppSettings() {
+ return sendWithPromise('initializeKioskAppSettings');
+ }
+
+ /** @override */
+ getKioskAppSettings() {
+ return sendWithPromise('getKioskAppSettings');
+ }
- /** @param {boolean} disableBailout */
- setDisableBailoutShortcut(disableBailout) {}
+ /** @override */
+ addKioskApp(appId) {
+ chrome.send('addKioskApp', [appId]);
}
- /** @implements {extensions.KioskBrowserProxy} */
- class KioskBrowserProxyImpl {
- /** @override */
- initializeKioskAppSettings() {
- return cr.sendWithPromise('initializeKioskAppSettings');
- }
-
- /** @override */
- getKioskAppSettings() {
- return cr.sendWithPromise('getKioskAppSettings');
- }
-
- /** @override */
- addKioskApp(appId) {
- chrome.send('addKioskApp', [appId]);
- }
-
- /** @override */
- disableKioskAutoLaunch(appId) {
- chrome.send('disableKioskAutoLaunch', [appId]);
- }
-
- /** @override */
- enableKioskAutoLaunch(appId) {
- chrome.send('enableKioskAutoLaunch', [appId]);
- }
-
- /** @override */
- removeKioskApp(appId) {
- chrome.send('removeKioskApp', [appId]);
- }
-
- /** @override */
- setDisableBailoutShortcut(disableBailout) {
- chrome.send('setDisableBailoutShortcut', [disableBailout]);
- }
+ /** @override */
+ disableKioskAutoLaunch(appId) {
+ chrome.send('disableKioskAutoLaunch', [appId]);
}
- cr.addSingletonGetter(KioskBrowserProxyImpl);
+ /** @override */
+ enableKioskAutoLaunch(appId) {
+ chrome.send('enableKioskAutoLaunch', [appId]);
+ }
+
+ /** @override */
+ removeKioskApp(appId) {
+ chrome.send('removeKioskApp', [appId]);
+ }
+
+ /** @override */
+ setDisableBailoutShortcut(disableBailout) {
+ chrome.send('setDisableBailoutShortcut', [disableBailout]);
+ }
+}
- return {
- KioskBrowserProxy: KioskBrowserProxy,
- KioskBrowserProxyImpl: KioskBrowserProxyImpl,
- };
-});
+addSingletonGetter(KioskBrowserProxyImpl);
diff --git a/chromium/chrome/browser/resources/extensions/kiosk_dialog.html b/chromium/chrome/browser/resources/extensions/kiosk_dialog.html
index 7210150053e..df122a2eca4 100644
--- a/chromium/chrome/browser/resources/extensions/kiosk_dialog.html
+++ b/chromium/chrome/browser/resources/extensions/kiosk_dialog.html
@@ -1,141 +1,120 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="cr-shared-style cr-icons">
+ #add-kiosk-app {
+ margin-bottom: 10px;
+ margin-top: 20px;
+ }
-<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_checkbox/cr_checkbox.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
-<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
-<link rel="import" href="chrome://resources/html/assert.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/html/util.html">
-<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html">
-<link rel="import" href="item_behavior.html">
-<link rel="import" href="kiosk_browser_proxy.html">
+ #add-kiosk-app cr-input {
+ width: 350px;
+ }
-<dom-module id="extensions-kiosk-dialog">
- <template>
- <style include="cr-shared-style cr-icons">
- #add-kiosk-app {
- margin-bottom: 10px;
- margin-top: 20px;
- }
+ #add-kiosk-app cr-button {
+ margin-inline-start: 10px;
+ }
- #add-kiosk-app cr-input {
- width: 350px;
- }
+ #kiosk-apps-list {
+ border: 1px solid var(--paper-grey-300);
+ padding: 10px;
+ }
- #add-kiosk-app cr-button {
- margin-inline-start: 10px;
- }
+ .list-item {
+ align-items: center;
+ border-bottom: 1px solid var(--paper-grey-300);
+ display: flex;
+ justify-content: space-between;
+ padding: 5px;
+ }
- #kiosk-apps-list {
- border: 1px solid var(--paper-grey-300);
- padding: 10px;
- }
+ .list-item:last-of-type {
+ border-bottom: none;
+ }
- .list-item {
- align-items: center;
- border-bottom: 1px solid var(--paper-grey-300);
- display: flex;
- justify-content: space-between;
- padding: 5px;
- }
+ .list-item:hover {
+ background-color: var(--paper-grey-300);
+ }
- .list-item:last-of-type {
- border-bottom: none;
- }
+ .item-icon {
+ vertical-align: middle;
+ width: 25px;
+ }
- .list-item:hover {
- background-color: var(--paper-grey-300);
- }
+ .item-controls {
+ visibility: hidden;
+ }
- .item-icon {
- vertical-align: middle;
- width: 25px;
- }
+ .list-item:hover .item-controls {
+ visibility: visible;
+ }
- .item-controls {
- visibility: hidden;
- }
-
- .list-item:hover .item-controls {
- visibility: visible;
- }
-
- cr-icon-button {
- margin: 0;
- }
- </style>
- <cr-dialog id="dialog" close-text="$i18n{close}"
- ignore-enter-key>
- <div slot="title">$i18n{manageKioskApp}</div>
- <div slot="body">
- <div id="kiosk-apps-list">
- <template is="dom-repeat" items="[[apps_]]">
- <div class="list-item">
- <div class="item-name">
- <img class="item-icon" src="[[item.iconURL]]"
- alt$="[[appOrExtension(
- data.type,
- '$i18nPolymer{appIcon}',
- '$i18nPolymer{extensionIcon}')]]">
- [[item.name]]
- <span hidden="[[!item.autoLaunch]]">
- $i18n{kioskAutoLaunch}
- </span>
- </div>
- <div class="item-controls">
- <cr-button hidden="[[!canEditAutoLaunch_]]"
- on-click="onAutoLaunchButtonTap_">
- [[getAutoLaunchButtonLabel_(item.autoLaunch,
- '$i18nPolymer{kioskDisableAutoLaunch}',
- '$i18nPolymer{kioskEnableAutoLaunch}')]]
- </cr-button>
- <cr-icon-button class="icon-delete-gray"
- on-click="onDeleteAppTap_"></cr-icon-button>
- </div>
- </div>
- </template>
- </div>
- <div id="add-kiosk-app">
- <cr-input id="add-input" label="$i18n{kioskAddApp}"
- placeholder="$i18n{kioskAddAppHint}" value="{{addAppInput_}}"
- invalid="[[errorAppId_]]" on-keydown="clearInputInvalid_"
- error-message="[[getErrorMessage_(
- '$i18nPolymer{kioskInvalidApp}', errorAppId_)]]">
- <cr-button id="add-button" on-click="onAddAppTap_"
- disabled="[[!addAppInput_]]" slot="suffix">
- $i18n{add}
+ cr-icon-button {
+ margin: 0;
+ }
+</style>
+<cr-dialog id="dialog" close-text="$i18n{close}"
+ ignore-enter-key>
+ <div slot="title">$i18n{manageKioskApp}</div>
+ <div slot="body">
+ <div id="kiosk-apps-list">
+ <template is="dom-repeat" items="[[apps_]]">
+ <div class="list-item">
+ <div class="item-name">
+ <img class="item-icon" src="[[item.iconURL]]"
+ alt$="[[appOrExtension(
+ data.type,
+ '$i18nPolymer{appIcon}',
+ '$i18nPolymer{extensionIcon}')]]">
+ [[item.name]]
+ <span hidden="[[!item.autoLaunch]]">
+ $i18n{kioskAutoLaunch}
+ </span>
+ </div>
+ <div class="item-controls">
+ <cr-button hidden="[[!canEditAutoLaunch_]]"
+ on-click="onAutoLaunchButtonTap_">
+ [[getAutoLaunchButtonLabel_(item.autoLaunch,
+ '$i18nPolymer{kioskDisableAutoLaunch}',
+ '$i18nPolymer{kioskEnableAutoLaunch}')]]
</cr-button>
- </cr-input>
+ <cr-icon-button class="icon-delete-gray"
+ on-click="onDeleteAppTap_"></cr-icon-button>
+ </div>
</div>
- <cr-checkbox disabled="[[!canEditBailout_]]" id="bailout"
- on-change="onBailoutChanged_" checked="[[bailoutDisabled_]]"
- hidden="[[!canEditAutoLaunch_]]">
- $i18n{kioskDisableBailout}
- </cr-checkbox>
- </div>
- <div slot="button-container">
- <cr-button class="action-button" on-click="onDoneTap_">
- $i18n{done}
- </cr-button>
- </div>
- </cr-dialog>
- <cr-dialog id="confirm-dialog" close-text="$i18n{close}"
- ignore-enter-key on-close="stopPropagation_">
- <div slot="title">$i18n{kioskDisableBailoutWarningTitle}</div>
- <div slot="body">$i18n{kioskDisableBailoutWarningBody}</div>
- <div slot="button-container">
- <cr-button class="cancel-button" on-click="onBailoutDialogCancelTap_">
- $i18n{cancel}
- </cr-button>
- <cr-button class="action-button" on-click="onBailoutDialogConfirmTap_">
- $i18n{confirm}
+ </template>
+ </div>
+ <div id="add-kiosk-app">
+ <cr-input id="add-input" label="$i18n{kioskAddApp}"
+ placeholder="$i18n{kioskAddAppHint}" value="{{addAppInput_}}"
+ invalid="[[errorAppId_]]" on-keydown="clearInputInvalid_"
+ error-message="[[getErrorMessage_(
+ '$i18nPolymer{kioskInvalidApp}', errorAppId_)]]">
+ <cr-button id="add-button" on-click="onAddAppTap_"
+ disabled="[[!addAppInput_]]" slot="suffix">
+ $i18n{add}
</cr-button>
- </div>
- </cr-dialog>
- </template>
- <script src="kiosk_dialog.js"></script>
-</dom-module>
+ </cr-input>
+ </div>
+ <cr-checkbox disabled="[[!canEditBailout_]]" id="bailout"
+ on-change="onBailoutChanged_" checked="[[bailoutDisabled_]]"
+ hidden="[[!canEditAutoLaunch_]]">
+ $i18n{kioskDisableBailout}
+ </cr-checkbox>
+ </div>
+ <div slot="button-container">
+ <cr-button class="action-button" on-click="onDoneTap_">
+ $i18n{done}
+ </cr-button>
+ </div>
+</cr-dialog>
+<cr-dialog id="confirm-dialog" close-text="$i18n{close}"
+ ignore-enter-key on-close="stopPropagation_">
+ <div slot="title">$i18n{kioskDisableBailoutWarningTitle}</div>
+ <div slot="body">$i18n{kioskDisableBailoutWarningBody}</div>
+ <div slot="button-container">
+ <cr-button class="cancel-button" on-click="onBailoutDialogCancelTap_">
+ $i18n{cancel}
+ </cr-button>
+ <cr-button class="action-button" on-click="onBailoutDialogConfirmTap_">
+ $i18n{confirm}
+ </cr-button>
+ </div>
+</cr-dialog>
diff --git a/chromium/chrome/browser/resources/extensions/kiosk_dialog.js b/chromium/chrome/browser/resources/extensions/kiosk_dialog.js
index 49e5056c0c1..04bc4cb1e9b 100644
--- a/chromium/chrome/browser/resources/extensions/kiosk_dialog.js
+++ b/chromium/chrome/browser/resources/extensions/kiosk_dialog.js
@@ -2,183 +2,195 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
+import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import 'chrome://resources/cr_elements/cr_checkbox/cr_checkbox.m.js';
+import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
+import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
+import 'chrome://resources/cr_elements/cr_icons_css.m.js';
+import 'chrome://resources/cr_elements/cr_input/cr_input.m.js';
+import 'chrome://resources/cr_elements/shared_style_css.m.js';
- const KioskDialog = Polymer({
- is: 'extensions-kiosk-dialog',
- behaviors: [WebUIListenerBehavior, extensions.ItemBehavior],
- properties: {
- /** @private {?string} */
- addAppInput_: {
- type: String,
- value: null,
- },
+import {assert} from 'chrome://resources/js/assert.m.js';
+import {WebUIListenerBehavior} from 'chrome://resources/js/web_ui_listener_behavior.m.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
- /** @private {!Array<!KioskApp>} */
- apps_: Array,
+import {ItemBehavior} from './item_behavior.js';
+import {KioskApp, KioskAppSettings, KioskBrowserProxy, KioskBrowserProxyImpl} from './kiosk_browser_proxy.js';
- /** @private */
- bailoutDisabled_: Boolean,
- /** @private */
- canEditAutoLaunch_: Boolean,
+Polymer({
+ is: 'extensions-kiosk-dialog',
- /** @private */
- canEditBailout_: Boolean,
+ _template: html`{__html_template__}`,
- /** @private {?string} */
- errorAppId_: String,
- },
-
- /** @private {?extensions.KioskBrowserProxy} */
- kioskBrowserProxy_: null,
-
- /** @override */
- ready: function() {
- this.kioskBrowserProxy_ = extensions.KioskBrowserProxyImpl.getInstance();
- },
-
- /** @override */
- attached: function() {
- this.kioskBrowserProxy_.initializeKioskAppSettings()
- .then(params => {
- this.canEditAutoLaunch_ = params.autoLaunchEnabled;
- return this.kioskBrowserProxy_.getKioskAppSettings();
- })
- .then(this.setSettings_.bind(this));
-
- this.addWebUIListener(
- 'kiosk-app-settings-changed', this.setSettings_.bind(this));
- this.addWebUIListener('kiosk-app-updated', this.updateApp_.bind(this));
- this.addWebUIListener('kiosk-app-error', this.showError_.bind(this));
-
- this.$.dialog.showModal();
- },
-
- /**
- * @param {!KioskAppSettings} settings
- * @private
- */
- setSettings_: function(settings) {
- this.apps_ = settings.apps;
- this.bailoutDisabled_ = settings.disableBailout;
- this.canEditBailout_ = settings.hasAutoLaunchApp;
- },
+ behaviors: [WebUIListenerBehavior, ItemBehavior],
- /**
- * @param {!KioskApp} app
- * @private
- */
- updateApp_: function(app) {
- const index = this.apps_.findIndex(a => a.id == app.id);
- assert(index < this.apps_.length);
- this.set('apps_.' + index, app);
+ properties: {
+ /** @private {?string} */
+ addAppInput_: {
+ type: String,
+ value: null,
},
- /**
- * @param {string} appId
- * @private
- */
- showError_: function(appId) {
- this.errorAppId_ = appId;
- },
-
- /**
- * @param {string} errorMessage
- * @return {string}
- * @private
- */
- getErrorMessage_: function(errorMessage) {
- return this.errorAppId_ + ' ' + errorMessage;
- },
+ /** @private {!Array<!KioskApp>} */
+ apps_: Array,
/** @private */
- onAddAppTap_: function() {
- assert(this.addAppInput_);
- this.kioskBrowserProxy_.addKioskApp(this.addAppInput_);
- this.addAppInput_ = null;
- },
+ bailoutDisabled_: Boolean,
/** @private */
- clearInputInvalid_: function() {
- this.errorAppId_ = null;
- },
-
- /**
- * @param {{model: {item: !KioskApp}}} event
- * @private
- */
- onAutoLaunchButtonTap_: function(event) {
- const app = event.model.item;
- if (app.autoLaunch) { // If the app is originally set to
- // auto-launch.
- this.kioskBrowserProxy_.disableKioskAutoLaunch(app.id);
- } else {
- this.kioskBrowserProxy_.enableKioskAutoLaunch(app.id);
- }
- },
-
- /**
- * @param {!Event} event
- * @private
- */
- onBailoutChanged_: function(event) {
- event.preventDefault();
- if (this.$.bailout.checked) {
- this.$['confirm-dialog'].showModal();
- } else {
- this.kioskBrowserProxy_.setDisableBailoutShortcut(false);
- this.$['confirm-dialog'].close();
- }
- },
-
- /** @private */
- onBailoutDialogCancelTap_: function() {
- this.$.bailout.checked = false;
- this.$['confirm-dialog'].cancel();
- },
+ canEditAutoLaunch_: Boolean,
/** @private */
- onBailoutDialogConfirmTap_: function() {
- this.kioskBrowserProxy_.setDisableBailoutShortcut(true);
+ canEditBailout_: Boolean,
+
+ /** @private {?string} */
+ errorAppId_: String,
+ },
+
+ /** @private {?KioskBrowserProxy} */
+ kioskBrowserProxy_: null,
+
+ /** @override */
+ ready: function() {
+ this.kioskBrowserProxy_ = KioskBrowserProxyImpl.getInstance();
+ },
+
+ /** @override */
+ attached: function() {
+ this.kioskBrowserProxy_.initializeKioskAppSettings()
+ .then(params => {
+ this.canEditAutoLaunch_ = params.autoLaunchEnabled;
+ return this.kioskBrowserProxy_.getKioskAppSettings();
+ })
+ .then(this.setSettings_.bind(this));
+
+ this.addWebUIListener(
+ 'kiosk-app-settings-changed', this.setSettings_.bind(this));
+ this.addWebUIListener('kiosk-app-updated', this.updateApp_.bind(this));
+ this.addWebUIListener('kiosk-app-error', this.showError_.bind(this));
+
+ this.$.dialog.showModal();
+ },
+
+ /**
+ * @param {!KioskAppSettings} settings
+ * @private
+ */
+ setSettings_: function(settings) {
+ this.apps_ = settings.apps;
+ this.bailoutDisabled_ = settings.disableBailout;
+ this.canEditBailout_ = settings.hasAutoLaunchApp;
+ },
+
+ /**
+ * @param {!KioskApp} app
+ * @private
+ */
+ updateApp_: function(app) {
+ const index = this.apps_.findIndex(a => a.id == app.id);
+ assert(index < this.apps_.length);
+ this.set('apps_.' + index, app);
+ },
+
+ /**
+ * @param {string} appId
+ * @private
+ */
+ showError_: function(appId) {
+ this.errorAppId_ = appId;
+ },
+
+ /**
+ * @param {string} errorMessage
+ * @return {string}
+ * @private
+ */
+ getErrorMessage_: function(errorMessage) {
+ return this.errorAppId_ + ' ' + errorMessage;
+ },
+
+ /** @private */
+ onAddAppTap_: function() {
+ assert(this.addAppInput_);
+ this.kioskBrowserProxy_.addKioskApp(this.addAppInput_);
+ this.addAppInput_ = null;
+ },
+
+ /** @private */
+ clearInputInvalid_: function() {
+ this.errorAppId_ = null;
+ },
+
+ /**
+ * @param {{model: {item: !KioskApp}}} event
+ * @private
+ */
+ onAutoLaunchButtonTap_: function(event) {
+ const app = event.model.item;
+ if (app.autoLaunch) { // If the app is originally set to
+ // auto-launch.
+ this.kioskBrowserProxy_.disableKioskAutoLaunch(app.id);
+ } else {
+ this.kioskBrowserProxy_.enableKioskAutoLaunch(app.id);
+ }
+ },
+
+ /**
+ * @param {!Event} event
+ * @private
+ */
+ onBailoutChanged_: function(event) {
+ event.preventDefault();
+ if (this.$.bailout.checked) {
+ this.$['confirm-dialog'].showModal();
+ } else {
+ this.kioskBrowserProxy_.setDisableBailoutShortcut(false);
this.$['confirm-dialog'].close();
- },
-
- /** @private */
- onDoneTap_: function() {
- this.$.dialog.close();
- },
-
- /**
- * @param {{model: {item: !KioskApp}}} event
- * @private
- */
- onDeleteAppTap_: function(event) {
- this.kioskBrowserProxy_.removeKioskApp(event.model.item.id);
- },
-
- /**
- * @param {boolean} autoLaunched
- * @param {string} disableStr
- * @param {string} enableStr
- * @return {string}
- * @private
- */
- getAutoLaunchButtonLabel_: function(autoLaunched, disableStr, enableStr) {
- return autoLaunched ? disableStr : enableStr;
- },
-
- /**
- * @param {!Event} e
- * @private
- */
- stopPropagation_: function(e) {
- e.stopPropagation();
- },
- });
-
- return {
- KioskDialog: KioskDialog,
- };
+ }
+ },
+
+ /** @private */
+ onBailoutDialogCancelTap_: function() {
+ this.$.bailout.checked = false;
+ this.$['confirm-dialog'].cancel();
+ },
+
+ /** @private */
+ onBailoutDialogConfirmTap_: function() {
+ this.kioskBrowserProxy_.setDisableBailoutShortcut(true);
+ this.$['confirm-dialog'].close();
+ },
+
+ /** @private */
+ onDoneTap_: function() {
+ this.$.dialog.close();
+ },
+
+ /**
+ * @param {{model: {item: !KioskApp}}} event
+ * @private
+ */
+ onDeleteAppTap_: function(event) {
+ this.kioskBrowserProxy_.removeKioskApp(event.model.item.id);
+ },
+
+ /**
+ * @param {boolean} autoLaunched
+ * @param {string} disableStr
+ * @param {string} enableStr
+ * @return {string}
+ * @private
+ */
+ getAutoLaunchButtonLabel_: function(autoLaunched, disableStr, enableStr) {
+ return autoLaunched ? disableStr : enableStr;
+ },
+
+ /**
+ * @param {!Event} e
+ * @private
+ */
+ stopPropagation_: function(e) {
+ e.stopPropagation();
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/load_error.html b/chromium/chrome/browser/resources/extensions/load_error.html
index 682b4fbcdf9..804fc40a5b6 100644
--- a/chromium/chrome/browser/resources/extensions/load_error.html
+++ b/chromium/chrome/browser/resources/extensions/load_error.html
@@ -1,57 +1,42 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="cr-shared-style">
+ .description-row {
+ display: flex;
+ }
-<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
-<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
-<link rel="import" href="chrome://resources/html/assert.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner-lite.html">
-<link rel="import" href="code_section.html">
+ .row-label {
+ display: block;
+ width: 104px; /* Magic number from the specs. */
+ }
-<dom-module id="extensions-load-error">
- <template>
- <style include="cr-shared-style">
- .description-row {
- display: flex;
- }
-
- .row-label {
- display: block;
- width: 104px; /* Magic number from the specs. */
- }
-
- paper-spinner-lite {
- margin-inline-end: 8px;
- }
- </style>
- <cr-dialog id="dialog" close-text="$i18n{close}">
- <div slot="title">$i18n{loadErrorHeading}</div>
- <div slot="body">
- <div id="info">
- <div id="file" class="description-row">
- <span class="row-label">$i18n{loadErrorFileLabel}</span>
- <span class="row-value">[[loadError.path]]</span>
- </div>
- <div id="error" class="description-row">
- <span class="row-label">$i18n{loadErrorErrorLabel}</span>
- <span class="row-value">[[loadError.error]]</span>
- </div>
- </div>
- <extensions-code-section id="code"
- could-not-display-code="$i18n{loadErrorCouldNotLoadManifest}">
- </extensions-code-section>
+ paper-spinner-lite {
+ margin-inline-end: 8px;
+ }
+</style>
+<cr-dialog id="dialog" close-text="$i18n{close}">
+ <div slot="title">$i18n{loadErrorHeading}</div>
+ <div slot="body">
+ <div id="info">
+ <div id="file" class="description-row">
+ <span class="row-label">$i18n{loadErrorFileLabel}</span>
+ <span class="row-value">[[loadError.path]]</span>
</div>
- <div slot="button-container">
- <paper-spinner-lite active="[[retrying_]]"></paper-spinner-lite>
- <cr-button class="cancel-button" on-click="close">
- $i18n{cancel}
- </cr-button>
- <cr-button class="action-button" disabled="[[retrying_]]"
- on-click="onRetryTap_">
- $i18n{loadErrorRetry}
- </cr-button>
+ <div id="error" class="description-row">
+ <span class="row-label">$i18n{loadErrorErrorLabel}</span>
+ <span class="row-value">[[loadError.error]]</span>
</div>
- </cr-dialog>
- </template>
- <script src="load_error.js"></script>
-</dom-module>
+ </div>
+ <extensions-code-section id="code"
+ could-not-display-code="$i18n{loadErrorCouldNotLoadManifest}">
+ </extensions-code-section>
+ </div>
+ <div slot="button-container">
+ <paper-spinner-lite active="[[retrying_]]"></paper-spinner-lite>
+ <cr-button class="cancel-button" on-click="close">
+ $i18n{cancel}
+ </cr-button>
+ <cr-button class="action-button" disabled="[[retrying_]]"
+ on-click="onRetryTap_">
+ $i18n{loadErrorRetry}
+ </cr-button>
+ </div>
+</cr-dialog>
diff --git a/chromium/chrome/browser/resources/extensions/load_error.js b/chromium/chrome/browser/resources/extensions/load_error.js
index be8d9022554..ff678ac6176 100644
--- a/chromium/chrome/browser/resources/extensions/load_error.js
+++ b/chromium/chrome/browser/resources/extensions/load_error.js
@@ -2,79 +2,85 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
+import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
+import 'chrome://resources/cr_elements/shared_style_css.m.js';
+import 'chrome://resources/polymer/v3_0/paper-spinner/paper-spinner-lite.js';
+import './code_section.js';
+import './strings.m.js';
- /** @interface */
- class LoadErrorDelegate {
- /**
- * Attempts to load the previously-attempted unpacked extension.
- * @param {string} retryId
- * @return {!Promise}
- */
- retryLoadUnpacked(retryId) {}
- }
+import {assert} from 'chrome://resources/js/assert.m.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
- const LoadError = Polymer({
- is: 'extensions-load-error',
- properties: {
- /** @type {extensions.LoadErrorDelegate} */
- delegate: Object,
+/** @interface */
+export class LoadErrorDelegate {
+ /**
+ * Attempts to load the previously-attempted unpacked extension.
+ * @param {string} retryId
+ * @return {!Promise}
+ */
+ retryLoadUnpacked(retryId) {}
+}
- /** @type {chrome.developerPrivate.LoadError} */
- loadError: Object,
+Polymer({
+ is: 'extensions-load-error',
- /** @private */
- retrying_: Boolean,
- },
+ _template: html`{__html_template__}`,
- observers: [
- 'observeLoadErrorChanges_(loadError)',
- ],
+ properties: {
+ /** @type {LoadErrorDelegate} */
+ delegate: Object,
- show: function() {
- /** @type {!CrDialogElement} */ (this.$.dialog).showModal();
- },
-
- close: function() {
- /** @type {!CrDialogElement} */ (this.$.dialog).close();
- },
+ /** @type {chrome.developerPrivate.LoadError} */
+ loadError: Object,
/** @private */
- onRetryTap_: function() {
- this.retrying_ = true;
- this.delegate.retryLoadUnpacked(this.loadError.retryGuid)
- .then(
- () => {
- this.close();
- },
- loadError => {
- this.loadError =
- /** @type {chrome.developerPrivate.LoadError} */ (
- loadError);
- this.retrying_ = false;
- });
- },
+ retrying_: Boolean,
+ },
- /** @private */
- observeLoadErrorChanges_: function() {
- assert(this.loadError);
- const source = this.loadError.source;
- // CodeSection expects a RequestFileSourceResponse, rather than an
- // ErrorFileSource. Massage into place.
- // TODO(devlin): Make RequestFileSourceResponse use ErrorFileSource.
- /** @type {!chrome.developerPrivate.RequestFileSourceResponse} */
- const codeSectionProperties = {
- beforeHighlight: source ? source.beforeHighlight : '',
- highlight: source ? source.highlight : '',
- afterHighlight: source ? source.afterHighlight : '',
- title: '',
- message: this.loadError.error,
- };
+ observers: [
+ 'observeLoadErrorChanges_(loadError)',
+ ],
+
+ show: function() {
+ /** @type {!CrDialogElement} */ (this.$.dialog).showModal();
+ },
+
+ close: function() {
+ /** @type {!CrDialogElement} */ (this.$.dialog).close();
+ },
+
+ /** @private */
+ onRetryTap_: function() {
+ this.retrying_ = true;
+ this.delegate.retryLoadUnpacked(this.loadError.retryGuid)
+ .then(
+ () => {
+ this.close();
+ },
+ loadError => {
+ this.loadError =
+ /** @type {chrome.developerPrivate.LoadError} */ (loadError);
+ this.retrying_ = false;
+ });
+ },
- this.$.code.code = codeSectionProperties;
- },
- });
+ /** @private */
+ observeLoadErrorChanges_: function() {
+ assert(this.loadError);
+ const source = this.loadError.source;
+ // CodeSection expects a RequestFileSourceResponse, rather than an
+ // ErrorFileSource. Massage into place.
+ // TODO(devlin): Make RequestFileSourceResponse use ErrorFileSource.
+ /** @type {!chrome.developerPrivate.RequestFileSourceResponse} */
+ const codeSectionProperties = {
+ beforeHighlight: source ? source.beforeHighlight : '',
+ highlight: source ? source.highlight : '',
+ afterHighlight: source ? source.afterHighlight : '',
+ title: '',
+ message: this.loadError.error,
+ };
- return {LoadError: LoadError, LoadErrorDelegate: LoadErrorDelegate};
+ this.$.code.code = codeSectionProperties;
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/manager.html b/chromium/chrome/browser/resources/extensions/manager.html
index 1c35c285068..87457fba166 100644
--- a/chromium/chrome/browser/resources/extensions/manager.html
+++ b/chromium/chrome/browser/resources/extensions/manager.html
@@ -1,145 +1,109 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="cr-hidden-style">
+ :host {
+ color: var(--cr-primary-text-color);
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ --cr-toolbar-field-width: 680px;
+ }
-<link rel="import" href="chrome://resources/cr_elements/cr_drawer/cr_drawer.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_toast/cr_toast_manager.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_toolbar/cr_toolbar.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_view_manager/cr_view_manager.html">
-<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.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/html/cr.html">
-<link rel="import" href="activity_log/activity_log.html">
-<link rel="import" href="detail_view.html">
-<link rel="import" href="drop_overlay.html">
-<link rel="import" href="error_page.html">
-<link rel="import" href="install_warnings_dialog.html">
-<link rel="import" href="item_list.html">
-<link rel="import" href="item_util.html">
-<link rel="import" href="keyboard_shortcuts.html">
-<link rel="import" href="load_error.html">
-<link rel="import" href="navigation_helper.html">
-<link rel="import" href="options_dialog.html">
-<link rel="import" href="service.html">
-<link rel="import" href="sidebar.html">
-<link rel="import" href="toolbar.html">
+ extensions-sidebar {
+ flex-basis: 256px;
+ }
-<if expr="chromeos">
-<link rel="import" href="kiosk_browser_proxy.html">
-<link rel="import" href="kiosk_dialog.html">
-</if>
-
-<dom-module id="extensions-manager">
- <template>
- <style include="cr-hidden-style">
- :host {
- color: var(--cr-primary-text-color);
- display: flex;
- flex-direction: column;
- height: 100%;
- --cr-toolbar-field-width: 680px;
- }
-
- extensions-sidebar {
- flex-basis: 256px;
- }
+ #viewManager {
+ flex: 1;
+ position: relative;
+ }
- #viewManager {
- flex: 1;
- position: relative;
- }
-
- extensions-item {
- display: inline-block;
- }
- </style>
- <extensions-drop-overlay drag-enabled="[[inDevMode]]">
- </extensions-drop-overlay>
- <extensions-toolbar in-dev-mode="[[inDevMode]]"
- can-load-unpacked="[[canLoadUnpacked]]"
- is-supervised="[[isSupervised_]]"
- dev-mode-controlled-by-policy="[[devModeControlledByPolicy]]"
- delegate="[[delegate]]" on-cr-toolbar-menu-tap="onMenuButtonTap_"
- on-search-changed="onFilterChanged_"
+ extensions-item {
+ display: inline-block;
+ }
+</style>
+<extensions-drop-overlay drag-enabled="[[inDevMode]]">
+</extensions-drop-overlay>
+<extensions-toolbar in-dev-mode="[[inDevMode]]"
+ can-load-unpacked="[[canLoadUnpacked]]"
+ is-supervised="[[isSupervised_]]"
+ dev-mode-controlled-by-policy="[[devModeControlledByPolicy]]"
+ delegate="[[delegate]]" on-cr-toolbar-menu-tap="onMenuButtonTap_"
+ on-search-changed="onFilterChanged_"
<if expr="chromeos">
- on-kiosk-tap="onKioskTap_"
- kiosk-enabled="[[kioskEnabled_]]"
+ on-kiosk-tap="onKioskTap_"
+ kiosk-enabled="[[kioskEnabled_]]"
</if>
- >
- </extensions-toolbar>
- <template is="dom-if" if="[[showDrawer_]]" restamp>
- <cr-drawer id="drawer" heading="$i18n{toolbarTitle}"
- align="$i18n{textdirection}" on-close="onDrawerClose_">
- <div class="drawer-content">
- <extensions-sidebar id="sidebar" is-supervised="[[isSupervised_]]"
- on-close-drawer="onCloseDrawer_">
- </extensions-sidebar>
- </div>
- </cr-drawer>
+ >
+</extensions-toolbar>
+<template is="dom-if" if="[[showDrawer_]]" restamp>
+ <cr-drawer id="drawer" heading="$i18n{toolbarTitle}"
+ align="$i18n{textdirection}" on-close="onDrawerClose_">
+ <div class="drawer-content">
+ <extensions-sidebar id="sidebar" is-supervised="[[isSupervised_]]"
+ on-close-drawer="onCloseDrawer_">
+ </extensions-sidebar>
+ </div>
+ </cr-drawer>
+</template>
+<cr-view-manager id="viewManager" role="main">
+ <extensions-item-list id="items-list" delegate="[[delegate]]"
+ in-dev-mode="[[inDevMode]]" filter="[[filter]]"
+ hidden$="[[!didInitPage_]]" slot="view" apps="[[apps_]]"
+ extensions="[[extensions_]]"
+ on-show-install-warnings="onShowInstallWarnings_">
+ </extensions-item-list>
+ <cr-lazy-render id="details-view">
+ <template>
+ <extensions-detail-view delegate="[[delegate]]" slot="view"
+ in-dev-mode="[[inDevMode]]"
+ from-activity-log="[[fromActivityLog_]]"
+ show-activity-log="[[showActivityLog]]"
+ incognito-available="[[incognitoAvailable_]]"
+ data="[[detailViewItem_]]">
+ </extensions-detail-view>
</template>
- <cr-view-manager id="viewManager" role="main">
- <extensions-item-list id="items-list" delegate="[[delegate]]"
- in-dev-mode="[[inDevMode]]" filter="[[filter]]"
- hidden$="[[!didInitPage_]]" slot="view" apps="[[apps_]]"
- extensions="[[extensions_]]"
- on-show-install-warnings="onShowInstallWarnings_">
- </extensions-item-list>
- <cr-lazy-render id="details-view">
- <template>
- <extensions-detail-view delegate="[[delegate]]" slot="view"
- in-dev-mode="[[inDevMode]]"
- from-activity-log="[[fromActivityLog_]]"
- show-activity-log="[[showActivityLog]]"
- incognito-available="[[incognitoAvailable_]]"
- data="[[detailViewItem_]]">
- </extensions-detail-view>
- </template>
- </cr-lazy-render>
- <cr-lazy-render id="activity-log">
- <template>
- <extensions-activity-log delegate="[[delegate]]" slot="view"
- extension-info="[[activityLogItem_]]">
- </extensions-activity-log>
- </template>
- </cr-lazy-render>
- <cr-lazy-render id="keyboard-shortcuts">
- <template>
- <extensions-keyboard-shortcuts delegate="[[delegate]]" slot="view"
- items="[[extensions_]]">
- </extensions-keyboard-shortcuts>
- </template>
- </cr-lazy-render>
- <cr-lazy-render id="error-page">
- <template>
- <extensions-error-page data="[[errorPageItem_]]" slot="view"
- delegate="[[delegate]]" in-dev-mode="[[inDevMode]]">
- </extensions-error-page>
- </template>
- </cr-lazy-render>
- </cr-view-manager>
- <template is="dom-if" if="[[showOptionsDialog_]]" restamp>
- <extensions-options-dialog id="options-dialog"
- on-close="onOptionsDialogClose_">
- </extensions-options-dialog>
+ </cr-lazy-render>
+ <cr-lazy-render id="activity-log">
+ <template>
+ <extensions-activity-log delegate="[[delegate]]" slot="view"
+ extension-info="[[activityLogItem_]]">
+ </extensions-activity-log>
</template>
- <template is="dom-if" if="[[showLoadErrorDialog_]]" restamp>
- <extensions-load-error id="load-error" delegate="[[delegate]]"
- on-close="onLoadErrorDialogClose_">
- </extensions-load-error>
+ </cr-lazy-render>
+ <cr-lazy-render id="keyboard-shortcuts">
+ <template>
+ <extensions-keyboard-shortcuts delegate="[[delegate]]" slot="view"
+ items="[[extensions_]]">
+ </extensions-keyboard-shortcuts>
</template>
-<if expr="chromeos">
- <template is="dom-if" if="[[showKioskDialog_]]" restamp>
- <extensions-kiosk-dialog id="kiosk-dialog" on-close="onKioskDialogClose_">
- </extensions-kiosk-dialog>
+ </cr-lazy-render>
+ <cr-lazy-render id="error-page">
+ <template>
+ <extensions-error-page data="[[errorPageItem_]]" slot="view"
+ delegate="[[delegate]]" in-dev-mode="[[inDevMode]]">
+ </extensions-error-page>
</template>
+ </cr-lazy-render>
+</cr-view-manager>
+<template is="dom-if" if="[[showOptionsDialog_]]" restamp>
+ <extensions-options-dialog id="options-dialog"
+ on-close="onOptionsDialogClose_">
+ </extensions-options-dialog>
+</template>
+<template is="dom-if" if="[[showLoadErrorDialog_]]" restamp>
+ <extensions-load-error id="load-error" delegate="[[delegate]]"
+ on-close="onLoadErrorDialogClose_">
+ </extensions-load-error>
+</template>
+<if expr="chromeos">
+<template is="dom-if" if="[[showKioskDialog_]]" restamp>
+ <extensions-kiosk-dialog id="kiosk-dialog" on-close="onKioskDialogClose_">
+ </extensions-kiosk-dialog>
+</template>
</if>
- <template is="dom-if" if="[[showInstallWarningsDialog_]]" restamp>
- <extensions-install-warnings-dialog
- on-close="onInstallWarningsDialogClose_"
- install-warnings="[[installWarnings_]]">
- </extensions-install-warnings-dialog>
- </template>
- <cr-toast-manager></cr-toast-manager>
- </template>
- <script src="manager.js"></script>
-</dom-module>
+<template is="dom-if" if="[[showInstallWarningsDialog_]]" restamp>
+ <extensions-install-warnings-dialog
+ on-close="onInstallWarningsDialogClose_"
+ install-warnings="[[installWarnings_]]">
+ </extensions-install-warnings-dialog>
+</template>
+<cr-toast-manager></cr-toast-manager>
diff --git a/chromium/chrome/browser/resources/extensions/manager.js b/chromium/chrome/browser/resources/extensions/manager.js
index 28e8b0fdece..b1df5c6fef5 100644
--- a/chromium/chrome/browser/resources/extensions/manager.js
+++ b/chromium/chrome/browser/resources/extensions/manager.js
@@ -2,632 +2,658 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
-
- /**
- * Compares two extensions to determine which should come first in the list.
- * @param {chrome.developerPrivate.ExtensionInfo} a
- * @param {chrome.developerPrivate.ExtensionInfo} b
- * @return {number}
- */
- const compareExtensions = function(a, b) {
- function compare(x, y) {
- return x < y ? -1 : (x > y ? 1 : 0);
- }
- function compareLocation(x, y) {
- if (x.location == y.location) {
- return 0;
- }
- if (x.location == chrome.developerPrivate.Location.UNPACKED) {
- return -1;
- }
- if (y.location == chrome.developerPrivate.Location.UNPACKED) {
- return 1;
- }
+import 'chrome://resources/cr_elements/cr_drawer/cr_drawer.m.js';
+import 'chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.m.js';
+import 'chrome://resources/cr_elements/cr_toast/cr_toast_manager.m.js';
+import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.m.js';
+import 'chrome://resources/cr_elements/cr_view_manager/cr_view_manager.m.js';
+import 'chrome://resources/cr_elements/hidden_style_css.m.js';
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+import './detail_view.js';
+import './drop_overlay.js';
+import './error_page.js';
+import './install_warnings_dialog.js';
+import './item_list.js';
+import './item_util.js';
+import './keyboard_shortcuts.js';
+import './load_error.js';
+import './options_dialog.js';
+import './sidebar.js';
+import './toolbar.js';
+// <if expr="chromeos">
+import './kiosk_dialog.js';
+// </if>
+
+import {assert, assertNotReached} from 'chrome://resources/js/assert.m.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {ActivityLogExtensionPlaceholder} from './activity_log/activity_log.js';
+// <if expr="chromeos">
+import {KioskBrowserProxyImpl} from './kiosk_browser_proxy.js';
+// </if>
+import {Dialog, navigation, Page, PageState} from './navigation_helper.js';
+import {Service} from './service.js';
+
+/**
+ * Compares two extensions to determine which should come first in the list.
+ * @param {chrome.developerPrivate.ExtensionInfo} a
+ * @param {chrome.developerPrivate.ExtensionInfo} b
+ * @return {number}
+ */
+const compareExtensions = function(a, b) {
+ function compare(x, y) {
+ return x < y ? -1 : (x > y ? 1 : 0);
+ }
+ function compareLocation(x, y) {
+ if (x.location == y.location) {
return 0;
}
- return compareLocation(a, b) ||
- compare(a.name.toLowerCase(), b.name.toLowerCase()) ||
- compare(a.id, b.id);
- };
-
- const Manager = Polymer({
- is: 'extensions-manager',
-
- properties: {
- canLoadUnpacked: {
- type: Boolean,
- value: false,
- },
-
- /** @type {!extensions.Service} */
- delegate: {
- type: Object,
- value: function() {
- return extensions.Service.getInstance();
- },
- },
-
- inDevMode: {
- type: Boolean,
- value: () => loadTimeData.getBoolean('inDevMode'),
- },
-
- showActivityLog: {
- type: Boolean,
- value: () => loadTimeData.getBoolean('showActivityLog'),
- },
-
- devModeControlledByPolicy: {
- type: Boolean,
- value: false,
- },
-
- /** @private */
- isSupervised_: {
- type: Boolean,
- value: false,
- },
-
- incognitoAvailable_: {
- type: Boolean,
- value: false,
- },
-
- filter: {
- type: String,
- value: '',
- },
+ if (x.location == chrome.developerPrivate.Location.UNPACKED) {
+ return -1;
+ }
+ if (y.location == chrome.developerPrivate.Location.UNPACKED) {
+ return 1;
+ }
+ return 0;
+ }
+ return compareLocation(a, b) ||
+ compare(a.name.toLowerCase(), b.name.toLowerCase()) ||
+ compare(a.id, b.id);
+};
+
+Polymer({
+ is: 'extensions-manager',
+
+ _template: html`{__html_template__}`,
+
+ properties: {
+ canLoadUnpacked: {
+ type: Boolean,
+ value: false,
+ },
- /**
- * The item currently displayed in the error subpage. We use a separate
- * item for different pages (rather than a single subpageItem_ property)
- * so that hidden subpages don't update when an item updates. That is, we
- * don't want the details view subpage to update when the item shown in
- * the errors page updates, and vice versa.
- * @private {!chrome.developerPrivate.ExtensionInfo|undefined}
- */
- errorPageItem_: Object,
-
- /**
- * The item currently displayed in the details view subpage. See also
- * errorPageItem_.
- * @private {!chrome.developerPrivate.ExtensionInfo|undefined}
- */
- detailViewItem_: Object,
-
- /**
- * The item that provides some information about the current extension
- * for the activity log view subpage. See also errorPageItem_.
- * @private {!chrome.developerPrivate.ExtensionInfo|undefined|
- * !extensions.ActivityLogExtensionPlaceholder}
- */
- activityLogItem_: Object,
-
- /** @private {!Array<!chrome.developerPrivate.ExtensionInfo>} */
- extensions_: Array,
-
- /** @private {!Array<!chrome.developerPrivate.ExtensionInfo>} */
- apps_: Array,
-
- /**
- * Prevents page content from showing before data is first loaded.
- * @private
- */
- didInitPage_: {
- type: Boolean,
- value: false,
+ /** @type {!Service} */
+ delegate: {
+ type: Object,
+ value: function() {
+ return Service.getInstance();
},
+ },
- /** @private */
- showDrawer_: Boolean,
-
- /** @private */
- showLoadErrorDialog_: Boolean,
-
- /** @private */
- showInstallWarningsDialog_: Boolean,
-
- /** @private {?Array<string>} */
- installWarnings_: Array,
+ inDevMode: {
+ type: Boolean,
+ value: () => loadTimeData.getBoolean('inDevMode'),
+ },
- /** @private */
- showOptionsDialog_: Boolean,
+ showActivityLog: {
+ type: Boolean,
+ value: () => loadTimeData.getBoolean('showActivityLog'),
+ },
- /**
- * Whether the last page the user navigated from was the activity log
- * page.
- * @private
- */
- fromActivityLog_: Boolean,
+ devModeControlledByPolicy: {
+ type: Boolean,
+ value: false,
+ },
- // <if expr="chromeos">
- /** @private */
- kioskEnabled_: {
- type: Boolean,
- value: false,
- },
+ /** @private */
+ isSupervised_: {
+ type: Boolean,
+ value: false,
+ },
- /** @private */
- showKioskDialog_: {
- type: Boolean,
- value: false,
- },
- // </if>
+ incognitoAvailable_: {
+ type: Boolean,
+ value: false,
},
- listeners: {
- 'load-error': 'onLoadError_',
- 'view-enter-start': 'onViewEnterStart_',
- 'view-exit-start': 'onViewExitStart_',
- 'view-exit-finish': 'onViewExitFinish_',
+ filter: {
+ type: String,
+ value: '',
},
/**
- * The current page being shown. Default to null, and initPage_ will figure
- * out the initial page based on url.
- * @private {?extensions.PageState}
+ * The item currently displayed in the error subpage. We use a separate
+ * item for different pages (rather than a single subpageItem_ property)
+ * so that hidden subpages don't update when an item updates. That is, we
+ * don't want the details view subpage to update when the item shown in
+ * the errors page updates, and vice versa.
+ * @private {!chrome.developerPrivate.ExtensionInfo|undefined}
*/
- currentPage_: null,
+ errorPageItem_: Object,
/**
- * The ID of the listener on |extensions.navigation|. Stored so that the
- * listener can be removed when this element is detached (happens in tests).
- * @private {?number}
+ * The item currently displayed in the details view subpage. See also
+ * errorPageItem_.
+ * @private {!chrome.developerPrivate.ExtensionInfo|undefined}
*/
- navigationListener_: null,
-
- /** @override */
- ready: function() {
- const service = extensions.Service.getInstance();
-
- const onProfileStateChanged = profileInfo => {
- this.isSupervised_ = profileInfo.isSupervised;
- this.incognitoAvailable_ = profileInfo.isIncognitoAvailable;
- this.devModeControlledByPolicy =
- profileInfo.isDeveloperModeControlledByPolicy;
- this.inDevMode = profileInfo.inDeveloperMode;
- this.canLoadUnpacked = profileInfo.canLoadUnpacked;
- };
- service.getProfileStateChangedTarget().addListener(onProfileStateChanged);
- service.getProfileConfiguration().then(onProfileStateChanged);
-
- service.getExtensionsInfo().then(extensionsAndApps => {
- this.initExtensionsAndApps_(extensionsAndApps);
- this.initPage_();
-
- service.getItemStateChangedTarget().addListener(
- this.onItemStateChanged_.bind(this));
- });
+ detailViewItem_: Object,
- // <if expr="chromeos">
- extensions.KioskBrowserProxyImpl.getInstance()
- .initializeKioskAppSettings()
- .then(params => {
- this.kioskEnabled_ = params.kioskEnabled;
- });
- // </if>
- },
+ /**
+ * The item that provides some information about the current extension
+ * for the activity log view subpage. See also errorPageItem_.
+ * @private {!chrome.developerPrivate.ExtensionInfo|undefined|
+ * !ActivityLogExtensionPlaceholder}
+ */
+ activityLogItem_: Object,
- /** @override */
- attached: function() {
- document.documentElement.classList.remove('loading');
- document.fonts.load('bold 12px Roboto');
+ /** @private {!Array<!chrome.developerPrivate.ExtensionInfo>} */
+ extensions_: Array,
- this.navigationListener_ = extensions.navigation.addListener(newPage => {
- this.changePage_(newPage);
- });
- },
-
- /** @override */
- detached: function() {
- assert(extensions.navigation.removeListener(this.navigationListener_));
- this.navigationListener_ = null;
- },
+ /** @private {!Array<!chrome.developerPrivate.ExtensionInfo>} */
+ apps_: Array,
/**
- * Initializes the page to reflect what's specified in the url so that if
- * the user visits chrome://extensions/?id=..., we land on the proper page.
+ * Prevents page content from showing before data is first loaded.
* @private
*/
- initPage_: function() {
- this.didInitPage_ = true;
- this.changePage_(extensions.navigation.getCurrentPage());
+ didInitPage_: {
+ type: Boolean,
+ value: false,
},
- /**
- * @param {!chrome.developerPrivate.EventData} eventData
- * @private
- */
- onItemStateChanged_: function(eventData) {
- const EventType = chrome.developerPrivate.EventType;
- switch (eventData.event_type) {
- case EventType.VIEW_REGISTERED:
- case EventType.VIEW_UNREGISTERED:
- case EventType.INSTALLED:
- case EventType.LOADED:
- case EventType.UNLOADED:
- case EventType.ERROR_ADDED:
- case EventType.ERRORS_REMOVED:
- case EventType.PREFS_CHANGED:
- case EventType.WARNINGS_CHANGED:
- case EventType.COMMAND_ADDED:
- case EventType.COMMAND_REMOVED:
- case EventType.PERMISSIONS_CHANGED:
- // |extensionInfo| can be undefined in the case of an extension
- // being unloaded right before uninstallation. There's nothing to do
- // here.
- if (!eventData.extensionInfo) {
- break;
- }
-
- if (this.delegate.shouldIgnoreUpdate(
- eventData.extensionInfo.id, eventData.event_type)) {
- break;
- }
-
- const listId = this.getListId_(eventData.extensionInfo);
- const currentIndex = this[listId].findIndex(
- item => item.id == eventData.extensionInfo.id);
-
- if (currentIndex >= 0) {
- this.updateItem_(listId, currentIndex, eventData.extensionInfo);
- } else {
- this.addItem_(listId, eventData.extensionInfo);
- }
- break;
- case EventType.UNINSTALLED:
- this.removeItem_(eventData.item_id);
- break;
- default:
- assertNotReached();
- }
- },
+ /** @private */
+ showDrawer_: Boolean,
- /**
- * @param {!CustomEvent<string>} event
- * @private
- */
- onFilterChanged_: function(event) {
- if (this.currentPage_.page !== extensions.Page.LIST) {
- extensions.navigation.navigateTo({page: extensions.Page.LIST});
- }
- this.filter = event.detail;
- },
+ /** @private */
+ showLoadErrorDialog_: Boolean,
/** @private */
- onMenuButtonTap_: function() {
- this.showDrawer_ = true;
- this.async(() => {
- this.$$('#drawer').openDrawer();
- });
- },
+ showInstallWarningsDialog_: Boolean,
- /**
- * @param {!chrome.developerPrivate.ExtensionInfo} item
- * @return {string} The ID of the list that the item belongs in.
- * @private
- */
- getListId_: function(item) {
- const ExtensionType = chrome.developerPrivate.ExtensionType;
- switch (item.type) {
- case ExtensionType.HOSTED_APP:
- case ExtensionType.LEGACY_PACKAGED_APP:
- case ExtensionType.PLATFORM_APP:
- return 'apps_';
- case ExtensionType.EXTENSION:
- case ExtensionType.SHARED_MODULE:
- return 'extensions_';
- case ExtensionType.THEME:
- assertNotReached(
- 'Don\'t send themes to the chrome://extensions page');
- break;
- }
- assertNotReached();
- },
+ /** @private {?Array<string>} */
+ installWarnings_: Array,
+
+ /** @private */
+ showOptionsDialog_: Boolean,
/**
- * @param {string} listId The list to look for the item in.
- * @param {string} itemId The id of the item to look for.
- * @return {number} The index of the item in the list, or -1 if not found.
+ * Whether the last page the user navigated from was the activity log
+ * page.
* @private
*/
- getIndexInList_: function(listId, itemId) {
- return this[listId].findIndex(function(item) {
- return item.id == itemId;
- });
+ fromActivityLog_: Boolean,
+
+ // <if expr="chromeos">
+ /** @private */
+ kioskEnabled_: {
+ type: Boolean,
+ value: false,
},
- /**
- * @return {?chrome.developerPrivate.ExtensionInfo}
- * @private
- */
- getData_: function(id) {
- return this.extensions_[this.getIndexInList_('extensions_', id)] ||
- this.apps_[this.getIndexInList_('apps_', id)];
+ /** @private */
+ showKioskDialog_: {
+ type: Boolean,
+ value: false,
},
+ // </if>
+ },
- /**
- * Categorizes |extensionsAndApps| to apps and extensions and initializes
- * those lists.
- * @param {!Array<!chrome.developerPrivate.ExtensionInfo>} extensionsAndApps
- * @private
- */
- initExtensionsAndApps_: function(extensionsAndApps) {
- extensionsAndApps.sort(compareExtensions);
- const apps = [];
- const extensions = [];
- for (const i of extensionsAndApps) {
- const list = this.getListId_(i) === 'apps_' ? apps : extensions;
- list.push(i);
- }
+ listeners: {
+ 'load-error': 'onLoadError_',
+ 'view-enter-start': 'onViewEnterStart_',
+ 'view-exit-start': 'onViewExitStart_',
+ 'view-exit-finish': 'onViewExitFinish_',
+ },
- this.apps_ = apps;
- this.extensions_ = extensions;
- },
+ /**
+ * The current page being shown. Default to null, and initPage_ will figure
+ * out the initial page based on url.
+ * @private {?PageState}
+ */
+ currentPage_: null,
- /**
- * Creates and adds a new extensions-item element to the list, inserting it
- * into its sorted position in the relevant section.
- * @param {!chrome.developerPrivate.ExtensionInfo} item The extension
- * the new element is representing.
- * @private
- */
- addItem_: function(listId, item) {
- // We should never try and add an existing item.
- assert(this.getIndexInList_(listId, item.id) == -1);
- let insertBeforeChild = this[listId].findIndex(function(listEl) {
- return compareExtensions(listEl, item) > 0;
- });
- if (insertBeforeChild == -1) {
- insertBeforeChild = this[listId].length;
- }
- this.splice(listId, insertBeforeChild, 0, item);
- },
+ /**
+ * The ID of the listener on |navigation|. Stored so that the
+ * listener can be removed when this element is detached (happens in tests).
+ * @private {?number}
+ */
+ navigationListener_: null,
+
+ /** @override */
+ ready: function() {
+ const service = Service.getInstance();
+
+ const onProfileStateChanged = profileInfo => {
+ this.isSupervised_ = profileInfo.isSupervised;
+ this.incognitoAvailable_ = profileInfo.isIncognitoAvailable;
+ this.devModeControlledByPolicy =
+ profileInfo.isDeveloperModeControlledByPolicy;
+ this.inDevMode = profileInfo.inDeveloperMode;
+ this.canLoadUnpacked = profileInfo.canLoadUnpacked;
+ };
+ service.getProfileStateChangedTarget().addListener(onProfileStateChanged);
+ service.getProfileConfiguration().then(onProfileStateChanged);
+
+ service.getExtensionsInfo().then(extensionsAndApps => {
+ this.initExtensionsAndApps_(extensionsAndApps);
+ this.initPage_();
+
+ service.getItemStateChangedTarget().addListener(
+ this.onItemStateChanged_.bind(this));
+ });
- /**
- * @param {!chrome.developerPrivate.ExtensionInfo} item The data for the
- * item to update.
- * @private
- */
- updateItem_: function(listId, index, item) {
- // We should never try and update a non-existent item.
- assert(index >= 0);
- this.set([listId, index], item);
-
- // Update the subpage if it is open and displaying the item. If it's not
- // open, we don't update the data even if it's displaying that item. We'll
- // set the item correctly before opening the page. It's a little weird
- // that the DOM will have stale data, but there's no point in causing the
- // extra work.
- if (this.detailViewItem_ && this.detailViewItem_.id == item.id &&
- this.currentPage_.page == extensions.Page.DETAILS) {
- this.detailViewItem_ = item;
- } else if (
- this.errorPageItem_ && this.errorPageItem_.id == item.id &&
- this.currentPage_.page == extensions.Page.ERRORS) {
- this.errorPageItem_ = item;
- } else if (
- this.activityLogItem_ && this.activityLogItem_.id == item.id &&
- this.currentPage_.page == extensions.Page.ACTIVITY_LOG) {
- this.activityLogItem_ = item;
- }
- },
+ // <if expr="chromeos">
+ KioskBrowserProxyImpl.getInstance().initializeKioskAppSettings().then(
+ params => {
+ this.kioskEnabled_ = params.kioskEnabled;
+ });
+ // </if>
+ },
- /**
- * @param {string} itemId The id of item to remove.
- * @private
- */
- removeItem_: function(itemId) {
- // Search for the item to be deleted in |extensions_|.
- let listId = 'extensions_';
- let index = this.getIndexInList_(listId, itemId);
- if (index == -1) {
- // If not in |extensions_| it must be in |apps_|.
- listId = 'apps_';
- index = this.getIndexInList_(listId, itemId);
- }
+ /** @override */
+ attached: function() {
+ document.documentElement.classList.remove('loading');
+ document.fonts.load('bold 12px Roboto');
- // We should never try and remove a non-existent item.
- assert(index >= 0);
- this.splice(listId, index, 1);
- if ((this.currentPage_.page == extensions.Page.ACTIVITY_LOG ||
- this.currentPage_.page == extensions.Page.DETAILS ||
- this.currentPage_.page == extensions.Page.ERRORS) &&
- this.currentPage_.extensionId == itemId) {
- // Leave the details page (the 'list' page is a fine choice).
- extensions.navigation.replaceWith({page: extensions.Page.LIST});
- }
- },
+ this.navigationListener_ = navigation.addListener(newPage => {
+ this.changePage_(newPage);
+ });
+ },
- /**
- * @param {!CustomEvent<!chrome.developerPrivate.LoadError>} e
- * @private
- */
- onLoadError_: function(e) {
- this.showLoadErrorDialog_ = true;
- this.async(() => {
- const dialog = this.$$('#load-error');
- dialog.loadError = e.detail;
- dialog.show();
- });
- },
+ /** @override */
+ detached: function() {
+ assert(navigation.removeListener(
+ /** @type {number} */ (this.navigationListener_)));
+ this.navigationListener_ = null;
+ },
- /**
- * Changes the active page selection.
- * @param {extensions.PageState} newPage
- * @private
- */
- changePage_: function(newPage) {
- this.onCloseDrawer_();
+ /**
+ * Initializes the page to reflect what's specified in the url so that if
+ * the user visits chrome://extensions/?id=..., we land on the proper page.
+ * @private
+ */
+ initPage_: function() {
+ this.didInitPage_ = true;
+ this.changePage_(navigation.getCurrentPage());
+ },
- const optionsDialog = this.$$('#options-dialog');
- if (optionsDialog && optionsDialog.open) {
- this.showOptionsDialog_ = false;
- }
+ /**
+ * @param {!chrome.developerPrivate.EventData} eventData
+ * @private
+ */
+ onItemStateChanged_: function(eventData) {
+ const EventType = chrome.developerPrivate.EventType;
+ switch (eventData.event_type) {
+ case EventType.VIEW_REGISTERED:
+ case EventType.VIEW_UNREGISTERED:
+ case EventType.INSTALLED:
+ case EventType.LOADED:
+ case EventType.UNLOADED:
+ case EventType.ERROR_ADDED:
+ case EventType.ERRORS_REMOVED:
+ case EventType.PREFS_CHANGED:
+ case EventType.WARNINGS_CHANGED:
+ case EventType.COMMAND_ADDED:
+ case EventType.COMMAND_REMOVED:
+ case EventType.PERMISSIONS_CHANGED:
+ // |extensionInfo| can be undefined in the case of an extension
+ // being unloaded right before uninstallation. There's nothing to do
+ // here.
+ if (!eventData.extensionInfo) {
+ break;
+ }
- const fromPage = this.currentPage_ ? this.currentPage_.page : null;
- const toPage = newPage.page;
- let data;
- let activityLogPlaceholder;
- if (newPage.extensionId) {
- data = this.getData_(newPage.extensionId);
- if (!data) {
- // Allow the user to navigate to the activity log page even if the
- // extension ID is not valid. This enables the use case of seeing an
- // extension's install-time activities by navigating to an extension's
- // activity log page, then installing the extension.
- if (this.showActivityLog && toPage == extensions.Page.ACTIVITY_LOG) {
- activityLogPlaceholder = {
- id: newPage.extensionId,
- isPlaceholder: true,
- };
- } else {
- // Attempting to view an invalid (removed?) app or extension ID.
- extensions.navigation.replaceWith({page: extensions.Page.LIST});
- return;
- }
+ if (this.delegate.shouldIgnoreUpdate(
+ eventData.extensionInfo.id, eventData.event_type)) {
+ break;
}
- }
- if (toPage == extensions.Page.DETAILS) {
- this.detailViewItem_ = assert(data);
- } else if (toPage == extensions.Page.ERRORS) {
- this.errorPageItem_ = assert(data);
- } else if (toPage == extensions.Page.ACTIVITY_LOG) {
- if (!this.showActivityLog) {
- // Redirect back to the details page if we try to view the
- // activity log of an extension but the flag is not set.
- extensions.navigation.replaceWith({
- page: extensions.Page.DETAILS,
- extensionId: newPage.extensionId
- });
- return;
+ const listId = this.getListId_(eventData.extensionInfo);
+ const currentIndex = this[listId].findIndex(
+ item => item.id == eventData.extensionInfo.id);
+
+ if (currentIndex >= 0) {
+ this.updateItem_(listId, currentIndex, eventData.extensionInfo);
+ } else {
+ this.addItem_(listId, eventData.extensionInfo);
}
+ break;
+ case EventType.UNINSTALLED:
+ this.removeItem_(eventData.item_id);
+ break;
+ default:
+ assertNotReached();
+ }
+ },
- this.activityLogItem_ = data ? assert(data) : activityLogPlaceholder;
- }
+ /**
+ * @param {!CustomEvent<string>} event
+ * @private
+ */
+ onFilterChanged_: function(event) {
+ if (this.currentPage_.page !== Page.LIST) {
+ navigation.navigateTo({page: Page.LIST});
+ }
+ this.filter = event.detail;
+ },
- if (fromPage != toPage) {
- /** @type {CrViewManagerElement} */ (this.$.viewManager)
- .switchView(/** @type {string} */ (toPage));
- }
+ /** @private */
+ onMenuButtonTap_: function() {
+ this.showDrawer_ = true;
+ this.async(() => {
+ this.$$('#drawer').openDrawer();
+ });
+ },
- if (newPage.subpage) {
- assert(newPage.subpage == extensions.Dialog.OPTIONS);
- assert(newPage.extensionId);
- this.showOptionsDialog_ = true;
- this.async(() => {
- this.$$('#options-dialog').show(data);
- });
- }
+ /**
+ * @param {!chrome.developerPrivate.ExtensionInfo} item
+ * @return {string} The ID of the list that the item belongs in.
+ * @private
+ */
+ getListId_: function(item) {
+ const ExtensionType = chrome.developerPrivate.ExtensionType;
+ switch (item.type) {
+ case ExtensionType.HOSTED_APP:
+ case ExtensionType.LEGACY_PACKAGED_APP:
+ case ExtensionType.PLATFORM_APP:
+ return 'apps_';
+ case ExtensionType.EXTENSION:
+ case ExtensionType.SHARED_MODULE:
+ return 'extensions_';
+ case ExtensionType.THEME:
+ assertNotReached('Don\'t send themes to the chrome://extensions page');
+ break;
+ }
+ assertNotReached();
+ },
- document.title = toPage == extensions.Page.DETAILS ?
- `${loadTimeData.getString('title')} - ${this.detailViewItem_.name}` :
- loadTimeData.getString('title');
- this.currentPage_ = newPage;
- },
+ /**
+ * @param {string} listId The list to look for the item in.
+ * @param {string} itemId The id of the item to look for.
+ * @return {number} The index of the item in the list, or -1 if not found.
+ * @private
+ */
+ getIndexInList_: function(listId, itemId) {
+ return this[listId].findIndex(function(item) {
+ return item.id == itemId;
+ });
+ },
- /**
- * This method detaches the drawer dialog completely. Should only be
- * triggered by the dialog's 'close' event.
- * @private
- */
- onDrawerClose_: function() {
- this.showDrawer_ = false;
- },
+ /**
+ * @return {?chrome.developerPrivate.ExtensionInfo}
+ * @private
+ */
+ getData_: function(id) {
+ return this.extensions_[this.getIndexInList_('extensions_', id)] ||
+ this.apps_[this.getIndexInList_('apps_', id)];
+ },
- /**
- * This method animates the closing of the drawer.
- * @private
- */
- onCloseDrawer_: function() {
- const drawer = this.$$('#drawer');
- if (drawer && drawer.open) {
- drawer.close();
- }
- },
+ /**
+ * Categorizes |extensionsAndApps| to apps and extensions and initializes
+ * those lists.
+ * @param {!Array<!chrome.developerPrivate.ExtensionInfo>} extensionsAndApps
+ * @private
+ */
+ initExtensionsAndApps_: function(extensionsAndApps) {
+ extensionsAndApps.sort(compareExtensions);
+ const apps = [];
+ const extensions = [];
+ for (const i of extensionsAndApps) {
+ const list = this.getListId_(i) === 'apps_' ? apps : extensions;
+ list.push(i);
+ }
- /** @private */
- onLoadErrorDialogClose_: function() {
- this.showLoadErrorDialog_ = false;
- },
+ this.apps_ = apps;
+ this.extensions_ = extensions;
+ },
- /** @private */
- onOptionsDialogClose_: function() {
- this.showOptionsDialog_ = false;
- this.$$('extensions-detail-view').focusOptionsButton();
- },
+ /**
+ * Creates and adds a new extensions-item element to the list, inserting it
+ * into its sorted position in the relevant section.
+ * @param {!chrome.developerPrivate.ExtensionInfo} item The extension
+ * the new element is representing.
+ * @private
+ */
+ addItem_: function(listId, item) {
+ // We should never try and add an existing item.
+ assert(this.getIndexInList_(listId, item.id) == -1);
+ let insertBeforeChild = this[listId].findIndex(function(listEl) {
+ return compareExtensions(listEl, item) > 0;
+ });
+ if (insertBeforeChild == -1) {
+ insertBeforeChild = this[listId].length;
+ }
+ this.splice(listId, insertBeforeChild, 0, item);
+ },
- /** @private */
- onViewEnterStart_: function() {
- this.fromActivityLog_ = false;
- },
+ /**
+ * @param {!chrome.developerPrivate.ExtensionInfo} item The data for the
+ * item to update.
+ * @private
+ */
+ updateItem_: function(listId, index, item) {
+ // We should never try and update a non-existent item.
+ assert(index >= 0);
+ this.set([listId, index], item);
+
+ // Update the subpage if it is open and displaying the item. If it's not
+ // open, we don't update the data even if it's displaying that item. We'll
+ // set the item correctly before opening the page. It's a little weird
+ // that the DOM will have stale data, but there's no point in causing the
+ // extra work.
+ if (this.detailViewItem_ && this.detailViewItem_.id == item.id &&
+ this.currentPage_.page == Page.DETAILS) {
+ this.detailViewItem_ = item;
+ } else if (
+ this.errorPageItem_ && this.errorPageItem_.id == item.id &&
+ this.currentPage_.page == Page.ERRORS) {
+ this.errorPageItem_ = item;
+ } else if (
+ this.activityLogItem_ && this.activityLogItem_.id == item.id &&
+ this.currentPage_.page == Page.ACTIVITY_LOG) {
+ this.activityLogItem_ = item;
+ }
+ },
- /**
- * @param {!Event} e
- * @private
- */
- onViewExitStart_: function(e) {
- const viewType = e.composedPath()[0].tagName;
- this.fromActivityLog_ = viewType == 'EXTENSIONS-ACTIVITY-LOG';
- },
+ /**
+ * @param {string} itemId The id of item to remove.
+ * @private
+ */
+ removeItem_: function(itemId) {
+ // Search for the item to be deleted in |extensions_|.
+ let listId = 'extensions_';
+ let index = this.getIndexInList_(listId, itemId);
+ if (index == -1) {
+ // If not in |extensions_| it must be in |apps_|.
+ listId = 'apps_';
+ index = this.getIndexInList_(listId, itemId);
+ }
- /**
- * @param {!Event} e
- * @private
- */
- onViewExitFinish_: function(e) {
- const viewType = e.composedPath()[0].tagName;
- if (viewType == 'EXTENSIONS-ITEM-LIST' ||
- viewType == 'EXTENSIONS-KEYBOARD-SHORTCUTS' ||
- viewType == 'EXTENSIONS-ACTIVITY-LOG') {
+ // We should never try and remove a non-existent item.
+ assert(index >= 0);
+ this.splice(listId, index, 1);
+ if ((this.currentPage_.page == Page.ACTIVITY_LOG ||
+ this.currentPage_.page == Page.DETAILS ||
+ this.currentPage_.page == Page.ERRORS) &&
+ this.currentPage_.extensionId == itemId) {
+ // Leave the details page (the 'list' page is a fine choice).
+ navigation.replaceWith({page: Page.LIST});
+ }
+ },
+
+ /**
+ * @param {!CustomEvent<!chrome.developerPrivate.LoadError>} e
+ * @private
+ */
+ onLoadError_: function(e) {
+ this.showLoadErrorDialog_ = true;
+ this.async(() => {
+ const dialog = this.$$('#load-error');
+ dialog.loadError = e.detail;
+ dialog.show();
+ });
+ },
+
+ /**
+ * Changes the active page selection.
+ * @param {PageState} newPage
+ * @private
+ */
+ changePage_: function(newPage) {
+ this.onCloseDrawer_();
+
+ const optionsDialog = this.$$('#options-dialog');
+ if (optionsDialog && optionsDialog.open) {
+ this.showOptionsDialog_ = false;
+ }
+
+ const fromPage = this.currentPage_ ? this.currentPage_.page : null;
+ const toPage = newPage.page;
+ let data;
+ let activityLogPlaceholder;
+ if (newPage.extensionId) {
+ data = this.getData_(newPage.extensionId);
+ if (!data) {
+ // Allow the user to navigate to the activity log page even if the
+ // extension ID is not valid. This enables the use case of seeing an
+ // extension's install-time activities by navigating to an extension's
+ // activity log page, then installing the extension.
+ if (this.showActivityLog && toPage == Page.ACTIVITY_LOG) {
+ activityLogPlaceholder = {
+ id: newPage.extensionId,
+ isPlaceholder: true,
+ };
+ } else {
+ // Attempting to view an invalid (removed?) app or extension ID.
+ navigation.replaceWith({page: Page.LIST});
+ return;
+ }
+ }
+ }
+
+ if (toPage == Page.DETAILS) {
+ this.detailViewItem_ = assert(data);
+ } else if (toPage == Page.ERRORS) {
+ this.errorPageItem_ = assert(data);
+ } else if (toPage == Page.ACTIVITY_LOG) {
+ if (!this.showActivityLog) {
+ // Redirect back to the details page if we try to view the
+ // activity log of an extension but the flag is not set.
+ navigation.replaceWith(
+ {page: Page.DETAILS, extensionId: newPage.extensionId});
return;
}
- const extensionId = e.composedPath()[0].data.id;
- const list = this.$$('extensions-item-list');
- const button = viewType == 'EXTENSIONS-DETAIL-VIEW' ?
- list.getDetailsButton(extensionId) :
- list.getErrorsButton(extensionId);
+ this.activityLogItem_ = data ? assert(data) : activityLogPlaceholder;
+ }
- // The button will not exist, when returning from a details page
- // because the corresponding extension/app was deleted.
- if (button) {
- button.focus();
- }
- },
+ if (fromPage != toPage) {
+ /** @type {CrViewManagerElement} */ (this.$.viewManager)
+ .switchView(/** @type {string} */ (toPage));
+ }
- /**
- * @param {!CustomEvent<!Array<string>>} e
- * @private
- */
- onShowInstallWarnings_: function(e) {
- // Leverage Polymer data bindings instead of just assigning the
- // installWarnings on the dialog since the dialog hasn't been stamped
- // in the DOM yet.
- this.installWarnings_ = e.detail;
- this.showInstallWarningsDialog_ = true;
- },
+ if (newPage.subpage) {
+ assert(newPage.subpage == Dialog.OPTIONS);
+ assert(newPage.extensionId);
+ this.showOptionsDialog_ = true;
+ this.async(() => {
+ this.$$('#options-dialog').show(data);
+ });
+ }
- /** @private */
- onInstallWarningsDialogClose_: function() {
- this.installWarnings_ = null;
- this.showInstallWarningsDialog_ = false;
- },
+ document.title = toPage == Page.DETAILS ?
+ `${loadTimeData.getString('title')} - ${this.detailViewItem_.name}` :
+ loadTimeData.getString('title');
+ this.currentPage_ = newPage;
+ },
- // <if expr="chromeos">
- /** @private */
- onKioskTap_: function() {
- this.showKioskDialog_ = true;
- },
+ /**
+ * This method detaches the drawer dialog completely. Should only be
+ * triggered by the dialog's 'close' event.
+ * @private
+ */
+ onDrawerClose_: function() {
+ this.showDrawer_ = false;
+ },
- onKioskDialogClose_: function() {
- this.showKioskDialog_ = false;
- },
- // </if>
- });
+ /**
+ * This method animates the closing of the drawer.
+ * @private
+ */
+ onCloseDrawer_: function() {
+ const drawer = this.$$('#drawer');
+ if (drawer && drawer.open) {
+ drawer.close();
+ }
+ },
+
+ /** @private */
+ onLoadErrorDialogClose_: function() {
+ this.showLoadErrorDialog_ = false;
+ },
- return {Manager: Manager};
+ /** @private */
+ onOptionsDialogClose_: function() {
+ this.showOptionsDialog_ = false;
+ this.$$('extensions-detail-view').focusOptionsButton();
+ },
+
+ /** @private */
+ onViewEnterStart_: function() {
+ this.fromActivityLog_ = false;
+ },
+
+ /**
+ * @param {!Event} e
+ * @private
+ */
+ onViewExitStart_: function(e) {
+ const viewType = e.composedPath()[0].tagName;
+ this.fromActivityLog_ = viewType == 'EXTENSIONS-ACTIVITY-LOG';
+ },
+
+ /**
+ * @param {!Event} e
+ * @private
+ */
+ onViewExitFinish_: function(e) {
+ const viewType = e.composedPath()[0].tagName;
+ if (viewType == 'EXTENSIONS-ITEM-LIST' ||
+ viewType == 'EXTENSIONS-KEYBOARD-SHORTCUTS' ||
+ viewType == 'EXTENSIONS-ACTIVITY-LOG') {
+ return;
+ }
+
+ const extensionId = e.composedPath()[0].data.id;
+ const list = this.$$('extensions-item-list');
+ const button = viewType == 'EXTENSIONS-DETAIL-VIEW' ?
+ list.getDetailsButton(extensionId) :
+ list.getErrorsButton(extensionId);
+
+ // The button will not exist, when returning from a details page
+ // because the corresponding extension/app was deleted.
+ if (button) {
+ button.focus();
+ }
+ },
+
+ /**
+ * @param {!CustomEvent<!Array<string>>} e
+ * @private
+ */
+ onShowInstallWarnings_: function(e) {
+ // Leverage Polymer data bindings instead of just assigning the
+ // installWarnings on the dialog since the dialog hasn't been stamped
+ // in the DOM yet.
+ this.installWarnings_ = e.detail;
+ this.showInstallWarningsDialog_ = true;
+ },
+
+ /** @private */
+ onInstallWarningsDialogClose_: function() {
+ this.installWarnings_ = null;
+ this.showInstallWarningsDialog_ = false;
+ },
+
+ // <if expr="chromeos">
+ /** @private */
+ onKioskTap_: function() {
+ this.showKioskDialog_ = true;
+ },
+
+ onKioskDialogClose_: function() {
+ this.showKioskDialog_ = false;
+ },
+ // </if>
});
diff --git a/chromium/chrome/browser/resources/extensions/navigation_helper.html b/chromium/chrome/browser/resources/extensions/navigation_helper.html
deleted file mode 100644
index 4ebc7d42b7a..00000000000
--- a/chromium/chrome/browser/resources/extensions/navigation_helper.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
-
-<link rel="import" href="chrome://resources/html/assert.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="strings.html">
-<script src="navigation_helper.js"></script>
diff --git a/chromium/chrome/browser/resources/extensions/navigation_helper.js b/chromium/chrome/browser/resources/extensions/navigation_helper.js
index 75748cd70ef..b4bc143d1e7 100644
--- a/chromium/chrome/browser/resources/extensions/navigation_helper.js
+++ b/chromium/chrome/browser/resources/extensions/navigation_helper.js
@@ -2,238 +2,228 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
+import {assert} from 'chrome://resources/js/assert.m.js';
+
+
+/**
+ * The different pages that can be shown at a time.
+ * Note: This must remain in sync with the page ids in manager.html!
+ * @enum {string}
+ */
+export const Page = {
+ LIST: 'items-list',
+ DETAILS: 'details-view',
+ ACTIVITY_LOG: 'activity-log',
+ SHORTCUTS: 'keyboard-shortcuts',
+ ERRORS: 'error-page',
+};
+
+/** @enum {string} */
+export const Dialog = {
+ OPTIONS: 'options',
+};
+
+/**
+ * @typedef {{page: Page,
+ * extensionId: (string|undefined),
+ * subpage: (!Dialog|undefined)}}
+ */
+export let PageState;
+
+/**
+ * @param {!PageState} a
+ * @param {!PageState} b
+ * @return {boolean} Whether a and b are equal.
+ */
+function isPageStateEqual(a, b) {
+ return a.page == b.page && a.subpage == b.subpage &&
+ a.extensionId == b.extensionId;
+}
+
+/**
+ * Regular expression that captures the leading slash, the content and the
+ * trailing slash in three different groups.
+ * @const {!RegExp}
+ */
+const CANONICAL_PATH_REGEX = /(^\/)([\/-\w]+)(\/$)/;
+
+/**
+ * A helper object to manage in-page navigations. Since the extensions page
+ * needs to support different urls for different subpages (like the details
+ * page), we use this object to manage the history and url conversions.
+ */
+export class NavigationHelper {
+ constructor() {
+ this.processRoute_();
+
+ /** @private {number} */
+ this.nextListenerId_ = 1;
+
+ /** @private {!Map<number, function(!PageState)>} */
+ this.listeners_ = new Map();
+
+ /** @private {!PageState} */
+ this.previousPage_;
+
+ window.addEventListener('popstate', () => {
+ this.notifyRouteChanged_(this.getCurrentPage());
+ });
+ }
+
+ /** @private */
+ get currentPath_() {
+ return location.pathname.replace(CANONICAL_PATH_REGEX, '$1$2');
+ }
/**
- * The different pages that can be shown at a time.
- * Note: This must remain in sync with the page ids in manager.html!
- * @enum {string}
+ * Going to /configureCommands and /shortcuts should land you on /shortcuts.
+ * These are the only two supported routes, so all other cases will redirect
+ * you to root path if not already on it.
+ * @private
*/
- const Page = {
- LIST: 'items-list',
- DETAILS: 'details-view',
- ACTIVITY_LOG: 'activity-log',
- SHORTCUTS: 'keyboard-shortcuts',
- ERRORS: 'error-page',
- };
-
- /** @enum {string} */
- const Dialog = {
- OPTIONS: 'options',
- };
+ processRoute_() {
+ if (this.currentPath_ == '/configureCommands' ||
+ this.currentPath_ == '/shortcuts') {
+ window.history.replaceState(
+ undefined /* stateObject */, '', '/shortcuts');
+ } else if (this.currentPath_ !== '/') {
+ window.history.replaceState(undefined /* stateObject */, '', '/');
+ }
+ }
/**
- * @typedef {{page: extensions.Page,
- * extensionId: (string|undefined),
- * subpage: (!extensions.Dialog|undefined)}}
+ * @return {!PageState} The page that should be displayed for the
+ * current URL.
*/
- let PageState;
+ getCurrentPage() {
+ const search = new URLSearchParams(location.search);
+ let id = search.get('id');
+ if (id) {
+ return {page: Page.DETAILS, extensionId: id};
+ }
+ id = search.get('activity');
+ if (id) {
+ return {page: Page.ACTIVITY_LOG, extensionId: id};
+ }
+ id = search.get('options');
+ if (id) {
+ return {page: Page.DETAILS, extensionId: id, subpage: Dialog.OPTIONS};
+ }
+ id = search.get('errors');
+ if (id) {
+ return {page: Page.ERRORS, extensionId: id};
+ }
+
+ if (this.currentPath_ == '/shortcuts') {
+ return {page: Page.SHORTCUTS};
+ }
+
+ return {page: Page.LIST};
+ }
/**
- * @param {!extensions.PageState} a
- * @param {!extensions.PageState} b
- * @return {boolean} Whether a and b are equal.
+ * Function to add subscribers.
+ * @param {!function(!PageState)} listener
+ * @return {number} A numerical ID to be used for removing the listener.
*/
- function isPageStateEqual(a, b) {
- return a.page == b.page && a.subpage == b.subpage &&
- a.extensionId == b.extensionId;
+ addListener(listener) {
+ const nextListenerId = this.nextListenerId_++;
+ this.listeners_.set(nextListenerId, listener);
+ return nextListenerId;
}
/**
- * Regular expression that captures the leading slash, the content and the
- * trailing slash in three different groups.
- * @const {!RegExp}
+ * Remove a previously registered listener.
+ * @param {number} id
+ * @return {boolean} Whether a listener with the given ID was actually found
+ * and removed.
*/
- const CANONICAL_PATH_REGEX = /(^\/)([\/-\w]+)(\/$)/;
+ removeListener(id) {
+ return this.listeners_.delete(id);
+ }
/**
- * A helper object to manage in-page navigations. Since the extensions page
- * needs to support different urls for different subpages (like the details
- * page), we use this object to manage the history and url conversions.
+ * Function to notify subscribers.
+ * @private
*/
- class NavigationHelper {
- constructor() {
- this.processRoute_();
-
- /** @private {number} */
- this.nextListenerId_ = 1;
-
- /** @private {!Map<number, function(!extensions.PageState)>} */
- this.listeners_ = new Map();
-
- /** @private {!extensions.PageState} */
- this.previousPage_;
-
- window.addEventListener('popstate', () => {
- this.notifyRouteChanged_(this.getCurrentPage());
- });
- }
-
- /** @private */
- get currentPath_() {
- return location.pathname.replace(CANONICAL_PATH_REGEX, '$1$2');
- }
-
- /**
- * Going to /configureCommands and /shortcuts should land you on /shortcuts.
- * These are the only two supported routes, so all other cases will redirect
- * you to root path if not already on it.
- * @private
- */
- processRoute_() {
- if (this.currentPath_ == '/configureCommands' ||
- this.currentPath_ == '/shortcuts') {
- window.history.replaceState(
- undefined /* stateObject */, '', '/shortcuts');
- } else if (this.currentPath_ !== '/') {
- window.history.replaceState(undefined /* stateObject */, '', '/');
- }
- }
-
- /**
- * @return {!extensions.PageState} The page that should be displayed for the
- * current URL.
- */
- getCurrentPage() {
- const search = new URLSearchParams(location.search);
- let id = search.get('id');
- if (id) {
- return {page: Page.DETAILS, extensionId: id};
- }
- id = search.get('activity');
- if (id) {
- return {page: Page.ACTIVITY_LOG, extensionId: id};
- }
- id = search.get('options');
- if (id) {
- return {page: Page.DETAILS, extensionId: id, subpage: Dialog.OPTIONS};
- }
- id = search.get('errors');
- if (id) {
- return {page: Page.ERRORS, extensionId: id};
- }
-
- if (this.currentPath_ == '/shortcuts') {
- return {page: Page.SHORTCUTS};
- }
-
- return {page: Page.LIST};
- }
-
- /**
- * Function to add subscribers.
- * @param {!function(!extensions.PageState)} listener
- * @return {number} A numerical ID to be used for removing the listener.
- */
- addListener(listener) {
- const nextListenerId = this.nextListenerId_++;
- this.listeners_.set(nextListenerId, listener);
- return nextListenerId;
- }
+ notifyRouteChanged_(newPage) {
+ this.listeners_.forEach((listener, id) => {
+ listener(newPage);
+ });
+ }
- /**
- * Remove a previously registered listener.
- * @param {number} id
- * @return {boolean} Whether a listener with the given ID was actually found
- * and removed.
- */
- removeListener(id) {
- return this.listeners_.delete(id);
+ /**
+ * @param {!PageState} newPage the page to navigate to.
+ */
+ navigateTo(newPage) {
+ const currentPage = this.getCurrentPage();
+ if (currentPage && isPageStateEqual(currentPage, newPage)) {
+ return;
}
- /**
- * Function to notify subscribers.
- * @private
- */
- notifyRouteChanged_(newPage) {
- this.listeners_.forEach((listener, id) => {
- listener(newPage);
- });
- }
+ this.updateHistory(newPage, false /* replaceState */);
+ this.notifyRouteChanged_(newPage);
+ }
- /**
- * @param {!extensions.PageState} newPage the page to navigate to.
- */
- navigateTo(newPage) {
- const currentPage = this.getCurrentPage();
- if (currentPage && isPageStateEqual(currentPage, newPage)) {
- return;
- }
-
- this.updateHistory(newPage, false /* replaceState */);
- this.notifyRouteChanged_(newPage);
+ /**
+ * @param {!PageState} newPage the page to replace the current
+ * page with.
+ */
+ replaceWith(newPage) {
+ this.updateHistory(newPage, true /* replaceState */);
+ if (this.previousPage_ && isPageStateEqual(this.previousPage_, newPage)) {
+ // Skip the duplicate history entry.
+ history.back();
+ return;
}
+ this.notifyRouteChanged_(newPage);
+ }
- /**
- * @param {!extensions.PageState} newPage the page to replace the current
- * page with.
- */
- replaceWith(newPage) {
- this.updateHistory(newPage, true /* replaceState */);
- if (this.previousPage_ && isPageStateEqual(this.previousPage_, newPage)) {
- // Skip the duplicate history entry.
- history.back();
- return;
- }
- this.notifyRouteChanged_(newPage);
+ /**
+ * Called when a page changes, and pushes state to history to reflect it.
+ * @param {!PageState} entry
+ * @param {boolean} replaceState
+ */
+ updateHistory(entry, replaceState) {
+ let path;
+ switch (entry.page) {
+ case Page.LIST:
+ path = '/';
+ break;
+ case Page.ACTIVITY_LOG:
+ path = '/?activity=' + entry.extensionId;
+ break;
+ case Page.DETAILS:
+ if (entry.subpage) {
+ assert(entry.subpage == Dialog.OPTIONS);
+ path = '/?options=' + entry.extensionId;
+ } else {
+ path = '/?id=' + entry.extensionId;
+ }
+ break;
+ case Page.SHORTCUTS:
+ path = '/shortcuts';
+ break;
+ case Page.ERRORS:
+ path = '/?errors=' + entry.extensionId;
+ break;
}
-
- /**
- * Called when a page changes, and pushes state to history to reflect it.
- * @param {!extensions.PageState} entry
- * @param {boolean} replaceState
- */
- updateHistory(entry, replaceState) {
- let path;
- switch (entry.page) {
- case Page.LIST:
- path = '/';
- break;
- case Page.ACTIVITY_LOG:
- path = '/?activity=' + entry.extensionId;
- break;
- case Page.DETAILS:
- if (entry.subpage) {
- assert(entry.subpage == Dialog.OPTIONS);
- path = '/?options=' + entry.extensionId;
- } else {
- path = '/?id=' + entry.extensionId;
- }
- break;
- case Page.SHORTCUTS:
- path = '/shortcuts';
- break;
- case Page.ERRORS:
- path = '/?errors=' + entry.extensionId;
- break;
- }
- assert(path);
- const state = {url: path};
- const currentPage = this.getCurrentPage();
- const isDialogNavigation = currentPage.page == entry.page &&
- currentPage.extensionId == entry.extensionId;
- // Navigating to a dialog doesn't visually change pages; it just opens
- // a dialog. As such, we replace state rather than pushing a new state
- // on the stack so that hitting the back button doesn't just toggle the
- // dialog.
- if (replaceState || isDialogNavigation) {
- history.replaceState(state, '', path);
- } else {
- this.previousPage_ = currentPage;
- history.pushState(state, '', path);
- }
+ assert(path);
+ const state = {url: path};
+ const currentPage = this.getCurrentPage();
+ const isDialogNavigation = currentPage.page == entry.page &&
+ currentPage.extensionId == entry.extensionId;
+ // Navigating to a dialog doesn't visually change pages; it just opens
+ // a dialog. As such, we replace state rather than pushing a new state
+ // on the stack so that hitting the back button doesn't just toggle the
+ // dialog.
+ if (replaceState || isDialogNavigation) {
+ history.replaceState(state, '', path);
+ } else {
+ this.previousPage_ = currentPage;
+ history.pushState(state, '', path);
}
}
+}
- const navigation = new NavigationHelper();
-
- return {
- Dialog: Dialog,
- // Constructor exposed for testing purposes.
- NavigationHelper: NavigationHelper,
- navigation: navigation,
- Page: Page,
- PageState: PageState,
- };
-});
+export const navigation = new NavigationHelper();
diff --git a/chromium/chrome/browser/resources/extensions/options_dialog.html b/chromium/chrome/browser/resources/extensions/options_dialog.html
index 77f5d941e0f..2319d0cdb9d 100644
--- a/chromium/chrome/browser/resources/extensions/options_dialog.html
+++ b/chromium/chrome/browser/resources/extensions/options_dialog.html
@@ -1,81 +1,68 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style>
+ #icon {
+ height: 32px;
+ margin-inline-end: 10px;
+ width: 32px;
+ }
-<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
-<link rel="import" href="chrome://resources/html/assert.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="item_behavior.html">
-<link rel="import" href="navigation_helper.html">
+ #icon-and-name-wrapper {
+ align-items: center;
+ display: flex;
+ }
-<dom-module id="extensions-options-dialog">
- <template>
- <style>
- #icon {
- height: 32px;
- margin-inline-end: 10px;
- width: 32px;
- }
+ ExtensionOptions {
+ display: block;
+ height: 100%;
+ overflow: hidden;
+ }
- #icon-and-name-wrapper {
- align-items: center;
- display: flex;
- }
+ cr-dialog::part(dialog) {
+ /* CSS variables are set by the JS. */
+ height: var(--dialog-height);
+ opacity: var(--dialog-opacity, 0);
+ /* When loading, it's possible for an size update to follow after the
+ initial size update. The debounce time on size updates is 50ms.
+ A 100ms delay for the opacity transition will allow two updates to
+ occur without showing the dialog resizing to the user. */
+ transition: opacity 100ms ease 100ms;
+ width: var(--dialog-width);
+ }
- ExtensionOptions {
- display: block;
- height: 100%;
- overflow: hidden;
- }
+ cr-dialog::part(wrapper) {
+ height: 100%;
+ max-height: initial;
+ overflow: hidden;
+ }
- cr-dialog::part(dialog) {
- /* CSS variables are set by the JS. */
- height: var(--dialog-height);
- opacity: var(--dialog-opacity, 0);
- /* When loading, it's possible for an size update to follow after the
- initial size update. The debounce time on size updates is 50ms.
- A 100ms delay for the opacity transition will allow two updates to
- occur without showing the dialog resizing to the user. */
- transition: opacity 100ms ease 100ms;
- width: var(--dialog-width);
- }
+ cr-dialog #body {
+ height: 100%;
+ padding: 0;
+ }
- cr-dialog::part(wrapper) {
- height: 100%;
- max-height: initial;
- overflow: hidden;
- }
+ cr-dialog {
+ --cr-dialog-body-border-bottom: none;
+ --cr-dialog-body-border-top: none;
+ --scroll-border: none;
+ }
- cr-dialog #body {
- height: 100%;
- padding: 0;
- }
+ cr-dialog::part(body-container) {
+ height: 100%;
+ min-height: initial;
+ }
+</style>
- cr-dialog {
- --cr-dialog-body-border-bottom: none;
- --cr-dialog-body-border-top: none;
- --scroll-border: none;
- }
-
- cr-dialog::part(body-container) {
- height: 100%;
- min-height: initial;
- }
- </style>
-
- <cr-dialog id="dialog" close-text="$i18n{close}"
- on-close="onClose_" show-close-button>
- <div slot="title">
- <div id="icon-and-name-wrapper">
- <img id="icon" src="[[data_.iconUrl]]"
- alt$="[[appOrExtension(
- data.type,
- '$i18nPolymer{appIcon}',
- '$i18nPolymer{extensionIcon}')]]">
- <span>[[data_.name]]</span>
- </div>
- </div>
- <div slot="body" id="body">
- </div>
- </cr-dialog>
- </template>
- <script src="options_dialog.js"></script>
-</dom-module>
+<cr-dialog id="dialog" close-text="$i18n{close}"
+ on-close="onClose_" show-close-button>
+ <div slot="title">
+ <div id="icon-and-name-wrapper">
+ <img id="icon" src="[[data_.iconUrl]]"
+ alt$="[[appOrExtension(
+ data.type,
+ '$i18nPolymer{appIcon}',
+ '$i18nPolymer{extensionIcon}')]]">
+ <span>[[data_.name]]</span>
+ </div>
+ </div>
+ <div slot="body" id="body">
+ </div>
+</cr-dialog>
diff --git a/chromium/chrome/browser/resources/extensions/options_dialog.js b/chromium/chrome/browser/resources/extensions/options_dialog.js
index 6e5279922d2..ce9aa267217 100644
--- a/chromium/chrome/browser/resources/extensions/options_dialog.js
+++ b/chromium/chrome/browser/resources/extensions/options_dialog.js
@@ -2,132 +2,130 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
+import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
- /**
- * @return {!Promise} A signal that the document is ready. Need to wait for
- * this, otherwise the custom ExtensionOptions element might not have been
- * registered yet.
- */
- function whenDocumentReady() {
- if (document.readyState == 'complete') {
- return Promise.resolve();
- }
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
- return new Promise(function(resolve) {
- document.addEventListener('readystatechange', function f() {
- if (document.readyState == 'complete') {
- document.removeEventListener('readystatechange', f);
- resolve();
- }
- });
- });
+import {ItemBehavior} from './item_behavior.js';
+import {navigation, Page} from './navigation_helper.js';
+
+/**
+ * @return {!Promise} A signal that the document is ready. Need to wait for
+ * this, otherwise the custom ExtensionOptions element might not have been
+ * registered yet.
+ */
+function whenDocumentReady() {
+ if (document.readyState == 'complete') {
+ return Promise.resolve();
}
- // The minimum width in pixels for the options dialog.
- const MIN_WIDTH = 400;
-
- // The maximum height in pixels for the options dialog.
- const MAX_HEIGHT = 640;
-
- const OptionsDialog = Polymer({
- is: 'extensions-options-dialog',
-
- behaviors: [extensions.ItemBehavior],
-
- properties: {
- /** @private {Object} */
- extensionOptions_: Object,
-
- /** @private {chrome.developerPrivate.ExtensionInfo} */
- data_: Object,
- },
-
- /** @private {?Function} */
- boundUpdateDialogSize_: null,
-
- /** @private {?{height: number, width: number}} */
- preferredSize_: null,
-
- get open() {
- return this.$.dialog.open;
- },
-
- /**
- * Resizes the dialog to the width/height stored in |preferredSize_|, taking
- * into account the window width/height.
- * @private
- */
- updateDialogSize_: function() {
- const headerHeight = this.$.body.offsetTop;
- const maxHeight = Math.min(0.9 * window.innerHeight, MAX_HEIGHT);
- const effectiveHeight =
- Math.min(maxHeight, headerHeight + this.preferredSize_.height);
- const effectiveWidth = Math.max(MIN_WIDTH, this.preferredSize_.width);
-
- this.$.dialog.style.setProperty(
- '--dialog-height', `${effectiveHeight}px`);
- this.$.dialog.style.setProperty('--dialog-width', `${effectiveWidth}px`);
- this.$.dialog.style.setProperty('--dialog-opacity', 1);
- },
-
- /** @param {chrome.developerPrivate.ExtensionInfo} data */
- show: function(data) {
- this.data_ = data;
- whenDocumentReady().then(() => {
- if (!this.extensionOptions_) {
- this.extensionOptions_ = document.createElement('ExtensionOptions');
- }
- this.extensionOptions_.extension = this.data_.id;
- this.extensionOptions_.onclose = () => this.$.dialog.close();
-
- const boundUpdateDialogSize = this.updateDialogSize_.bind(this);
- this.boundUpdateDialogSize_ = boundUpdateDialogSize;
- this.extensionOptions_.onpreferredsizechanged = e => {
- if (!this.$.dialog.open) {
- this.$.dialog.showModal();
- }
- this.preferredSize_ = e;
- this.debounce('updateDialogSize_', boundUpdateDialogSize, 50);
- };
-
- // Add a 'resize' such that the dialog is resized when window size
- // changes.
- window.addEventListener('resize', this.boundUpdateDialogSize_);
- this.$.body.appendChild(this.extensionOptions_);
- });
- },
-
- /** @private */
- onClose_: function() {
- this.extensionOptions_.onpreferredsizechanged = null;
-
- if (this.boundUpdateDialogSize_) {
- window.removeEventListener('resize', this.boundUpdateDialogSize_);
- this.boundUpdateDialogSize_ = null;
+ return new Promise(function(resolve) {
+ document.addEventListener('readystatechange', function f() {
+ if (document.readyState == 'complete') {
+ document.removeEventListener('readystatechange', f);
+ resolve();
}
+ });
+ });
+}
+
+// The minimum width in pixels for the options dialog.
+export const OptionsDialogMinWidth = 400;
+
+// The maximum height in pixels for the options dialog.
+export const OptionsDialogMaxHeight = 640;
+
+Polymer({
+ is: 'extensions-options-dialog',
+
+ _template: html`{__html_template__}`,
+
+ behaviors: [ItemBehavior],
- const currentPage = extensions.navigation.getCurrentPage();
- // We update the page when the options dialog closes, but only if we're
- // still on the details page. We could be on a different page if the
- // user hit back while the options dialog was visible; in that case, the
- // new page is already correct.
- if (currentPage && currentPage.page == extensions.Page.DETAILS) {
- // This will update the currentPage_ and the NavigationHelper; since
- // the active page is already the details page, no main page
- // transition occurs.
- extensions.navigation.navigateTo({
- page: extensions.Page.DETAILS,
- extensionId: currentPage.extensionId
- });
+ properties: {
+ /** @private {Object} */
+ extensionOptions_: Object,
+
+ /** @private {chrome.developerPrivate.ExtensionInfo} */
+ data_: Object,
+ },
+
+ /** @private {?Function} */
+ boundUpdateDialogSize_: null,
+
+ /** @private {?{height: number, width: number}} */
+ preferredSize_: null,
+
+ get open() {
+ return this.$.dialog.open;
+ },
+
+ /**
+ * Resizes the dialog to the width/height stored in |preferredSize_|, taking
+ * into account the window width/height.
+ * @private
+ */
+ updateDialogSize_: function() {
+ const headerHeight = this.$.body.offsetTop;
+ const maxHeight =
+ Math.min(0.9 * window.innerHeight, OptionsDialogMaxHeight);
+ const effectiveHeight =
+ Math.min(maxHeight, headerHeight + this.preferredSize_.height);
+ const effectiveWidth =
+ Math.max(OptionsDialogMinWidth, this.preferredSize_.width);
+
+ this.$.dialog.style.setProperty('--dialog-height', `${effectiveHeight}px`);
+ this.$.dialog.style.setProperty('--dialog-width', `${effectiveWidth}px`);
+ this.$.dialog.style.setProperty('--dialog-opacity', '1');
+ },
+
+ /** @param {chrome.developerPrivate.ExtensionInfo} data */
+ show: function(data) {
+ this.data_ = data;
+ whenDocumentReady().then(() => {
+ if (!this.extensionOptions_) {
+ this.extensionOptions_ = document.createElement('ExtensionOptions');
}
- },
- });
+ this.extensionOptions_.extension = this.data_.id;
+ this.extensionOptions_.onclose = () => this.$.dialog.close();
+
+ const boundUpdateDialogSize = this.updateDialogSize_.bind(this);
+ this.boundUpdateDialogSize_ = boundUpdateDialogSize;
+ this.extensionOptions_.onpreferredsizechanged = e => {
+ if (!this.$.dialog.open) {
+ this.$.dialog.showModal();
+ }
+ this.preferredSize_ = e;
+ this.debounce('updateDialogSize_', boundUpdateDialogSize, 50);
+ };
+
+ // Add a 'resize' such that the dialog is resized when window size
+ // changes.
+ window.addEventListener('resize', this.boundUpdateDialogSize_);
+ this.$.body.appendChild(/** @type {Node} */ (this.extensionOptions_));
+ });
+ },
+
+ /** @private */
+ onClose_: function() {
+ this.extensionOptions_.onpreferredsizechanged = null;
- return {
- OptionsDialog: OptionsDialog,
- OptionsDialogMinWidth: MIN_WIDTH,
- OptionsDialogMaxHeight: MAX_HEIGHT,
- };
+ if (this.boundUpdateDialogSize_) {
+ window.removeEventListener('resize', this.boundUpdateDialogSize_);
+ this.boundUpdateDialogSize_ = null;
+ }
+
+ const currentPage = navigation.getCurrentPage();
+ // We update the page when the options dialog closes, but only if we're
+ // still on the details page. We could be on a different page if the
+ // user hit back while the options dialog was visible; in that case, the
+ // new page is already correct.
+ if (currentPage && currentPage.page == Page.DETAILS) {
+ // This will update the currentPage_ and the NavigationHelper; since
+ // the active page is already the details page, no main page
+ // transition occurs.
+ navigation.navigateTo(
+ {page: Page.DETAILS, extensionId: currentPage.extensionId});
+ }
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/pack_dialog.html b/chromium/chrome/browser/resources/extensions/pack_dialog.html
index 6718e23fec0..e945104391a 100644
--- a/chromium/chrome/browser/resources/extensions/pack_dialog.html
+++ b/chromium/chrome/browser/resources/extensions/pack_dialog.html
@@ -1,66 +1,49 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="cr-shared-style">
+ cr-input {
+ margin-top: var(--cr-form-field-bottom-spacing);
+ --cr-input-error-display: none;
+ }
-<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.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">
-<link rel="import" href="chrome://resources/html/assert.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/html/util.html">
-<link rel="import" href="pack_dialog_alert.html">
+ cr-button[slot='suffix'] {
+ margin-inline-start: 10px;
+ }
-<dom-module id="extensions-pack-dialog">
- <template>
- <style include="cr-shared-style">
- cr-input {
- margin-top: var(--cr-form-field-bottom-spacing);
- --cr-input-error-display: none;
- }
-
- cr-button[slot='suffix'] {
- margin-inline-start: 10px;
- }
-
- /* Prevent focus-outline from being chopped by bottom of dialog body. */
- cr-input {
- margin-bottom: 2px;
- }
- </style>
- <cr-dialog id="dialog" close-text="$i18n{close}">
- <div slot="title">$i18n{packDialogTitle}</div>
- <div slot="body">
- <div>$i18n{packDialogContent}</div>
- <cr-input id="root-dir" label="$i18n{packDialogExtensionRoot}"
- value="{{packDirectory_}}">
- <cr-button id="root-dir-browse" on-click="onRootBrowse_"
- slot="suffix">
- $i18n{packDialogBrowse}
- </cr-button>
- </cr-input>
- <cr-input id="key-file" label="$i18n{packDialogKeyFile}"
- value="{{keyFile_}}">
- <cr-button id="key-file-browse" on-click="onKeyBrowse_"
- slot="suffix">
- $i18n{packDialogBrowse}
- </cr-button>
- </cr-input>
- </div>
- <div slot="button-container">
- <cr-button class="cancel-button" on-click="onCancelTap_">
- $i18n{cancel}
- </cr-button>
- <cr-button class="action-button" on-click="onConfirmTap_"
- disabled="[[!packDirectory_]]">
- $i18n{packDialogConfirm}
- </cr-button>
- </div>
- </cr-dialog>
- <template is="dom-if" if="[[lastResponse_]]" restamp>
- <extensions-pack-dialog-alert model="[[lastResponse_]]"
- on-close="onAlertClose_">
- </extensions-pack-dialog-alert>
- </template>
- </template>
- <script src="pack_dialog.js"></script>
-</dom-module>
+ /* Prevent focus-outline from being chopped by bottom of dialog body. */
+ cr-input {
+ margin-bottom: 2px;
+ }
+</style>
+<cr-dialog id="dialog" close-text="$i18n{close}">
+ <div slot="title">$i18n{packDialogTitle}</div>
+ <div slot="body">
+ <div>$i18n{packDialogContent}</div>
+ <cr-input id="root-dir" label="$i18n{packDialogExtensionRoot}"
+ value="{{packDirectory_}}">
+ <cr-button id="root-dir-browse" on-click="onRootBrowse_"
+ slot="suffix">
+ $i18n{packDialogBrowse}
+ </cr-button>
+ </cr-input>
+ <cr-input id="key-file" label="$i18n{packDialogKeyFile}"
+ value="{{keyFile_}}">
+ <cr-button id="key-file-browse" on-click="onKeyBrowse_"
+ slot="suffix">
+ $i18n{packDialogBrowse}
+ </cr-button>
+ </cr-input>
+ </div>
+ <div slot="button-container">
+ <cr-button class="cancel-button" on-click="onCancelTap_">
+ $i18n{cancel}
+ </cr-button>
+ <cr-button class="action-button" on-click="onConfirmTap_"
+ disabled="[[!packDirectory_]]">
+ $i18n{packDialogConfirm}
+ </cr-button>
+ </div>
+</cr-dialog>
+<template is="dom-if" if="[[lastResponse_]]" restamp>
+ <extensions-pack-dialog-alert model="[[lastResponse_]]"
+ on-close="onAlertClose_">
+ </extensions-pack-dialog-alert>
+</template>
diff --git a/chromium/chrome/browser/resources/extensions/pack_dialog.js b/chromium/chrome/browser/resources/extensions/pack_dialog.js
index 720d86942a4..4791d6ba9eb 100644
--- a/chromium/chrome/browser/resources/extensions/pack_dialog.js
+++ b/chromium/chrome/browser/resources/extensions/pack_dialog.js
@@ -2,126 +2,132 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
-
- /** @interface */
- class PackDialogDelegate {
- /**
- * Opens a file browser for the user to select the root directory.
- * @return {Promise<string>} A promise that is resolved with the path the
- * user selected.
- */
- choosePackRootDirectory() {}
-
- /**
- * Opens a file browser for the user to select the private key file.
- * @return {Promise<string>} A promise that is resolved with the path the
- * user selected.
- */
- choosePrivateKeyPath() {}
-
- /**
- * Packs the extension into a .crx.
- * @param {string} rootPath
- * @param {string} keyPath
- * @param {number=} flag
- * @param {function(chrome.developerPrivate.PackDirectoryResponse)=}
- * callback
- */
- packExtension(rootPath, keyPath, flag, callback) {}
- }
-
- const PackDialog = Polymer({
- is: 'extensions-pack-dialog',
- properties: {
- /** @type {extensions.PackDialogDelegate} */
- delegate: Object,
-
- /** @private */
- packDirectory_: {
- type: String,
- value: '', // Initialized to trigger binding when attached.
- },
-
- /** @private */
- keyFile_: String,
-
- /** @private {?chrome.developerPrivate.PackDirectoryResponse} */
- lastResponse_: Object,
- },
-
- /** @override */
- attached: function() {
- this.$.dialog.showModal();
- },
-
- /** @private */
- onRootBrowse_: function() {
- this.delegate.choosePackRootDirectory().then(path => {
- if (path) {
- this.set('packDirectory_', path);
- }
- });
- },
-
- /** @private */
- onKeyBrowse_: function() {
- this.delegate.choosePrivateKeyPath().then(path => {
- if (path) {
- this.set('keyFile_', path);
- }
- });
- },
+import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
+import 'chrome://resources/cr_elements/cr_input/cr_input.m.js';
+import 'chrome://resources/cr_elements/shared_style_css.m.js';
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+import './pack_dialog_alert.js';
+import './strings.m.js';
+
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+/** @interface */
+export class PackDialogDelegate {
+ /**
+ * Opens a file browser for the user to select the root directory.
+ * @return {Promise<string>} A promise that is resolved with the path the
+ * user selected.
+ */
+ choosePackRootDirectory() {}
+
+ /**
+ * Opens a file browser for the user to select the private key file.
+ * @return {Promise<string>} A promise that is resolved with the path the
+ * user selected.
+ */
+ choosePrivateKeyPath() {}
+
+ /**
+ * Packs the extension into a .crx.
+ * @param {string} rootPath
+ * @param {string} keyPath
+ * @param {number=} flag
+ * @param {function(chrome.developerPrivate.PackDirectoryResponse)=}
+ * callback
+ */
+ packExtension(rootPath, keyPath, flag, callback) {}
+}
+
+Polymer({
+ is: 'extensions-pack-dialog',
+
+ _template: html`{__html_template__}`,
+
+ properties: {
+ /** @type {PackDialogDelegate} */
+ delegate: Object,
/** @private */
- onCancelTap_: function() {
- this.$.dialog.cancel();
+ packDirectory_: {
+ type: String,
+ value: '', // Initialized to trigger binding when attached.
},
/** @private */
- onConfirmTap_: function() {
- this.delegate.packExtension(
- this.packDirectory_, this.keyFile_, 0,
- this.onPackResponse_.bind(this));
- },
-
- /**
- * @param {chrome.developerPrivate.PackDirectoryResponse} response the
- * response from request to pack an extension.
- * @private
- */
- onPackResponse_: function(response) {
- this.lastResponse_ = response;
- },
-
- /**
- * In the case that the alert dialog was a success message, the entire
- * pack-dialog should close. Otherwise, we detach the alert by setting
- * lastResponse_ null. Additionally, if the user selected "proceed anyway"
- * in the dialog, we pack the extension again with override flags.
- * @param {!Event} e
- * @private
- */
- onAlertClose_: function(e) {
- e.stopPropagation();
-
- if (this.lastResponse_.status ==
- chrome.developerPrivate.PackStatus.SUCCESS) {
- this.$.dialog.close();
- return;
+ keyFile_: String,
+
+ /** @private {?chrome.developerPrivate.PackDirectoryResponse} */
+ lastResponse_: Object,
+ },
+
+ /** @override */
+ attached: function() {
+ this.$.dialog.showModal();
+ },
+
+ /** @private */
+ onRootBrowse_: function() {
+ this.delegate.choosePackRootDirectory().then(path => {
+ if (path) {
+ this.set('packDirectory_', path);
}
-
- // This is only possible for a warning dialog.
- if (this.$$('extensions-pack-dialog-alert').returnValue == 'success') {
- this.delegate.packExtension(
- this.lastResponse_.item_path, this.lastResponse_.pem_path,
- this.lastResponse_.override_flags, this.onPackResponse_.bind(this));
+ });
+ },
+
+ /** @private */
+ onKeyBrowse_: function() {
+ this.delegate.choosePrivateKeyPath().then(path => {
+ if (path) {
+ this.set('keyFile_', path);
}
+ });
+ },
+
+ /** @private */
+ onCancelTap_: function() {
+ this.$.dialog.cancel();
+ },
+
+ /** @private */
+ onConfirmTap_: function() {
+ this.delegate.packExtension(
+ this.packDirectory_, this.keyFile_, 0, this.onPackResponse_.bind(this));
+ },
+
+ /**
+ * @param {chrome.developerPrivate.PackDirectoryResponse} response the
+ * response from request to pack an extension.
+ * @private
+ */
+ onPackResponse_: function(response) {
+ this.lastResponse_ = response;
+ },
+
+ /**
+ * In the case that the alert dialog was a success message, the entire
+ * pack-dialog should close. Otherwise, we detach the alert by setting
+ * lastResponse_ null. Additionally, if the user selected "proceed anyway"
+ * in the dialog, we pack the extension again with override flags.
+ * @param {!Event} e
+ * @private
+ */
+ onAlertClose_: function(e) {
+ e.stopPropagation();
+
+ if (this.lastResponse_.status ==
+ chrome.developerPrivate.PackStatus.SUCCESS) {
+ this.$.dialog.close();
+ return;
+ }
+
+ // This is only possible for a warning dialog.
+ if (this.$$('extensions-pack-dialog-alert').returnValue == 'success') {
+ this.delegate.packExtension(
+ this.lastResponse_.item_path, this.lastResponse_.pem_path,
+ this.lastResponse_.override_flags, this.onPackResponse_.bind(this));
+ }
- this.lastResponse_ = null;
- },
- });
-
- return {PackDialog: PackDialog, PackDialogDelegate: PackDialogDelegate};
+ this.lastResponse_ = null;
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/pack_dialog_alert.html b/chromium/chrome/browser/resources/extensions/pack_dialog_alert.html
index a08e9feb5e0..79fc2f76efc 100644
--- a/chromium/chrome/browser/resources/extensions/pack_dialog_alert.html
+++ b/chromium/chrome/browser/resources/extensions/pack_dialog_alert.html
@@ -1,35 +1,22 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="cr-shared-style">
+ .body {
+ white-space: pre-wrap;
+ word-break: break-word;
+ }
+</style>
-<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
-<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
-<link rel="import" href="chrome://resources/html/assert.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-
-<dom-module id="extensions-pack-dialog-alert">
- <template>
- <style include="cr-shared-style">
- .body {
- white-space: pre-wrap;
- word-break: break-word;
- }
- </style>
-
- <cr-dialog id="dialog" close-text="$i18n{close}">
- <div class="title" slot="title">[[title_]]</div>
- <!-- No whitespace or new-lines allowed within the div.body tag. -->
- <div class="body" slot="body">[[model.message]]</div>
- <div class="button-container" slot="button-container">
- <cr-button class$="[[getCancelButtonClass_(confirmLabel_)]]"
- on-click="onCancelTap_" hidden="[[!cancelLabel_]]">
- [[cancelLabel_]]
- </cr-button>
- <cr-button class="action-button" on-click="onConfirmTap_"
- hidden="[[!confirmLabel_]]">
- [[confirmLabel_]]
- </cr-button>
- </div>
- </cr-dialog>
- </template>
- <script src="pack_dialog_alert.js"></script>
-</dom-module>
+<cr-dialog id="dialog" close-text="$i18n{close}">
+ <div class="title" slot="title">[[title_]]</div>
+ <!-- No whitespace or new-lines allowed within the div.body tag. -->
+ <div class="body" slot="body">[[model.message]]</div>
+ <div class="button-container" slot="button-container">
+ <cr-button class$="[[getCancelButtonClass_(confirmLabel_)]]"
+ on-click="onCancelTap_" hidden="[[!cancelLabel_]]">
+ [[cancelLabel_]]
+ </cr-button>
+ <cr-button class="action-button" on-click="onConfirmTap_"
+ hidden="[[!confirmLabel_]]">
+ [[confirmLabel_]]
+ </cr-button>
+ </div>
+</cr-dialog>
diff --git a/chromium/chrome/browser/resources/extensions/pack_dialog_alert.js b/chromium/chrome/browser/resources/extensions/pack_dialog_alert.js
index 9b33668c7ca..a39869e2f70 100644
--- a/chromium/chrome/browser/resources/extensions/pack_dialog_alert.js
+++ b/chromium/chrome/browser/resources/extensions/pack_dialog_alert.js
@@ -2,93 +2,96 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
+import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
+import 'chrome://resources/cr_elements/shared_style_css.m.js';
+import {assert, assertNotReached} from 'chrome://resources/js/assert.m.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
- const PackDialogAlert = Polymer({
- is: 'extensions-pack-dialog-alert',
- properties: {
- /** @private {chrome.developerPrivate.PackDirectoryResponse} */
- model: Object,
+Polymer({
+ is: 'extensions-pack-dialog-alert',
- /** @private */
- title_: String,
+ _template: html`{__html_template__}`,
- /** @private */
- message_: String,
+ properties: {
+ /** @private {chrome.developerPrivate.PackDirectoryResponse} */
+ model: Object,
- /** @private {?string} */
- cancelLabel_: String,
-
- /**
- * This needs to be initialized to trigger data-binding.
- * @private {?string}
- */
- confirmLabel_: {
- type: String,
- value: '',
- }
- },
-
- /** @return {string} */
- get returnValue() {
- return /** @type {!CrDialogElement} */ (this.$.dialog)
- .getNative()
- .returnValue;
- },
-
- /** @override */
- ready: function() {
- // Initialize button label values for initial html binding.
- this.cancelLabel_ = null;
- this.confirmLabel_ = null;
+ /** @private */
+ title_: String,
- switch (this.model.status) {
- case chrome.developerPrivate.PackStatus.WARNING:
- this.title_ = loadTimeData.getString('packDialogWarningTitle');
- this.cancelLabel_ = loadTimeData.getString('cancel');
- this.confirmLabel_ =
- loadTimeData.getString('packDialogProceedAnyway');
- break;
- case chrome.developerPrivate.PackStatus.ERROR:
- this.title_ = loadTimeData.getString('packDialogErrorTitle');
- this.cancelLabel_ = loadTimeData.getString('ok');
- break;
- case chrome.developerPrivate.PackStatus.SUCCESS:
- this.title_ = loadTimeData.getString('packDialogTitle');
- this.cancelLabel_ = loadTimeData.getString('ok');
- break;
- default:
- assertNotReached();
- return;
- }
- },
+ /** @private */
+ message_: String,
- /** @override */
- attached: function() {
- this.$.dialog.showModal();
- },
+ /** @private {?string} */
+ cancelLabel_: String,
/**
- * @return {string}
- * @private
+ * This needs to be initialized to trigger data-binding.
+ * @private {?string}
*/
- getCancelButtonClass_: function() {
- return this.confirmLabel_ ? 'cancel-button' : 'action-button';
- },
+ confirmLabel_: {
+ type: String,
+ value: '',
+ }
+ },
- /** @private */
- onCancelTap_: function() {
- this.$.dialog.cancel();
- },
+ /** @return {string} */
+ get returnValue() {
+ return /** @type {!CrDialogElement} */ (this.$.dialog)
+ .getNative()
+ .returnValue;
+ },
- /** @private */
- onConfirmTap_: function() {
- // The confirm button should only be available in WARNING state.
- assert(this.model.status === chrome.developerPrivate.PackStatus.WARNING);
- this.$.dialog.close();
+ /** @override */
+ ready: function() {
+ // Initialize button label values for initial html binding.
+ this.cancelLabel_ = null;
+ this.confirmLabel_ = null;
+
+ switch (this.model.status) {
+ case chrome.developerPrivate.PackStatus.WARNING:
+ this.title_ = loadTimeData.getString('packDialogWarningTitle');
+ this.cancelLabel_ = loadTimeData.getString('cancel');
+ this.confirmLabel_ = loadTimeData.getString('packDialogProceedAnyway');
+ break;
+ case chrome.developerPrivate.PackStatus.ERROR:
+ this.title_ = loadTimeData.getString('packDialogErrorTitle');
+ this.cancelLabel_ = loadTimeData.getString('ok');
+ break;
+ case chrome.developerPrivate.PackStatus.SUCCESS:
+ this.title_ = loadTimeData.getString('packDialogTitle');
+ this.cancelLabel_ = loadTimeData.getString('ok');
+ break;
+ default:
+ assertNotReached();
+ return;
}
- });
+ },
+
+ /** @override */
+ attached: function() {
+ this.$.dialog.showModal();
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ getCancelButtonClass_: function() {
+ return this.confirmLabel_ ? 'cancel-button' : 'action-button';
+ },
+
+ /** @private */
+ onCancelTap_: function() {
+ this.$.dialog.cancel();
+ },
- return {PackDialogAlert: PackDialogAlert};
+ /** @private */
+ onConfirmTap_: function() {
+ // The confirm button should only be available in WARNING state.
+ assert(this.model.status === chrome.developerPrivate.PackStatus.WARNING);
+ this.$.dialog.close();
+ }
});
diff --git a/chromium/chrome/browser/resources/extensions/runtime_host_permissions.html b/chromium/chrome/browser/resources/extensions/runtime_host_permissions.html
index 038343a0cdb..390e3e8c363 100644
--- a/chromium/chrome/browser/resources/extensions/runtime_host_permissions.html
+++ b/chromium/chrome/browser/resources/extensions/runtime_host_permissions.html
@@ -1,138 +1,115 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="cr-shared-style action-link md-select shared-style">
+ iron-icon {
+ --iron-icon-height: var(--cr-icon-size);
+ --iron-icon-width: var(--cr-icon-size);
+ }
-<link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_radio_group/cr_radio_group.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_radio_button/cr_radio_button.html">
-<link rel="import" href="chrome://resources/cr_elements/icons.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">
-<link rel="import" href="chrome://resources/html/action_link.html">
-<link rel="import" href="chrome://resources/cr_elements/action_link_css.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/html/cr/ui/focus_without_ink.html">
-<link rel="import" href="chrome://resources/cr_elements/md_select_css.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html">
-<link rel="import" href="runtime_hosts_dialog.html">
-<link rel="import" href="shared_style.html">
-<link rel="import" href="strings.html">
+ #section-heading {
+ align-items: center;
+ display: flex;
+ justify-content: space-between;
+ }
-<dom-module id="extensions-runtime-host-permissions">
- <template>
- <style include="cr-shared-style action-link md-select shared-style">
- iron-icon {
- --iron-icon-height: var(--cr-icon-size);
- --iron-icon-width: var(--cr-icon-size);
- }
+ #host-access {
+ margin-inline-start: 20px;
+ width: 100%;
+ }
- #section-heading {
- align-items: center;
- display: flex;
- justify-content: space-between;
- }
+ #hosts {
+ margin-bottom: 0;
+ padding: 0;
+ }
- #host-access {
- margin-inline-start: 20px;
- width: 100%;
- }
+ #hosts li {
+ align-items: center;
+ border-bottom: var(--cr-separator-line);
+ display: flex;
+ height: var(--cr-section-min-height);
+ justify-content: space-between;
+ }
- #hosts {
- margin-bottom: 0;
- padding: 0;
- }
+ #hosts li:last-child {
+ border-bottom: none;
+ }
- #hosts li {
- align-items: center;
- border-bottom: var(--cr-separator-line);
- display: flex;
- height: var(--cr-section-min-height);
- justify-content: space-between;
- }
+ #add-host {
+ font-weight: 500;
+ width: 100%;
+ }
- #hosts li:last-child {
- border-bottom: none;
- }
+ #permissions-mode {
+ color: var(--cr-primary-text-color);
+ margin-top: 12px;
+ }
- #add-host {
- font-weight: 500;
- width: 100%;
- }
+ cr-radio-button.multi-row {
+ align-items: normal;
+ }
- #permissions-mode {
- color: var(--cr-primary-text-color);
- margin-top: 12px;
- }
-
- cr-radio-button.multi-row {
- align-items: normal;
- }
-
- cr-icon-button {
- margin: 0;
- }
- </style>
- <div id="permissions-mode">
- <div id="section-heading">
- <span>$i18n{hostPermissionsHeading}</span>
- <a class="link-icon-button" aria-label="$i18n{learnMore}"
- href="$i18n{hostPermissionsLearnMoreLink}" target="_blank">
- <iron-icon icon="cr:help-outline"></iron-icon>
- </a>
+ cr-icon-button {
+ margin: 0;
+ }
+</style>
+<div id="permissions-mode">
+ <div id="section-heading">
+ <span>$i18n{hostPermissionsHeading}</span>
+ <a class="link-icon-button" aria-label="$i18n{learnMore}"
+ href="$i18n{hostPermissionsLearnMoreLink}" target="_blank">
+ <iron-icon icon="cr:help-outline"></iron-icon>
+ </a>
+ </div>
+ <cr-radio-group id="host-access" selected="[[permissions.hostAccess]]"
+ on-selected-changed="onHostAccessChange_">
+ <cr-radio-button name="[[HostAccess_.ON_CLICK]]">
+ $i18n{hostAccessOnClick}
+ </cr-radio-button>
+ <cr-radio-button name="[[HostAccess_.ON_SPECIFIC_SITES]]"
+ class="multi-row">
+ <div>
+ $i18n{hostAccessOnSpecificSites}
</div>
- <cr-radio-group id="host-access" selected="[[permissions.hostAccess]]"
- on-selected-changed="onHostAccessChange_">
- <cr-radio-button name="[[HostAccess_.ON_CLICK]]">
- $i18n{hostAccessOnClick}
- </cr-radio-button>
- <cr-radio-button name="[[HostAccess_.ON_SPECIFIC_SITES]]"
- class="multi-row">
- <div>
- $i18n{hostAccessOnSpecificSites}
- </div>
- <template is="dom-if" if="[[showSpecificSites_(permissions.*)]]">
- <ul id="hosts">
- <template is="dom-repeat"
- items="[[getRuntimeHosts_(permissions.hosts)]]">
- <li>
- <div>[[item]]</div>
- <cr-icon-button class="icon-more-vert edit-host"
- on-click="onEditHostClick_"
- title="$i18n{hostPermissionsEdit}"></cr-icon-button>
- </li>
- </template>
- <li>
- <a id="add-host" is="action-link" on-click="onAddHostClick_">
- $i18n{itemSiteAccessAddHost}
- </a>
- </li>
- </ul>
+ <template is="dom-if" if="[[showSpecificSites_(permissions.*)]]">
+ <ul id="hosts">
+ <template is="dom-repeat"
+ items="[[getRuntimeHosts_(permissions.hosts)]]">
+ <li>
+ <div>[[item]]</div>
+ <cr-icon-button class="icon-more-vert edit-host"
+ on-click="onEditHostClick_"
+ title="$i18n{hostPermissionsEdit}"></cr-icon-button>
+ </li>
</template>
- </cr-radio-button>
- <cr-radio-button name="[[HostAccess_.ON_ALL_SITES]]">
- $i18n{hostAccessOnAllSites}
- </cr-radio-button>
- </cr-radio-group>
- </div>
- <cr-action-menu id="hostActionMenu"
- on-close="onActionMenuClose_">
- <button class="dropdown-item" id="action-menu-edit"
- on-click="onActionMenuEditClick_">
- $i18n{hostPermissionsEdit}
- </button>
- <button class="dropdown-item" id="action-menu-remove"
- on-click="onActionMenuRemoveClick_">
- $i18n{remove}
- </button>
- </cr-action-menu>
- <template is="dom-if" if="[[showHostDialog_]]" restamp>
- <extensions-runtime-hosts-dialog
- delegate="[[delegate]]" item-id="[[itemId]]"
- current-site="[[hostDialogModel_]]"
- update-host-access="[[dialogShouldUpdateHostAccess_(oldHostAccess_)]]"
- on-close="onHostDialogClose_"
- on-cancel="onHostDialogCancel_">
- </extensions-runtime-hosts-dialog>
- </template>
- </template>
- <script src="runtime_host_permissions.js"></script>
-</dom-module>
+ <li>
+ <a id="add-host" is="action-link" on-click="onAddHostClick_">
+ $i18n{itemSiteAccessAddHost}
+ </a>
+ </li>
+ </ul>
+ </template>
+ </cr-radio-button>
+ <cr-radio-button name="[[HostAccess_.ON_ALL_SITES]]">
+ $i18n{hostAccessOnAllSites}
+ </cr-radio-button>
+ </cr-radio-group>
+</div>
+<cr-action-menu id="hostActionMenu"
+ role-description="$i18n{menu}"
+ on-close="onActionMenuClose_">
+ <button class="dropdown-item" id="action-menu-edit"
+ on-click="onActionMenuEditClick_">
+ $i18n{hostPermissionsEdit}
+ </button>
+ <button class="dropdown-item" id="action-menu-remove"
+ on-click="onActionMenuRemoveClick_">
+ $i18n{remove}
+ </button>
+</cr-action-menu>
+<template is="dom-if" if="[[showHostDialog_]]" restamp>
+ <extensions-runtime-hosts-dialog
+ delegate="[[delegate]]" item-id="[[itemId]]"
+ current-site="[[hostDialogModel_]]"
+ update-host-access="[[dialogShouldUpdateHostAccess_(oldHostAccess_)]]"
+ on-close="onHostDialogClose_"
+ on-cancel="onHostDialogCancel_">
+ </extensions-runtime-hosts-dialog>
+</template>
diff --git a/chromium/chrome/browser/resources/extensions/runtime_host_permissions.js b/chromium/chrome/browser/resources/extensions/runtime_host_permissions.js
index 6fbc21ac3e7..1814e423fe8 100644
--- a/chromium/chrome/browser/resources/extensions/runtime_host_permissions.js
+++ b/chromium/chrome/browser/resources/extensions/runtime_host_permissions.js
@@ -2,250 +2,265 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
-
- const RuntimeHostPermissions = Polymer({
- is: 'extensions-runtime-host-permissions',
-
- properties: {
- /**
- * The underlying permissions data.
- * @type {chrome.developerPrivate.RuntimeHostPermissions}
- */
- permissions: Object,
-
- /** @private */
- itemId: String,
-
- /** @type {!extensions.ItemDelegate} */
- delegate: Object,
-
- /**
- * Whether the dialog to add a new host permission is shown.
- * @private
- */
- showHostDialog_: Boolean,
-
- /**
- * The current site of the entry that the host dialog is editing, if the
- * dialog is open for editing.
- * @type {?string}
- * @private
- */
- hostDialogModel_: {
- type: String,
- value: null,
- },
-
- /**
- * The element to return focus to once the host dialog closes.
- * @type {?HTMLElement}
- * @private
- */
- hostDialogAnchorElement_: {
- type: Object,
- value: null,
- },
-
- /**
- * If the action menu is open, the site of the entry it is open for.
- * Otherwise null.
- * @type {?string}
- * @private
- */
- actionMenuModel_: {
- type: String,
- value: null,
- },
-
- /**
- * The element that triggered the action menu, so that the page will
- * return focus once the action menu (or dialog) closes.
- * @type {?HTMLElement}
- * @private
- */
- actionMenuAnchorElement_: {
- type: Object,
- value: null,
- },
-
- /**
- * The old host access setting; used when we don't immediately commit the
- * change to host access so that we can reset it if the user cancels.
- * @type {?string}
- * @private
- */
- oldHostAccess_: {
- type: String,
- value: null,
- },
-
- /**
- * Proxying the enum to be used easily by the html template.
- * @private
- */
- HostAccess_: {
- type: Object,
- value: chrome.developerPrivate.HostAccess,
- },
- },
+import 'chrome://resources/cr_elements/cr_action_menu/cr_action_menu.m.js';
+import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
+import 'chrome://resources/cr_elements/cr_radio_group/cr_radio_group.m.js';
+import 'chrome://resources/cr_elements/cr_radio_button/cr_radio_button.m.js';
+import 'chrome://resources/cr_elements/icons.m.js';
+import 'chrome://resources/cr_elements/shared_style_css.m.js';
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+import 'chrome://resources/js/action_link.js';
+import 'chrome://resources/cr_elements/action_link_css.m.js';
+import 'chrome://resources/cr_elements/md_select_css.m.js';
+import 'chrome://resources/polymer/v3_0/iron-icon/iron-icon.js';
+import './runtime_hosts_dialog.js';
+import './shared_style.js';
+import './strings.m.js';
+
+import {assert} from 'chrome://resources/js/assert.m.js';
+import {focusWithoutInk} from 'chrome://resources/js/cr/ui/focus_without_ink.m.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {ItemDelegate} from './item.js';
+
+Polymer({
+ is: 'extensions-runtime-host-permissions',
+
+ _template: html`{__html_template__}`,
+ properties: {
/**
- * @param {!Event} event
- * @private
+ * The underlying permissions data.
+ * @type {chrome.developerPrivate.RuntimeHostPermissions}
*/
- onHostAccessChange_: function(event) {
- const group = this.$['host-access'];
- const access = group.selected;
-
- if (access == chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES &&
- this.permissions.hostAccess !=
- chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES) {
- // If the user is transitioning to the "on specific sites" option, show
- // the "add host" dialog. This serves two purposes:
- // - The user is prompted to add a host immediately, since otherwise
- // "on specific sites" is meaningless, and
- // - The way the C++ code differentiates between "on click" and "on
- // specific sites" is by checking if there are any specific sites.
- // This ensures there will be at least one, so that the host access
- // is properly calculated.
- this.oldHostAccess_ = this.permissions.hostAccess;
- this.doShowHostDialog_(group, null);
- } else {
- this.delegate.setItemHostAccess(this.itemId, access);
- }
- },
+ permissions: Object,
+
+ /** @private */
+ itemId: String,
+
+ /** @type {!ItemDelegate} */
+ delegate: Object,
/**
- * @return {boolean}
+ * Whether the dialog to add a new host permission is shown.
* @private
*/
- showSpecificSites_: function() {
- return this.permissions.hostAccess ==
- chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES;
- },
+ showHostDialog_: Boolean,
/**
- * Returns the granted host permissions as a sorted set of strings.
- * @return {!Array<string>}
+ * The current site of the entry that the host dialog is editing, if the
+ * dialog is open for editing.
+ * @type {?string}
* @private
*/
- getRuntimeHosts_: function() {
- if (!this.permissions.hosts) {
- return [];
- }
-
- // Only show granted hosts in the list.
- // TODO(devlin): For extensions that request a finite set of hosts,
- // display them in a toggle list. https://crbug.com/891803.
- return this.permissions.hosts.filter(control => control.granted)
- .map(control => control.host)
- .sort();
+ hostDialogModel_: {
+ type: String,
+ value: null,
},
/**
- * @param {Event} e
+ * The element to return focus to once the host dialog closes.
+ * @type {?HTMLElement}
* @private
*/
- onAddHostClick_: function(e) {
- const target = /** @type {!HTMLElement} */ (e.target);
- this.doShowHostDialog_(target, null);
+ hostDialogAnchorElement_: {
+ type: Object,
+ value: null,
},
/**
- * @param {!HTMLElement} anchorElement The element to return focus to once
- * the dialog closes.
- * @param {?string} currentSite The site entry currently being
- * edited, or null if this is to add a new entry.
+ * If the action menu is open, the site of the entry it is open for.
+ * Otherwise null.
+ * @type {?string}
* @private
*/
- doShowHostDialog_: function(anchorElement, currentSite) {
- this.hostDialogAnchorElement_ = anchorElement;
- this.hostDialogModel_ = currentSite;
- this.showHostDialog_ = true;
- },
-
- /** @private */
- onHostDialogClose_: function() {
- this.hostDialogModel_ = null;
- this.showHostDialog_ = false;
- cr.ui.focusWithoutInk(
- assert(this.hostDialogAnchorElement_, 'Host Anchor'));
- this.hostDialogAnchorElement_ = null;
- this.oldHostAccess_ = null;
+ actionMenuModel_: {
+ type: String,
+ value: null,
},
- /** @private */
- onHostDialogCancel_: function() {
- // The user canceled the dialog. Set host-access back to the old value,
- // if the dialog was shown when just transitioning to a new state.
- if (this.oldHostAccess_) {
- assert(this.permissions.hostAccess == this.oldHostAccess_);
- this.$['host-access'].selected = this.oldHostAccess_;
- this.oldHostAccess_ = null;
- }
+ /**
+ * The element that triggered the action menu, so that the page will
+ * return focus once the action menu (or dialog) closes.
+ * @type {?HTMLElement}
+ * @private
+ */
+ actionMenuAnchorElement_: {
+ type: Object,
+ value: null,
},
/**
- * @return {boolean}
+ * The old host access setting; used when we don't immediately commit the
+ * change to host access so that we can reset it if the user cancels.
+ * @type {?string}
* @private
*/
- dialogShouldUpdateHostAccess_: function() {
- return !!this.oldHostAccess_;
+ oldHostAccess_: {
+ type: String,
+ value: null,
},
/**
- * @param {!{
- * model: !{item: string},
- * target: !HTMLElement,
- * }} e
+ * Proxying the enum to be used easily by the html template.
* @private
*/
- onEditHostClick_: function(e) {
- this.actionMenuModel_ = e.model.item;
- this.actionMenuAnchorElement_ = e.target;
- const actionMenu =
- /** @type {CrActionMenuElement} */ (this.$.hostActionMenu);
- actionMenu.showAt(e.target);
+ HostAccess_: {
+ type: Object,
+ value: chrome.developerPrivate.HostAccess,
},
+ },
- /** @private */
- onActionMenuEditClick_: function() {
- // Cache the site before closing the action menu, since it's cleared.
- const site = this.actionMenuModel_;
-
- // Cache and reset actionMenuAnchorElement_ so focus is not returned
- // to the action menu's trigger (since the dialog will be shown next).
- // Instead, curry the element to the dialog, so once it closes, focus
- // will be returned.
- const anchorElement =
- assert(this.actionMenuAnchorElement_, 'Menu Anchor');
- this.actionMenuAnchorElement_ = null;
- this.closeActionMenu_();
- this.doShowHostDialog_(anchorElement, site);
- },
+ /**
+ * @param {!Event} event
+ * @private
+ */
+ onHostAccessChange_: function(event) {
+ const group = /** @type {!HTMLElement} */ (this.$['host-access']);
+ const access = group.selected;
- /** @private */
- onActionMenuRemoveClick_: function() {
- this.delegate.removeRuntimeHostPermission(
- this.itemId, assert(this.actionMenuModel_, 'Action Menu Model'));
- this.closeActionMenu_();
- },
+ if (access == chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES &&
+ this.permissions.hostAccess !=
+ chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES) {
+ // If the user is transitioning to the "on specific sites" option, show
+ // the "add host" dialog. This serves two purposes:
+ // - The user is prompted to add a host immediately, since otherwise
+ // "on specific sites" is meaningless, and
+ // - The way the C++ code differentiates between "on click" and "on
+ // specific sites" is by checking if there are any specific sites.
+ // This ensures there will be at least one, so that the host access
+ // is properly calculated.
+ this.oldHostAccess_ = this.permissions.hostAccess;
+ this.doShowHostDialog_(group, null);
+ } else {
+ this.delegate.setItemHostAccess(this.itemId, access);
+ }
+ },
- /** @private */
- closeActionMenu_: function() {
- const menu = this.$.hostActionMenu;
- assert(menu.open);
- menu.close();
- },
+ /**
+ * @return {boolean}
+ * @private
+ */
+ showSpecificSites_: function() {
+ return this.permissions.hostAccess ==
+ chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES;
+ },
- /** @private */
- onActionMenuClose_: function() {
- this.actionMenuModel_ = null;
- this.actionMenuAnchorElement_ = null;
- },
- });
+ /**
+ * Returns the granted host permissions as a sorted set of strings.
+ * @return {!Array<string>}
+ * @private
+ */
+ getRuntimeHosts_: function() {
+ if (!this.permissions.hosts) {
+ return [];
+ }
+
+ // Only show granted hosts in the list.
+ // TODO(devlin): For extensions that request a finite set of hosts,
+ // display them in a toggle list. https://crbug.com/891803.
+ return this.permissions.hosts.filter(control => control.granted)
+ .map(control => control.host)
+ .sort();
+ },
+
+ /**
+ * @param {Event} e
+ * @private
+ */
+ onAddHostClick_: function(e) {
+ const target = /** @type {!HTMLElement} */ (e.target);
+ this.doShowHostDialog_(target, null);
+ },
+
+ /**
+ * @param {!HTMLElement} anchorElement The element to return focus to once
+ * the dialog closes.
+ * @param {?string} currentSite The site entry currently being
+ * edited, or null if this is to add a new entry.
+ * @private
+ */
+ doShowHostDialog_: function(anchorElement, currentSite) {
+ this.hostDialogAnchorElement_ = anchorElement;
+ this.hostDialogModel_ = currentSite;
+ this.showHostDialog_ = true;
+ },
+
+ /** @private */
+ onHostDialogClose_: function() {
+ this.hostDialogModel_ = null;
+ this.showHostDialog_ = false;
+ focusWithoutInk(assert(this.hostDialogAnchorElement_, 'Host Anchor'));
+ this.hostDialogAnchorElement_ = null;
+ this.oldHostAccess_ = null;
+ },
+
+ /** @private */
+ onHostDialogCancel_: function() {
+ // The user canceled the dialog. Set host-access back to the old value,
+ // if the dialog was shown when just transitioning to a new state.
+ if (this.oldHostAccess_) {
+ assert(this.permissions.hostAccess == this.oldHostAccess_);
+ this.$['host-access'].selected = this.oldHostAccess_;
+ this.oldHostAccess_ = null;
+ }
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ dialogShouldUpdateHostAccess_: function() {
+ return !!this.oldHostAccess_;
+ },
+
+ /**
+ * @param {!{
+ * model: !{item: string},
+ * target: !HTMLElement,
+ * }} e
+ * @private
+ */
+ onEditHostClick_: function(e) {
+ this.actionMenuModel_ = e.model.item;
+ this.actionMenuAnchorElement_ = e.target;
+ const actionMenu =
+ /** @type {CrActionMenuElement} */ (this.$.hostActionMenu);
+ actionMenu.showAt(e.target);
+ },
+
+ /** @private */
+ onActionMenuEditClick_: function() {
+ // Cache the site before closing the action menu, since it's cleared.
+ const site = this.actionMenuModel_;
+
+ // Cache and reset actionMenuAnchorElement_ so focus is not returned
+ // to the action menu's trigger (since the dialog will be shown next).
+ // Instead, curry the element to the dialog, so once it closes, focus
+ // will be returned.
+ const anchorElement = assert(this.actionMenuAnchorElement_, 'Menu Anchor');
+ this.actionMenuAnchorElement_ = null;
+ this.closeActionMenu_();
+ this.doShowHostDialog_(anchorElement, site);
+ },
+
+ /** @private */
+ onActionMenuRemoveClick_: function() {
+ this.delegate.removeRuntimeHostPermission(
+ this.itemId, assert(this.actionMenuModel_, 'Action Menu Model'));
+ this.closeActionMenu_();
+ },
+
+ /** @private */
+ closeActionMenu_: function() {
+ const menu = this.$.hostActionMenu;
+ assert(menu.open);
+ menu.close();
+ },
- return {RuntimeHostPermissions: RuntimeHostPermissions};
+ /** @private */
+ onActionMenuClose_: function() {
+ this.actionMenuModel_ = null;
+ this.actionMenuAnchorElement_ = null;
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/runtime_hosts_dialog.html b/chromium/chrome/browser/resources/extensions/runtime_hosts_dialog.html
index db6b162825e..e8013bd69e0 100644
--- a/chromium/chrome/browser/resources/extensions/runtime_hosts_dialog.html
+++ b/chromium/chrome/browser/resources/extensions/runtime_hosts_dialog.html
@@ -1,36 +1,23 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
-
-<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
-<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
-<link rel="import" href="strings.html">
-
-<dom-module id="extensions-runtime-hosts-dialog">
- <template>
- <style include="cr-shared-style"></style>
- <cr-dialog id="dialog" close-text="$i18n{close}">
- <div slot="title">[[computeDialogTitle_(currentSite)]]</div>
- <div slot="body">
- <cr-input id="input" label="$i18n{runtimeHostsDialogInputLabel}"
- placeholder="http://example.com"
- value="{{site_}}" on-input="validate_"
- invalid="[[inputInvalid_]]"
- error-message="$i18n{runtimeHostsDialogInputError}"
- spellcheck="false"
- autofocus>
- </cr-input>
- </div>
- <div slot="button-container">
- <cr-button class="cancel-button" on-click="onCancelTap_">
- $i18n{cancel}
- </cr-button>
- <cr-button class="action-button" id="submit" on-click="onSubmitTap_"
- disabled="[[computeSubmitButtonDisabled_(inputInvalid_, site_)]]">
- [[computeSubmitButtonLabel_(currentSite)]]
- </cr-button>
- </div>
- </cr-dialog>
- </template>
- <script src="runtime_hosts_dialog.js"></script>
-</dom-module>
+<style include="cr-shared-style"></style>
+<cr-dialog id="dialog" close-text="$i18n{close}">
+ <div slot="title">[[computeDialogTitle_(currentSite)]]</div>
+ <div slot="body">
+ <cr-input id="input" label="$i18n{runtimeHostsDialogInputLabel}"
+ placeholder="http://example.com"
+ value="{{site_}}" on-input="validate_"
+ invalid="[[inputInvalid_]]"
+ error-message="$i18n{runtimeHostsDialogInputError}"
+ spellcheck="false"
+ autofocus>
+ </cr-input>
+ </div>
+ <div slot="button-container">
+ <cr-button class="cancel-button" on-click="onCancelTap_">
+ $i18n{cancel}
+ </cr-button>
+ <cr-button class="action-button" id="submit" on-click="onSubmitTap_"
+ disabled="[[computeSubmitButtonDisabled_(inputInvalid_, site_)]]">
+ [[computeSubmitButtonLabel_(currentSite)]]
+ </cr-button>
+ </div>
+</cr-dialog>
diff --git a/chromium/chrome/browser/resources/extensions/runtime_hosts_dialog.js b/chromium/chrome/browser/resources/extensions/runtime_hosts_dialog.js
index 61ffd43ba63..bbe15acfcda 100644
--- a/chromium/chrome/browser/resources/extensions/runtime_hosts_dialog.js
+++ b/chromium/chrome/browser/resources/extensions/runtime_hosts_dialog.js
@@ -2,223 +2,228 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
-
- // A RegExp to roughly match acceptable patterns entered by the user.
- // exec'ing() this RegExp will match the following groups:
- // 0: Full matched string.
- // 1: Scheme + scheme separator (e.g., 'https://').
- // 2: Scheme only (e.g., 'https').
- // 3: Match subdomains ('*.').
- // 4: Hostname (e.g., 'example.com').
- // 5: Port, including ':' separator (e.g., ':80').
- // 6: Path, include '/' separator (e.g., '/*').
- const patternRegExp = new RegExp(
- '^' +
- // Scheme; optional.
- '((http|https|\\*)://)?' +
- // Include subdomains specifier; optional.
- '(\\*\\.)?' +
- // Hostname, required.
- '([a-z0-9\\.-]+\\.[a-z0-9]+)' +
- // Port, optional.
- '(:[0-9]+)?' +
- // Path, optional but if present must be '/' or '/*'.
- '(\\/\\*|\\/)?' +
- '$');
-
- function getPatternFromSite(site) {
- const res = patternRegExp.exec(site);
- assert(res);
- const scheme = res[1] || '*://';
- const host = (res[3] || '') + res[4];
- const port = res[5] || '';
- const path = '/*';
- return scheme + host + port + path;
- }
-
- const RuntimeHostsDialog = Polymer({
- is: 'extensions-runtime-hosts-dialog',
-
- properties: {
- /** @type {!extensions.ItemDelegate} */
- delegate: Object,
-
- /** @type {string} */
- itemId: String,
-
- /**
- * The site that this entry is currently managing. Only non-empty if this
- * is for editing an existing entry.
- * @type {?string}
- */
- currentSite: {
- type: String,
- value: null,
- },
-
- /**
- * Whether the dialog should update the host access to be "on specific
- * sites" before adding a new host permission.
- */
- updateHostAccess: {
- type: Boolean,
- value: false,
- },
-
- /**
- * The site to add an exception for.
- * @private
- */
- site_: String,
-
- /**
- * Whether the currently-entered input is valid.
- * @private
- */
- inputInvalid_: {
- type: Boolean,
- value: false,
- },
- },
-
- /** @override */
- attached: function() {
- if (this.currentSite !== null && this.currentSite !== undefined) {
- this.site_ = this.currentSite;
- this.validate_();
- }
- this.$.dialog.showModal();
- },
-
- /** @return {boolean} */
- isOpen: function() {
- return this.$.dialog.open;
- },
+import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import 'chrome://resources/cr_elements/cr_dialog/cr_dialog.m.js';
+import 'chrome://resources/cr_elements/cr_input/cr_input.m.js';
+import 'chrome://resources/cr_elements/shared_style_css.m.js';
+import './strings.m.js';
+
+import {assert} from 'chrome://resources/js/assert.m.js';
+import {loadTimeData} from 'chrome://resources/js/load_time_data.m.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {ItemDelegate} from './item.js';
+
+// A RegExp to roughly match acceptable patterns entered by the user.
+// exec'ing() this RegExp will match the following groups:
+// 0: Full matched string.
+// 1: Scheme + scheme separator (e.g., 'https://').
+// 2: Scheme only (e.g., 'https').
+// 3: Match subdomains ('*.').
+// 4: Hostname (e.g., 'example.com').
+// 5: Port, including ':' separator (e.g., ':80').
+// 6: Path, include '/' separator (e.g., '/*').
+const patternRegExp = new RegExp(
+ '^' +
+ // Scheme; optional.
+ '((http|https|\\*)://)?' +
+ // Include subdomains specifier; optional.
+ '(\\*\\.)?' +
+ // Hostname, required.
+ '([a-z0-9\\.-]+\\.[a-z0-9]+)' +
+ // Port, optional.
+ '(:[0-9]+)?' +
+ // Path, optional but if present must be '/' or '/*'.
+ '(\\/\\*|\\/)?' +
+ '$');
+
+export function getPatternFromSite(site) {
+ const res = patternRegExp.exec(site);
+ assert(res);
+ const scheme = res[1] || '*://';
+ const host = (res[3] || '') + res[4];
+ const port = res[5] || '';
+ const path = '/*';
+ return scheme + host + port + path;
+}
+
+Polymer({
+ is: 'extensions-runtime-hosts-dialog',
+
+ _template: html`{__html_template__}`,
+
+ properties: {
+ /** @type {!ItemDelegate} */
+ delegate: Object,
+
+ /** @type {string} */
+ itemId: String,
/**
- * Validates that the pattern entered is valid.
- * @private
+ * The site that this entry is currently managing. Only non-empty if this
+ * is for editing an existing entry.
+ * @type {?string}
*/
- validate_: function() {
- // If input is empty, disable the action button, but don't show the red
- // invalid message.
- if (this.site_.trim().length == 0) {
- this.inputInvalid_ = false;
- return;
- }
-
- const valid = patternRegExp.test(this.site_);
- this.inputInvalid_ = !valid;
+ currentSite: {
+ type: String,
+ value: null,
},
/**
- * @return {string}
- * @private
+ * Whether the dialog should update the host access to be "on specific
+ * sites" before adding a new host permission.
*/
- computeDialogTitle_: function() {
- const stringId = this.currentSite === null ? 'runtimeHostsDialogTitle' :
- 'hostPermissionsEdit';
- return loadTimeData.getString(stringId);
+ updateHostAccess: {
+ type: Boolean,
+ value: false,
},
/**
- * @return {boolean}
+ * The site to add an exception for.
* @private
*/
- computeSubmitButtonDisabled_: function() {
- return this.inputInvalid_ || this.site_ === undefined ||
- this.site_.trim().length == 0;
- },
+ site_: String,
/**
- * @return {string}
+ * Whether the currently-entered input is valid.
* @private
*/
- computeSubmitButtonLabel_: function() {
- const stringId = this.currentSite === null ? 'add' : 'save';
- return loadTimeData.getString(stringId);
+ inputInvalid_: {
+ type: Boolean,
+ value: false,
},
-
- /** @private */
- onCancelTap_: function() {
- this.$.dialog.cancel();
- },
-
- /**
- * The tap handler for the submit button (adds the pattern and closes
- * the dialog).
- * @private
- */
- onSubmitTap_: function() {
- if (this.currentSite !== null) {
- this.handleEdit_();
- } else {
- this.handleAdd_();
- }
- },
-
- /**
- * Handles adding a new site entry.
- * @private
- */
- handleAdd_: function() {
- assert(!this.currentSite);
-
- if (this.updateHostAccess) {
- this.delegate.setItemHostAccess(
- this.itemId, chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES);
- }
-
- this.addPermission_();
- },
-
- /**
- * Handles editing an existing site entry.
- * @private
- */
- handleEdit_: function() {
- assert(this.currentSite);
- assert(
- !this.updateHostAccess,
- 'Editing host permissions should only be possible if the host ' +
- 'access is already set to specific sites.');
-
- if (this.currentSite == this.site_) {
- // No change in values, so no need to update anything.
- this.$.dialog.close();
- return;
- }
-
- // Editing an existing entry is done by removing the current site entry,
- // and then adding the new one.
- this.delegate.removeRuntimeHostPermission(this.itemId, this.currentSite)
- .then(() => {
- this.addPermission_();
- });
- },
-
- /**
- * Adds the runtime host permission through the delegate. If successful,
- * closes the dialog; otherwise displays the invalid input message.
- * @private
- */
- addPermission_: function() {
- const pattern = getPatternFromSite(this.site_);
- this.delegate.addRuntimeHostPermission(this.itemId, pattern)
- .then(
- () => {
- this.$.dialog.close();
- },
- () => {
- this.inputInvalid_ = true;
- });
- },
- });
-
- return {
- RuntimeHostsDialog: RuntimeHostsDialog,
- getPatternFromSite: getPatternFromSite
- };
+ },
+
+ /** @override */
+ attached: function() {
+ if (this.currentSite !== null && this.currentSite !== undefined) {
+ this.site_ = this.currentSite;
+ this.validate_();
+ }
+ this.$.dialog.showModal();
+ },
+
+ /** @return {boolean} */
+ isOpen: function() {
+ return this.$.dialog.open;
+ },
+
+ /**
+ * Validates that the pattern entered is valid.
+ * @private
+ */
+ validate_: function() {
+ // If input is empty, disable the action button, but don't show the red
+ // invalid message.
+ if (this.site_.trim().length == 0) {
+ this.inputInvalid_ = false;
+ return;
+ }
+
+ const valid = patternRegExp.test(this.site_);
+ this.inputInvalid_ = !valid;
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ computeDialogTitle_: function() {
+ const stringId = this.currentSite === null ? 'runtimeHostsDialogTitle' :
+ 'hostPermissionsEdit';
+ return loadTimeData.getString(stringId);
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ computeSubmitButtonDisabled_: function() {
+ return this.inputInvalid_ || this.site_ === undefined ||
+ this.site_.trim().length == 0;
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ computeSubmitButtonLabel_: function() {
+ const stringId = this.currentSite === null ? 'add' : 'save';
+ return loadTimeData.getString(stringId);
+ },
+
+ /** @private */
+ onCancelTap_: function() {
+ this.$.dialog.cancel();
+ },
+
+ /**
+ * The tap handler for the submit button (adds the pattern and closes
+ * the dialog).
+ * @private
+ */
+ onSubmitTap_: function() {
+ if (this.currentSite !== null) {
+ this.handleEdit_();
+ } else {
+ this.handleAdd_();
+ }
+ },
+
+ /**
+ * Handles adding a new site entry.
+ * @private
+ */
+ handleAdd_: function() {
+ assert(!this.currentSite);
+
+ if (this.updateHostAccess) {
+ this.delegate.setItemHostAccess(
+ this.itemId, chrome.developerPrivate.HostAccess.ON_SPECIFIC_SITES);
+ }
+
+ this.addPermission_();
+ },
+
+ /**
+ * Handles editing an existing site entry.
+ * @private
+ */
+ handleEdit_: function() {
+ assert(this.currentSite);
+ assert(
+ !this.updateHostAccess,
+ 'Editing host permissions should only be possible if the host ' +
+ 'access is already set to specific sites.');
+
+ if (this.currentSite == this.site_) {
+ // No change in values, so no need to update anything.
+ this.$.dialog.close();
+ return;
+ }
+
+ // Editing an existing entry is done by removing the current site entry,
+ // and then adding the new one.
+ this.delegate.removeRuntimeHostPermission(this.itemId, this.currentSite)
+ .then(() => {
+ this.addPermission_();
+ });
+ },
+
+ /**
+ * Adds the runtime host permission through the delegate. If successful,
+ * closes the dialog; otherwise displays the invalid input message.
+ * @private
+ */
+ addPermission_: function() {
+ const pattern = getPatternFromSite(this.site_);
+ this.delegate.addRuntimeHostPermission(this.itemId, pattern)
+ .then(
+ () => {
+ this.$.dialog.close();
+ },
+ () => {
+ this.inputInvalid_ = true;
+ });
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/service.html b/chromium/chrome/browser/resources/extensions/service.html
deleted file mode 100644
index 21bf453e676..00000000000
--- a/chromium/chrome/browser/resources/extensions/service.html
+++ /dev/null
@@ -1,6 +0,0 @@
-<link rel="import" href="chrome://resources/html/assert.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="strings.html">
-<link rel="import" href="item.html">
-<link rel="import" href="navigation_helper.html">
-<script src="service.js"></script>
diff --git a/chromium/chrome/browser/resources/extensions/service.js b/chromium/chrome/browser/resources/extensions/service.js
index 1acc69798be..0e1e52cb28d 100644
--- a/chromium/chrome/browser/resources/extensions/service.js
+++ b/chromium/chrome/browser/resources/extensions/service.js
@@ -2,457 +2,462 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
-
- /**
- * @implements {extensions.ActivityLogDelegate}
- * @implements {extensions.ActivityLogEventDelegate}
- * @implements {extensions.ErrorPageDelegate}
- * @implements {extensions.ItemDelegate}
- * @implements {extensions.KeyboardShortcutDelegate}
- * @implements {extensions.LoadErrorDelegate}
- * @implements {extensions.PackDialogDelegate}
- * @implements {extensions.ToolbarDelegate}
- */
- class Service {
- constructor() {
- /** @private {boolean} */
- this.isDeleting_ = false;
+import {assert} from 'chrome://resources/js/assert.m.js';
+import {addSingletonGetter} from 'chrome://resources/js/cr.m.js';
+
+import {ActivityLogDelegate} from './activity_log/activity_log_history.js';
+import {ActivityLogEventDelegate} from './activity_log/activity_log_stream.js';
+import {ErrorPageDelegate} from './error_page.js';
+import {ItemDelegate} from './item.js';
+import {KeyboardShortcutDelegate} from './keyboard_shortcut_delegate.js';
+import {LoadErrorDelegate} from './load_error.js';
+import {Dialog, navigation, Page} from './navigation_helper.js';
+import {PackDialogDelegate} from './pack_dialog.js';
+import {ToolbarDelegate} from './toolbar.js';
+
+
+/**
+ * @implements {ActivityLogDelegate}
+ * @implements {ActivityLogEventDelegate}
+ * @implements {ErrorPageDelegate}
+ * @implements {ItemDelegate}
+ * @implements {KeyboardShortcutDelegate}
+ * @implements {LoadErrorDelegate}
+ * @implements {PackDialogDelegate}
+ * @implements {ToolbarDelegate}
+ */
+export class Service {
+ constructor() {
+ /** @private {boolean} */
+ this.isDeleting_ = false;
+
+ /** @private {!Set<string>} */
+ this.eventsToIgnoreOnce_ = new Set();
+ }
- /** @private {!Set<string>} */
- this.eventsToIgnoreOnce_ = new Set();
- }
+ getProfileConfiguration() {
+ return new Promise(function(resolve, reject) {
+ chrome.developerPrivate.getProfileConfiguration(resolve);
+ });
+ }
- getProfileConfiguration() {
- return new Promise(function(resolve, reject) {
- chrome.developerPrivate.getProfileConfiguration(resolve);
- });
- }
+ getItemStateChangedTarget() {
+ return chrome.developerPrivate.onItemStateChanged;
+ }
- getItemStateChangedTarget() {
- return chrome.developerPrivate.onItemStateChanged;
- }
+ /**
+ * @param {string} extensionId
+ * @param {!chrome.developerPrivate.EventType} eventType
+ * @return {boolean}
+ */
+ shouldIgnoreUpdate(extensionId, eventType) {
+ return this.eventsToIgnoreOnce_.delete(`${extensionId}_${eventType}`);
+ }
- /**
- * @param {string} extensionId
- * @param {!chrome.developerPrivate.EventType} eventType
- * @return {boolean}
- */
- shouldIgnoreUpdate(extensionId, eventType) {
- return this.eventsToIgnoreOnce_.delete(`${extensionId}_${eventType}`);
- }
+ /**
+ * @param {string} extensionId
+ * @param {!chrome.developerPrivate.EventType} eventType
+ */
+ ignoreNextEvent(extensionId, eventType) {
+ this.eventsToIgnoreOnce_.add(`${extensionId}_${eventType}`);
+ }
- /**
- * @param {string} extensionId
- * @param {!chrome.developerPrivate.EventType} eventType
- */
- ignoreNextEvent(extensionId, eventType) {
- this.eventsToIgnoreOnce_.add(`${extensionId}_${eventType}`);
- }
+ getProfileStateChangedTarget() {
+ return chrome.developerPrivate.onProfileStateChanged;
+ }
- getProfileStateChangedTarget() {
- return chrome.developerPrivate.onProfileStateChanged;
- }
+ getExtensionsInfo() {
+ return new Promise(function(resolve, reject) {
+ chrome.developerPrivate.getExtensionsInfo(
+ {includeDisabled: true, includeTerminated: true}, resolve);
+ });
+ }
- getExtensionsInfo() {
- return new Promise(function(resolve, reject) {
- chrome.developerPrivate.getExtensionsInfo(
- {includeDisabled: true, includeTerminated: true}, resolve);
- });
- }
+ /** @override */
+ getExtensionSize(id) {
+ return new Promise(function(resolve, reject) {
+ chrome.developerPrivate.getExtensionSize(id, resolve);
+ });
+ }
- /** @override */
- getExtensionSize(id) {
- return new Promise(function(resolve, reject) {
- chrome.developerPrivate.getExtensionSize(id, resolve);
+ /** @override */
+ addRuntimeHostPermission(id, host) {
+ return new Promise((resolve, reject) => {
+ chrome.developerPrivate.addHostPermission(id, host, () => {
+ if (chrome.runtime.lastError) {
+ reject(chrome.runtime.lastError.message);
+ return;
+ }
+ resolve();
});
- }
+ });
+ }
- /** @override */
- addRuntimeHostPermission(id, host) {
- return new Promise((resolve, reject) => {
- chrome.developerPrivate.addHostPermission(id, host, () => {
- if (chrome.runtime.lastError) {
- reject(chrome.runtime.lastError.message);
- return;
- }
- resolve();
- });
+ /** @override */
+ removeRuntimeHostPermission(id, host) {
+ return new Promise((resolve, reject) => {
+ chrome.developerPrivate.removeHostPermission(id, host, () => {
+ if (chrome.runtime.lastError) {
+ reject(chrome.runtime.lastError.message);
+ return;
+ }
+ resolve();
});
- }
+ });
+ }
- /** @override */
- removeRuntimeHostPermission(id, host) {
- return new Promise((resolve, reject) => {
- chrome.developerPrivate.removeHostPermission(id, host, () => {
- if (chrome.runtime.lastError) {
- reject(chrome.runtime.lastError.message);
- return;
- }
- resolve();
- });
+ /**
+ * Opens a file browser dialog for the user to select a file (or directory).
+ * @param {chrome.developerPrivate.SelectType} selectType
+ * @param {chrome.developerPrivate.FileType} fileType
+ * @return {Promise<string>} The promise to be resolved with the selected
+ * path.
+ */
+ chooseFilePath_(selectType, fileType) {
+ return new Promise(function(resolve, reject) {
+ chrome.developerPrivate.choosePath(selectType, fileType, function(path) {
+ if (chrome.runtime.lastError &&
+ chrome.runtime.lastError != 'File selection was canceled.') {
+ reject(chrome.runtime.lastError);
+ } else {
+ resolve(path || '');
+ }
});
- }
+ });
+ }
- /**
- * Opens a file browser dialog for the user to select a file (or directory).
- * @param {chrome.developerPrivate.SelectType} selectType
- * @param {chrome.developerPrivate.FileType} fileType
- * @return {Promise<string>} The promise to be resolved with the selected
- * path.
- */
- chooseFilePath_(selectType, fileType) {
- return new Promise(function(resolve, reject) {
- chrome.developerPrivate.choosePath(
- selectType, fileType, function(path) {
- if (chrome.runtime.lastError &&
- chrome.runtime.lastError != 'File selection was canceled.') {
- reject(chrome.runtime.lastError);
- } else {
- resolve(path || '');
- }
- });
- });
- }
+ /** @override */
+ updateExtensionCommandKeybinding(extensionId, commandName, keybinding) {
+ chrome.developerPrivate.updateExtensionCommand({
+ extensionId: extensionId,
+ commandName: commandName,
+ keybinding: keybinding,
+ });
+ }
- /** @override */
- updateExtensionCommandKeybinding(extensionId, commandName, keybinding) {
- chrome.developerPrivate.updateExtensionCommand({
- extensionId: extensionId,
- commandName: commandName,
- keybinding: keybinding,
- });
- }
+ /** @override */
+ updateExtensionCommandScope(extensionId, commandName, scope) {
+ // The COMMAND_REMOVED event needs to be ignored since it is sent before
+ // the command is added back with the updated scope but can be handled
+ // after the COMMAND_ADDED event.
+ this.ignoreNextEvent(
+ extensionId, chrome.developerPrivate.EventType.COMMAND_REMOVED);
+ chrome.developerPrivate.updateExtensionCommand({
+ extensionId: extensionId,
+ commandName: commandName,
+ scope: scope,
+ });
+ }
- /** @override */
- updateExtensionCommandScope(extensionId, commandName, scope) {
- // The COMMAND_REMOVED event needs to be ignored since it is sent before
- // the command is added back with the updated scope but can be handled
- // after the COMMAND_ADDED event.
- this.ignoreNextEvent(
- extensionId, chrome.developerPrivate.EventType.COMMAND_REMOVED);
- chrome.developerPrivate.updateExtensionCommand({
- extensionId: extensionId,
- commandName: commandName,
- scope: scope,
- });
- }
+ /** @override */
+ setShortcutHandlingSuspended(isCapturing) {
+ chrome.developerPrivate.setShortcutHandlingSuspended(isCapturing);
+ }
- /** @override */
- setShortcutHandlingSuspended(isCapturing) {
- chrome.developerPrivate.setShortcutHandlingSuspended(isCapturing);
- }
+ /**
+ * @param {chrome.developerPrivate.LoadUnpackedOptions=} opt_options
+ * @return {!Promise} A signal that loading finished, rejected if any error
+ * occurred.
+ * @private
+ */
+ loadUnpackedHelper_(opt_options) {
+ return new Promise(function(resolve, reject) {
+ const options = Object.assign(
+ {
+ failQuietly: true,
+ populateError: true,
+ },
+ opt_options);
+
+ chrome.developerPrivate.loadUnpacked(options, (loadError) => {
+ if (chrome.runtime.lastError &&
+ chrome.runtime.lastError.message !=
+ 'File selection was canceled.') {
+ throw new Error(chrome.runtime.lastError.message);
+ }
+ if (loadError) {
+ return reject(loadError);
+ }
- /**
- * @param {chrome.developerPrivate.LoadUnpackedOptions=} opt_options
- * @return {!Promise} A signal that loading finished, rejected if any error
- * occurred.
- * @private
- */
- loadUnpackedHelper_(opt_options) {
- return new Promise(function(resolve, reject) {
- const options = Object.assign(
- {
- failQuietly: true,
- populateError: true,
- },
- opt_options);
-
- chrome.developerPrivate.loadUnpacked(
- options, (loadError) => {
- if (chrome.runtime.lastError &&
- chrome.runtime.lastError.message !=
- 'File selection was canceled.') {
- throw new Error(chrome.runtime.lastError.message);
- }
- if (loadError) {
- return reject(loadError);
- }
-
- resolve();
- });
+ resolve();
});
- }
+ });
+ }
- /** @override */
- deleteItem(id) {
- if (this.isDeleting_) {
- return;
- }
- this.isDeleting_ = true;
- chrome.management.uninstall(id, {showConfirmDialog: true}, () => {
- // The "last error" was almost certainly the user canceling the dialog.
- // Do nothing. We only check it so we don't get noisy logs.
- /** @suppress {suspiciousCode} */
- chrome.runtime.lastError;
- this.isDeleting_ = false;
- });
- }
+ /** @override */
+ deleteItem(id) {
+ if (this.isDeleting_) {
+ return;
+ }
+ this.isDeleting_ = true;
+ chrome.management.uninstall(id, {showConfirmDialog: true}, () => {
+ // The "last error" was almost certainly the user canceling the dialog.
+ // Do nothing. We only check it so we don't get noisy logs.
+ /** @suppress {suspiciousCode} */
+ chrome.runtime.lastError;
+ this.isDeleting_ = false;
+ });
+ }
- /** @override */
- setItemEnabled(id, isEnabled) {
- chrome.management.setEnabled(id, isEnabled);
- }
+ /** @override */
+ setItemEnabled(id, isEnabled) {
+ chrome.management.setEnabled(id, isEnabled);
+ }
- /** @override */
- setItemAllowedIncognito(id, isAllowedIncognito) {
- chrome.developerPrivate.updateExtensionConfiguration({
- extensionId: id,
- incognitoAccess: isAllowedIncognito,
- });
- }
+ /** @override */
+ setItemAllowedIncognito(id, isAllowedIncognito) {
+ chrome.developerPrivate.updateExtensionConfiguration({
+ extensionId: id,
+ incognitoAccess: isAllowedIncognito,
+ });
+ }
- /** @override */
- setItemAllowedOnFileUrls(id, isAllowedOnFileUrls) {
- chrome.developerPrivate.updateExtensionConfiguration({
- extensionId: id,
- fileAccess: isAllowedOnFileUrls,
- });
- }
+ /** @override */
+ setItemAllowedOnFileUrls(id, isAllowedOnFileUrls) {
+ chrome.developerPrivate.updateExtensionConfiguration({
+ extensionId: id,
+ fileAccess: isAllowedOnFileUrls,
+ });
+ }
- /** @override */
- setItemHostAccess(id, hostAccess) {
- chrome.developerPrivate.updateExtensionConfiguration({
- extensionId: id,
- hostAccess: hostAccess,
- });
- }
+ /** @override */
+ setItemHostAccess(id, hostAccess) {
+ chrome.developerPrivate.updateExtensionConfiguration({
+ extensionId: id,
+ hostAccess: hostAccess,
+ });
+ }
- /** @override */
- setItemCollectsErrors(id, collectsErrors) {
- chrome.developerPrivate.updateExtensionConfiguration({
- extensionId: id,
- errorCollection: collectsErrors,
- });
- }
+ /** @override */
+ setItemCollectsErrors(id, collectsErrors) {
+ chrome.developerPrivate.updateExtensionConfiguration({
+ extensionId: id,
+ errorCollection: collectsErrors,
+ });
+ }
- /** @override */
- inspectItemView(id, view) {
- chrome.developerPrivate.openDevTools({
- extensionId: id,
- renderProcessId: view.renderProcessId,
- renderViewId: view.renderViewId,
- incognito: view.incognito,
- });
- }
+ /** @override */
+ inspectItemView(id, view) {
+ chrome.developerPrivate.openDevTools({
+ extensionId: id,
+ renderProcessId: view.renderProcessId,
+ renderViewId: view.renderViewId,
+ incognito: view.incognito,
+ });
+ }
- /**
- * @param {string} url
- * @override
- */
- openUrl(url) {
- window.open(url);
- }
+ /**
+ * @param {string} url
+ * @override
+ */
+ openUrl(url) {
+ window.open(url);
+ }
- /** @override */
- reloadItem(id) {
- return new Promise(function(resolve, reject) {
- chrome.developerPrivate.reload(
- id, {failQuietly: true, populateErrorForUnpacked: true},
- (loadError) => {
- if (loadError) {
- reject(loadError);
- return;
- }
-
- resolve();
- });
- });
- }
+ /** @override */
+ reloadItem(id) {
+ return new Promise(function(resolve, reject) {
+ chrome.developerPrivate.reload(
+ id, {failQuietly: true, populateErrorForUnpacked: true},
+ (loadError) => {
+ if (loadError) {
+ reject(loadError);
+ return;
+ }
+
+ resolve();
+ });
+ });
+ }
- /** @override */
- repairItem(id) {
- chrome.developerPrivate.repairExtension(id);
- }
+ /** @override */
+ repairItem(id) {
+ chrome.developerPrivate.repairExtension(id);
+ }
- /** @override */
- showItemOptionsPage(extension) {
- assert(extension && extension.optionsPage);
- if (extension.optionsPage.openInTab) {
- chrome.developerPrivate.showOptions(extension.id);
- } else {
- extensions.navigation.navigateTo({
- page: extensions.Page.DETAILS,
- subpage: extensions.Dialog.OPTIONS,
- extensionId: extension.id,
- });
- }
+ /** @override */
+ showItemOptionsPage(extension) {
+ assert(extension && extension.optionsPage);
+ if (extension.optionsPage.openInTab) {
+ chrome.developerPrivate.showOptions(extension.id);
+ } else {
+ navigation.navigateTo({
+ page: Page.DETAILS,
+ subpage: Dialog.OPTIONS,
+ extensionId: extension.id,
+ });
}
+ }
- /** @override */
- setProfileInDevMode(inDevMode) {
- chrome.developerPrivate.updateProfileConfiguration(
- {inDeveloperMode: inDevMode});
- }
+ /** @override */
+ setProfileInDevMode(inDevMode) {
+ chrome.developerPrivate.updateProfileConfiguration(
+ {inDeveloperMode: inDevMode});
+ }
- /** @override */
- loadUnpacked() {
- return this.loadUnpackedHelper_();
- }
+ /** @override */
+ loadUnpacked() {
+ return this.loadUnpackedHelper_();
+ }
- /** @override */
- retryLoadUnpacked(retryGuid) {
- // Attempt to load an unpacked extension, optionally as another attempt at
- // a previously-specified load.
- return this.loadUnpackedHelper_({retryGuid: retryGuid});
- }
+ /** @override */
+ retryLoadUnpacked(retryGuid) {
+ // Attempt to load an unpacked extension, optionally as another attempt at
+ // a previously-specified load.
+ return this.loadUnpackedHelper_({retryGuid: retryGuid});
+ }
- /** @override */
- choosePackRootDirectory() {
- return this.chooseFilePath_(
- chrome.developerPrivate.SelectType.FOLDER,
- chrome.developerPrivate.FileType.LOAD);
- }
+ /** @override */
+ choosePackRootDirectory() {
+ return this.chooseFilePath_(
+ chrome.developerPrivate.SelectType.FOLDER,
+ chrome.developerPrivate.FileType.LOAD);
+ }
- /** @override */
- choosePrivateKeyPath() {
- return this.chooseFilePath_(
- chrome.developerPrivate.SelectType.FILE,
- chrome.developerPrivate.FileType.PEM);
- }
+ /** @override */
+ choosePrivateKeyPath() {
+ return this.chooseFilePath_(
+ chrome.developerPrivate.SelectType.FILE,
+ chrome.developerPrivate.FileType.PEM);
+ }
- /** @override */
- packExtension(rootPath, keyPath, flag, callback) {
- chrome.developerPrivate.packDirectory(rootPath, keyPath, flag, callback);
- }
+ /** @override */
+ packExtension(rootPath, keyPath, flag, callback) {
+ chrome.developerPrivate.packDirectory(rootPath, keyPath, flag, callback);
+ }
- /** @override */
- updateAllExtensions() {
- return new Promise((resolve) => {
- chrome.developerPrivate.autoUpdate(resolve);
- chrome.metricsPrivate.recordUserAction('Options_UpdateExtensions');
- });
- }
+ /** @override */
+ updateAllExtensions() {
+ return new Promise((resolve) => {
+ chrome.developerPrivate.autoUpdate(resolve);
+ chrome.metricsPrivate.recordUserAction('Options_UpdateExtensions');
+ });
+ }
- /** @override */
- deleteErrors(extensionId, errorIds, type) {
- chrome.developerPrivate.deleteExtensionErrors({
- extensionId: extensionId,
- errorIds: errorIds,
- type: type,
- });
- }
+ /** @override */
+ deleteErrors(extensionId, errorIds, type) {
+ chrome.developerPrivate.deleteExtensionErrors({
+ extensionId: extensionId,
+ errorIds: errorIds,
+ type: type,
+ });
+ }
- /** @override */
- requestFileSource(args) {
- return new Promise(function(resolve, reject) {
- chrome.developerPrivate.requestFileSource(args, resolve);
- });
- }
+ /** @override */
+ requestFileSource(args) {
+ return new Promise(function(resolve, reject) {
+ chrome.developerPrivate.requestFileSource(args, resolve);
+ });
+ }
- /** @override */
- showInFolder(id) {
- chrome.developerPrivate.showPath(id);
- }
+ /** @override */
+ showInFolder(id) {
+ chrome.developerPrivate.showPath(id);
+ }
- /** @override */
- getExtensionActivityLog(extensionId) {
- return new Promise(function(resolve, reject) {
- chrome.activityLogPrivate.getExtensionActivities(
- {
- activityType:
- chrome.activityLogPrivate.ExtensionActivityFilter.ANY,
- extensionId: extensionId
- },
- resolve);
- });
- }
+ /** @override */
+ getExtensionActivityLog(extensionId) {
+ return new Promise(function(resolve, reject) {
+ chrome.activityLogPrivate.getExtensionActivities(
+ {
+ activityType: chrome.activityLogPrivate.ExtensionActivityFilter.ANY,
+ extensionId: extensionId
+ },
+ resolve);
+ });
+ }
- /** @override */
- getFilteredExtensionActivityLog(extensionId, searchTerm) {
- const anyType = chrome.activityLogPrivate.ExtensionActivityFilter.ANY;
-
- // Construct one filter for each API call we will make: one for substring
- // search by api call, one for substring search by page URL, and one for
- // substring search by argument URL. % acts as a wildcard.
- const activityLogFilters = [
- {
- activityType: anyType,
- extensionId: extensionId,
- apiCall: `%${searchTerm}%`,
- },
- {
- activityType: anyType,
- extensionId: extensionId,
- pageUrl: `%${searchTerm}%`,
- },
- {
- activityType: anyType,
- extensionId: extensionId,
- argUrl: `%${searchTerm}%`
- }
- ];
-
- const promises = activityLogFilters.map(
- filter => new Promise(function(resolve, reject) {
- chrome.activityLogPrivate.getExtensionActivities(filter, resolve);
- }));
-
- return Promise.all(promises).then(results => {
- // We may have results that are present in one or more searches, so
- // we merge them here. We also assume that every distinct activity
- // id corresponds to exactly one activity.
- const activitiesById = new Map();
- for (const result of results) {
- for (const activity of result.activities) {
- activitiesById.set(activity.activityId, activity);
- }
- }
+ /** @override */
+ getFilteredExtensionActivityLog(extensionId, searchTerm) {
+ const anyType = chrome.activityLogPrivate.ExtensionActivityFilter.ANY;
- return {activities: Array.from(activitiesById.values())};
- });
- }
+ // Construct one filter for each API call we will make: one for substring
+ // search by api call, one for substring search by page URL, and one for
+ // substring search by argument URL. % acts as a wildcard.
+ const activityLogFilters = [
+ {
+ activityType: anyType,
+ extensionId: extensionId,
+ apiCall: `%${searchTerm}%`,
+ },
+ {
+ activityType: anyType,
+ extensionId: extensionId,
+ pageUrl: `%${searchTerm}%`,
+ },
+ {
+ activityType: anyType,
+ extensionId: extensionId,
+ argUrl: `%${searchTerm}%`
+ }
+ ];
+
+ const promises = activityLogFilters.map(
+ filter => new Promise(function(resolve, reject) {
+ chrome.activityLogPrivate.getExtensionActivities(filter, resolve);
+ }));
+
+ return Promise.all(promises).then(results => {
+ // We may have results that are present in one or more searches, so
+ // we merge them here. We also assume that every distinct activity
+ // id corresponds to exactly one activity.
+ const activitiesById = new Map();
+ for (const result of results) {
+ for (const activity of result.activities) {
+ activitiesById.set(activity.activityId, activity);
+ }
+ }
- /** @override */
- deleteActivitiesById(activityIds) {
- return new Promise(function(resolve, reject) {
- chrome.activityLogPrivate.deleteActivities(activityIds, resolve);
- });
- }
+ return {activities: Array.from(activitiesById.values())};
+ });
+ }
- /** @override */
- deleteActivitiesFromExtension(extensionId) {
- return new Promise(function(resolve, reject) {
- chrome.activityLogPrivate.deleteActivitiesByExtension(
- extensionId, resolve);
- });
- }
+ /** @override */
+ deleteActivitiesById(activityIds) {
+ return new Promise(function(resolve, reject) {
+ chrome.activityLogPrivate.deleteActivities(activityIds, resolve);
+ });
+ }
- /** @override */
- getOnExtensionActivity() {
- return chrome.activityLogPrivate.onExtensionActivity;
- }
+ /** @override */
+ deleteActivitiesFromExtension(extensionId) {
+ return new Promise(function(resolve, reject) {
+ chrome.activityLogPrivate.deleteActivitiesByExtension(
+ extensionId, resolve);
+ });
+ }
- /** @override */
- downloadActivities(rawActivityData, fileName) {
- const blob = new Blob([rawActivityData], {type: 'application/json'});
- const url = URL.createObjectURL(blob);
- const a = document.createElement('a');
- a.href = url;
- a.download = fileName;
- a.click();
- }
+ /** @override */
+ getOnExtensionActivity() {
+ return chrome.activityLogPrivate.onExtensionActivity;
+ }
- /**
- * Attempts to load an unpacked extension via a drag-n-drop gesture.
- * @return {!Promise}
- */
- loadUnpackedFromDrag() {
- return this.loadUnpackedHelper_({useDraggedPath: true});
- }
+ /** @override */
+ downloadActivities(rawActivityData, fileName) {
+ const blob = new Blob([rawActivityData], {type: 'application/json'});
+ const url = URL.createObjectURL(blob);
+ const a = document.createElement('a');
+ a.href = url;
+ a.download = fileName;
+ a.click();
+ }
- installDroppedFile() {
- chrome.developerPrivate.installDroppedFile();
- }
+ /**
+ * Attempts to load an unpacked extension via a drag-n-drop gesture.
+ * @return {!Promise}
+ */
+ loadUnpackedFromDrag() {
+ return this.loadUnpackedHelper_({useDraggedPath: true});
+ }
- notifyDragInstallInProgress() {
- chrome.developerPrivate.notifyDragInstallInProgress();
- }
+ installDroppedFile() {
+ chrome.developerPrivate.installDroppedFile();
}
- cr.addSingletonGetter(Service);
+ notifyDragInstallInProgress() {
+ chrome.developerPrivate.notifyDragInstallInProgress();
+ }
+}
- return {Service: Service};
-});
+addSingletonGetter(Service);
diff --git a/chromium/chrome/browser/resources/extensions/shared_style.html b/chromium/chrome/browser/resources/extensions/shared_style.html
index 0410a18c21b..41ca789f85c 100644
--- a/chromium/chrome/browser/resources/extensions/shared_style.html
+++ b/chromium/chrome/browser/resources/extensions/shared_style.html
@@ -1,86 +1,81 @@
-<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
-<link rel="import" href="shared_vars.html">
+<template>
+ <style include="cr-shared-style">
+ a[href] {
+ color: var(--cr-link-color);
+ text-decoration: none;
+ }
-<dom-module id="shared-style">
- <template>
- <style include="cr-shared-style">
- a[href] {
- color: var(--cr-link-color);
- text-decoration: none;
- }
+ .activity-message {
+ color: var(--md-loading-message-color);
+ font-size: 123%; /* Should be 16px when 100% is 13px. */
+ font-weight: 500;
+ margin-top: 80px;
+ text-align: center;
+ }
- .activity-message {
- color: var(--md-loading-message-color);
- font-size: 123%; /* Should be 16px when 100% is 13px. */
- font-weight: 500;
- margin-top: 80px;
- text-align: center;
- }
+ .activity-subpage-header {
+ display: flex;
+ justify-content: flex-end;
+ padding: 12px 12px;
+ }
- .activity-subpage-header {
- display: flex;
- justify-content: flex-end;
- padding: 12px 12px;
- }
+ .activity-table-headings {
+ align-items: center;
+ display: flex;
+ flex-direction: row;
+ font-weight: 500;
+ margin-inline-end: auto;
- .activity-table-headings {
- align-items: center;
- display: flex;
- flex-direction: row;
- font-weight: 500;
- margin-inline-end: auto;
+ /* Match separator height. */
+ min-height: calc(var(--cr-section-min-height) - var(--separator-gap));
+ padding: 0 var(--cr-section-padding);
+ }
- /* Match separator height. */
- min-height: calc(var(--cr-section-min-height) - var(--separator-gap));
- padding: 0 var(--cr-section-padding);
- }
+ .clear-activities-button {
+ margin: 0 8px;
+ }
- .clear-activities-button {
- margin: 0 8px;
- }
+ .page-container {
+ height: 100%;
+ overflow: overlay;
+ }
- .page-container {
- height: 100%;
- overflow: overlay;
- }
+ .page-content {
+ @apply --cr-card-elevation;
+ background-color: var(--cr-card-background-color);
+ box-sizing: border-box;
+ margin: auto;
+ min-height: 100%;
+ padding-bottom: 64px;
+ width: var(--cr-toolbar-field-width);
+ }
- .page-content {
- @apply --cr-card-elevation;
- background-color: var(--cr-card-background-color);
- box-sizing: border-box;
- margin: auto;
- min-height: 100%;
- padding-bottom: 64px;
- width: var(--cr-toolbar-field-width);
- }
+ .page-header {
+ align-items: center;
+ display: flex;
+ height: 40px;
+ margin-bottom: 12px;
+ padding: 8px 12px 0;
+ }
- .page-header {
- align-items: center;
- display: flex;
- height: 40px;
- margin-bottom: 12px;
- padding: 8px 12px 0;
- }
+ .link-icon-button {
+ align-items: center;
+ display: flex;
+ justify-content: center;
+ }
- .link-icon-button {
- align-items: center;
- display: flex;
- justify-content: center;
- }
+ .separator {
+ border-inline-start: var(--cr-separator-line);
+ flex-shrink: 0;
- .separator {
- border-inline-start: var(--cr-separator-line);
- flex-shrink: 0;
+ /* Section height - gap. */
+ height: calc(var(--cr-section-min-height) - var(--separator-gap));
+ margin-inline-end: var(--cr-section-padding);
- /* Section height - gap. */
- height: calc(var(--cr-section-min-height) - var(--separator-gap));
- margin-inline-end: var(--cr-section-padding);
-
- /* Makes the tappable area fill its parent.
- * TODO(crbug.com/949697): This is an explicit reminder to override
- * once .separator styling is extracted from settings. */
- margin-inline-start: 0;
- }
- </style>
- </template>
-</dom-module>
+ /* Makes the tappable area fill its parent.
+ * TODO(crbug.com/949697): This is an explicit reminder to override
+ * once .separator styling is extracted from settings. */
+ margin-inline-start: 0;
+ }
+ </style>
+</template>
diff --git a/chromium/chrome/browser/resources/extensions/shared_style.js b/chromium/chrome/browser/resources/extensions/shared_style.js
new file mode 100644
index 00000000000..3b6d04fc5e9
--- /dev/null
+++ b/chromium/chrome/browser/resources/extensions/shared_style.js
@@ -0,0 +1,12 @@
+// 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.
+
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+import './shared_vars.js';
+
+const template = document.createElement('template');
+template.innerHTML = `
+<dom-module id="shared-style">{__html_template__}</dom-module>
+`;
+document.body.appendChild(template.content.cloneNode(true));
diff --git a/chromium/chrome/browser/resources/extensions/shared_vars.html b/chromium/chrome/browser/resources/extensions/shared_vars.html
index 86b2870213f..b826b8a16d0 100644
--- a/chromium/chrome/browser/resources/extensions/shared_vars.html
+++ b/chromium/chrome/browser/resources/extensions/shared_vars.html
@@ -1,8 +1,3 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
-
-<link rel="import" href="chrome://resources/cr_elements/shared_vars_css.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
-
<custom-style>
<style>
html {
diff --git a/chromium/chrome/browser/resources/extensions/shared_vars.js b/chromium/chrome/browser/resources/extensions/shared_vars.js
new file mode 100644
index 00000000000..59a50b0cc6d
--- /dev/null
+++ b/chromium/chrome/browser/resources/extensions/shared_vars.js
@@ -0,0 +1,12 @@
+// 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.
+
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+import 'chrome://resources/polymer/v3_0/paper-styles/color.js';
+
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+const $_documentContainer = document.createElement('template');
+$_documentContainer.innerHTML = `{__html_template__}`;
+document.head.appendChild($_documentContainer.content);
diff --git a/chromium/chrome/browser/resources/extensions/shortcut_input.html b/chromium/chrome/browser/resources/extensions/shortcut_input.html
index d35415d4f8c..f2c4f4247fb 100644
--- a/chromium/chrome/browser/resources/extensions/shortcut_input.html
+++ b/chromium/chrome/browser/resources/extensions/shortcut_input.html
@@ -1,47 +1,31 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="cr-icons cr-hidden-style">
+ #main {
+ position: relative;
+ width: 200px;
+ }
-<link rel="import" href="chrome://resources/cr_elements/cr_icon_button/cr_icon_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_input/cr_input.html">
-<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
-<link rel="import" href="chrome://resources/html/assert.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/html/i18n_behavior.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
-<link rel="import" href="shortcut_util.html">
+ #clear {
+ --cr-icon-button-size: 28px;
+ position: absolute;
+ right: 2px;
+ }
-<dom-module id="extensions-shortcut-input">
- <template>
- <style include="cr-icons cr-hidden-style">
- #main {
- position: relative;
- width: 200px;
- }
-
- #clear {
- --cr-icon-button-size: 28px;
- position: absolute;
- right: 2px;
- }
-
- :host-context([dir='rtl']) #clear {
- left: -2px;
- right: inherit;
- }
- </style>
- <div id="main">
- <cr-input id="input" placeholder="$i18n{shortcutTypeAShortcut}"
- error-message="[[getErrorString_(error_,
- '$i18nPolymer{shortcutIncludeStartModifier}',
- '$i18nPolymer{shortcutTooManyModifiers}',
- '$i18nPolymer{shortcutNeedCharacter}')]]"
- value="[[computeText_(capturing_, shortcut, pendingShortcut_)]]">
- <cr-icon-button id="clear" aria-label="$i18nPolymer{clear}"
- slot="suffix" class="icon-cancel no-overlap"
- hidden$="[[computeClearHidden_(capturing_, shortcut)]]"
- on-click="onClearTap_"></cr-icon-button>
- </cr-input>
- </div>
- </template>
- <script src="shortcut_input.js"></script>
-</dom-module>
+ :host-context([dir='rtl']) #clear {
+ left: -2px;
+ right: inherit;
+ }
+</style>
+<div id="main">
+ <cr-input id="input" placeholder="$i18n{shortcutTypeAShortcut}"
+ invalid="[[getIsInvalid_(error_)]]"
+ error-message="[[getErrorString_(error_,
+ '$i18nPolymer{shortcutIncludeStartModifier}',
+ '$i18nPolymer{shortcutTooManyModifiers}',
+ '$i18nPolymer{shortcutNeedCharacter}')]]"
+ value="[[computeText_(capturing_, shortcut, pendingShortcut_)]]">
+ <cr-icon-button id="clear" aria-label="$i18nPolymer{clear}"
+ slot="suffix" class="icon-cancel no-overlap"
+ hidden$="[[computeClearHidden_(capturing_, shortcut)]]"
+ on-click="onClearTap_"></cr-icon-button>
+ </cr-input>
+</div>
diff --git a/chromium/chrome/browser/resources/extensions/shortcut_input.js b/chromium/chrome/browser/resources/extensions/shortcut_input.js
index 43f7d273ed1..6f56ac6c1aa 100644
--- a/chromium/chrome/browser/resources/extensions/shortcut_input.js
+++ b/chromium/chrome/browser/resources/extensions/shortcut_input.js
@@ -2,6 +2,18 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.m.js';
+import 'chrome://resources/cr_elements/cr_icons_css.m.js';
+import 'chrome://resources/cr_elements/cr_input/cr_input.m.js';
+import 'chrome://resources/cr_elements/hidden_style_css.m.js';
+import 'chrome://resources/polymer/v3_0/paper-styles/color.js';
+
+import {assert} from 'chrome://resources/js/assert.m.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {KeyboardShortcutDelegate} from './keyboard_shortcut_delegate.js';
+import {hasValidModifiers, isValidKeyCode, Key, keystrokeToString} from './shortcut_util.js';
+
/** @enum {number} */
const ShortcutError = {
NO_ERROR: 0,
@@ -10,228 +22,233 @@ const ShortcutError = {
NEED_CHARACTER: 3,
};
-cr.define('extensions', function() {
- 'use strict';
-
- // The UI to display and manage keyboard shortcuts set for extension commands.
- const ShortcutInput = Polymer({
- is: 'extensions-shortcut-input',
-
- properties: {
- /** @type {!extensions.KeyboardShortcutDelegate} */
- delegate: Object,
-
- item: {
- type: String,
- value: '',
- },
-
- commandName: {
- type: String,
- value: '',
- },
-
- shortcut: {
- type: String,
- value: '',
- },
-
- /** @private */
- capturing_: {
- type: Boolean,
- value: false,
- },
-
- /** @private {!ShortcutError} */
- error_: {
- type: Number,
- value: 0,
- },
-
- /** @private */
- pendingShortcut_: {
- type: String,
- value: '',
- },
- },
+// The UI to display and manage keyboard shortcuts set for extension commands.
+Polymer({
+ is: 'extensions-shortcut-input',
- /** @override */
- ready: function() {
- const node = this.$.input;
- node.addEventListener('mouseup', this.startCapture_.bind(this));
- node.addEventListener('blur', this.endCapture_.bind(this));
- node.addEventListener('focus', this.startCapture_.bind(this));
- node.addEventListener('keydown', this.onKeyDown_.bind(this));
- node.addEventListener('keyup', this.onKeyUp_.bind(this));
- },
+ _template: html`{__html_template__}`,
- /** @private */
- startCapture_: function() {
- if (this.capturing_) {
- return;
- }
- this.capturing_ = true;
- this.delegate.setShortcutHandlingSuspended(true);
- },
+ properties: {
+ /** @type {!KeyboardShortcutDelegate} */
+ delegate: Object,
- /** @private */
- endCapture_: function() {
- if (!this.capturing_) {
- return;
- }
- this.pendingShortcut_ = '';
- this.capturing_ = false;
- const input = this.$.input;
- input.blur();
- input.invalid = false;
- this.delegate.setShortcutHandlingSuspended(false);
+ item: {
+ type: String,
+ value: '',
},
- /**
- * @param {!KeyboardEvent} e
- * @private
- */
- onKeyDown_: function(e) {
- if (e.target == this.$.clear) {
- return;
- }
-
- if (e.keyCode == extensions.Key.Escape) {
- if (!this.capturing_) {
- // If we're not currently capturing, allow escape to propagate.
- return;
- }
- // Otherwise, escape cancels capturing.
- this.endCapture_();
- e.preventDefault();
- e.stopPropagation();
- return;
- }
- if (e.keyCode == extensions.Key.Tab) {
- // Allow tab propagation for keyboard navigation.
- return;
- }
-
- if (!this.capturing_) {
- this.startCapture_();
- }
-
- this.handleKey_(e);
+ commandName: {
+ type: String,
+ value: '',
},
- /**
- * @param {!KeyboardEvent} e
- * @private
- */
- onKeyUp_: function(e) {
- // Ignores pressing 'Space' or 'Enter' on the clear button. In 'Enter's
- // case, the clear button disappears before key-up, so 'Enter's key-up
- // target becomes the input field, not the clear button, and needs to
- // be caught explicitly.
- if (e.target == this.$.clear || e.key == 'Enter') {
- return;
- }
-
- if (e.keyCode == extensions.Key.Escape ||
- e.keyCode == extensions.Key.Tab) {
- return;
- }
-
- this.handleKey_(e);
- },
-
- /**
- * @param {!ShortcutError} error
- * @param {string} includeStartModifier
- * @param {string} tooManyModifiers
- * @param {string} needCharacter
- * @return {string} UI string.
- * @private
- */
- getErrorString_: function(
- error, includeStartModifier, tooManyModifiers, needCharacter) {
- if (error == ShortcutError.TOO_MANY_MODIFIERS) {
- return tooManyModifiers;
- }
- if (error == ShortcutError.NEED_CHARACTER) {
- return needCharacter;
- }
- return includeStartModifier;
- },
-
- /**
- * @param {!KeyboardEvent} e
- * @private
- */
- handleKey_: function(e) {
- // While capturing, we prevent all events from bubbling, to prevent
- // shortcuts lacking the right modifier (F3 for example) from activating
- // and ending capture prematurely.
- e.preventDefault();
- e.stopPropagation();
-
- // We don't allow both Ctrl and Alt in the same keybinding.
- // TODO(devlin): This really should go in extensions.hasValidModifiers,
- // but that requires updating the existing page as well.
- if (e.ctrlKey && e.altKey) {
- this.error_ = ShortcutError.TOO_MANY_MODIFIERS;
- this.$.input.invalid = true;
- return;
- }
- if (!extensions.hasValidModifiers(e)) {
- this.pendingShortcut_ = '';
- this.error_ = ShortcutError.INCLUDE_START_MODIFIER;
- this.$.input.invalid = true;
- return;
- }
- this.pendingShortcut_ = extensions.keystrokeToString(e);
- if (!extensions.isValidKeyCode(e.keyCode)) {
- this.error_ = ShortcutError.NEED_CHARACTER;
- this.$.input.invalid = true;
- return;
- }
- this.$.input.invalid = false;
-
- this.commitPending_();
- this.endCapture_();
+ shortcut: {
+ type: String,
+ value: '',
},
/** @private */
- commitPending_: function() {
- this.shortcut = this.pendingShortcut_;
- this.delegate.updateExtensionCommandKeybinding(
- this.item, this.commandName, this.shortcut);
- },
-
- /**
- * @return {string} The text to be displayed in the shortcut field.
- * @private
- */
- computeText_: function() {
- const shortcutString =
- this.capturing_ ? this.pendingShortcut_ : this.shortcut;
- return shortcutString.split('+').join(' + ');
+ capturing_: {
+ type: Boolean,
+ value: false,
},
- /**
- * @return {boolean} Whether the clear button is hidden.
- * @private
- */
- computeClearHidden_: function() {
- // We don't want to show the clear button if the input is currently
- // capturing a new shortcut or if there is no shortcut to clear.
- return this.capturing_ || !this.shortcut;
+ /** @private {!ShortcutError} */
+ error_: {
+ type: Number,
+ value: ShortcutError.NO_ERROR,
},
/** @private */
- onClearTap_: function() {
- assert(this.shortcut);
-
- this.pendingShortcut_ = '';
- this.commitPending_();
- this.endCapture_();
+ pendingShortcut_: {
+ type: String,
+ value: '',
},
- });
-
- return {ShortcutInput: ShortcutInput};
+ },
+
+ /** @override */
+ ready: function() {
+ const node = this.$.input;
+ node.addEventListener('mouseup', this.startCapture_.bind(this));
+ node.addEventListener('blur', this.endCapture_.bind(this));
+ node.addEventListener('focus', this.startCapture_.bind(this));
+ node.addEventListener('keydown', this.onKeyDown_.bind(this));
+ node.addEventListener('keyup', this.onKeyUp_.bind(this));
+ },
+
+ /** @private */
+ startCapture_: function() {
+ if (this.capturing_) {
+ return;
+ }
+ this.capturing_ = true;
+ this.delegate.setShortcutHandlingSuspended(true);
+ },
+
+ /** @private */
+ endCapture_: function() {
+ if (!this.capturing_) {
+ return;
+ }
+ this.pendingShortcut_ = '';
+ this.capturing_ = false;
+ const input = this.$.input;
+ input.blur();
+ this.error_ = ShortcutError.NO_ERROR;
+ this.delegate.setShortcutHandlingSuspended(false);
+ },
+
+ /**
+ * @param {!Event} e
+ * @private
+ */
+ onKeyDown_: function(e) {
+ if (e.target == this.$.clear) {
+ return;
+ }
+
+ if (e.keyCode == Key.Escape) {
+ if (!this.capturing_) {
+ // If we're not currently capturing, allow escape to propagate.
+ return;
+ }
+ // Otherwise, escape cancels capturing.
+ this.endCapture_();
+ e.preventDefault();
+ e.stopPropagation();
+ return;
+ }
+ if (e.keyCode == Key.Tab) {
+ // Allow tab propagation for keyboard navigation.
+ return;
+ }
+
+ if (!this.capturing_) {
+ this.startCapture_();
+ }
+
+ this.handleKey_(/** @type {!KeyboardEvent} */ (e));
+ },
+
+ /**
+ * @param {!Event} e
+ * @private
+ */
+ onKeyUp_: function(e) {
+ // Ignores pressing 'Space' or 'Enter' on the clear button. In 'Enter's
+ // case, the clear button disappears before key-up, so 'Enter's key-up
+ // target becomes the input field, not the clear button, and needs to
+ // be caught explicitly.
+ if (e.target == this.$.clear || e.key == 'Enter') {
+ return;
+ }
+
+ if (e.keyCode == Key.Escape || e.keyCode == Key.Tab) {
+ return;
+ }
+
+ this.handleKey_(/** @type {!KeyboardEvent} */ (e));
+ },
+
+ /**
+ * @param {!ShortcutError} error
+ * @param {string} includeStartModifier
+ * @param {string} tooManyModifiers
+ * @param {string} needCharacter
+ * @return {string} UI string.
+ * @private
+ */
+ getErrorString_: function(
+ error, includeStartModifier, tooManyModifiers, needCharacter) {
+ switch (this.error_) {
+ case ShortcutError.INCLUDE_START_MODIFIER:
+ return includeStartModifier;
+ case ShortcutError.TOO_MANY_MODIFIERS:
+ return tooManyModifiers;
+ case ShortcutError.NEED_CHARACTER:
+ return needCharacter;
+ default:
+ assert(this.error_ == ShortcutError.NO_ERROR);
+ return '';
+ }
+ },
+
+ /**
+ * @param {!KeyboardEvent} e
+ * @private
+ */
+ handleKey_: function(e) {
+ // While capturing, we prevent all events from bubbling, to prevent
+ // shortcuts lacking the right modifier (F3 for example) from activating
+ // and ending capture prematurely.
+ e.preventDefault();
+ e.stopPropagation();
+
+ // We don't allow both Ctrl and Alt in the same keybinding.
+ // TODO(devlin): This really should go in hasValidModifiers,
+ // but that requires updating the existing page as well.
+ if (e.ctrlKey && e.altKey) {
+ this.error_ = ShortcutError.TOO_MANY_MODIFIERS;
+ return;
+ }
+ if (!hasValidModifiers(e)) {
+ this.pendingShortcut_ = '';
+ this.error_ = ShortcutError.INCLUDE_START_MODIFIER;
+ return;
+ }
+ this.pendingShortcut_ = keystrokeToString(e);
+ if (!isValidKeyCode(e.keyCode)) {
+ this.error_ = ShortcutError.NEED_CHARACTER;
+ return;
+ }
+
+ this.error_ = ShortcutError.NO_ERROR;
+
+ this.commitPending_();
+ this.endCapture_();
+ },
+
+ /** @private */
+ commitPending_: function() {
+ this.shortcut = this.pendingShortcut_;
+ this.delegate.updateExtensionCommandKeybinding(
+ this.item, this.commandName, this.shortcut);
+ },
+
+ /**
+ * @return {string} The text to be displayed in the shortcut field.
+ * @private
+ */
+ computeText_: function() {
+ const shortcutString =
+ this.capturing_ ? this.pendingShortcut_ : this.shortcut;
+ return shortcutString.split('+').join(' + ');
+ },
+
+ /**
+ * @return {boolean} Whether the clear button is hidden.
+ * @private
+ */
+ computeClearHidden_: function() {
+ // We don't want to show the clear button if the input is currently
+ // capturing a new shortcut or if there is no shortcut to clear.
+ return this.capturing_ || !this.shortcut;
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ getIsInvalid_: function() {
+ return this.error_ != ShortcutError.NO_ERROR;
+ },
+
+ /** @private */
+ onClearTap_: function() {
+ assert(this.shortcut);
+
+ this.pendingShortcut_ = '';
+ this.commitPending_();
+ this.endCapture_();
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/shortcut_util.html b/chromium/chrome/browser/resources/extensions/shortcut_util.html
deleted file mode 100644
index e44359faac7..00000000000
--- a/chromium/chrome/browser/resources/extensions/shortcut_util.html
+++ /dev/null
@@ -1,3 +0,0 @@
-<link rel="import" href="chrome://resources/html/assert.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<script src="shortcut_util.js"></script>
diff --git a/chromium/chrome/browser/resources/extensions/shortcut_util.js b/chromium/chrome/browser/resources/extensions/shortcut_util.js
index 05bb904c9bd..0f61a402dab 100644
--- a/chromium/chrome/browser/resources/extensions/shortcut_util.js
+++ b/chromium/chrome/browser/resources/extensions/shortcut_util.js
@@ -2,202 +2,198 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
+import {assertNotReached} from 'chrome://resources/js/assert.m.js';
+import {isChromeOS, isMac} from 'chrome://resources/js/cr.m.js';
- /** @enum {number} */
- const Key = {
- Comma: 188,
- Del: 46,
- Down: 40,
- End: 35,
- Escape: 27,
- Home: 36,
- Ins: 45,
- Left: 37,
- MediaNextTrack: 176,
- MediaPlayPause: 179,
- MediaPrevTrack: 177,
- MediaStop: 178,
- PageDown: 34,
- PageUp: 33,
- Period: 190,
- Right: 39,
- Space: 32,
- Tab: 9,
- Up: 38,
- };
- /**
- * Enum for whether we require modifiers of a keycode.
- * @enum {number}
- */
- const ModifierPolicy = {NOT_ALLOWED: 0, REQUIRED: 1};
+/** @enum {number} */
+export const Key = {
+ Comma: 188,
+ Del: 46,
+ Down: 40,
+ End: 35,
+ Escape: 27,
+ Home: 36,
+ Ins: 45,
+ Left: 37,
+ MediaNextTrack: 176,
+ MediaPlayPause: 179,
+ MediaPrevTrack: 177,
+ MediaStop: 178,
+ PageDown: 34,
+ PageUp: 33,
+ Period: 190,
+ Right: 39,
+ Space: 32,
+ Tab: 9,
+ Up: 38,
+};
- /**
- * Gets the ModifierPolicy. Currently only "MediaNextTrack", "MediaPrevTrack",
- * "MediaStop", "MediaPlayPause" are required to be used without any modifier.
- * @param {number} keyCode
- * @return {ModifierPolicy}
- */
- function getModifierPolicy(keyCode) {
- switch (keyCode) {
- case Key.MediaNextTrack:
- case Key.MediaPlayPause:
- case Key.MediaPrevTrack:
- case Key.MediaStop:
- return ModifierPolicy.NOT_ALLOWED;
- default:
- return ModifierPolicy.REQUIRED;
- }
- }
+/**
+ * Enum for whether we require modifiers of a keycode.
+ * @enum {number}
+ */
+const ModifierPolicy = {
+ NOT_ALLOWED: 0,
+ REQUIRED: 1
+};
- /**
- * Returns whether the keyboard event has a key modifier, which could affect
- * how it's handled.
- * @param {!KeyboardEvent} e
- * @param {boolean} countShiftAsModifier Whether the 'Shift' key should be
- * counted as modifier.
- * @return {boolean} True if the event has any modifiers.
- */
- function hasModifier(e, countShiftAsModifier) {
- return e.ctrlKey || e.altKey ||
- // Meta key is only relevant on Mac and CrOS, where we treat Command
- // and Search (respectively) as modifiers.
- (cr.isMac && e.metaKey) || (cr.isChromeOS && e.metaKey) ||
- (countShiftAsModifier && e.shiftKey);
+/**
+ * Gets the ModifierPolicy. Currently only "MediaNextTrack", "MediaPrevTrack",
+ * "MediaStop", "MediaPlayPause" are required to be used without any modifier.
+ * @param {number} keyCode
+ * @return {ModifierPolicy}
+ */
+function getModifierPolicy(keyCode) {
+ switch (keyCode) {
+ case Key.MediaNextTrack:
+ case Key.MediaPlayPause:
+ case Key.MediaPrevTrack:
+ case Key.MediaStop:
+ return ModifierPolicy.NOT_ALLOWED;
+ default:
+ return ModifierPolicy.REQUIRED;
}
+}
- /**
- * Checks whether the passed in |keyCode| is a valid extension command key.
- * @param {number} keyCode
- * @return {boolean} Whether the key is valid.
- */
- function isValidKeyCode(keyCode) {
- if (keyCode == Key.Escape) {
- return false;
- }
- for (const k in Key) {
- if (Key[k] == keyCode) {
- return true;
- }
+/**
+ * Returns whether the keyboard event has a key modifier, which could affect
+ * how it's handled.
+ * @param {!KeyboardEvent} e
+ * @param {boolean} countShiftAsModifier Whether the 'Shift' key should be
+ * counted as modifier.
+ * @return {boolean} True if the event has any modifiers.
+ */
+function hasModifier(e, countShiftAsModifier) {
+ return e.ctrlKey || e.altKey ||
+ // Meta key is only relevant on Mac and CrOS, where we treat Command
+ // and Search (respectively) as modifiers.
+ (isMac && e.metaKey) || (isChromeOS && e.metaKey) ||
+ (countShiftAsModifier && e.shiftKey);
+}
+
+/**
+ * Checks whether the passed in |keyCode| is a valid extension command key.
+ * @param {number} keyCode
+ * @return {boolean} Whether the key is valid.
+ */
+export function isValidKeyCode(keyCode) {
+ if (keyCode == Key.Escape) {
+ return false;
+ }
+ for (const k in Key) {
+ if (Key[k] == keyCode) {
+ return true;
}
- return (keyCode >= 'A'.charCodeAt(0) && keyCode <= 'Z'.charCodeAt(0)) ||
- (keyCode >= '0'.charCodeAt(0) && keyCode <= '9'.charCodeAt(0));
}
+ return (keyCode >= 'A'.charCodeAt(0) && keyCode <= 'Z'.charCodeAt(0)) ||
+ (keyCode >= '0'.charCodeAt(0) && keyCode <= '9'.charCodeAt(0));
+}
- /**
- * Converts a keystroke event to string form, ignoring invalid extension
- * commands.
- * @param {!KeyboardEvent} e
- * @return {string} The keystroke as a string.
- */
- function keystrokeToString(e) {
- const output = [];
- // TODO(devlin): Should this be i18n'd?
- if (cr.isMac && e.metaKey) {
- output.push('Command');
- }
- if (cr.isChromeOS && e.metaKey) {
- output.push('Search');
- }
- if (e.ctrlKey) {
- output.push('Ctrl');
- }
- if (!e.ctrlKey && e.altKey) {
- output.push('Alt');
- }
- if (e.shiftKey) {
- output.push('Shift');
- }
+/**
+ * Converts a keystroke event to string form, ignoring invalid extension
+ * commands.
+ * @param {!KeyboardEvent} e
+ * @return {string} The keystroke as a string.
+ */
+export function keystrokeToString(e) {
+ const output = [];
+ // TODO(devlin): Should this be i18n'd?
+ if (isMac && e.metaKey) {
+ output.push('Command');
+ }
+ if (isChromeOS && e.metaKey) {
+ output.push('Search');
+ }
+ if (e.ctrlKey) {
+ output.push('Ctrl');
+ }
+ if (!e.ctrlKey && e.altKey) {
+ output.push('Alt');
+ }
+ if (e.shiftKey) {
+ output.push('Shift');
+ }
- const keyCode = e.keyCode;
- if (isValidKeyCode(keyCode)) {
- if ((keyCode >= 'A'.charCodeAt(0) && keyCode <= 'Z'.charCodeAt(0)) ||
- (keyCode >= '0'.charCodeAt(0) && keyCode <= '9'.charCodeAt(0))) {
- output.push(String.fromCharCode(keyCode));
- } else {
- switch (keyCode) {
- case Key.Comma:
- output.push('Comma');
- break;
- case Key.Del:
- output.push('Delete');
- break;
- case Key.Down:
- output.push('Down');
- break;
- case Key.End:
- output.push('End');
- break;
- case Key.Home:
- output.push('Home');
- break;
- case Key.Ins:
- output.push('Insert');
- break;
- case Key.Left:
- output.push('Left');
- break;
- case Key.MediaNextTrack:
- output.push('MediaNextTrack');
- break;
- case Key.MediaPlayPause:
- output.push('MediaPlayPause');
- break;
- case Key.MediaPrevTrack:
- output.push('MediaPrevTrack');
- break;
- case Key.MediaStop:
- output.push('MediaStop');
- break;
- case Key.PageDown:
- output.push('PageDown');
- break;
- case Key.PageUp:
- output.push('PageUp');
- break;
- case Key.Period:
- output.push('Period');
- break;
- case Key.Right:
- output.push('Right');
- break;
- case Key.Space:
- output.push('Space');
- break;
- case Key.Tab:
- output.push('Tab');
- break;
- case Key.Up:
- output.push('Up');
- break;
- }
+ const keyCode = e.keyCode;
+ if (isValidKeyCode(keyCode)) {
+ if ((keyCode >= 'A'.charCodeAt(0) && keyCode <= 'Z'.charCodeAt(0)) ||
+ (keyCode >= '0'.charCodeAt(0) && keyCode <= '9'.charCodeAt(0))) {
+ output.push(String.fromCharCode(keyCode));
+ } else {
+ switch (keyCode) {
+ case Key.Comma:
+ output.push('Comma');
+ break;
+ case Key.Del:
+ output.push('Delete');
+ break;
+ case Key.Down:
+ output.push('Down');
+ break;
+ case Key.End:
+ output.push('End');
+ break;
+ case Key.Home:
+ output.push('Home');
+ break;
+ case Key.Ins:
+ output.push('Insert');
+ break;
+ case Key.Left:
+ output.push('Left');
+ break;
+ case Key.MediaNextTrack:
+ output.push('MediaNextTrack');
+ break;
+ case Key.MediaPlayPause:
+ output.push('MediaPlayPause');
+ break;
+ case Key.MediaPrevTrack:
+ output.push('MediaPrevTrack');
+ break;
+ case Key.MediaStop:
+ output.push('MediaStop');
+ break;
+ case Key.PageDown:
+ output.push('PageDown');
+ break;
+ case Key.PageUp:
+ output.push('PageUp');
+ break;
+ case Key.Period:
+ output.push('Period');
+ break;
+ case Key.Right:
+ output.push('Right');
+ break;
+ case Key.Space:
+ output.push('Space');
+ break;
+ case Key.Tab:
+ output.push('Tab');
+ break;
+ case Key.Up:
+ output.push('Up');
+ break;
}
}
-
- return output.join('+');
}
- /**
- * Returns true if the event has valid modifiers.
- * @param {!KeyboardEvent} e The keyboard event to consider.
- * @return {boolean} True if the event is valid.
- */
- function hasValidModifiers(e) {
- switch (getModifierPolicy(e.keyCode)) {
- case ModifierPolicy.REQUIRED:
- return hasModifier(e, false);
- case ModifierPolicy.NOT_ALLOWED:
- return !hasModifier(e, true);
- }
- assertNotReached();
- }
+ return output.join('+');
+}
- return {
- isValidKeyCode: isValidKeyCode,
- keystrokeToString: keystrokeToString,
- hasValidModifiers: hasValidModifiers,
- Key: Key,
- };
-});
+/**
+ * Returns true if the event has valid modifiers.
+ * @param {!KeyboardEvent} e The keyboard event to consider.
+ * @return {boolean} True if the event is valid.
+ */
+export function hasValidModifiers(e) {
+ switch (getModifierPolicy(e.keyCode)) {
+ case ModifierPolicy.REQUIRED:
+ return hasModifier(e, false);
+ case ModifierPolicy.NOT_ALLOWED:
+ return !hasModifier(e, true);
+ }
+ assertNotReached();
+}
diff --git a/chromium/chrome/browser/resources/extensions/sidebar.html b/chromium/chrome/browser/resources/extensions/sidebar.html
index 4024fb27744..3aa0c784932 100644
--- a/chromium/chrome/browser/resources/extensions/sidebar.html
+++ b/chromium/chrome/browser/resources/extensions/sidebar.html
@@ -1,94 +1,80 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="cr-icons">
+ :host {
+ --sidebar-inactive-color: #5a5a5a;
+ color: var(--sidebar-inactive-color);
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ justify-content: space-between;
+ overflow-x: hidden;
+ overflow-y: auto;
+ width: 256px;
+ }
-<link rel="import" href="chrome://resources/cr_elements/cr_icons_css.html">
-<link rel="import" href="chrome://resources/html/cr.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-selector/iron-selector.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-ripple/paper-ripple.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
-<link rel="import" href="navigation_helper.html">
+ @media (prefers-color-scheme: dark) {
+ :host {
+ --sidebar-inactive-color: var(--cr-primary-text-color);
+ }
+ }
-<dom-module id="extensions-sidebar">
- <template>
- <style include="cr-icons">
- :host {
- --sidebar-inactive-color: #5a5a5a;
- color: var(--sidebar-inactive-color);
- display: flex;
- flex-direction: column;
- height: 100%;
- justify-content: space-between;
- overflow-x: hidden;
- overflow-y: auto;
- width: 256px;
- }
+ iron-selector .iron-selected {
+ color: var(--cr-link-color);
+ }
- @media (prefers-color-scheme: dark) {
- :host {
- --sidebar-inactive-color: var(--cr-primary-text-color);
- }
- }
+ #sectionMenu {
+ padding-top: 8px;
+ user-select: none;
+ }
- iron-selector .iron-selected {
- color: var(--cr-link-color);
- }
+ .section-item {
+ align-items: center;
+ color: inherit;
+ display: flex;
+ font-weight: 500;
+ /* Ensure the focus outline appears correctly (crbug.com/655503). */
+ margin-inline-end: 4px;
+ min-height: 40px;
+ padding-inline-start: 24px;
+ position: relative;
+ text-decoration: none;
+ }
- #sectionMenu {
- padding-top: 8px;
- user-select: none;
- }
+ .separator {
+ border-top: var(--cr-separator-line);
+ margin: 8px 0;
+ }
- .section-item {
- align-items: center;
- color: inherit;
- display: flex;
- font-weight: 500;
- /* Ensure the focus outline appears correctly (crbug.com/655503). */
- margin-inline-end: 4px;
- min-height: 40px;
- padding-inline-start: 24px;
- position: relative;
- text-decoration: none;
- }
+ #more-extensions {
+ align-items: center;
+ display: flex;
+ justify-content: space-between;
+ margin-bottom: 8px;
+ }
- .separator {
- border-top: var(--cr-separator-line);
- margin: 8px 0;
- }
-
- #more-extensions {
- align-items: center;
- display: flex;
- justify-content: space-between;
- margin-bottom: 8px;
- }
-
- .cr-icon {
- margin-inline-end: calc(
- var(--cr-section-padding) - var(--cr-icon-ripple-padding));
- }
- </style>
- <iron-selector id="sectionMenu">
- <!-- Values for "data-path" attribute must match the "Page" enum. -->
- <a class="section-item" id="sections-extensions" href="/"
- on-click="onLinkTap_" data-path="items-list">
- $i18n{sidebarExtensions}
- <paper-ripple></paper-ripple>
- </a>
- <a class="section-item" id="sections-shortcuts" href="/shortcuts"
- on-click="onLinkTap_" data-path="keyboard-shortcuts">
- $i18n{keyboardShortcuts}
- <paper-ripple></paper-ripple>
- </a>
- </iron-selector>
- <div hidden="[[isSupervised]]">
- <div class="separator"></div>
- <a class="section-item" id="more-extensions" target="_blank"
- href="$i18n{getMoreExtensionsUrl}" on-click="onMoreExtensionsTap_">
- <span>$i18n{openChromeWebStore}</span>
- <div class="cr-icon icon-external"></div>
- <paper-ripple></paper-ripple>
- </a>
- </div>
- </template>
- <script src="sidebar.js"></script>
-</dom-module>
+ .cr-icon {
+ margin-inline-end: calc(
+ var(--cr-section-padding) - var(--cr-icon-ripple-padding));
+ }
+</style>
+<iron-selector id="sectionMenu">
+ <!-- Values for "data-path" attribute must match the "Page" enum. -->
+ <a class="section-item" id="sections-extensions" href="/"
+ on-click="onLinkTap_" data-path="items-list">
+ $i18n{sidebarExtensions}
+ <paper-ripple></paper-ripple>
+ </a>
+ <a class="section-item" id="sections-shortcuts" href="/shortcuts"
+ on-click="onLinkTap_" data-path="keyboard-shortcuts">
+ $i18n{keyboardShortcuts}
+ <paper-ripple></paper-ripple>
+ </a>
+</iron-selector>
+<div hidden="[[isSupervised]]">
+ <div class="separator"></div>
+ <a class="section-item" id="more-extensions" target="_blank"
+ href="$i18n{getMoreExtensionsUrl}" on-click="onMoreExtensionsTap_">
+ <span>$i18n{openChromeWebStore}</span>
+ <div class="cr-icon icon-external"></div>
+ <paper-ripple></paper-ripple>
+ </a>
+</div>
diff --git a/chromium/chrome/browser/resources/extensions/sidebar.js b/chromium/chrome/browser/resources/extensions/sidebar.js
index 19619f17912..5252323fb94 100644
--- a/chromium/chrome/browser/resources/extensions/sidebar.js
+++ b/chromium/chrome/browser/resources/extensions/sidebar.js
@@ -1,43 +1,48 @@
// Copyright 2015 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('extensions', function() {
- const Sidebar = Polymer({
- is: 'extensions-sidebar',
-
- properties: {
- isSupervised: Boolean,
- },
-
- hostAttributes: {
- role: 'navigation',
- },
-
- /** @override */
- attached: function() {
- this.$.sectionMenu.select(
- extensions.navigation.getCurrentPage().page ==
- extensions.Page.SHORTCUTS ?
- 1 :
- 0);
- },
-
- /**
- * @param {!Event} e
- * @private
- */
- onLinkTap_: function(e) {
- e.preventDefault();
- extensions.navigation.navigateTo({page: e.target.dataset.path});
- this.fire('close-drawer');
- },
-
- /** @private */
- onMoreExtensionsTap_: function() {
- assert(!this.isSupervised);
- chrome.metricsPrivate.recordUserAction('Options_GetMoreExtensions');
- },
- });
-
- return {Sidebar: Sidebar};
+import 'chrome://resources/cr_elements/cr_icons_css.m.js';
+import 'chrome://resources/polymer/v3_0/iron-selector/iron-selector.js';
+import 'chrome://resources/polymer/v3_0/paper-ripple/paper-ripple.js';
+import 'chrome://resources/polymer/v3_0/paper-styles/color.js';
+
+import {assert} from 'chrome://resources/js/assert.m.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+import {navigation, Page} from './navigation_helper.js';
+
+Polymer({
+ is: 'extensions-sidebar',
+
+ _template: html`{__html_template__}`,
+
+ properties: {
+ isSupervised: Boolean,
+ },
+
+ hostAttributes: {
+ role: 'navigation',
+ },
+
+ /** @override */
+ attached: function() {
+ this.$.sectionMenu.select(
+ navigation.getCurrentPage().page == Page.SHORTCUTS ? 1 : 0);
+ },
+
+ /**
+ * @param {!Event} e
+ * @private
+ */
+ onLinkTap_: function(e) {
+ e.preventDefault();
+ navigation.navigateTo({page: e.target.dataset.path});
+ this.fire('close-drawer');
+ },
+
+ /** @private */
+ onMoreExtensionsTap_: function() {
+ assert(!this.isSupervised);
+ chrome.metricsPrivate.recordUserAction('Options_GetMoreExtensions');
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/strings.html b/chromium/chrome/browser/resources/extensions/strings.html
deleted file mode 100644
index cdc7c9b2a5b..00000000000
--- a/chromium/chrome/browser/resources/extensions/strings.html
+++ /dev/null
@@ -1,2 +0,0 @@
-<link rel="import" href="chrome://resources/html/load_time_data.html">
-<script src="strings.js"></script>
diff --git a/chromium/chrome/browser/resources/extensions/toggle_row.html b/chromium/chrome/browser/resources/extensions/toggle_row.html
index f8cdcb4aee9..68c0a299250 100644
--- a/chromium/chrome/browser/resources/extensions/toggle_row.html
+++ b/chromium/chrome/browser/resources/extensions/toggle_row.html
@@ -1,48 +1,38 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style>
+ :host {
+ flex-direction: column;
+ touch-action: none;
+ }
-<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
-<link rel="import" href="chrome://resources/cr_elements/shared_style_css.html">
+ input {
+ display: none;
+ }
-<dom-module id="extensions-toggle-row">
- <template>
- <style>
- :host {
- flex-direction: column;
- touch-action: none;
- }
+ label {
+ align-items: center;
+ box-sizing: border-box;
+ cursor: pointer;
+ display: flex;
+ flex: 1;
+ padding: var(--toggle-row-label-vertical-padding, 0)
+ var(--toggle-row-label-horizontal-padding, 0);
+ width: 100%;
+ }
- input {
- display: none;
- }
+ cr-toggle {
+ display: inline-block;
+ }
- label {
- align-items: center;
- box-sizing: border-box;
- cursor: pointer;
- display: flex;
- flex: 1;
- padding: var(--toggle-row-label-vertical-padding, 0)
- var(--toggle-row-label-horizontal-padding, 0);
- width: 100%;
- }
-
- cr-toggle {
- display: inline-block;
- }
-
- :host ::slotted(*) {
- flex: 1;
- margin-inline-end: 20px;
- }
- </style>
- <label id="label">
- <input id="native" type="checkbox" checked="[[checked]]"
- on-change="onNativeChange_" on-click="onNativeClick_"
- disabled="[[disabled]]">
- <slot></slot>
- <cr-toggle id="crToggle" checked="{{checked}}" aria-labelledby="label"
- on-change="onCrToggleChange_" disabled="[[disabled]]"></cr-toggle>
- </label>
- </template>
- <script src="toggle_row.js"></script>
-</dom-module>
+ :host ::slotted(*) {
+ flex: 1;
+ margin-inline-end: 20px;
+ }
+</style>
+<label id="label">
+ <input id="native" type="checkbox" checked="[[checked]]"
+ on-change="onNativeChange_" on-click="onNativeClick_"
+ disabled="[[disabled]]">
+ <slot></slot>
+ <cr-toggle id="crToggle" checked="{{checked}}" aria-labelledby="label"
+ on-change="onCrToggleChange_" disabled="[[disabled]]"></cr-toggle>
+</label>
diff --git a/chromium/chrome/browser/resources/extensions/toggle_row.js b/chromium/chrome/browser/resources/extensions/toggle_row.js
index c4f67baec15..43be17b5f42 100644
--- a/chromium/chrome/browser/resources/extensions/toggle_row.js
+++ b/chromium/chrome/browser/resources/extensions/toggle_row.js
@@ -2,73 +2,75 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- 'use strict';
+import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.m.js';
+import 'chrome://resources/cr_elements/shared_style_css.m.js';
+
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
- /**
- * An extensions-toggle-row provides a way of having a clickable row that can
- * modify a cr-toggle, by leveraging the native <label> functionality. It uses
- * a hidden native <input type="checkbox"> to achieve this.
- */
- const ExtensionsToggleRow = Polymer({
- is: 'extensions-toggle-row',
- properties: {
- checked: Boolean,
+/**
+ * An extensions-toggle-row provides a way of having a clickable row that can
+ * modify a cr-toggle, by leveraging the native <label> functionality. It uses
+ * a hidden native <input type="checkbox"> to achieve this.
+ */
+Polymer({
+ is: 'extensions-toggle-row',
- disabled: Boolean,
- },
+ _template: html`{__html_template__}`,
- /**
- * Exposing the clickable part of extensions-toggle-row for testing
- * purposes.
- * @return {!HTMLElement}
- */
- getLabel() {
- return this.$.label;
- },
+ properties: {
+ checked: Boolean,
- /**
- * @param {!Event}
- * @private
- */
- onNativeClick_: function(e) {
- // Even though the native checkbox is hidden and can't be actually
- // cilcked/tapped by the user, because it resides within the <label> the
- // browser emits an extraneous event when the label is clicked. Stop
- // propagation so that it does not interfere with |onLabelTap_| listener.
- e.stopPropagation();
- },
+ disabled: Boolean,
+ },
+
+ /**
+ * Exposing the clickable part of extensions-toggle-row for testing
+ * purposes.
+ * @return {!HTMLElement}
+ */
+ getLabel() {
+ return /** @type {!HTMLElement} */ (this.$.label);
+ },
- /**
- * Fires when the native checkbox changes value. This happens when the user
- * clicks directly on the <label>.
- * @param {!Event} e
- * @private
- */
- onNativeChange_: function(e) {
- e.stopPropagation();
+ /**
+ * @param {!Event} e
+ * @private
+ */
+ onNativeClick_: function(e) {
+ // Even though the native checkbox is hidden and can't be actually
+ // cilcked/tapped by the user, because it resides within the <label> the
+ // browser emits an extraneous event when the label is clicked. Stop
+ // propagation so that it does not interfere with |onLabelTap_| listener.
+ e.stopPropagation();
+ },
- // Sync value of native checkbox and cr-toggle and |checked|.
- this.$.crToggle.checked = this.$.native.checked;
- this.checked = this.$.native.checked;
+ /**
+ * Fires when the native checkbox changes value. This happens when the user
+ * clicks directly on the <label>.
+ * @param {!Event} e
+ * @private
+ */
+ onNativeChange_: function(e) {
+ e.stopPropagation();
- this.fire('change', this.checked);
- },
+ // Sync value of native checkbox and cr-toggle and |checked|.
+ this.$.crToggle.checked = this.$.native.checked;
+ this.checked = this.$.native.checked;
- /**
- * @param {!CustomEvent<boolean>} e
- * @private
- */
- onCrToggleChange_: function(e) {
- e.stopPropagation();
+ this.fire('change', this.checked);
+ },
- // Sync value of native checkbox and cr-toggle.
- this.$.native.checked = e.detail;
+ /**
+ * @param {!CustomEvent<boolean>} e
+ * @private
+ */
+ onCrToggleChange_: function(e) {
+ e.stopPropagation();
- this.fire('change', this.checked);
- },
- });
+ // Sync value of native checkbox and cr-toggle.
+ this.$.native.checked = e.detail;
- return {ExtensionsToggleRow: ExtensionsToggleRow};
+ this.fire('change', this.checked);
+ },
});
diff --git a/chromium/chrome/browser/resources/extensions/toolbar.html b/chromium/chrome/browser/resources/extensions/toolbar.html
index 38cf1124e61..fcc00263fd8 100644
--- a/chromium/chrome/browser/resources/extensions/toolbar.html
+++ b/chromium/chrome/browser/resources/extensions/toolbar.html
@@ -1,141 +1,119 @@
-<link rel="import" href="chrome://resources/html/polymer.html">
+<style include="cr-hidden-style">
+ :host {
+ --border-bottom-height: 1px;
+ --button-row-height: calc(2 * var(--padding-top-bottom) +
+ var(--cr-button-height));
+ --drawer-transition: 0.3s cubic-bezier(.25, .1, .25, 1);
+ --padding-top-bottom: 10px;
+ }
-<link rel="import" href="chrome://resources/cr_elements/cr_button/cr_button.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_toast/cr_toast_manager.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_toggle/cr_toggle.html">
-<link rel="import" href="chrome://resources/cr_elements/cr_toolbar/cr_toolbar.html">
-<link rel="import" href="chrome://resources/cr_elements/hidden_style_css.html">
-<link rel="import" href="chrome://resources/cr_elements/policy/cr_tooltip_icon.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/html/cr.html">
-<link rel="import" href="chrome://resources/html/util.html">
-<link rel="import" href="chrome://resources/html/i18n_behavior.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-announcer/iron-a11y-announcer.html">
-<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html">
-<link rel="import" href="pack_dialog.html">
+ /* This toggle needs special styling because it's on blue background. */
+ @media (prefers-color-scheme: light) {
+ cr-toolbar cr-toggle {
+ --cr-toggle-checked-bar-color: var(--google-grey-refresh-100);
+ --cr-toggle-checked-button-color: white;
+ --cr-toggle-checked-ripple-color: rgba(255, 255, 255, .2);
+ --cr-toggle-unchecked-bar-color: var(--google-grey-600);
+ --cr-toggle-unchecked-ripple-color: rgba(255, 255, 255, .15);
+ }
+ }
-<dom-module id="extensions-toolbar">
- <template>
- <style include="cr-hidden-style">
- :host {
- --border-bottom-height: 1px;
- --button-row-height: calc(2 * var(--padding-top-bottom) +
- var(--cr-button-height));
- --drawer-transition: 0.3s cubic-bezier(.25, .1, .25, 1);
- --padding-top-bottom: 10px;
- }
+ cr-tooltip-icon {
+ margin-inline-end: 20px;
+ }
- /* This toggle needs special styling because it's on blue background. */
- @media (prefers-color-scheme: light) {
- cr-toolbar cr-toggle {
- --cr-toggle-checked-bar-color: var(--google-grey-refresh-100);
- --cr-toggle-checked-button-color: white;
- --cr-toggle-checked-ink-color: white;
- --cr-toggle-unchecked-bar-color: var(--google-grey-600);
- --cr-toggle-unchecked-ink-color: white;
- }
- }
+ #devDrawer[expanded] #buttonStrip {
+ top: 0;
+ }
- cr-tooltip-icon {
- margin-inline-end: 20px;
- }
+ #devDrawer {
+ background: #fff;
+ border-bottom: 1px solid var(--google-grey-300);
+ height: 0;
+ overflow-x: hidden;
+ overflow-y: auto;
+ position: relative;
+ transition: height var(--drawer-transition);
+ }
- #devDrawer[expanded] #buttonStrip {
- top: 0;
- }
+ @media (prefers-color-scheme: dark) {
+ #devDrawer {
+ background: none;
+ border-bottom-color: var(--cr-separator-color);
+ }
+ }
- #devDrawer {
- background: #fff;
- border-bottom: 1px solid var(--google-grey-300);
- height: 0;
- overflow-x: hidden;
- overflow-y: auto;
- position: relative;
- transition: height var(--drawer-transition);
- }
+ #devDrawer[expanded] {
+ height: calc(var(--button-row-height) + var(--border-bottom-height));
+ }
- @media (prefers-color-scheme: dark) {
- #devDrawer {
- background: none;
- border-bottom-color: var(--cr-separator-color);
- }
- }
+ #buttonStrip {
+ margin-inline-end: auto;
+ margin-inline-start: 24px;
+ padding: var(--padding-top-bottom) 0;
+ position: absolute;
+ top: calc(var(--button-row-height) * -1);
+ transition: top var(--drawer-transition);
+ /* Prevent selection of the blank space between buttons. */
+ user-select: none;
+ width: 100%;
+ }
- #devDrawer[expanded] {
- height: calc(var(--button-row-height) + var(--border-bottom-height));
- }
+ #buttonStrip cr-button {
+ margin-inline-end: 16px;
+ }
- #buttonStrip {
- margin-inline-end: auto;
- margin-inline-start: 24px;
- padding: var(--padding-top-bottom) 0;
- position: absolute;
- top: calc(var(--button-row-height) * -1);
- transition: top var(--drawer-transition);
- /* Prevent selection of the blank space between buttons. */
- user-select: none;
- width: 100%;
- }
+ .more-actions {
+ align-items: center;
+ display: flex;
+ justify-content: flex-end;
+ }
- #buttonStrip cr-button {
- margin-inline-end: 16px;
- }
-
- .more-actions {
- align-items: center;
- display: flex;
- justify-content: flex-end;
- }
-
- .more-actions span {
- margin-inline-end: 16px;
- }
- </style>
- <cr-toolbar page-name="$i18n{toolbarTitle}" search-prompt="$i18n{search}"
- clear-label="$i18n{clearSearch}" menu-label="$i18n{mainMenu}" show-menu
- narrow-threshold="1000">
- <div class="more-actions">
- <span id="devModeLabel">$i18n{toolbarDevMode}</span>
- <cr-tooltip-icon hidden="[[!shouldDisableDevMode_(
+ .more-actions span {
+ margin-inline-end: 16px;
+ }
+</style>
+<cr-toolbar page-name="$i18n{toolbarTitle}" search-prompt="$i18n{search}"
+ clear-label="$i18n{clearSearch}" menu-label="$i18n{mainMenu}" show-menu
+ narrow-threshold="1000">
+ <div class="more-actions">
+ <span id="devModeLabel">$i18n{toolbarDevMode}</span>
+ <cr-tooltip-icon hidden="[[!shouldDisableDevMode_(
+ devModeControlledByPolicy, isSupervised)]]"
+ tooltip-text="[[getTooltipText_(isSupervised)]]"
+ icon-class="[[getIcon_(isSupervised)]]"
+ icon-aria-label="[[getTooltipText_(isSupervised)]]">
+ </cr-tooltip-icon>
+ <cr-toggle id="devMode" on-change="onDevModeToggleChange_"
+ disabled="[[shouldDisableDevMode_(
devModeControlledByPolicy, isSupervised)]]"
- tooltip-text="[[getTooltipText_(isSupervised)]]"
- icon-class="[[getIcon_(isSupervised)]]"
- icon-aria-label="[[getTooltipText_(isSupervised)]]">
- </cr-tooltip-icon>
- <cr-toggle id="devMode" on-change="onDevModeToggleChange_"
- disabled="[[shouldDisableDevMode_(
- devModeControlledByPolicy, isSupervised)]]"
- checked="[[inDevMode]]" aria-labelledby="devModeLabel">
- </cr-toggle>
- </div>
- </cr-toolbar>
- <template is="dom-if" if="[[showPackDialog_]]" restamp>
- <extensions-pack-dialog delegate="[[delegate]]"
- on-close="onPackDialogClose_">
- </extensions-pack-dialog>
- </template>
- <div id="devDrawer" expanded$="[[expanded_]]">
- <div id="buttonStrip">
- <cr-button hidden$="[[!canLoadUnpacked]]" id="loadUnpacked"
- on-click="onLoadUnpackedTap_">
- $i18n{toolbarLoadUnpacked}
- </cr-button>
- <cr-button id="packExtensions" on-click="onPackTap_">
- $i18n{toolbarPack}
- </cr-button>
- <cr-button id="updateNow" on-click="onUpdateNowTap_"
- title="$i18n{toolbarUpdateNowTooltip}">
- $i18n{toolbarUpdateNow}
- </cr-button>
+ checked="[[inDevMode]]" aria-labelledby="devModeLabel">
+ </cr-toggle>
+ </div>
+</cr-toolbar>
+<template is="dom-if" if="[[showPackDialog_]]" restamp>
+ <extensions-pack-dialog delegate="[[delegate]]"
+ on-close="onPackDialogClose_">
+ </extensions-pack-dialog>
+</template>
+<div id="devDrawer" expanded$="[[expanded_]]">
+ <div id="buttonStrip">
+ <cr-button hidden$="[[!canLoadUnpacked]]" id="loadUnpacked"
+ on-click="onLoadUnpackedTap_">
+ $i18n{toolbarLoadUnpacked}
+ </cr-button>
+ <cr-button id="packExtensions" on-click="onPackTap_">
+ $i18n{toolbarPack}
+ </cr-button>
+ <cr-button id="updateNow" on-click="onUpdateNowTap_"
+ title="$i18n{toolbarUpdateNowTooltip}">
+ $i18n{toolbarUpdateNow}
+ </cr-button>
<if expr="chromeos">
- <cr-button id="kioskExtensions" on-click="onKioskTap_"
- hidden$="[[!kioskEnabled]]">
- $i18n{manageKioskApp}
- </cr-button>
+ <cr-button id="kioskExtensions" on-click="onKioskTap_"
+ hidden$="[[!kioskEnabled]]">
+ $i18n{manageKioskApp}
+ </cr-button>
</if>
- </div>
- </div>
- </template>
- <script src="toolbar.js"></script>
-</dom-module>
+ </div>
+</div>
diff --git a/chromium/chrome/browser/resources/extensions/toolbar.js b/chromium/chrome/browser/resources/extensions/toolbar.js
index 228cc45667d..ad6b7eae96c 100644
--- a/chromium/chrome/browser/resources/extensions/toolbar.js
+++ b/chromium/chrome/browser/resources/extensions/toolbar.js
@@ -2,192 +2,202 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-cr.define('extensions', function() {
- /** @interface */
- class ToolbarDelegate {
- /**
- * Toggles whether or not the profile is in developer mode.
- * @param {boolean} inDevMode
- */
- setProfileInDevMode(inDevMode) {}
-
- /**
- * Opens the dialog to load unpacked extensions.
- * @return {!Promise}
- */
- loadUnpacked() {}
-
- /**
- * Updates all extensions.
- * @return {!Promise}
- */
- updateAllExtensions() {}
- }
-
- const Toolbar = Polymer({
- is: 'extensions-toolbar',
-
- properties: {
- /** @type {extensions.ToolbarDelegate} */
- delegate: Object,
-
- inDevMode: {
- type: Boolean,
- value: false,
- observer: 'onInDevModeChanged_',
- reflectToAttribute: true,
- },
-
- devModeControlledByPolicy: Boolean,
-
- isSupervised: Boolean,
-
- // <if expr="chromeos">
- kioskEnabled: Boolean,
- // </if>
-
- canLoadUnpacked: Boolean,
-
- /** @private */
- expanded_: Boolean,
-
- /** @private */
- showPackDialog_: Boolean,
-
- /**
- * Prevents initiating update while update is in progress.
- * @private
- */
- isUpdating_: {type: Boolean, value: false}
+import 'chrome://resources/cr_elements/cr_button/cr_button.m.js';
+import 'chrome://resources/cr_elements/cr_toggle/cr_toggle.m.js';
+import 'chrome://resources/cr_elements/cr_toolbar/cr_toolbar.m.js';
+import 'chrome://resources/cr_elements/hidden_style_css.m.js';
+import 'chrome://resources/cr_elements/policy/cr_tooltip_icon.m.js';
+import 'chrome://resources/cr_elements/shared_vars_css.m.js';
+import 'chrome://resources/polymer/v3_0/paper-styles/color.js';
+import './pack_dialog.js';
+
+import {getToastManager} from 'chrome://resources/cr_elements/cr_toast/cr_toast_manager.m.js';
+import {I18nBehavior} from 'chrome://resources/js/i18n_behavior.m.js';
+import {listenOnce} from 'chrome://resources/js/util.m.js';
+import {IronA11yAnnouncer} from 'chrome://resources/polymer/v3_0/iron-a11y-announcer/iron-a11y-announcer.js';
+import {html, Polymer} from 'chrome://resources/polymer/v3_0/polymer/polymer_bundled.min.js';
+
+/** @interface */
+export class ToolbarDelegate {
+ /**
+ * Toggles whether or not the profile is in developer mode.
+ * @param {boolean} inDevMode
+ */
+ setProfileInDevMode(inDevMode) {}
+
+ /**
+ * Opens the dialog to load unpacked extensions.
+ * @return {!Promise}
+ */
+ loadUnpacked() {}
+
+ /**
+ * Updates all extensions.
+ * @return {!Promise}
+ */
+ updateAllExtensions() {}
+}
+
+Polymer({
+ is: 'extensions-toolbar',
+
+ _template: html`{__html_template__}`,
+
+ properties: {
+ /** @type {ToolbarDelegate} */
+ delegate: Object,
+
+ inDevMode: {
+ type: Boolean,
+ value: false,
+ observer: 'onInDevModeChanged_',
+ reflectToAttribute: true,
},
- behaviors: [I18nBehavior],
+ devModeControlledByPolicy: Boolean,
- hostAttributes: {
- role: 'banner',
- },
+ isSupervised: Boolean,
- /**
- * @return {boolean}
- * @private
- */
- shouldDisableDevMode_: function() {
- return this.devModeControlledByPolicy || this.isSupervised;
- },
+ // <if expr="chromeos">
+ kioskEnabled: Boolean,
+ // </if>
- /**
- * @return {string}
- * @private
- */
- getTooltipText_: function() {
- return this.i18n(
- this.isSupervised ? 'controlledSettingChildRestriction' :
- 'controlledSettingPolicy');
- },
+ canLoadUnpacked: Boolean,
- /**
- * @return {string}
- * @private
- */
- getIcon_: function() {
- return this.isSupervised ? 'cr20:kite' : 'cr20:domain';
- },
+ /** @private */
+ expanded_: Boolean,
- /**
- * @param {!CustomEvent<boolean>} e
- * @private
- */
- onDevModeToggleChange_: function(e) {
- this.delegate.setProfileInDevMode(e.detail);
- chrome.metricsPrivate.recordUserAction(
- 'Options_ToggleDeveloperMode_' + (e.detail ? 'Enabled' : 'Disabled'));
- },
+ /** @private */
+ showPackDialog_: Boolean,
/**
- * @param {boolean} current
- * @param {boolean} previous
+ * Prevents initiating update while update is in progress.
* @private
*/
- onInDevModeChanged_: function(current, previous) {
- const drawer = this.$.devDrawer;
- if (this.inDevMode) {
- if (drawer.hidden) {
- drawer.hidden = false;
- // Requesting the offsetTop will cause a reflow (to account for
- // hidden).
- /** @suppress {suspiciousCode} */ drawer.offsetTop;
- }
- } else {
- if (previous == undefined) {
- drawer.hidden = true;
- return;
- }
-
- listenOnce(drawer, 'transitionend', e => {
- if (!this.inDevMode) {
- drawer.hidden = true;
- }
- });
+ isUpdating_: {type: Boolean, value: false}
+ },
+
+ behaviors: [I18nBehavior],
+
+ hostAttributes: {
+ role: 'banner',
+ },
+
+ /**
+ * @return {boolean}
+ * @private
+ */
+ shouldDisableDevMode_: function() {
+ return this.devModeControlledByPolicy || this.isSupervised;
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ getTooltipText_: function() {
+ return this.i18n(
+ this.isSupervised ? 'controlledSettingChildRestriction' :
+ 'controlledSettingPolicy');
+ },
+
+ /**
+ * @return {string}
+ * @private
+ */
+ getIcon_: function() {
+ return this.isSupervised ? 'cr20:kite' : 'cr20:domain';
+ },
+
+ /**
+ * @param {!CustomEvent<boolean>} e
+ * @private
+ */
+ onDevModeToggleChange_: function(e) {
+ this.delegate.setProfileInDevMode(e.detail);
+ chrome.metricsPrivate.recordUserAction(
+ 'Options_ToggleDeveloperMode_' + (e.detail ? 'Enabled' : 'Disabled'));
+ },
+
+ /**
+ * @param {boolean} current
+ * @param {boolean} previous
+ * @private
+ */
+ onInDevModeChanged_: function(current, previous) {
+ const drawer = this.$.devDrawer;
+ if (this.inDevMode) {
+ if (drawer.hidden) {
+ drawer.hidden = false;
+ // Requesting the offsetTop will cause a reflow (to account for
+ // hidden).
+ /** @suppress {suspiciousCode} */ drawer.offsetTop;
}
- this.expanded_ = !this.expanded_;
- },
-
- /** @private */
- onLoadUnpackedTap_: function() {
- this.delegate.loadUnpacked().catch(loadError => {
- this.fire('load-error', loadError);
- });
- chrome.metricsPrivate.recordUserAction('Options_LoadUnpackedExtension');
- },
-
- /** @private */
- onPackTap_: function() {
- chrome.metricsPrivate.recordUserAction('Options_PackExtension');
- this.showPackDialog_ = true;
- },
-
- /** @private */
- onPackDialogClose_: function() {
- this.showPackDialog_ = false;
- this.$.packExtensions.focus();
- },
-
- // <if expr="chromeos">
- /** @private */
- onKioskTap_: function() {
- this.fire('kiosk-tap');
- },
- // </if>
-
- /** @private */
- onUpdateNowTap_: function() {
- // If already updating, do not initiate another update.
- if (this.isUpdating_) {
+ } else {
+ if (previous == undefined) {
+ drawer.hidden = true;
return;
}
- this.isUpdating_ = true;
-
- const toastManager = cr.toastManager.getInstance();
- // Keep the toast open indefinitely.
- toastManager.duration = 0;
- toastManager.show(this.i18n('toolbarUpdatingToast'), false);
- this.delegate.updateAllExtensions().then(
- () => {
- toastManager.hide();
- toastManager.duration = 3000;
- toastManager.show(this.i18n('toolbarUpdateDone'), false);
- this.isUpdating_ = false;
- },
- () => {
- toastManager.hide();
- this.isUpdating_ = false;
- });
- },
- });
-
- return {
- Toolbar: Toolbar,
- ToolbarDelegate: ToolbarDelegate,
- };
+ listenOnce(drawer, 'transitionend', e => {
+ if (!this.inDevMode) {
+ drawer.hidden = true;
+ }
+ });
+ }
+ this.expanded_ = !this.expanded_;
+ },
+
+ /** @private */
+ onLoadUnpackedTap_: function() {
+ this.delegate.loadUnpacked().catch(loadError => {
+ this.fire('load-error', loadError);
+ });
+ chrome.metricsPrivate.recordUserAction('Options_LoadUnpackedExtension');
+ },
+
+ /** @private */
+ onPackTap_: function() {
+ chrome.metricsPrivate.recordUserAction('Options_PackExtension');
+ this.showPackDialog_ = true;
+ },
+
+ /** @private */
+ onPackDialogClose_: function() {
+ this.showPackDialog_ = false;
+ this.$.packExtensions.focus();
+ },
+
+ // <if expr="chromeos">
+ /** @private */
+ onKioskTap_: function() {
+ this.fire('kiosk-tap');
+ },
+ // </if>
+
+ /** @private */
+ onUpdateNowTap_: function() {
+ // If already updating, do not initiate another update.
+ if (this.isUpdating_) {
+ return;
+ }
+
+ this.isUpdating_ = true;
+
+ const toastManager = getToastManager();
+ // Keep the toast open indefinitely.
+ toastManager.duration = 0;
+ toastManager.show(this.i18n('toolbarUpdatingToast'));
+ this.delegate.updateAllExtensions().then(
+ () => {
+ toastManager.hide();
+ toastManager.duration = 3000;
+ toastManager.show(this.i18n('toolbarUpdateDone'));
+ this.isUpdating_ = false;
+ },
+ () => {
+ toastManager.hide();
+ this.isUpdating_ = false;
+ });
+ },
});