diff options
author | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-03-08 10:28:10 +0100 |
---|---|---|
committer | Allan Sandfeld Jensen <allan.jensen@qt.io> | 2017-03-20 13:40:30 +0000 |
commit | e733310db58160074f574c429d48f8308c0afe17 (patch) | |
tree | f8aef4b7e62a69928dbcf880620eece20f98c6df /chromium/chrome/browser | |
parent | 2f583e4aec1ae3a86fa047829c96b310dc12ecdf (diff) | |
download | qtwebengine-chromium-e733310db58160074f574c429d48f8308c0afe17.tar.gz |
BASELINE: Update Chromium to 56.0.2924.122
Change-Id: I4e04de8f47e47e501c46ed934c76a431c6337ced
Reviewed-by: Michael BrĂ¼ning <michael.bruning@qt.io>
Diffstat (limited to 'chromium/chrome/browser')
600 files changed, 13897 insertions, 8661 deletions
diff --git a/chromium/chrome/browser/BUILD.gn b/chromium/chrome/browser/BUILD.gn index 87409e5e5df..c727f67c8f7 100644 --- a/chromium/chrome/browser/BUILD.gn +++ b/chromium/chrome/browser/BUILD.gn @@ -9,7 +9,12 @@ import("//build/config/ui.gni") import("//build/split_static_library.gni") import("//chrome/common/features.gni") import("//components/os_crypt/features.gni") +import("//components/spellcheck/spellcheck_build_features.gni") +import("//extensions/features/features.gni") import("//media/media_options.gni") +import("//net/features.gni") +import("//ppapi/features/features.gni") +import("//printing/features/features.gni") import("//third_party/protobuf/proto_library.gni") # //build/config/android/rules.gni imports //tools/grit/grit_rule.gni, which @@ -152,6 +157,8 @@ split_static_library("browser") { "browsing_data/browsing_data_indexed_db_helper.h", "browsing_data/browsing_data_local_storage_helper.cc", "browsing_data/browsing_data_local_storage_helper.h", + "browsing_data/browsing_data_media_license_helper.cc", + "browsing_data/browsing_data_media_license_helper.h", "browsing_data/browsing_data_quota_helper.cc", "browsing_data/browsing_data_quota_helper.h", "browsing_data/browsing_data_quota_helper_impl.cc", @@ -552,6 +559,8 @@ split_static_library("browser") { "media/webrtc/window_icon_util_chromeos.cc", "media/webrtc/window_icon_util_mac.mm", "media/webrtc/window_icon_util_win.cc", + "memory/chrome_memory_coordinator_delegate.cc", + "memory/chrome_memory_coordinator_delegate.h", "memory_details.cc", "memory_details.h", "memory_details_android.cc", @@ -599,8 +608,6 @@ split_static_library("browser") { "metrics/time_ticks_experiment_win.h", "metrics/variations/chrome_variations_service_client.cc", "metrics/variations/chrome_variations_service_client.h", - "metrics/variations/variations_registry_syncer_win.cc", - "metrics/variations/variations_registry_syncer_win.h", "mod_pagespeed/mod_pagespeed_metrics.cc", "mod_pagespeed/mod_pagespeed_metrics.h", "native_window_notification_source.h", @@ -680,6 +687,8 @@ split_static_library("browser") { "ntp_snippets/bookmark_last_visit_updater.h", "ntp_snippets/content_suggestions_service_factory.cc", "ntp_snippets/content_suggestions_service_factory.h", + "ntp_snippets/download_suggestions_provider.cc", + "ntp_snippets/download_suggestions_provider.h", "page_load_metrics/browser_page_track_decider.cc", "page_load_metrics/browser_page_track_decider.h", "page_load_metrics/metrics_navigation_throttle.cc", @@ -710,14 +719,19 @@ split_static_library("browser") { "page_load_metrics/observers/no_state_prefetch_page_load_metrics_observer.h", "page_load_metrics/observers/previews_page_load_metrics_observer.cc", "page_load_metrics/observers/previews_page_load_metrics_observer.h", + "page_load_metrics/observers/protocol_page_load_metrics_observer.cc", + "page_load_metrics/observers/protocol_page_load_metrics_observer.h", "page_load_metrics/observers/service_worker_page_load_metrics_observer.cc", "page_load_metrics/observers/service_worker_page_load_metrics_observer.h", + "page_load_metrics/page_load_metrics_embedder_interface.h", "page_load_metrics/page_load_metrics_initialize.cc", "page_load_metrics/page_load_metrics_initialize.h", "page_load_metrics/page_load_metrics_observer.cc", "page_load_metrics/page_load_metrics_observer.h", "page_load_metrics/page_load_metrics_util.cc", "page_load_metrics/page_load_metrics_util.h", + "page_load_metrics/page_load_tracker.cc", + "page_load_metrics/page_load_tracker.h", "password_manager/chrome_password_manager_client.cc", "password_manager/chrome_password_manager_client.h", "password_manager/password_manager_setting_migrator_service_factory.cc", @@ -749,8 +763,6 @@ split_static_library("browser") { "permissions/permission_context_base.h", "permissions/permission_decision_auto_blocker.cc", "permissions/permission_decision_auto_blocker.h", - "permissions/permission_infobar_delegate.cc", - "permissions/permission_infobar_delegate.h", "permissions/permission_manager.cc", "permissions/permission_manager.h", "permissions/permission_manager_factory.cc", @@ -759,6 +771,8 @@ split_static_library("browser") { "permissions/permission_request.h", "permissions/permission_request_id.cc", "permissions/permission_request_id.h", + "permissions/permission_request_impl.cc", + "permissions/permission_request_impl.h", "permissions/permission_request_manager.cc", "permissions/permission_request_manager.h", "permissions/permission_uma_util.cc", @@ -836,12 +850,12 @@ split_static_library("browser") { "predictors/resource_prefetcher_manager.h", "prefs/browser_prefs.cc", "prefs/browser_prefs.h", + "prefs/chrome_command_line_pref_store.cc", + "prefs/chrome_command_line_pref_store.h", "prefs/chrome_pref_model_associator_client.cc", "prefs/chrome_pref_model_associator_client.h", "prefs/chrome_pref_service_factory.cc", "prefs/chrome_pref_service_factory.h", - "prefs/command_line_pref_store.cc", - "prefs/command_line_pref_store.h", "prefs/incognito_mode_prefs.cc", "prefs/incognito_mode_prefs.h", "prefs/origin_trial_prefs.cc", @@ -995,6 +1009,8 @@ split_static_library("browser") { "safe_browsing/srt_field_trial_win.h", "safe_browsing/srt_global_error_win.cc", "safe_browsing/srt_global_error_win.h", + "safe_search_api/safe_search_url_checker.cc", + "safe_search_api/safe_search_url_checker.h", "search/iframe_source.cc", "search/iframe_source.h", "search/instant_io_context.cc", @@ -1113,14 +1129,14 @@ split_static_library("browser") { "ssl/cert_report_helper.h", "ssl/chrome_expect_ct_reporter.cc", "ssl/chrome_expect_ct_reporter.h", - "ssl/chrome_security_state_model_client.cc", - "ssl/chrome_security_state_model_client.h", "ssl/chrome_ssl_host_state_delegate.cc", "ssl/chrome_ssl_host_state_delegate.h", "ssl/chrome_ssl_host_state_delegate_factory.cc", "ssl/chrome_ssl_host_state_delegate_factory.h", "ssl/common_name_mismatch_handler.cc", "ssl/common_name_mismatch_handler.h", + "ssl/security_state_tab_helper.cc", + "ssl/security_state_tab_helper.h", "ssl/ssl_blocking_page.cc", "ssl/ssl_blocking_page.h", "ssl/ssl_cert_reporter.h", @@ -1235,12 +1251,13 @@ split_static_library("browser") { "win/jumplist_updater.h", "win/settings_app_monitor.cc", "win/settings_app_monitor.h", + "win/titlebar_config.cc", + "win/titlebar_config.h", ] configs += [ "//build/config/compiler:wexit_time_destructors", "//build/config:precompiled_headers", - "//third_party/WebKit/public:debug_devtools", ] defines = [] libs = [] @@ -1253,6 +1270,7 @@ split_static_library("browser") { public_deps = [ "//chrome/common", "//components/autofill/core/browser", + "//components/payments:payment_validation", "//components/sync", "//content/public/browser", "//sql", @@ -1265,11 +1283,9 @@ split_static_library("browser") { "//chrome:strings", "//chrome/app/resources:platform_locale_settings", "//chrome/app/theme:theme_resources", - "//chrome/app/theme:theme_resources", "//chrome/browser/budget_service:budget_proto", "//chrome/browser/devtools", "//chrome/browser/metrics/variations:chrome_ui_string_overrider_factory", - "//chrome/browser/metrics/variations:chrome_ui_string_overrider_factory", "//chrome/browser/net:probe_message_proto", "//chrome/browser/resources:component_extension_resources", "//chrome/browser/ui", @@ -1298,7 +1314,7 @@ split_static_library("browser") { "//components/data_reduction_proxy/core/browser", "//components/data_usage/core", "//components/data_use_measurement/content", - "//components/data_use_measurement/core", + "//components/data_use_measurement/core:ascriber", "//components/device_event_log", "//components/dom_distiller/content/browser", "//components/domain_reliability", @@ -1348,12 +1364,13 @@ split_static_library("browser") { "//components/policy:generated", "//components/policy/core/browser", "//components/policy/proto", + "//components/prefs:prefs", "//components/previews/core", "//components/profile_metrics", "//components/proxy_config", - "//components/proxy_config", "//components/query_parser", "//components/rappor", + "//components/rappor:rappor_recorder", "//components/renderer_context_menu", "//components/resources", "//components/safe_browsing_db", @@ -1362,9 +1379,11 @@ split_static_library("browser") { "//components/search_engines", "//components/search_provider_logos", "//components/security_interstitials/core", - "//components/security_state", + "//components/security_state/content", + "//components/security_state/core", "//components/sessions", "//components/signin/core/browser", + "//components/spellcheck:build_features", "//components/ssl_config", "//components/ssl_errors", "//components/startup_metric_utils/browser:host", @@ -1377,8 +1396,9 @@ split_static_library("browser") { "//components/supervised_user_error_page", "//components/sync", "//components/sync_bookmarks", + "//components/sync_preferences", "//components/sync_sessions", - "//components/syncable_prefs", + "//components/task_scheduler_util", "//components/tracing:startup_tracing", "//components/translate/content/browser", "//components/translate/core/browser", @@ -1391,6 +1411,7 @@ split_static_library("browser") { "//components/user_prefs", "//components/user_prefs/tracked:user_prefs_tracked", "//components/variations", + "//components/variations/field_trial_config", "//components/variations/net", "//components/variations/service", "//components/visitedlink/browser", @@ -1405,13 +1426,16 @@ split_static_library("browser") { "//content/public/common", "//content/public/common:feature_h264_with_openh264_ffmpeg", "//content/public/common:features", + "//content/public/common:service_names", "//courgette:courgette_lib", "//crypto", "//crypto:platform", + "//device/base", "//device/bluetooth:mojo", - "//device/core", + "//device/power_save_blocker", "//device/usb/mojo", "//device/usb/public/interfaces", + "//extensions/features", "//google_apis", "//gpu/config", "//media", @@ -1422,11 +1446,14 @@ split_static_library("browser") { "//mojo/public/js", "//net:extras", "//net:net_with_v8", - "//services/shell/public/cpp", + "//printing/features", + "//services/image_decoder/public/cpp", + "//services/service_manager/public/cpp", "//skia", "//sql", "//storage/browser", "//storage/common", + "//third_party/WebKit/public:features", "//third_party/WebKit/public:image_resources", "//third_party/WebKit/public:resources", "//third_party/cacheinvalidation", @@ -1440,7 +1467,7 @@ split_static_library("browser") { "//third_party/re2", "//third_party/smhasher:cityhash", "//third_party/webrtc/modules/desktop_capture", - "//third_party/widevine/cdm:version_h", + "//third_party/widevine/cdm:headers", "//third_party/zlib", "//third_party/zlib:compression_utils", "//third_party/zlib:minizip", @@ -1455,7 +1482,6 @@ split_static_library("browser") { "//ui/gl:gl_features", "//ui/message_center", "//ui/resources", - "//ui/resources", "//ui/shell_dialogs", "//ui/strings", "//ui/surface", @@ -1873,6 +1899,10 @@ split_static_library("browser") { "plugins/flash_download_interception.h", "plugins/flash_permission_context.cc", "plugins/flash_permission_context.h", + "plugins/flash_temporary_permission_tracker.cc", + "plugins/flash_temporary_permission_tracker.h", + "plugins/flash_temporary_permission_tracker_factory.cc", + "plugins/flash_temporary_permission_tracker_factory.h", "plugins/plugin_data_remover_helper.cc", "plugins/plugin_data_remover_helper.h", "plugins/plugin_finder.cc", @@ -1885,6 +1915,8 @@ split_static_library("browser") { "plugins/plugin_metadata.h", "plugins/plugin_observer.cc", "plugins/plugin_observer.h", + "plugins/plugin_policy_handler.cc", + "plugins/plugin_policy_handler.h", "plugins/plugin_prefs.cc", "plugins/plugin_prefs.h", "plugins/plugin_prefs_factory.cc", @@ -1913,9 +1945,12 @@ split_static_library("browser") { "renderer_host/pepper/pepper_isolated_file_system_message_filter.h", "renderer_host/pepper/pepper_output_protection_message_filter.cc", "renderer_host/pepper/pepper_output_protection_message_filter.h", + "renderer_host/pepper/pepper_platform_verification_message_filter.cc", + "renderer_host/pepper/pepper_platform_verification_message_filter.h", ] deps += [ "//components/pdf/browser", + "//ppapi/features", "//ppapi/proxy:ipc", "//third_party/adobe/flash:flapper_version_h", ] @@ -1926,8 +1961,6 @@ split_static_library("browser") { sources += [ "loader/data_reduction_proxy_resource_throttle_android.cc", "loader/data_reduction_proxy_resource_throttle_android.h", - "safe_browsing/mock_permission_report_sender.cc", - "safe_browsing/mock_permission_report_sender.h", "safe_browsing/permission_reporter.cc", "safe_browsing/permission_reporter.h", "safe_browsing/ping_manager.cc", @@ -1936,6 +1969,10 @@ split_static_library("browser") { "safe_browsing/protocol_manager_helper.h", "safe_browsing/safe_browsing_blocking_page.cc", "safe_browsing/safe_browsing_blocking_page.h", + "safe_browsing/safe_browsing_navigation_observer.cc", + "safe_browsing/safe_browsing_navigation_observer.h", + "safe_browsing/safe_browsing_navigation_observer_manager.cc", + "safe_browsing/safe_browsing_navigation_observer_manager.h", "safe_browsing/safe_browsing_service.cc", "safe_browsing/safe_browsing_service.h", "safe_browsing/services_delegate.h", @@ -2133,11 +2170,6 @@ split_static_library("browser") { "metrics/perf/windowed_incognito_observer.h", "policy/default_geolocation_policy_handler.cc", "policy/default_geolocation_policy_handler.h", - - # This is technically also dependent on enable_plugins but we don"t - # support ChromeOS with enable_plugins==0. - "renderer_host/pepper/pepper_platform_verification_message_filter.cc", - "renderer_host/pepper/pepper_platform_verification_message_filter.h", ] deps += [ "//chrome/browser/chromeos" ] public_deps += [ @@ -2187,6 +2219,7 @@ split_static_library("browser") { "//services/ui/public/cpp/input_devices", "//ui/aura", "//ui/compositor", + "//ui/snapshot", "//ui/views/mus", ] } @@ -2222,8 +2255,11 @@ split_static_library("browser") { ] } if (use_aura && !use_ozone && is_desktop_linux) { - deps += [ "//chrome/browser/ui/libgtk2ui" ] - allow_circular_includes_from += [ "//chrome/browser/ui/libgtk2ui" ] + if (use_gtk3) { + deps += [ "//chrome/browser/ui/libgtkui:libgtk3ui" ] + } else { + deps += [ "//chrome/browser/ui/libgtkui:libgtk2ui" ] + } } if (is_posix && !is_mac) { sources += [ @@ -2349,7 +2385,6 @@ split_static_library("browser") { "themes/custom_theme_supplier.cc", "themes/custom_theme_supplier.h", "themes/theme_properties.cc", - "themes/theme_properties.h", "themes/theme_service.cc", "themes/theme_service.h", "themes/theme_service_factory.cc", @@ -2358,6 +2393,7 @@ split_static_library("browser") { "themes/theme_syncable_service.cc", "themes/theme_syncable_service.h", ] + deps += [ ":theme_properties" ] } if (enable_basic_printing || enable_print_preview) { @@ -2533,6 +2569,7 @@ split_static_library("browser") { ] deps += [ "//components/cdm/browser", + "//components/payments/android:payments_jni", "//components/resources:components_resources", "//third_party/android_opengl/etc1", "//third_party/android_tools:cpu_features", @@ -2763,10 +2800,10 @@ split_static_library("browser") { "obsolete_system/obsolete_system_win.cc", "pdf/pdf_extension_util.cc", "pdf/pdf_extension_util.h", - "permissions/permission_request_impl.cc", - "permissions/permission_request_impl.h", "power/process_power_collector.cc", "power/process_power_collector.h", + "power_usage_monitor/power_usage_monitor.cc", + "power_usage_monitor/power_usage_monitor.h", "process_singleton_modal_dialog_lock.cc", "process_singleton_modal_dialog_lock.h", "process_singleton_posix.cc", @@ -2815,8 +2852,6 @@ split_static_library("browser") { "signin/signin_ui_util.h", "speech/extension_api/tts_extension_api_constants.cc", # Should be moved to extensions section? "speech/extension_api/tts_extension_api_constants.h", - "ssl/ssl_add_certificate.cc", - "ssl/ssl_add_certificate.h", "ssl/ssl_client_auth_observer.cc", "ssl/ssl_client_auth_observer.h", "status_icons/desktop_notification_balloon.cc", @@ -2842,6 +2877,7 @@ split_static_library("browser") { "//chrome/browser/profile_resetter:profile_reset_report_proto", "//components/feedback", "//components/web_modal", + "//device/battery", "//net:net_browser_services", ] } @@ -2898,6 +2934,9 @@ split_static_library("browser") { "android/browsing_data/url_filter_bridge.h", "android/chrome_application.cc", "android/chrome_application.h", + "android/chrome_backup_agent.cc", + "android/chrome_backup_agent.h", + "android/chrome_backup_watcher.cc", "android/chrome_feature_list.cc", "android/chrome_feature_list.h", "android/chrome_jni_registrar.cc", @@ -2988,12 +3027,12 @@ split_static_library("browser") { "android/document/document_web_contents_delegate.cc", "android/dom_distiller/distiller_ui_handle_android.cc", "android/dom_distiller/distiller_ui_handle_android.h", - "android/download/android_download_manager_overwrite_infobar_delegate.cc", - "android/download/android_download_manager_overwrite_infobar_delegate.h", + "android/download/android_download_manager_duplicate_infobar_delegate.cc", + "android/download/android_download_manager_duplicate_infobar_delegate.h", "android/download/chrome_download_delegate.cc", "android/download/chrome_download_delegate.h", - "android/download/chrome_download_manager_overwrite_infobar_delegate.cc", - "android/download/chrome_download_manager_overwrite_infobar_delegate.h", + "android/download/chrome_duplicate_download_infobar_delegate.cc", + "android/download/chrome_duplicate_download_infobar_delegate.h", "android/download/dangerous_download_infobar_delegate.cc", "android/download/dangerous_download_infobar_delegate.h", "android/download/download_controller.cc", @@ -3002,8 +3041,8 @@ split_static_library("browser") { "android/download/download_controller_base.h", "android/download/download_manager_service.cc", "android/download/download_manager_service.h", - "android/download/download_overwrite_infobar_delegate.cc", - "android/download/download_overwrite_infobar_delegate.h", + "android/download/duplicate_download_infobar_delegate.cc", + "android/download/duplicate_download_infobar_delegate.h", "android/download/mock_download_controller.cc", "android/download/mock_download_controller.h", "android/download/ui/thumbnail_provider.cc", @@ -3144,6 +3183,10 @@ split_static_library("browser") { "android/precache/precache_launcher.h", "android/preferences/autofill/autofill_profile_bridge.cc", "android/preferences/autofill/autofill_profile_bridge.h", + "android/preferences/browser_prefs_android.cc", + "android/preferences/browser_prefs_android.h", + "android/preferences/command_line_pref_store_android.cc", + "android/preferences/command_line_pref_store_android.h", "android/preferences/pref_service_bridge.cc", "android/preferences/pref_service_bridge.h", "android/preferences/website_preference_bridge.cc", @@ -3168,6 +3211,10 @@ split_static_library("browser") { "android/rlz/revenue_stats.h", "android/safe_browsing/safe_browsing_api_handler_bridge.cc", "android/safe_browsing/safe_browsing_api_handler_bridge.h", + "android/search_geolocation_disclosure_infobar_delegate.cc", + "android/search_geolocation_disclosure_infobar_delegate.h", + "android/search_geolocation_disclosure_tab_helper.cc", + "android/search_geolocation_disclosure_tab_helper.h", "android/seccomp_support_detector.cc", "android/seccomp_support_detector.h", "android/service_tab_launcher.cc", @@ -3298,6 +3345,12 @@ split_static_library("browser") { "password_manager/update_password_infobar_delegate_android.h", "permissions/grouped_permission_infobar_delegate_android.cc", "permissions/grouped_permission_infobar_delegate_android.h", + "permissions/permission_dialog_delegate.cc", + "permissions/permission_dialog_delegate.h", + "permissions/permission_infobar_delegate.cc", + "permissions/permission_infobar_delegate.h", + "permissions/permission_prompt_android.cc", + "permissions/permission_prompt_android.h", "permissions/permission_queue_controller.cc", "permissions/permission_queue_controller.h", "permissions/permission_update_infobar_delegate_android.cc", @@ -3319,7 +3372,6 @@ split_static_library("browser") { "signin/oauth2_token_service_delegate_android.h", "ssl/security_state_model_android.cc", "ssl/security_state_model_android.h", - "ssl/ssl_add_certificate_android.cc", "sync/glue/synced_tab_delegate_android.cc", "sync/glue/synced_tab_delegate_android.h", "sync/glue/synced_window_delegate_android.cc", @@ -3336,6 +3388,7 @@ split_static_library("browser") { ":delta_file_proto", ":jni_headers", "//blimp/client/public", + "//blimp/client/support/resources", "//chrome/browser/android/webapk:proto", "//components/data_usage/android", "//components/precache/content", @@ -3353,11 +3406,24 @@ split_static_library("browser") { "supervised_user/child_accounts/child_account_service_android.h", ] } + + # Used for testing only, should not be shipped to end users. + if (!is_official_build) { + sources += [ + "android/offline_pages/evaluation/evaluation_test_scheduler.cc", + "android/offline_pages/evaluation/evaluation_test_scheduler.h", + "android/offline_pages/evaluation/offline_page_evaluation_bridge.cc", + "android/offline_pages/evaluation/offline_page_evaluation_bridge.h", + ] + } } - if (enable_vr_shell && android_java_ui) { - defines += [ "ENABLE_VR_SHELL" ] - deps += [ "android/vr_shell:vr_shell" ] + if (enable_vr_shell || enable_webvr) { + if (enable_vr_shell) { + defines += [ "ENABLE_VR_SHELL" ] + } + + deps += [ "android/vr_shell:vr_common" ] configs += [ "//third_party/gvr-android-sdk:libgvr_config" ] } @@ -3365,6 +3431,7 @@ split_static_library("browser") { deps += [ "//chrome/app_shim", "//chrome/browser/apps/app_shim", + "//third_party/crashpad/crashpad/client:client", "//third_party/google_toolbox_for_mac", "//third_party/mozilla", ] @@ -3409,6 +3476,7 @@ split_static_library("browser") { "//components/browser_watcher", "//components/browser_watcher:browser_watcher_client", "//google_update", + "//third_party/crashpad/crashpad/client:client", "//third_party/iaccessible2", "//third_party/isimpledom", "//third_party/wtl", @@ -3465,20 +3533,33 @@ split_static_library("browser") { "first_run/upgrade_util.cc", "first_run/upgrade_util_linux.cc", "first_run/upgrade_util_linux.h", - "fullscreen_aurax11.cc", "icon_loader_auralinux.cc", - "media/webrtc/window_icon_util_x11.cc", "password_manager/native_backend_kwallet_x.cc", "password_manager/native_backend_kwallet_x.h", "platform_util_linux.cc", "shell_integration_linux.cc", "shell_integration_linux.h", "speech/tts_linux.cc", - "themes/theme_service_aurax11.cc", - "themes/theme_service_aurax11.h", "web_applications/web_app_linux.cc", ] - if (!use_ozone) { + + if (use_x11) { + sources += [ + "fullscreen_aurax11.cc", + "media/webrtc/window_icon_util_x11.cc", + + # ThemeServiceAuraX11 does not depend on X11, although its + # instantiation/inclusion in theme_service_factory.cc is conditioned + # by USE_X11. + # TODO(tonikitoo): Check if non-x11 could benefit from it. If so, + # rename and use it. + "themes/theme_service_aurax11.cc", + "themes/theme_service_aurax11.h", + ] + } + + # libsecret hard depends on GLib. + if (use_glib) { sources += [ "password_manager/native_backend_libsecret.cc", "password_manager/native_backend_libsecret.h", @@ -3486,6 +3567,13 @@ split_static_library("browser") { defines += [ "USE_LIBSECRET" ] deps += [ "//third_party/libsecret" ] } + + if (use_ozone) { + sources += [ + "fullscreen_ozone.cc", + "media/webrtc/window_icon_util_ozone.cc", + ] + } } if (android_java_ui) { @@ -3521,8 +3609,6 @@ split_static_library("browser") { "supervised_user/child_accounts/permission_request_creator_apiary.h", "supervised_user/experimental/safe_search_url_reporter.cc", "supervised_user/experimental/safe_search_url_reporter.h", - "supervised_user/experimental/supervised_user_async_url_checker.cc", - "supervised_user/experimental/supervised_user_async_url_checker.h", "supervised_user/experimental/supervised_user_blacklist.cc", "supervised_user/experimental/supervised_user_blacklist.h", "supervised_user/experimental/supervised_user_filtering_switches.cc", @@ -3734,6 +3820,8 @@ if (android_java_ui) { "../android/java/src/org/chromium/chrome/browser/BackgroundSyncLauncher.java", "../android/java/src/org/chromium/chrome/browser/BluetoothChooserDialog.java", "../android/java/src/org/chromium/chrome/browser/ChromeApplication.java", + "../android/java/src/org/chromium/chrome/browser/ChromeBackupAgent.java", + "../android/java/src/org/chromium/chrome/browser/ChromeBackupWatcher.java", "../android/java/src/org/chromium/chrome/browser/ChromeFeatureList.java", "../android/java/src/org/chromium/chrome/browser/ChromeHttpAuthHandler.java", "../android/java/src/org/chromium/chrome/browser/DevToolsServer.java", @@ -3807,7 +3895,7 @@ if (android_java_ui) { "../android/java/src/org/chromium/chrome/browser/infobar/AutofillSaveCardInfoBar.java", "../android/java/src/org/chromium/chrome/browser/infobar/ConfirmInfoBar.java", "../android/java/src/org/chromium/chrome/browser/infobar/DataReductionPromoInfoBarDelegate.java", - "../android/java/src/org/chromium/chrome/browser/infobar/DownloadOverwriteInfoBar.java", + "../android/java/src/org/chromium/chrome/browser/infobar/DuplicateDownloadInfoBar.java", "../android/java/src/org/chromium/chrome/browser/infobar/GeneratedPasswordSavedInfoBarDelegate.java", "../android/java/src/org/chromium/chrome/browser/infobar/GroupedPermissionInfoBar.java", "../android/java/src/org/chromium/chrome/browser/infobar/InfoBar.java", @@ -3816,7 +3904,7 @@ if (android_java_ui) { "../android/java/src/org/chromium/chrome/browser/infobar/InstantAppsInfoBarDelegate.java", "../android/java/src/org/chromium/chrome/browser/infobar/PermissionInfoBar.java", "../android/java/src/org/chromium/chrome/browser/infobar/PermissionUpdateInfoBarDelegate.java", - "../android/java/src/org/chromium/chrome/browser/infobar/SavePasswordInfoBar.java", + "../android/java/src/org/chromium/chrome/browser/infobar/SearchGeolocationDisclosureInfoBar.java", "../android/java/src/org/chromium/chrome/browser/infobar/SimpleConfirmInfoBarBuilder.java", "../android/java/src/org/chromium/chrome/browser/infobar/SubresourceFilterInfoBar.java", "../android/java/src/org/chromium/chrome/browser/infobar/TranslateInfoBar.java", @@ -3837,6 +3925,7 @@ if (android_java_ui) { "../android/java/src/org/chromium/chrome/browser/mojo/ChromeInterfaceRegistrar.java", "../android/java/src/org/chromium/chrome/browser/net/qualityprovider/ExternalEstimateProviderAndroid.java", "../android/java/src/org/chromium/chrome/browser/net/spdyproxy/DataReductionProxySettings.java", + "../android/java/src/org/chromium/chrome/browser/notifications/ActionInfo.java", "../android/java/src/org/chromium/chrome/browser/notifications/NotificationPlatformBridge.java", "../android/java/src/org/chromium/chrome/browser/ntp/ForeignSessionHelper.java", "../android/java/src/org/chromium/chrome/browser/ntp/LogoBridge.java", @@ -3854,6 +3943,7 @@ if (android_java_ui) { "../android/java/src/org/chromium/chrome/browser/omnibox/OmniboxPrerender.java", "../android/java/src/org/chromium/chrome/browser/omnibox/OmniboxUrlEmphasizer.java", "../android/java/src/org/chromium/chrome/browser/omnibox/OmniboxViewUtil.java", + "../android/java/src/org/chromium/chrome/browser/omnibox/geo/GeolocationHeader.java", "../android/java/src/org/chromium/chrome/browser/pageinfo/CertificateViewer.java", "../android/java/src/org/chromium/chrome/browser/pageinfo/ConnectionInfoPopup.java", "../android/java/src/org/chromium/chrome/browser/pageinfo/WebsiteSettingsPopup.java", @@ -3861,6 +3951,10 @@ if (android_java_ui) { "../android/java/src/org/chromium/chrome/browser/password_manager/AccountChooserDialog.java", "../android/java/src/org/chromium/chrome/browser/password_manager/AutoSigninFirstRunDialog.java", "../android/java/src/org/chromium/chrome/browser/password_manager/Credential.java", + "../android/java/src/org/chromium/chrome/browser/payments/PaymentValidator.java", + "../android/java/src/org/chromium/chrome/browser/permissions/PermissionDialogController.java", + "../android/java/src/org/chromium/chrome/browser/permissions/PermissionDialogDelegate.java", + "../android/java/src/org/chromium/chrome/browser/physicalweb/UrlManager.java", "../android/java/src/org/chromium/chrome/browser/policy/PolicyAuditor.java", "../android/java/src/org/chromium/chrome/browser/precache/PrecacheLauncher.java", "../android/java/src/org/chromium/chrome/browser/preferences/LocationSettings.java", @@ -3906,6 +4000,11 @@ if (android_java_ui) { "../android/java/src/org/chromium/chrome/browser/webapps/WebApkUpdateManager.java", "../android/java/src/org/chromium/chrome/browser/webapps/WebappRegistry.java", ] + + # Used for testing only, should not be shipped to end users. + if (!is_official_build) { + sources += [ "../android/java/src/org/chromium/chrome/browser/offlinepages/evaluation/OfflinePageEvaluationBridge.java" ] + } jni_package = "chrome" } @@ -3938,6 +4037,12 @@ if (is_win) { } } +source_set("theme_properties") { + sources = [ + "themes/theme_properties.h", + ] +} + proto_library("resource_prefetch_predictor_proto") { sources = [ "predictors/resource_prefetch_predictor.proto", @@ -3947,7 +4052,12 @@ proto_library("resource_prefetch_predictor_proto") { grit("resources") { source = "browser_resources.grd" use_qualified_include = true + defines = chrome_grit_defines + if (enable_hangout_services_extension) { + defines += [ "enable_hangout_services_extension" ] + } + output_dir = "$root_gen_dir/chrome" outputs = [ "grit/browser_resources.h", @@ -3967,6 +4077,7 @@ grit("resources") { # Depend only on the generated mojo bindings since we read the .mojom.js # file, rather than the whole mojo target which will link the C++ bindings. + "//chrome/app:chrome_content_browser_manifest_overlay", "//chrome/browser/ui/webui/engagement:mojo_bindings__generator", "//chrome/browser/ui/webui/omnibox:mojo_bindings__generator", "//chrome/browser/ui/webui/plugins:mojo_bindings__generator", @@ -4027,12 +4138,16 @@ static_library("test_support") { "browsing_data/mock_browsing_data_indexed_db_helper.h", "browsing_data/mock_browsing_data_local_storage_helper.cc", "browsing_data/mock_browsing_data_local_storage_helper.h", + "browsing_data/mock_browsing_data_media_license_helper.cc", + "browsing_data/mock_browsing_data_media_license_helper.h", "browsing_data/mock_browsing_data_quota_helper.cc", "browsing_data/mock_browsing_data_quota_helper.h", "browsing_data/mock_browsing_data_service_worker_helper.cc", "browsing_data/mock_browsing_data_service_worker_helper.h", "download/download_test_file_activity_observer.cc", "download/download_test_file_activity_observer.h", + "history/history_test_utils.cc", + "history/history_test_utils.h", "media/webrtc/fake_desktop_media_list.cc", "media/webrtc/fake_desktop_media_list.h", "net/dns_probe_test_util.cc", @@ -4061,6 +4176,15 @@ static_library("test_support") { "sync/profile_sync_test_util.h", ] + if (safe_browsing_mode != 0) { + # "Safe Browsing Basic" files used for safe browsing in full mode + # (safe_browsing=1) and mobile (=2) + sources += [ + "safe_browsing/mock_permission_report_sender.cc", + "safe_browsing/mock_permission_report_sender.h", + ] + } + configs += [ "//build/config:precompiled_headers" ] public_deps = [ @@ -4081,7 +4205,7 @@ static_library("test_support") { "//components/sessions:test_support", "//components/subresource_filter/core/browser:test_support", "//components/subresource_filter/core/common:test_support", - "//components/syncable_prefs:test_support", + "//components/sync_preferences:test_support", "//components/user_prefs/tracked:user_prefs_tracked_test_support", "//content/test:test_support", "//google_apis:test_support", @@ -4259,7 +4383,7 @@ static_library("test_support_ui") { deps = [ "//components/metrics:test_support", - "//components/password_manager/content/public/interfaces", + "//components/password_manager/content/common:mojo_interfaces", "//components/password_manager/core/browser:test_support", "//components/translate/content/common", "//skia", diff --git a/chromium/chrome/browser/android/vr_shell/BUILD.gn b/chromium/chrome/browser/android/vr_shell/BUILD.gn index f2e1f803d8a..2a495d5e3d3 100644 --- a/chromium/chrome/browser/android/vr_shell/BUILD.gn +++ b/chromium/chrome/browser/android/vr_shell/BUILD.gn @@ -6,73 +6,95 @@ import("//build/config/android/rules.gni") import("//chrome/common/features.gni") import("//testing/test.gni") -assert(enable_vr_shell && android_java_ui) +assert(enable_vr_shell || enable_webvr) -static_library("vr_shell") { - sources = [ - "animation.cc", - "animation.h", - "easing.cc", - "easing.h", - "ui_elements.cc", - "ui_elements.h", - "ui_scene.cc", - "ui_scene.h", - "vr_compositor.cc", - "vr_compositor.h", - "vr_controller.cc", - "vr_controller.h", - "vr_gesture.h", - "vr_gl_util.cc", - "vr_gl_util.h", - "vr_input_manager.cc", - "vr_input_manager.h", - "vr_math.cc", - "vr_math.h", - "vr_shell.cc", - "vr_shell.h", - "vr_shell_delegate.cc", - "vr_shell_delegate.h", - "vr_shell_renderer.cc", - "vr_shell_renderer.h", - ] +if (current_cpu == "arm" || current_cpu == "arm64") { + static_library("vr_common") { + defines = [] - deps = [ - ":vr_shell_jni_headers", - "//base", - "//cc", - "//content/public/browser", - "//content/public/common", - "//device/vr", - "//third_party/gvr-android-sdk:libgvr", - "//ui/android", - "//ui/base", - "//ui/gl", - "//ui/gl/init", - ] + sources = [ + "animation.cc", + "animation.h", + "easing.cc", + "easing.h", + "ui_elements.cc", + "ui_elements.h", + "ui_interface.cc", + "ui_interface.h", + "ui_scene.cc", + "ui_scene.h", + "vr_compositor.cc", + "vr_compositor.h", + "vr_controller.cc", + "vr_controller.h", + "vr_gesture.h", + "vr_gl_util.cc", + "vr_gl_util.h", + "vr_input_manager.cc", + "vr_input_manager.h", + "vr_math.cc", + "vr_math.h", + "vr_shell.cc", + "vr_shell.h", + "vr_shell_delegate.cc", + "vr_shell_delegate.h", + "vr_shell_renderer.cc", + "vr_shell_renderer.h", + "vr_usage_monitor.cc", + "vr_usage_monitor.h", + "vr_web_contents_observer.cc", + "vr_web_contents_observer.h", + ] - configs += [ "//third_party/gvr-android-sdk:libgvr_config" ] -} + if (enable_vr_shell) { + defines += [ "ENABLE_VR_SHELL" ] + } + if (enable_vr_shell_ui_dev) { + assert(enable_vr_shell) + defines += [ "ENABLE_VR_SHELL_UI_DEV" ] + } + + deps = [ + ":vr_shell_jni_headers", + "//base", + "//cc", + "//content/public/browser", + "//content/public/common", + "//device/vr", + "//ui/android", + "//ui/base", + "//ui/display", + "//ui/gl", + "//ui/gl/init", + ] + + libs = + [ "//third_party/gvr-android-sdk/libgvr_shim_static_${current_cpu}.a" ] + configs += [ "//third_party/gvr-android-sdk:libgvr_config" ] + } -generate_jni("vr_shell_jni_headers") { - sources = [ - "//chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShell.java", - "//chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java", - ] - jni_package = "vr_shell" + generate_jni("vr_shell_jni_headers") { + sources = [ + "//chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellDelegate.java", + "//chrome/android/java/src/org/chromium/chrome/browser/vr_shell/VrShellImpl.java", + ] + jni_package = "vr_shell" + } } -test("vr_shell_unittests") { - sources = [ - "ui_elements_unittest.cc", - "ui_scene_unittest.cc", - ] +if (enable_vr_shell) { + test("vr_shell_unittests") { + sources = [ + "ui_elements_unittest.cc", + "ui_scene_unittest.cc", + ] - deps = [ - ":vr_shell", - "//base/test:run_all_unittests", - "//base/test:test_support", - "//testing/gtest", - "//ui/gfx/geometry", - ] + deps = [ + ":vr_common", + "//base/test:run_all_unittests", + "//base/test:test_support", + "//testing/gtest", + "//ui/gfx/geometry", + ] + } } diff --git a/chromium/chrome/browser/browser_resources.grd b/chromium/chrome/browser/browser_resources.grd index d9563006385..bd05bf6fd69 100644 --- a/chromium/chrome/browser/browser_resources.grd +++ b/chromium/chrome/browser/browser_resources.grd @@ -72,6 +72,19 @@ </if> <structure name="IDR_READER_OUT_OF_DATE_HTML" file="resources\reader_out_of_date.html" flattenhtml="true" type="chrome_html" /> <structure name="IDR_SIGNIN_SHARED_CSS_HTML" file="resources\signin\signin_shared_css.html" preprocess="true" allowexternalscript="true" type="chrome_html" /> + <if expr="not is_android and not is_ios and not chromeos"> + <structure name="IDR_WELCOME_CSS" file="resources\welcome\welcome.css" type="chrome_html" preprocess="true"/> + <structure name="IDR_WELCOME_HTML" file="resources\welcome\welcome.html" type="chrome_html" preprocess="true"/> + <structure name="IDR_WELCOME_JS" file="resources\welcome\welcome.js" type="chrome_html" preprocess="true"/> + </if> + <if expr="is_win"> + <structure name="IDR_WELCOME_WIN10_INLINE_CSS" file="resources\welcome\win10\inline.css" type="chrome_html" /> + <structure name="IDR_WELCOME_WIN10_INLINE_HTML" file="resources\welcome\win10\inline.html" type="chrome_html" /> + <structure name="IDR_WELCOME_WIN10_INLINE_JS" file="resources\welcome\win10\inline.js" type="chrome_html" /> + <structure name="IDR_WELCOME_WIN10_SECTIONED_CSS" file="resources\welcome\win10\sectioned.css" type="chrome_html" /> + <structure name="IDR_WELCOME_WIN10_SECTIONED_HTML" file="resources\welcome\win10\sectioned.html" type="chrome_html" /> + <structure name="IDR_WELCOME_WIN10_SECTIONED_JS" file="resources\welcome\win10\sectioned.js" type="chrome_html" /> + </if> </structures> <includes> <if expr="is_win"> @@ -91,10 +104,15 @@ <include name="IDR_ABOUT_SYS_HTML" file="resources\about_sys\about_sys.html" flattenhtml="true" type="BINDATA" /> </if> <include name="IDR_AD_NETWORK_HASHES" file="resources\ad_networks.dat" type="BINDATA" /> + <include name="IDR_BLUETOOTH_ADAPTER_MOJO_JS" file="${root_gen_dir}\device\bluetooth\public\interfaces\adapter.mojom.js" use_base_dir="false" type="BINDATA" compress="gzip" /> + <include name="IDR_BLUETOOTH_DEVICE_MOJO_JS" file="${root_gen_dir}\device\bluetooth\public\interfaces\device.mojom.js" use_base_dir="false" type="BINDATA" compress="gzip" /> <include name="IDR_BLUETOOTH_INTERNALS_CSS" file="resources\bluetooth_internals\bluetooth_internals.css" type="BINDATA" compress="gzip" /> + <include name="IDR_BLUETOOTH_INTERNALS_ADAPTER_BROKER_JS" file="resources\bluetooth_internals\adapter_broker.js" type="BINDATA" compress="gzip" /> + <include name="IDR_BLUETOOTH_INTERNALS_DEVICE_COLLECTION_JS" file="resources\bluetooth_internals\device_collection.js" type="BINDATA" compress="gzip" /> + <include name="IDR_BLUETOOTH_INTERNALS_DEVICE_TABLE_JS" file="resources\bluetooth_internals\device_table.js" type="BINDATA" compress="gzip" /> <include name="IDR_BLUETOOTH_INTERNALS_HTML" file="resources\bluetooth_internals\bluetooth_internals.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" compress="gzip" /> + <include name="IDR_BLUETOOTH_INTERNALS_INTERFACES_JS" file="resources\bluetooth_internals\interfaces.js" type="BINDATA" compress="gzip" /> <include name="IDR_BLUETOOTH_INTERNALS_JS" file="resources\bluetooth_internals\bluetooth_internals.js" type="BINDATA" compress="gzip" /> - <include name="IDR_BLUETOOTH_MOJO_JS" file="${root_gen_dir}\device\bluetooth\public\interfaces\adapter.mojom.js" use_base_dir="false" type="BINDATA" compress="gzip" /> <include name="IDR_BOOKMARKS_MANIFEST" file="resources\bookmark_manager\manifest.json" type="BINDATA" /> <if expr="is_posix and not is_macosx and not is_ios"> <include name="IDR_CERTIFICATE_VIEWER_HTML" file="resources\certificate_viewer.html" type="BINDATA" /> @@ -153,10 +171,14 @@ <include name="IDR_MD_EXTENSIONS_EXTENSIONS_JS" file="resources\md_extensions\extensions.js" type="BINDATA" /> <include name="IDR_MD_EXTENSIONS_ANIMATION_HELPER_HTML" file="resources\md_extensions\animation_helper.html" type="BINDATA" /> <include name="IDR_MD_EXTENSIONS_ANIMATION_HELPER_JS" file="resources\md_extensions\animation_helper.js" type="BINDATA" /> + <include name="IDR_MD_EXTENSIONS_CODE_SECTION_HTML" file="resources\md_extensions\code_section.html" type="BINDATA" /> + <include name="IDR_MD_EXTENSIONS_CODE_SECTION_JS" file="resources\md_extensions\code_section.js" type="BINDATA" /> <include name="IDR_MD_EXTENSIONS_DETAIL_VIEW_HTML" file="resources\md_extensions\detail_view.html" type="BINDATA" /> <include name="IDR_MD_EXTENSIONS_DETAIL_VIEW_JS" file="resources\md_extensions\detail_view.js" type="BINDATA" /> <include name="IDR_MD_EXTENSIONS_DROP_OVERLAY_HTML" file="resources\md_extensions\drop_overlay.html" type="BINDATA" /> <include name="IDR_MD_EXTENSIONS_DROP_OVERLAY_JS" file="resources\md_extensions\drop_overlay.js" type="BINDATA" /> + <include name="IDR_MD_EXTENSIONS_ERROR_PAGE_HTML" file="resources\md_extensions\error_page.html" flattenhtml="true" type="BINDATA" /> + <include name="IDR_MD_EXTENSIONS_ERROR_PAGE_JS" file="resources\md_extensions\error_page.js" type="BINDATA" /> <include name="IDR_MD_EXTENSIONS_KEYBOARD_SHORTCUTS_HTML" file="resources\md_extensions\keyboard_shortcuts.html" type="BINDATA" /> <include name="IDR_MD_EXTENSIONS_KEYBOARD_SHORTCUTS_JS" file="resources\md_extensions\keyboard_shortcuts.js" type="BINDATA" /> <include name="IDR_MD_EXTENSIONS_MANAGER_HTML" file="resources\md_extensions\manager.html" type="BINDATA" /> @@ -192,14 +214,10 @@ <include name="IDR_OFFLINE_INTERNALS_CSS" file="resources\offline_pages\offline_internals.css" type="BINDATA" compress="gzip" /> <include name="IDR_OFFLINE_INTERNALS_JS" file="resources\offline_pages\offline_internals.js" type="BINDATA" compress="gzip" /> <include name="IDR_OFFLINE_INTERNALS_BROWSER_PROXY_JS" file="resources\offline_pages\offline_internals_browser_proxy.js" type="BINDATA" compress="gzip" /> - <include name="IDR_POPULAR_SITES_INTERNALS_HTML" file="resources\popular_sites_internals.html" allowexternalscript="true" compress="gzip" type="BINDATA" /> - <include name="IDR_POPULAR_SITES_INTERNALS_CSS" file="resources\popular_sites_internals.css" compress="gzip" type="BINDATA" /> - <include name="IDR_POPULAR_SITES_INTERNALS_JS" file="resources\popular_sites_internals.js" compress="gzip" type="BINDATA" /> <include name="IDR_SNIPPETS_INTERNALS_HTML" file="resources\snippets_internals.html" allowexternalscript="true" compress="gzip" type="BINDATA" /> <include name="IDR_SNIPPETS_INTERNALS_CSS" file="resources\snippets_internals.css" compress="gzip" type="BINDATA" /> <include name="IDR_SNIPPETS_INTERNALS_JS" file="resources\snippets_internals.js" compress="gzip" type="BINDATA" /> - <!-- TODO: Enable only for VrShell, independent of Android. --> - <if expr="enable_vr_shell"> + <if expr="enable_vr_shell or enable_webvr"> <include name="IDR_VR_SHELL_UI_HTML" file="resources\vr_shell\vr_shell_ui.html" allowexternalscript="true" flattenhtml="true" type="BINDATA" /> <include name="IDR_VR_SHELL_UI_CSS" file="resources\vr_shell\vr_shell_ui.css" type="BINDATA" /> <include name="IDR_VR_SHELL_UI_JS" file="resources\vr_shell\vr_shell_ui.js" type="BINDATA" /> @@ -210,7 +228,7 @@ <include name="IDR_SUPERVISED_USER_INTERNALS_HTML" file="resources\supervised_user_internals.html" allowexternalscript="true" compress="gzip" type="BINDATA" /> <include name="IDR_SUPERVISED_USER_INTERNALS_CSS" file="resources\supervised_user_internals.css" compress="gzip" type="BINDATA" /> <include name="IDR_SUPERVISED_USER_INTERNALS_JS" file="resources\supervised_user_internals.js" compress="gzip" type="BINDATA" /> - <if expr="_google_chrome or enable_hangout_services_extension"> + <if expr="enable_hangout_services_extension"> <!-- Hangout Services extension, included in Google Chrome builds only. --> <include name="IDR_HANGOUT_SERVICES_MANIFEST" file="resources\hangout_services\manifest.json" type="BINDATA" /> </if> @@ -228,6 +246,10 @@ <include name="IDR_OTHER_DEVICES_JS" file="resources\history\other_devices.js" flattenhtml="true" type="BINDATA" compress="gzip" /> <if expr="not is_android and not is_ios"> + <!-- MD Bookmarks. --> + <include name="IDR_MD_BOOKMARKS_BOOKMARKS_HTML" file="resources\md_bookmarks\bookmarks.html" type="BINDATA" /> + + <!-- MD History. --> <include name="IDR_MD_HISTORY_CONSTANTS_HTML" file="resources\md_history\constants.html" type="BINDATA" /> <include name="IDR_MD_HISTORY_CONSTANTS_JS" file="resources\md_history\constants.js" type="BINDATA" /> <include name="IDR_MD_HISTORY_HISTORY_HTML" file="resources\md_history\history.html" flattenhtml="true" type="BINDATA" /> @@ -453,11 +475,6 @@ <include name="IDR_FIRST_RUN_DIALOG_MANIFEST" file="resources\chromeos\first_run\app/manifest.json" type="BINDATA" /> <include name="IDR_ARC_SUPPORT_MANIFEST" file="resources\chromeos\arc_support\manifest.json" type="BINDATA" /> </if> - <if expr="not is_android and not is_ios and not chromeos"> - <include name="IDR_WELCOME_CSS" file="resources\welcome\welcome.css" type="BINDATA" /> - <include name="IDR_WELCOME_HTML" file="resources\welcome\welcome.html" type="BINDATA" /> - <include name="IDR_WELCOME_JS" file="resources\welcome\welcome.js" type="BINDATA" /> - </if> <if expr="chromeos and _google_chrome"> <include name="IDR_GENIUS_APP_MANIFEST" file="resources\chromeos\genius_app\manifest.json" type="BINDATA" /> <include name="IDR_HELP_MANIFEST" file="resources\help_app\manifest.json" type="BINDATA" /> @@ -468,10 +485,6 @@ <include name="IDR_SET_AS_DEFAULT_BROWSER_HTML" file="resources\set_as_default_browser.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> </if> <if expr="not is_android and not is_ios and not chromeos"> - <include name="IDR_USER_MANAGER_JS" file="resources\user_manager\user_manager.js" flattenhtml="true" type="BINDATA" /> - <include name="IDR_USER_MANAGER_HTML" file="resources\user_manager\user_manager.html" flattenhtml="true" allowexternalscript="true" type="BINDATA" /> - </if> - <if expr="not is_android and not is_ios and not chromeos"> <include name="IDR_MD_CONTROL_BAR_HTML" file="resources\md_user_manager\control_bar.html" type="BINDATA" /> <include name="IDR_MD_CONTROL_BAR_JS" file="resources\md_user_manager\control_bar.js" type="BINDATA" /> <include name="IDR_MD_CREATE_PROFILE_HTML" file="resources\md_user_manager\create_profile.html" type="BINDATA" /> @@ -593,8 +606,10 @@ <include name="IDR_IME_WINDOW_CLOSE_C" file="resources\input_ime\ime_window_close_click.png" type="BINDATA" /> <include name="IDR_IME_WINDOW_CLOSE_H" file="resources\input_ime\ime_window_close_hover.png" type="BINDATA" /> </if> - <include name="IDR_CHROME_CONTENT_BROWSER_MANIFEST_OVERLAY" file="chrome_content_browser_manifest_overlay.json" type="BINDATA" /> + <include name="IDR_CHROME_CONTENT_BROWSER_MANIFEST_OVERLAY" file="${root_gen_dir}\chrome_content_browser_manifest_overlay.json" use_base_dir="false" type="BINDATA" /> <include name="IDR_CHROME_CONTENT_GPU_MANIFEST_OVERLAY" file="chrome_content_gpu_manifest_overlay.json" type="BINDATA" /> + <include name="IDR_CHROME_CONTENT_PLUGIN_MANIFEST_OVERLAY" file="chrome_content_plugin_manifest_overlay.json" type="BINDATA" /> + <include name="IDR_CHROME_CONTENT_RENDERER_MANIFEST_OVERLAY" file="chrome_content_renderer_manifest_overlay.json" type="BINDATA" /> <include name="IDR_CHROME_CONTENT_UTILITY_MANIFEST_OVERLAY" file="chrome_content_utility_manifest_overlay.json" type="BINDATA" /> </includes> </release> diff --git a/chromium/chrome/browser/chrome_content_browser_manifest_overlay.json b/chromium/chrome/browser/chrome_content_browser_manifest_overlay.json index 3d6190b0822..f1004cbf6de 100644 --- a/chromium/chrome/browser/chrome_content_browser_manifest_overlay.json +++ b/chromium/chrome/browser/chrome_content_browser_manifest_overlay.json @@ -1,22 +1,70 @@ { - "name": "service:content_browser", - "capabilities": { - "provided": { - "renderer": [ - "autofill::mojom::AutofillDriver", - "autofill::mojom::PasswordManagerDriver", - "extensions::StashService", - "metrics::mojom::LeakDetector", - "startup_metric_utils::mojom::StartupMetricHost", - "translate::mojom::ContentTranslateDriver" - ], - "gpu": [ - "metrics::mojom::CallStackProfileCollector" - ], - "ash": [ - "ash::mojom::SystemTray", - "ash::mojom::SystemTrayClient" - ] + "name": "content_browser", + "display_name": "Chrome", + "interface_provider_specs": { + "service_manager:connector": { + "provides": { + "renderer": [ + "autofill::mojom::AutofillDriver", + "autofill::mojom::PasswordManagerDriver", + "extensions::StashService", + "metrics::mojom::LeakDetector", + "rappor::mojom::RapporRecorder", + "startup_metric_utils::mojom::StartupMetricHost", + "translate::mojom::ContentTranslateDriver" + ], + "gpu": [ + "metrics::mojom::CallStackProfileCollector" + ], + "ash": [ + // Under classic ash the browser provides some of the ash interfaces + // to itself. + "ash::mojom::LocaleNotificationController", + "ash::mojom::NewWindowClient", + "ash::mojom::ShelfController", + "ash::mojom::ShutdownController", + "ash::mojom::SystemTray", + "ash::mojom::SystemTrayClient", + "ash::mojom::WallpaperController", + "ash::mojom::WallpaperManager", + "ash::mojom::VolumeController", + "keyboard::mojom::Keyboard" + ], + "mash:launchable": [ + "mash::mojom::Launchable" + ] + }, + "requires": { + "ash": [ "ash" ], + "image_decoder": [ "decode" ] + } + }, + "navigation:frame": { + "provides": { + "renderer": [ + "autofill::mojom::AutofillDriver", + "autofill::mojom::PasswordManagerDriver", + "blink::mojom::ShareService", + "bluetooth::mojom::AdapterFactory", + "device::usb::ChooserService", + "device::usb::DeviceManager", + "contextual_search::mojom::ContextualSearchJsApiService", + "dom_distiller::mojom::DistillabilityService", + "dom_distiller::mojom::DistillerJavaScriptService", + "extensions::KeepAlive", + "extensions::mime_handler::MimeHandlerService", + "media_router::mojom::MediaRouter", + "mojom::OmniboxPageHandler", + "password_manager::mojom::CredentialManager", + "translate::mojom::ContentTranslateDriver", + + // TODO(beng): These should be moved to a separate capability. + "mojom::OmniboxPageHandler", + "mojom::PluginsPageHandler", + "mojom::SiteEngagementUIHandler", + "mojom::UsbInternalsPageHandler" + ] + } } } } diff --git a/chromium/chrome/browser/chrome_content_gpu_manifest_overlay.json b/chromium/chrome/browser/chrome_content_gpu_manifest_overlay.json index 60670f28a4b..1a1a45378b3 100644 --- a/chromium/chrome/browser/chrome_content_gpu_manifest_overlay.json +++ b/chromium/chrome/browser/chrome_content_gpu_manifest_overlay.json @@ -1,11 +1,14 @@ { - "name": "service:content_gpu", - "capabilities": { - "provided": { - "browser": [ - "arc::mojom::VideoAcceleratorService", - "arc::mojom::VideoAcceleratorServiceClient" - ] + "name": "content_gpu", + "interface_provider_specs": { + "service_manager:connector": { + "provides": { + "browser": [ + "arc::mojom::VideoAcceleratorService", + "arc::mojom::VideoAcceleratorServiceClient", + "mojom::ResourceUsageReporter" + ] + } } } } diff --git a/chromium/chrome/browser/chrome_content_plugin_manifest_overlay.json b/chromium/chrome/browser/chrome_content_plugin_manifest_overlay.json new file mode 100644 index 00000000000..d608eacfc13 --- /dev/null +++ b/chromium/chrome/browser/chrome_content_plugin_manifest_overlay.json @@ -0,0 +1,12 @@ +{ + "name": "content_plugin", + "interface_provider_specs": { + "service_manager:connector": { + "provides": { + "browser": [ + "mojom::ResourceUsageReporter" + ] + } + } + } +} diff --git a/chromium/chrome/browser/chrome_content_renderer_manifest_overlay.json b/chromium/chrome/browser/chrome_content_renderer_manifest_overlay.json new file mode 100644 index 00000000000..3a81d7febab --- /dev/null +++ b/chromium/chrome/browser/chrome_content_renderer_manifest_overlay.json @@ -0,0 +1,23 @@ +{ + "display_name": "Chrome Render Process", + "interface_provider_specs": { + "service_manager:connector": { + "provides": { + "browser": [ + "mojom::ResourceUsageReporter" + ] + } + }, + "navigation:frame": { + "provides": { + "browser": [ + "autofill::mojom::AutofillAgent", + "autofill::mojom::PasswordAutofillAgent", + "autofill::mojom::PasswordGenerationAgent", + "contextual_search::mojom::OverlayPageNotifierService", + "dom_distiller::mojom::DistillerPageNotifierService" + ] + } + } + } +} diff --git a/chromium/chrome/browser/chrome_content_utility_manifest_overlay.json b/chromium/chrome/browser/chrome_content_utility_manifest_overlay.json index 256153c8677..5577edf485a 100644 --- a/chromium/chrome/browser/chrome_content_utility_manifest_overlay.json +++ b/chromium/chrome/browser/chrome_content_utility_manifest_overlay.json @@ -1,14 +1,16 @@ { - "name": "service:content_utility", - "capabilities": { - "provided": { - "browser": [ - "mojom::ImageDecoder", - "mojom::ResourceUsageReporter", - "mojom::ShellHandler", - "net::interfaces::ProxyResolverFactory", - "safe_json::mojom::SafeJsonParser" - ] + "name": "content_utility", + "interface_provider_specs": { + "service_manager:connector": { + "provides": { + "browser": [ + "mojom::ImageDecoder", + "mojom::ResourceUsageReporter", + "mojom::ShellHandler", + "net::interfaces::ProxyResolverFactory", + "safe_json::mojom::SafeJsonParser" + ] + } } } } diff --git a/chromium/chrome/browser/chrome_notification_types.h b/chromium/chrome/browser/chrome_notification_types.h index 8ca989ae344..2e6b7fc4a76 100644 --- a/chromium/chrome/browser/chrome_notification_types.h +++ b/chromium/chrome/browser/chrome_notification_types.h @@ -6,14 +6,15 @@ #define CHROME_BROWSER_CHROME_NOTIFICATION_TYPES_H_ #include "build/build_config.h" +#include "extensions/features/features.h" -#if defined(ENABLE_EXTENSIONS) +#if BUILDFLAG(ENABLE_EXTENSIONS) #include "extensions/browser/notification_types.h" #else #include "content/public/browser/notification_types.h" #endif -#if defined(ENABLE_EXTENSIONS) +#if BUILDFLAG(ENABLE_EXTENSIONS) #define PREVIOUS_END extensions::NOTIFICATION_EXTENSIONS_END #else #define PREVIOUS_END content::NOTIFICATION_CONTENT_END @@ -127,7 +128,7 @@ enum NotificationType { // Details<InfoBar::RemovedDetails>. NOTIFICATION_TAB_CONTENTS_INFOBAR_REMOVED, -#if defined(ENABLE_EXTENSIONS) +#if BUILDFLAG(ENABLE_EXTENSIONS) // This notification is sent when extensions::TabHelper::SetExtensionApp is // invoked. The source is the extensions::TabHelper SetExtensionApp was // invoked on. @@ -313,7 +314,7 @@ enum NotificationType { // Cookies ----------------------------------------------------------------- -#if defined(ENABLE_EXTENSIONS) +#if BUILDFLAG(ENABLE_EXTENSIONS) // Sent when a cookie changes, for consumption by extensions. The source is a // Profile object, the details are a ChromeCookieDetails object. NOTIFICATION_COOKIE_CHANGED_FOR_EXTENSIONS, @@ -453,15 +454,6 @@ enum NotificationType { #if defined(USE_ASH) // Sent when wallpaper show animation has finished. NOTIFICATION_WALLPAPER_ANIMATION_FINISHED, - - // Sent when the Ash session has started. In its current incantation this is - // generated when the metro app has connected to the browser IPC channel. - // Used only on Windows. - NOTIFICATION_ASH_SESSION_STARTED, - - // Sent when the Ash session ended. Currently this means the metro app exited. - // Used only on Windows. - NOTIFICATION_ASH_SESSION_ENDED, #endif // Protocol Handler Registry ----------------------------------------------- diff --git a/chromium/chrome/browser/chromeos/BUILD.gn b/chromium/chrome/browser/chromeos/BUILD.gn index 67b07187dbb..15b99519803 100644 --- a/chromium/chrome/browser/chromeos/BUILD.gn +++ b/chromium/chrome/browser/chromeos/BUILD.gn @@ -4,7 +4,9 @@ import("//build/config/features.gni") import("//build/config/ui.gni") +import("//extensions/features/features.gni") import("//media/media_options.gni") +import("//printing/features/features.gni") import("//third_party/protobuf/proto_library.gni") assert(is_chromeos) @@ -39,7 +41,6 @@ source_set("chromeos") { "//ash:ash_with_content", "//ash/autoclick/mus/public/interfaces", "//ash/public/interfaces", - "//ash/public/interfaces", "//build/linux:fontconfig", "//chrome/browser/devtools", "//chrome/browser/extensions", @@ -62,6 +63,7 @@ source_set("chromeos") { "//components/feedback", "//components/flags_ui", "//components/login", + "//components/metrics/leak_detector", "//components/onc", "//components/ownership", "//components/pairing", @@ -69,8 +71,8 @@ source_set("chromeos") { "//components/proxy_config", "//components/safe_browsing_db:metadata_proto", "//components/session_manager/core", + "//components/sync_wifi", "//components/user_manager", - "//components/wifi_sync", # This depends directly on the variations target, rather than just # transitively via the common target because the proto sources need to @@ -91,7 +93,7 @@ source_set("chromeos") { "//mojo/common", "//net", "//ppapi/proxy:ipc", # For PpapiMsg_LoadPlugin - "//services/shell/public/cpp", + "//services/service_manager/public/cpp", # TODO: care about enable_basic_printing and enable_print_preview. "//components/sync", @@ -163,6 +165,14 @@ source_set("chromeos") { "app_mode/app_launch_utils.h", "app_mode/app_session.cc", "app_mode/app_session.h", + "app_mode/arc/arc_kiosk_app_launcher.cc", + "app_mode/arc/arc_kiosk_app_launcher.h", + "app_mode/arc/arc_kiosk_app_manager.cc", + "app_mode/arc/arc_kiosk_app_manager.h", + "app_mode/arc/arc_kiosk_app_service.cc", + "app_mode/arc/arc_kiosk_app_service.h", + "app_mode/arc/arc_kiosk_app_service_factory.cc", + "app_mode/arc/arc_kiosk_app_service_factory.h", "app_mode/certificate_manager_dialog.cc", "app_mode/certificate_manager_dialog.h", "app_mode/kiosk_app_data.cc", @@ -194,53 +204,70 @@ source_set("chromeos") { "app_mode/kiosk_session_plugin_handler_delegate.h", "app_mode/startup_app_launcher.cc", "app_mode/startup_app_launcher.h", - "arc/arc_android_management_checker.cc", - "arc/arc_android_management_checker.h", - "arc/arc_android_management_checker_delegate.h", "arc/arc_auth_code_fetcher.cc", "arc/arc_auth_code_fetcher.h", - "arc/arc_auth_code_fetcher_delegate.h", "arc/arc_auth_context.cc", "arc/arc_auth_context.h", - "arc/arc_auth_context_delegate.h", "arc/arc_auth_notification.cc", "arc/arc_auth_notification.h", "arc/arc_auth_service.cc", "arc/arc_auth_service.h", - "arc/arc_boot_error_notification.cc", - "arc/arc_boot_error_notification.h", - "arc/arc_downloads_watcher_service.cc", - "arc/arc_downloads_watcher_service.h", - "arc/arc_enterprise_reporting_service.cc", - "arc/arc_enterprise_reporting_service.h", - "arc/arc_external_protocol_dialog.cc", - "arc/arc_external_protocol_dialog.h", - "arc/arc_navigation_throttle.cc", - "arc/arc_navigation_throttle.h", "arc/arc_optin_uma.cc", "arc/arc_optin_uma.h", - "arc/arc_policy_bridge.cc", - "arc/arc_policy_bridge.h", - "arc/arc_print_service.cc", - "arc/arc_print_service.h", - "arc/arc_process.cc", - "arc/arc_process.h", - "arc/arc_process_service.cc", - "arc/arc_process_service.h", "arc/arc_service_launcher.cc", "arc/arc_service_launcher.h", - "arc/arc_settings_service.cc", - "arc/arc_settings_service.h", "arc/arc_support_host.cc", "arc/arc_support_host.h", - "arc/arc_tts_service.cc", - "arc/arc_tts_service.h", - "arc/arc_wallpaper_service.cc", - "arc/arc_wallpaper_service.h", - "arc/gpu_arc_video_service_host.cc", - "arc/gpu_arc_video_service_host.h", - "arc/page_transition_util.cc", - "arc/page_transition_util.h", + "arc/auth/arc_robot_auth.cc", + "arc/auth/arc_robot_auth.h", + "arc/downloads_watcher/arc_downloads_watcher_service.cc", + "arc/downloads_watcher/arc_downloads_watcher_service.h", + "arc/enterprise/arc_enterprise_reporting_service.cc", + "arc/enterprise/arc_enterprise_reporting_service.h", + "arc/extensions/arc_support_message_host.cc", + "arc/extensions/arc_support_message_host.h", + "arc/fileapi/arc_content_file_system_async_file_util.cc", + "arc/fileapi/arc_content_file_system_async_file_util.h", + "arc/fileapi/arc_content_file_system_backend_delegate.cc", + "arc/fileapi/arc_content_file_system_backend_delegate.h", + "arc/fileapi/arc_content_file_system_file_stream_reader.cc", + "arc/fileapi/arc_content_file_system_file_stream_reader.h", + "arc/fileapi/arc_content_file_system_service.cc", + "arc/fileapi/arc_content_file_system_service.h", + "arc/fileapi/arc_content_file_system_url_util.cc", + "arc/fileapi/arc_content_file_system_url_util.h", + "arc/fileapi/intent_helper_util.cc", + "arc/fileapi/intent_helper_util.h", + "arc/intent_helper/arc_external_protocol_dialog.cc", + "arc/intent_helper/arc_external_protocol_dialog.h", + "arc/intent_helper/arc_navigation_throttle.cc", + "arc/intent_helper/arc_navigation_throttle.h", + "arc/intent_helper/arc_settings_service.cc", + "arc/intent_helper/arc_settings_service.h", + "arc/notification/arc_boot_error_notification.cc", + "arc/notification/arc_boot_error_notification.h", + "arc/optin/arc_optin_preference_handler.cc", + "arc/optin/arc_optin_preference_handler.h", + "arc/optin/arc_optin_preference_handler_delegate.h", + "arc/policy/arc_android_management_checker.cc", + "arc/policy/arc_android_management_checker.h", + "arc/policy/arc_android_management_checker_delegate.h", + "arc/policy/arc_policy_bridge.cc", + "arc/policy/arc_policy_bridge.h", + "arc/policy/arc_policy_util.cc", + "arc/policy/arc_policy_util.h", + "arc/print/arc_print_service.cc", + "arc/print/arc_print_service.h", + "arc/process/arc_process.cc", + "arc/process/arc_process.h", + "arc/process/arc_process_service.cc", + "arc/process/arc_process_service.h", + "arc/tts/arc_tts_service.cc", + "arc/tts/arc_tts_service.h", + "arc/video/gpu_arc_video_service_host.cc", + "arc/video/gpu_arc_video_service_host.h", + "arc/wallpaper/arc_wallpaper_service.cc", + "arc/wallpaper/arc_wallpaper_service.h", "attestation/attestation_ca_client.cc", "attestation/attestation_ca_client.h", "attestation/attestation_policy_observer.cc", @@ -357,6 +384,8 @@ source_set("chromeos") { "extensions/dictionary_event_router.h", "extensions/extension_system_event_observer.cc", "extensions/extension_system_event_observer.h", + "extensions/extension_volume_observer.cc", + "extensions/extension_volume_observer.h", "extensions/external_cache.cc", "extensions/external_cache.h", "extensions/gfx_utils.cc", @@ -540,6 +569,8 @@ source_set("chromeos") { "genius_app/app_id.h", "hats/hats_dialog.cc", "hats/hats_dialog.h", + "hats/hats_finch_helper.cc", + "hats/hats_finch_helper.h", "hats/hats_notification_controller.cc", "hats/hats_notification_controller.h", "idle_detector.cc", @@ -656,8 +687,6 @@ source_set("chromeos") { "login/language_list.h", "login/lock/screen_locker.cc", "login/lock/screen_locker.h", - "login/lock/screen_locker_delegate.cc", - "login/lock/screen_locker_delegate.h", "login/lock/webui_screen_locker.cc", "login/lock/webui_screen_locker.h", "login/login_wizard.h", @@ -680,6 +709,9 @@ source_set("chromeos") { "login/saml/saml_offline_signin_limiter_factory.h", "login/screen_manager.cc", "login/screen_manager.h", + "login/screens/arc_terms_of_service_screen.cc", + "login/screens/arc_terms_of_service_screen.h", + "login/screens/arc_terms_of_service_screen_actor.h", "login/screens/base_screen.cc", "login/screens/base_screen.h", "login/screens/base_screen_delegate.h", @@ -757,14 +789,6 @@ source_set("chromeos") { "login/screens/wrong_hwid_screen_actor.h", "login/session/chrome_session_manager.cc", "login/session/chrome_session_manager.h", - "login/session/kiosk_auto_launcher_session_manager_delegate.cc", - "login/session/kiosk_auto_launcher_session_manager_delegate.h", - "login/session/login_oobe_session_manager_delegate.cc", - "login/session/login_oobe_session_manager_delegate.h", - "login/session/restore_after_crash_session_manager_delegate.cc", - "login/session/restore_after_crash_session_manager_delegate.h", - "login/session/stub_login_session_manager_delegate.cc", - "login/session/stub_login_session_manager_delegate.h", "login/session/user_session_manager.cc", "login/session/user_session_manager.h", "login/signin/auth_sync_observer.cc", @@ -827,8 +851,6 @@ source_set("chromeos") { "login/ui/keyboard_driven_oobe_key_handler.h", "login/ui/lock_window.cc", "login/ui/lock_window.h", - "login/ui/lock_window_aura.cc", - "login/ui/lock_window_aura.h", "login/ui/login_display.cc", "login/ui/login_display.h", "login/ui/login_display_host.cc", @@ -902,6 +924,8 @@ source_set("chromeos") { "net/client_cert_store_chromeos.h", "net/delay_network_call.cc", "net/delay_network_call.h", + "net/network_connect_delegate_chromeos.cc", + "net/network_connect_delegate_chromeos.h", "net/network_portal_detector_impl.cc", "net/network_portal_detector_impl.h", "net/network_portal_detector_test_impl.cc", @@ -910,10 +934,14 @@ source_set("chromeos") { "net/network_portal_notification_controller.h", "net/network_portal_web_dialog.cc", "net/network_portal_web_dialog.h", - "net/onc_utils.cc", - "net/onc_utils.h", - "net/proxy_config_handler.cc", - "net/proxy_config_handler.h", + "net/network_pref_state_observer.cc", + "net/network_pref_state_observer.h", + "net/network_state_notifier.cc", + "net/network_state_notifier.h", + "net/network_throttling_observer.cc", + "net/network_throttling_observer.h", + "net/shill_error.cc", + "net/shill_error.h", "net/wake_on_wifi_connection_observer.cc", "net/wake_on_wifi_connection_observer.h", "net/wake_on_wifi_manager.cc", @@ -1089,14 +1117,24 @@ source_set("chromeos") { "power/power_prefs.h", "power/renderer_freezer.cc", "power/renderer_freezer.h", - "power/session_state_controller_delegate_chromeos.cc", - "power/session_state_controller_delegate_chromeos.h", "preferences.cc", "preferences.h", "printer_detector/printer_detector.cc", "printer_detector/printer_detector.h", "printer_detector/printer_detector_factory.cc", "printer_detector/printer_detector_factory.h", + "printing/cups_print_job.cc", + "printing/cups_print_job.h", + "printing/cups_print_job_manager.cc", + "printing/cups_print_job_manager.h", + "printing/cups_print_job_manager_factory.cc", + "printing/cups_print_job_manager_factory.h", + "printing/cups_print_job_notification.cc", + "printing/cups_print_job_notification.h", + "printing/cups_print_job_notification_manager.cc", + "printing/cups_print_job_notification_manager.h", + "printing/fake_cups_print_job_manager.cc", + "printing/fake_cups_print_job_manager.h", "printing/printer_pref_manager.cc", "printing/printer_pref_manager.h", "printing/printer_pref_manager_factory.cc", @@ -1114,8 +1152,6 @@ source_set("chromeos") { "profiles/profile_list_chromeos.h", "profiles/profile_util.cc", "profiles/profile_util.h", - "proxy_config_service_impl.cc", - "proxy_config_service_impl.h", "proxy_cros_settings_parser.cc", "proxy_cros_settings_parser.h", "reset/metrics.h", @@ -1147,6 +1183,8 @@ source_set("chromeos") { "settings/owner_flags_storage.h", "settings/session_manager_operation.cc", "settings/session_manager_operation.h", + "settings/shutdown_policy_forwarder.cc", + "settings/shutdown_policy_forwarder.h", "settings/shutdown_policy_handler.cc", "settings/shutdown_policy_handler.h", "settings/stub_cros_settings_provider.cc", @@ -1228,10 +1266,6 @@ source_set("chromeos") { "ui/mobile_config_ui.h", "ui/screen_capture_notification_ui_chromeos.cc", "ui/screen_capture_notification_ui_chromeos.h", - "ui_proxy_config.cc", - "ui_proxy_config.h", - "ui_proxy_config_service.cc", - "ui_proxy_config_service.h", "upgrade_detector_chromeos.cc", "upgrade_detector_chromeos.h", @@ -1352,10 +1386,13 @@ source_set("unit_tests") { "accessibility/magnification_manager_unittest.cc", "accessibility/spoken_feedback_event_rewriter_unittest.cc", "arc/arc_auth_service_unittest.cc", - "arc/arc_downloads_watcher_service_unittest.cc", - "arc/arc_navigation_throttle_unittest.cc", - "arc/arc_policy_bridge_unittest.cc", - "arc/page_transition_util_unittest.cc", + "arc/downloads_watcher/arc_downloads_watcher_service_unittest.cc", + "arc/fileapi/arc_content_file_system_async_file_util_unittest.cc", + "arc/fileapi/arc_content_file_system_file_stream_reader_unittest.cc", + "arc/fileapi/arc_content_file_system_url_util_unittest.cc", + "arc/intent_helper/arc_external_protocol_dialog_unittest.cc", + "arc/intent_helper/arc_navigation_throttle_unittest.cc", + "arc/policy/arc_policy_bridge_unittest.cc", "attestation/attestation_ca_client_unittest.cc", "attestation/attestation_policy_observer_unittest.cc", "attestation/fake_certificate.cc", @@ -1432,6 +1469,7 @@ source_set("unit_tests") { "fileapi/external_file_url_util_unittest.cc", "fileapi/file_access_permissions_unittest.cc", "fileapi/file_system_backend_unittest.cc", + "hats/hats_finch_helper_unittest.cc", "hats/hats_notification_controller_unittest.cc", "input_method/browser_state_monitor_unittest.cc", "input_method/input_method_configuration_unittest.cc", @@ -1461,6 +1499,9 @@ source_set("unit_tests") { "net/client_cert_store_chromeos_unittest.cc", "net/network_portal_detector_impl_unittest.cc", "net/network_portal_notification_controller_unittest.cc", + "net/network_pref_state_observer_unittest.cc", + "net/network_state_notifier_unittest.cc", + "net/network_throttling_observer_unittest.cc", "net/wake_on_wifi_manager_unittest.cc", "options/network_property_ui_data_unittest.cc", "ownership/fake_owner_settings_service.cc", diff --git a/chromium/chrome/browser/devtools/BUILD.gn b/chromium/chrome/browser/devtools/BUILD.gn index ed12e5f62da..88bf81a5404 100644 --- a/chromium/chrome/browser/devtools/BUILD.gn +++ b/chromium/chrome/browser/devtools/BUILD.gn @@ -4,6 +4,7 @@ if (!is_android) { import("//build/config/features.gni") + import("//chrome/common/features.gni") import("//tools/grit/grit_rule.gni") } @@ -54,7 +55,6 @@ static_library("devtools") { "//build/config/compiler:no_size_t_to_int_warning", "//build/config/compiler:wexit_time_destructors", "//build/config:precompiled_headers", - "//third_party/WebKit/public:debug_devtools", ] deps = [ @@ -62,6 +62,7 @@ static_library("devtools") { "//base", "//content/public/browser", "//net", + "//third_party/WebKit/public:features", "//ui/events:dom_keycode_converter", ] @@ -71,6 +72,7 @@ static_library("devtools") { "//chrome:resources", "//chrome:strings", "//chrome/app/theme:theme_resources", + "//chrome/common", "//chrome/common/extensions/api", "//net:http_server", "//skia", @@ -90,6 +92,8 @@ static_library("devtools") { "device/android_web_socket.cc", "device/devtools_android_bridge.cc", "device/devtools_android_bridge.h", + "device/devtools_device_discovery.cc", + "device/devtools_device_discovery.h", "device/port_forwarding_controller.cc", "device/port_forwarding_controller.h", "device/tcp_device_provider.cc", @@ -126,6 +130,8 @@ static_library("devtools") { "global_confirm_info_bar.h", "remote_debugging_server.cc", "remote_debugging_server.h", + "url_constants.cc", + "url_constants.h", ] if (enable_service_discovery) { sources += [ diff --git a/chromium/chrome/browser/extensions/BUILD.gn b/chromium/chrome/browser/extensions/BUILD.gn index 2e050759cac..965847ac5e0 100644 --- a/chromium/chrome/browser/extensions/BUILD.gn +++ b/chromium/chrome/browser/extensions/BUILD.gn @@ -5,6 +5,7 @@ import("//build/config/features.gni") import("//build/config/ui.gni") import("//chrome/common/features.gni") +import("//extensions/features/features.gni") assert(enable_extensions) @@ -291,8 +292,6 @@ static_library("extensions") { "api/messaging/native_messaging_policy_handler.h", "api/metrics_private/chrome_metrics_private_delegate.cc", "api/metrics_private/chrome_metrics_private_delegate.h", - "api/metrics_private/metrics_private_api.cc", - "api/metrics_private/metrics_private_api.h", "api/module/module.cc", "api/module/module.h", "api/music_manager_private/device_id.cc", @@ -837,6 +836,7 @@ static_library("extensions") { "//components/crx_file", "//components/data_reduction_proxy/core/browser", "//components/dom_distiller/core", + "//components/drive", "//components/favicon/content", "//components/feedback", "//components/gcm_driver", @@ -861,6 +861,7 @@ static_library("extensions") { "//components/rappor", "//components/resources", "//components/safe_browsing_db:database_manager", + "//components/safe_browsing_db:safe_browsing_prefs", "//components/safe_json", "//components/search_engines", "//components/sessions", @@ -869,8 +870,8 @@ static_library("extensions") { "//components/storage_monitor", "//components/strings", "//components/sync", + "//components/sync_preferences", "//components/sync_sessions", - "//components/syncable_prefs", "//components/translate/core/browser", "//components/undo", "//components/update_client", @@ -885,10 +886,12 @@ static_library("extensions") { "//device/hid", "//extensions:extensions_resources", "//extensions/browser", + "//extensions/browser/api:api_registration", "//extensions/common/api", - "//extensions/common/api:api_registration", + "//extensions/features", "//extensions/strings", "//net", + "//printing/features", "//skia", "//sql", "//storage/browser", @@ -919,8 +922,6 @@ static_library("extensions") { if (is_chromeos) { sources += [ - "api/cast_devices_private/cast_devices_private_api.cc", - "api/cast_devices_private/cast_devices_private_api.h", "api/certificate_provider/certificate_provider_api.cc", "api/certificate_provider/certificate_provider_api.h", "api/enterprise_device_attributes/enterprise_device_attributes_api.cc", @@ -1059,6 +1060,16 @@ static_library("extensions") { deps += [ "//components/wifi" ] } + if (is_win || is_mac || is_chromeos) { + sources += [ + "api/networking_private/networking_private_crypto.cc", + "api/networking_private/networking_private_crypto.h", + ] + + # networking_private_crypto.cc depends on boringssl. + public_deps += [ "//third_party/boringssl" ] + } + if (is_win) { deps += [ "//third_party/iaccessible2", diff --git a/chromium/chrome/browser/extensions/api/activity_log_private/OWNERS b/chromium/chrome/browser/extensions/api/activity_log_private/OWNERS index 9091c448fc6..e3ff774e42d 100644 --- a/chromium/chrome/browser/extensions/api/activity_log_private/OWNERS +++ b/chromium/chrome/browser/extensions/api/activity_log_private/OWNERS @@ -1,4 +1,4 @@ # If you are editing this file, please also update # chrome/browser/extensions/activity_log/OWNERS rdevlin.cronin@chromium.org -felt@chromium.org +asargent@chromium.org diff --git a/chromium/chrome/browser/extensions/api/activity_log_private/activity_log_private_apitest.cc b/chromium/chrome/browser/extensions/api/activity_log_private/activity_log_private_apitest.cc index 478e75f53b5..fe00902f063 100644 --- a/chromium/chrome/browser/extensions/api/activity_log_private/activity_log_private_apitest.cc +++ b/chromium/chrome/browser/extensions/api/activity_log_private/activity_log_private_apitest.cc @@ -30,7 +30,6 @@ class ActivityLogApiTest : public ExtensionApiTest { ActivityLogApiTest() : saved_cmdline_(base::CommandLine::NO_PROGRAM) {} ~ActivityLogApiTest() override { - ExtensionApiTest::SetUpCommandLine(&saved_cmdline_); *base::CommandLine::ForCurrentProcess() = saved_cmdline_; } diff --git a/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc b/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc index 2b95e0ec180..82a29234514 100644 --- a/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc +++ b/chromium/chrome/browser/extensions/api/autofill_private/autofill_private_apitest.cc @@ -45,22 +45,12 @@ class AutofillPrivateApiTest : public ExtensionApiTest { // TODO(hcarmona): Investigate converting these tests to unittests. // TODO(crbug.com/643097) Disabled for flakiness. -#if defined(OS_WIN) -#define MAYBE_SaveAddress DISABLED_SaveAddress -#else -#define MAYBE_SaveAddress SaveAddress -#endif // defined(OS_WIN) -IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, MAYBE_SaveAddress) { +IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, DISABLED_SaveAddress) { EXPECT_TRUE(RunAutofillSubtest("saveAddress")) << message_; } // TODO(crbug.com/643097) Disabled for flakiness. -#if defined(OS_WIN) -#define MAYBE_GetCountryList DISABLED_GetCountryList -#else -#define MAYBE_GetCountryList GetCountryList -#endif // defined(OS_WIN) -IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, MAYBE_GetCountryList) { +IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, DISABLED_GetCountryList) { EXPECT_TRUE(RunAutofillSubtest("getCountryList")) << message_; } @@ -69,22 +59,12 @@ IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, GetAddressComponents) { } // TODO(crbug.com/643097) Disabled for flakiness. -#if defined(OS_WIN) -#define MAYBE_SaveCreditCard DISABLED_SaveCreditCard -#else -#define MAYBE_SaveCreditCard SaveCreditCard -#endif // defined(OS_WIN) -IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, MAYBE_SaveCreditCard) { +IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, DISABLED_SaveCreditCard) { EXPECT_TRUE(RunAutofillSubtest("saveCreditCard")) << message_; } // TODO(crbug.com/643097) Disabled for flakiness. -#if defined(OS_WIN) -#define MAYBE_RemoveEntry DISABLED_RemoveEntry -#else -#define MAYBE_RemoveEntry RemoveEntry -#endif // defined(OS_WIN) -IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, MAYBE_RemoveEntry) { +IN_PROC_BROWSER_TEST_F(AutofillPrivateApiTest, DISABLED_RemoveEntry) { EXPECT_TRUE(RunAutofillSubtest("removeEntry")) << message_; } diff --git a/chromium/chrome/browser/extensions/api/autofill_private/autofill_util.cc b/chromium/chrome/browser/extensions/api/autofill_private/autofill_util.cc index 6f6d7f976ff..dc02e1981e5 100644 --- a/chromium/chrome/browser/extensions/api/autofill_private/autofill_util.cc +++ b/chromium/chrome/browser/extensions/api/autofill_private/autofill_util.cc @@ -191,12 +191,13 @@ CountryEntryList GenerateCountryList( const autofill::PersonalDataManager& personal_data) { autofill::CountryComboboxModel model; model.SetCountries(personal_data, base::Callback<bool(const std::string&)>()); - const std::vector<autofill::AutofillCountry*>& countries = model.countries(); + const std::vector<std::unique_ptr<autofill::AutofillCountry>>& countries = + model.countries(); CountryEntryList list; - for (size_t i = 0; i < countries.size(); ++i) - list.push_back(CountryToCountryEntry(countries[i])); + for (const auto& country : countries) + list.push_back(CountryToCountryEntry(country.get())); return list; } diff --git a/chromium/chrome/browser/extensions/api/automation_internal/automation_action_adapter.h b/chromium/chrome/browser/extensions/api/automation_internal/automation_action_adapter.h index f6206983629..a5323cd990b 100644 --- a/chromium/chrome/browser/extensions/api/automation_internal/automation_action_adapter.h +++ b/chromium/chrome/browser/extensions/api/automation_internal/automation_action_adapter.h @@ -7,32 +7,20 @@ #include <stdint.h> +#include "ui/accessibility/ax_enums.h" #include "ui/gfx/geometry/point.h" +namespace ui { +struct AXActionData; +} + namespace extensions { // Adapts an object to receive actions from the Automation extension API. class AutomationActionAdapter { public: - // Performs a default action (e.g. click, check) on the target node. - virtual void DoDefault(int32_t id) = 0; - - // Performs a focus action on the target node. - virtual void Focus(int32_t id) = 0; - - // Makes the node visible by scrolling; does not change nodes from hidden to - // shown. - virtual void MakeVisible(int32_t id) = 0; - - // Sets selection for anchor and focus node/offset pairs. Also used to set - // selection in text fields. - virtual void SetSelection(int32_t anchor_id, - int32_t anchor_offset, - int32_t focus_id, - int32_t focus_offset) = 0; - - // Shows the context menu resulting from a right click. - virtual void ShowContextMenu(int32_t id) = 0; + // Performs an action on the target node. + virtual void PerformAction(const ui::AXActionData& data) = 0; }; } // namespace extensions diff --git a/chromium/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc b/chromium/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc index 6ada5f161f5..f1ff4d860a4 100644 --- a/chromium/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc +++ b/chromium/chrome/browser/extensions/api/automation_internal/automation_internal_api.cc @@ -37,6 +37,7 @@ #include "content/public/browser/web_contents_user_data.h" #include "extensions/common/extension_messages.h" #include "extensions/common/permissions/permissions_data.h" +#include "ui/accessibility/ax_action_data.h" #if defined(USE_AURA) #include "chrome/browser/ui/aura/accessibility/automation_manager_aura.h" @@ -162,26 +163,8 @@ class RenderFrameHostActionAdapter : public AutomationActionAdapter { virtual ~RenderFrameHostActionAdapter() {} // AutomationActionAdapter implementation. - void DoDefault(int32_t id) override { - rfh_->AccessibilityDoDefaultAction(id); - } - - void Focus(int32_t id) override { rfh_->AccessibilitySetFocus(id); } - - void MakeVisible(int32_t id) override { - rfh_->AccessibilityScrollToMakeVisible(id, gfx::Rect()); - } - - void SetSelection(int32_t anchor_id, - int32_t anchor_offset, - int32_t focus_id, - int32_t focus_offset) override { - rfh_->AccessibilitySetSelection(anchor_id, anchor_offset, focus_id, - focus_offset); - } - - void ShowContextMenu(int32_t id) override { - rfh_->AccessibilityShowContextMenu(id); + void PerformAction(const ui::AXActionData& data) override { + rfh_->AccessibilityPerformAction(data); } private: @@ -366,29 +349,49 @@ ExtensionFunction::ResponseAction AutomationInternalPerformActionFunction::RouteActionToAdapter( api::automation_internal::PerformAction::Params* params, AutomationActionAdapter* adapter) { - int32_t automation_id = params->args.automation_node_id; + ui::AXActionData action; + action.target_node_id = params->args.automation_node_id; switch (params->args.action_type) { case api::automation_internal::ACTION_TYPE_DODEFAULT: - adapter->DoDefault(automation_id); + action.action = ui::AX_ACTION_DO_DEFAULT; + adapter->PerformAction(action); break; case api::automation_internal::ACTION_TYPE_FOCUS: - adapter->Focus(automation_id); + action.action = ui::AX_ACTION_SET_FOCUS; + adapter->PerformAction(action); break; case api::automation_internal::ACTION_TYPE_MAKEVISIBLE: - adapter->MakeVisible(automation_id); + action.action = ui::AX_ACTION_SCROLL_TO_MAKE_VISIBLE; + adapter->PerformAction(action); break; case api::automation_internal::ACTION_TYPE_SETSELECTION: { api::automation_internal::SetSelectionParams selection_params; EXTENSION_FUNCTION_VALIDATE( api::automation_internal::SetSelectionParams::Populate( params->opt_args.additional_properties, &selection_params)); - adapter->SetSelection(automation_id, selection_params.anchor_offset, - selection_params.focus_node_id, - selection_params.focus_offset); + action.anchor_node_id = params->args.automation_node_id; + action.anchor_offset = selection_params.anchor_offset; + action.focus_node_id = selection_params.focus_node_id; + action.focus_offset = selection_params.focus_offset; + action.action = ui::AX_ACTION_SET_SELECTION; + adapter->PerformAction(action); break; } case api::automation_internal::ACTION_TYPE_SHOWCONTEXTMENU: { - adapter->ShowContextMenu(automation_id); + action.action = ui::AX_ACTION_SHOW_CONTEXT_MENU; + adapter->PerformAction(action); + break; + } + case api::automation_internal::ACTION_TYPE_SETACCESSIBILITYFOCUS: { + action.action = ui::AX_ACTION_SET_ACCESSIBILITY_FOCUS; + adapter->PerformAction(action); + break; + } + case api::automation_internal:: + ACTION_TYPE_SETSEQUENTIALFOCUSNAVIGATIONSTARTINGPOINT: { + action.action = + ui::AX_ACTION_SET_SEQUENTIAL_FOCUS_NAVIGATION_STARTING_POINT; + adapter->PerformAction(action); break; } default: diff --git a/chromium/chrome/browser/extensions/api/autotest_private/autotest_private_api.cc b/chromium/chrome/browser/extensions/api/autotest_private/autotest_private_api.cc index d8aee6b8404..3583b207472 100644 --- a/chromium/chrome/browser/extensions/api/autotest_private/autotest_private_api.cc +++ b/chromium/chrome/browser/extensions/api/autotest_private/autotest_private_api.cc @@ -119,8 +119,8 @@ ExtensionFunction::ResponseAction AutotestPrivateLoginStatusFunction::Run() { result->SetBoolean("isGuest", user_manager->IsLoggedInAsGuest()); result->SetBoolean("isKiosk", user_manager->IsLoggedInAsKioskApp()); - const user_manager::User* user = user_manager->GetLoggedInUser(); - result->SetString("email", user->email()); + const user_manager::User* user = user_manager->GetActiveUser(); + result->SetString("email", user->GetAccountId().GetUserEmail()); result->SetString("displayEmail", user->display_email()); std::string user_image; diff --git a/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc b/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc index bfe4f352c37..fbf447cb498 100644 --- a/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc +++ b/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.cc @@ -21,11 +21,11 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/api/bookmarks/bookmark_api_constants.h" #include "chrome/browser/extensions/api/bookmarks/bookmark_api_helpers.h" -#include "chrome/browser/extensions/extension_web_ui.h" #include "chrome/browser/profiles/profile.h" #include "chrome/browser/ui/bookmarks/bookmark_drag_drop.h" #include "chrome/browser/undo/bookmark_undo_service_factory.h" #include "chrome/common/extensions/api/bookmark_manager_private.h" +#include "chrome/common/extensions/extension_constants.h" #include "chrome/grit/generated_resources.h" #include "components/bookmarks/browser/bookmark_model.h" #include "components/bookmarks/browser/bookmark_node_data.h" @@ -41,6 +41,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_ui.h" #include "extensions/browser/extension_function_dispatcher.h" +#include "extensions/browser/extension_registry.h" #include "extensions/browser/view_type_utils.h" #include "ui/base/dragdrop/drag_drop_types.h" #include "ui/base/l10n/l10n_util.h" @@ -51,6 +52,9 @@ using bookmarks::BookmarkNode; using bookmarks::BookmarkNodeData; using content::WebContents; +DEFINE_WEB_CONTENTS_USER_DATA_KEY( + extensions::BookmarkManagerPrivateDragEventRouter); + namespace extensions { namespace bookmark_keys = bookmark_api_constants; @@ -283,9 +287,12 @@ void BookmarkManagerPrivateAPI::OnListenerAdded( } BookmarkManagerPrivateDragEventRouter::BookmarkManagerPrivateDragEventRouter( - Profile* profile, content::WebContents* web_contents) - : profile_(profile), web_contents_(web_contents) { + : web_contents_(web_contents), + profile_( + Profile::FromBrowserContext(web_contents_->GetBrowserContext())) { + // We need to guarantee the BookmarkTabHelper is created. + BookmarkTabHelper::CreateForWebContents(web_contents_); BookmarkTabHelper* bookmark_tab_helper = BookmarkTabHelper::FromWebContents(web_contents_); bookmark_tab_helper->set_bookmark_drag_delegate(this); @@ -293,10 +300,8 @@ BookmarkManagerPrivateDragEventRouter::BookmarkManagerPrivateDragEventRouter( BookmarkManagerPrivateDragEventRouter:: ~BookmarkManagerPrivateDragEventRouter() { - BookmarkTabHelper* bookmark_tab_helper = - BookmarkTabHelper::FromWebContents(web_contents_); - if (bookmark_tab_helper->bookmark_drag_delegate() == this) - bookmark_tab_helper->set_bookmark_drag_delegate(NULL); + // No need to remove ourselves as the BookmarkTabHelper's delegate, since they + // are both WebContentsUserData and will be deleted at the same time. } void BookmarkManagerPrivateDragEventRouter::DispatchEvent( @@ -600,11 +605,8 @@ bool BookmarkManagerPrivateDropFunction::RunOnReady() { WebContents* web_contents = GetAssociatedWebContents(); CHECK(web_contents); - ExtensionWebUI* web_ui = - static_cast<ExtensionWebUI*>(web_contents->GetWebUI()->GetController()); - CHECK(web_ui); BookmarkManagerPrivateDragEventRouter* router = - web_ui->bookmark_manager_private_drag_event_router(); + BookmarkManagerPrivateDragEventRouter::FromWebContents(web_contents); DCHECK(router); const BookmarkNodeData* drag_data = router->GetBookmarkNodeData(); diff --git a/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h b/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h index 932a1b82220..c67a854e198 100644 --- a/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h +++ b/chromium/chrome/browser/extensions/api/bookmark_manager_private/bookmark_manager_private_api.h @@ -16,6 +16,7 @@ #include "components/bookmarks/browser/base_bookmark_model_observer.h" #include "components/bookmarks/browser/bookmark_node_data.h" #include "components/undo/bookmark_undo_service.h" +#include "content/public/browser/web_contents_user_data.h" #include "extensions/browser/browser_context_keyed_api_factory.h" #include "extensions/browser/event_router.h" @@ -93,10 +94,12 @@ class BookmarkManagerPrivateAPI : public BrowserContextKeyedAPI, // Class that handles the drag and drop related chrome.bookmarkManagerPrivate // events. This class has one instance per bookmark manager tab. class BookmarkManagerPrivateDragEventRouter - : public BookmarkTabHelper::BookmarkDrag { + : public BookmarkTabHelper::BookmarkDrag, + public content::WebContentsUserData< + BookmarkManagerPrivateDragEventRouter> { public: - BookmarkManagerPrivateDragEventRouter(Profile* profile, - content::WebContents* web_contents); + explicit BookmarkManagerPrivateDragEventRouter( + content::WebContents* web_contents); ~BookmarkManagerPrivateDragEventRouter() override; // BookmarkTabHelper::BookmarkDrag interface @@ -118,8 +121,8 @@ class BookmarkManagerPrivateDragEventRouter const std::string& event_name, std::unique_ptr<base::ListValue> args); - Profile* profile_; content::WebContents* web_contents_; + Profile* profile_; bookmarks::BookmarkNodeData bookmark_drag_data_; DISALLOW_COPY_AND_ASSIGN(BookmarkManagerPrivateDragEventRouter); diff --git a/chromium/chrome/browser/extensions/api/braille_display_private/braille_controller.h b/chromium/chrome/browser/extensions/api/braille_display_private/braille_controller.h index 73ec3e6b5fa..5b575d2a32e 100644 --- a/chromium/chrome/browser/extensions/api/braille_display_private/braille_controller.h +++ b/chromium/chrome/browser/extensions/api/braille_display_private/braille_controller.h @@ -24,7 +24,9 @@ class BrailleController { static BrailleController* GetInstance(); virtual std::unique_ptr<DisplayState> GetDisplayState() = 0; - virtual void WriteDots(const std::vector<char>& cells) = 0; + virtual void WriteDots(const std::vector<char>& cells, + unsigned int cols, + unsigned int rows) = 0; virtual void AddObserver(BrailleObserver* observer) = 0; virtual void RemoveObserver(BrailleObserver* observer) = 0; diff --git a/chromium/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc b/chromium/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc index 78e84507d67..5a406e35074 100644 --- a/chromium/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc +++ b/chromium/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.cc @@ -87,29 +87,41 @@ std::unique_ptr<DisplayState> BrailleControllerImpl::GetDisplayState() { StartConnecting(); std::unique_ptr<DisplayState> display_state(new DisplayState); if (connection_.get() && connection_->Connected()) { - size_t size; - if (!connection_->GetDisplaySize(&size)) { + unsigned int columns = 0; + unsigned int rows = 0; + if (!connection_->GetDisplaySize(&columns, &rows)) { Disconnect(); - } else if (size > 0) { // size == 0 means no display present. + } else if (rows * columns > 0) { + // rows * columns == 0 means no display present. display_state->available = true; - display_state->text_cell_count.reset(new int(size)); + display_state->text_column_count.reset(new int(columns)); + display_state->text_row_count.reset(new int(rows)); } } return display_state; } -void BrailleControllerImpl::WriteDots(const std::vector<char>& cells) { +void BrailleControllerImpl::WriteDots(const std::vector<char>& cells, + unsigned int cells_cols, + unsigned int cells_rows) { DCHECK_CURRENTLY_ON(BrowserThread::IO); if (connection_ && connection_->Connected()) { - size_t size; - if (!connection_->GetDisplaySize(&size)) { + // Row count and column count of current display. + unsigned int columns = 0; + unsigned int rows = 0; + if (!connection_->GetDisplaySize(&columns, &rows)) { Disconnect(); } - std::vector<unsigned char> sizedCells(size); - std::memcpy(&sizedCells[0], cells.data(), std::min(cells.size(), size)); - if (size > cells.size()) - std::fill(sizedCells.begin() + cells.size(), sizedCells.end(), 0); - if (!connection_->WriteDots(&sizedCells[0])) + std::vector<unsigned char> sized_cells(rows * columns, 0); + unsigned int row_limit = std::min(rows, cells_rows); + unsigned int col_limit = std::min(columns, cells_cols); + for (unsigned int row = 0; row < row_limit; row++) { + for (unsigned int col = 0; col < col_limit; col++) { + sized_cells[row * columns + col] = cells[row * cells_cols + col]; + } + } + + if (!connection_->WriteDots(sized_cells)) Disconnect(); } } @@ -303,7 +315,8 @@ void BrailleControllerImpl::DispatchKeyEvent(std::unique_ptr<KeyEvent> event) { return; } VLOG(1) << "Dispatching key event: " << *event->ToValue(); - FOR_EACH_OBSERVER(BrailleObserver, observers_, OnBrailleKeyEvent(*event)); + for (auto& observer : observers_) + observer.OnBrailleKeyEvent(*event); } void BrailleControllerImpl::DispatchOnDisplayStateChanged( @@ -318,8 +331,8 @@ void BrailleControllerImpl::DispatchOnDisplayStateChanged( } return; } - FOR_EACH_OBSERVER(BrailleObserver, observers_, - OnBrailleDisplayStateChanged(*new_state)); + for (auto& observer : observers_) + observer.OnBrailleDisplayStateChanged(*new_state); } } // namespace braille_display_private diff --git a/chromium/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.h b/chromium/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.h index aafa57d7b46..63962e844f5 100644 --- a/chromium/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.h +++ b/chromium/chrome/browser/extensions/api/braille_display_private/braille_controller_brlapi.h @@ -25,7 +25,9 @@ class BrailleControllerImpl : public BrailleController { public: static BrailleControllerImpl* GetInstance(); std::unique_ptr<DisplayState> GetDisplayState() override; - void WriteDots(const std::vector<char>& cells) override; + void WriteDots(const std::vector<char>& cells, + unsigned int cols, + unsigned int rows) override; void AddObserver(BrailleObserver* observer) override; void RemoveObserver(BrailleObserver* observer) override; diff --git a/chromium/chrome/browser/extensions/api/braille_display_private/braille_display_private_api.cc b/chromium/chrome/browser/extensions/api/braille_display_private/braille_display_private_api.cc index 73d1bdbf342..efa0629297f 100644 --- a/chromium/chrome/browser/extensions/api/braille_display_private/braille_display_private_api.cc +++ b/chromium/chrome/browser/extensions/api/braille_display_private/braille_display_private_api.cc @@ -169,11 +169,15 @@ BrailleDisplayPrivateWriteDotsFunction:: bool BrailleDisplayPrivateWriteDotsFunction::Prepare() { params_ = WriteDots::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(params_); + EXTENSION_FUNCTION_VALIDATE( + params_->cells.size() >= + static_cast<size_t>(params_->columns * params_->rows)); return true; } void BrailleDisplayPrivateWriteDotsFunction::Work() { - BrailleController::GetInstance()->WriteDots(params_->cells); + BrailleController::GetInstance()->WriteDots(params_->cells, params_->columns, + params_->rows); } bool BrailleDisplayPrivateWriteDotsFunction::Respond() { diff --git a/chromium/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc b/chromium/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc index c69dc92cc27..97a4424dcd0 100644 --- a/chromium/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc +++ b/chromium/chrome/browser/extensions/api/braille_display_private/braille_display_private_apitest.cc @@ -2,10 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef USE_BRLAPI -#error This test requires brlapi. -#endif - #include <stddef.h> #include <deque> @@ -24,7 +20,7 @@ #include "chrome/browser/profiles/profile_manager.h" #include "chrome/test/base/testing_profile.h" #include "chromeos/chromeos_switches.h" -#include "components/user_manager/user_manager.h" +#include "components/session_manager/core/session_manager.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" #include "content/public/test/test_utils.h" @@ -54,7 +50,8 @@ brlapi_keyCode_t kErrorKeyCode = BRLAPI_KEY_MAX; // itself. struct MockBrlapiConnectionData { bool connected; - size_t display_size; + size_t display_columns; + size_t display_rows; brlapi_error_t error; std::vector<std::string> written_content; // List of brlapi key codes. A negative number makes the connection mock @@ -84,7 +81,7 @@ class MockBrlapiConnection : public BrlapiConnection { void Disconnect() override { data_->connected = false; if (data_->reappear_on_disconnect) { - data_->display_size *= 2; + data_->display_columns *= 2; BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&BrailleControllerImpl::PokeSocketDirForTesting, @@ -100,14 +97,16 @@ class MockBrlapiConnection : public BrlapiConnection { return data_->error.brlerrno != BRLAPI_ERROR_SUCCESS ? "Error" : "Success"; } - bool GetDisplaySize(size_t* size) override { - *size = data_->display_size; + bool GetDisplaySize(unsigned int* columns, unsigned int* rows) override { + *columns = data_->display_columns; + *rows = data_->display_rows; return true; } - bool WriteDots(const unsigned char* cells) override { - std::string written(reinterpret_cast<const char*>(cells), - data_->display_size); + bool WriteDots(const std::vector<unsigned char>& cells) override { + std::string written( + cells.begin(), + cells.begin() + data_->display_rows * data_->display_columns); data_->written_content.push_back(written); return true; } @@ -147,7 +146,8 @@ class BrailleDisplayPrivateApiTest : public ExtensionApiTest { void SetUpInProcessBrowserTestFixture() override { ExtensionApiTest::SetUpInProcessBrowserTestFixture(); connection_data_.connected = false; - connection_data_.display_size = 0; + connection_data_.display_rows = 0; + connection_data_.display_columns = 0; connection_data_.error.brlerrno = BRLAPI_ERROR_SUCCESS; connection_data_.reappear_on_disconnect = false; BrailleControllerImpl::GetInstance()->SetCreateBrlapiConnectionForTesting( @@ -178,22 +178,25 @@ class BrailleDisplayPrivateApiTest : public ExtensionApiTest { }; IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateApiTest, WriteDots) { - connection_data_.display_size = 11; + connection_data_.display_columns = 11; + connection_data_.display_rows = 1; ASSERT_TRUE(RunComponentExtensionTest("braille_display_private/write_dots")) << message_; ASSERT_EQ(3U, connection_data_.written_content.size()); - const std::string expected_content(connection_data_.display_size, '\0'); + const std::string expected_content( + connection_data_.display_columns * connection_data_.display_rows, '\0'); for (size_t i = 0; i < connection_data_.written_content.size(); ++i) { - ASSERT_EQ(std::string( - connection_data_.display_size, - static_cast<char>(i)), - connection_data_.written_content[i]) + ASSERT_EQ(std::string(connection_data_.display_columns * + connection_data_.display_rows, + static_cast<char>(i)), + connection_data_.written_content[i]) << "String " << i << " doesn't match"; } } IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateApiTest, KeyEvents) { - connection_data_.display_size = 11; + connection_data_.display_columns = 11; + connection_data_.display_rows = 1; // Braille navigation commands. connection_data_.pending_keys.push_back(BRLAPI_KEY_TYPE_CMD | @@ -256,7 +259,8 @@ IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateApiTest, KeyEvents) { } IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateApiTest, DisplayStateChanges) { - connection_data_.display_size = 11; + connection_data_.display_columns = 11; + connection_data_.display_rows = 1; connection_data_.pending_keys.push_back(kErrorKeyCode); connection_data_.reappear_on_disconnect = true; ASSERT_TRUE(RunComponentExtensionTest( @@ -330,9 +334,9 @@ IN_PROC_BROWSER_TEST_F(BrailleDisplayPrivateAPIUserTest, MAYBE_KeyEventOnLockScreen) { std::unique_ptr<ScreenLockerTester> tester(ScreenLocker::GetTester()); // Log in. - user_manager::UserManager::Get()->UserLoggedIn( - AccountId::FromUserEmail(kTestUserName), kTestUserName, true); - user_manager::UserManager::Get()->SessionStarted(); + session_manager::SessionManager::Get()->CreateSession( + AccountId::FromUserEmail(kTestUserName), kTestUserName); + session_manager::SessionManager::Get()->SessionStarted(); Profile* profile = ProfileManager::GetActiveUserProfile(); ASSERT_FALSE( ProfileHelper::GetSigninProfile()->IsSameProfile(profile)) diff --git a/chromium/chrome/browser/extensions/api/braille_display_private/brlapi_connection.cc b/chromium/chrome/browser/extensions/api/braille_display_private/brlapi_connection.cc index 10dd503680c..b163d73a3d4 100644 --- a/chromium/chrome/browser/extensions/api/braille_display_private/brlapi_connection.cc +++ b/chromium/chrome/browser/extensions/api/braille_display_private/brlapi_connection.cc @@ -19,7 +19,7 @@ namespace braille_display_private { namespace { // Default virtual terminal. This can be overriden by setting the // WINDOWPATH environment variable. This is only used when not running -// under Crhome OS (that is in aura for a Linux desktop). +// under Chrome OS (that is in aura for a Linux desktop). // TODO(plundblad): Find a way to detect the controlling terminal of the // X server. static const int kDefaultTtyLinux = 7; @@ -41,8 +41,8 @@ class BrlapiConnectionImpl : public BrlapiConnection { bool Connected() override { return handle_ != nullptr; } brlapi_error_t* BrlapiError() override; std::string BrlapiStrError() override; - bool GetDisplaySize(size_t* size) override; - bool WriteDots(const unsigned char* cells) override; + bool GetDisplaySize(unsigned int* rows, unsigned int* columns) override; + bool WriteDots(const std::vector<unsigned char>& cells) override; int ReadKey(brlapi_keyCode_t* keyCode) override; private: @@ -93,9 +93,10 @@ BrlapiConnection::ConnectResult BrlapiConnectionImpl::Connect( Disconnect(); return CONNECT_ERROR_RETRY; } + unsigned int rows = 0; + unsigned int columns = 0; - size_t size; - if (!GetDisplaySize(&size)) { + if (!GetDisplaySize(&rows, &columns)) { // Error already logged. Disconnect(); return CONNECT_ERROR_RETRY; @@ -104,7 +105,7 @@ BrlapiConnection::ConnectResult BrlapiConnectionImpl::Connect( // A display size of 0 means no display connected. We can't reliably // detect when a display gets connected, so fail and let the caller // retry connecting. - if (size == 0) { + if (rows * columns == 0) { VLOG(1) << "No braille display connected"; Disconnect(); return CONNECT_ERROR_RETRY; @@ -148,24 +149,24 @@ std::string BrlapiConnectionImpl::BrlapiStrError() { return libbrlapi_loader_->brlapi_strerror(BrlapiError()); } -bool BrlapiConnectionImpl::GetDisplaySize(size_t* size) { +bool BrlapiConnectionImpl::GetDisplaySize(unsigned int* columns, + unsigned int* rows) { if (!CheckConnected()) { return false; } - unsigned int columns, rows; - if (libbrlapi_loader_->brlapi__getDisplaySize( - handle_.get(), &columns, &rows) < 0) { + if (libbrlapi_loader_->brlapi__getDisplaySize(handle_.get(), columns, rows) < + 0) { LOG(ERROR) << "Couldn't get braille display size " << BrlapiStrError(); return false; } - *size = columns * rows; return true; } -bool BrlapiConnectionImpl::WriteDots(const unsigned char* cells) { +bool BrlapiConnectionImpl::WriteDots(const std::vector<unsigned char>& cells) { + // Cells is a 2D vector, compressed into 1D. if (!CheckConnected()) return false; - if (libbrlapi_loader_->brlapi__writeDots(handle_.get(), cells) < 0) { + if (libbrlapi_loader_->brlapi__writeDots(handle_.get(), cells.data()) < 0) { VLOG(1) << "Couldn't write to brlapi: " << BrlapiStrError(); return false; } diff --git a/chromium/chrome/browser/extensions/api/braille_display_private/brlapi_connection.h b/chromium/chrome/browser/extensions/api/braille_display_private/brlapi_connection.h index f1cba434098..0d1fddeb00a 100644 --- a/chromium/chrome/browser/extensions/api/braille_display_private/brlapi_connection.h +++ b/chromium/chrome/browser/extensions/api/braille_display_private/brlapi_connection.h @@ -8,6 +8,7 @@ #include <stddef.h> #include <memory> +#include <vector> #include "base/callback_forward.h" #include "base/macros.h" @@ -50,14 +51,15 @@ class BrlapiConnection { // for logging. virtual std::string BrlapiStrError() = 0; - // Gets the total size of the display, which may be 0 if no display is - // present, returning true on success. Note that this is cached in the - // brlapi client so it is cheap. - virtual bool GetDisplaySize(size_t* size) = 0; + // Gets the row and column size of the display. Row x columns might be 0 + // if no display is present, returning true on success. Note that this is + // cached in the brlapi client so it is cheap. + virtual bool GetDisplaySize(unsigned int* columns, unsigned int* rows) = 0; // Sends the specified cells to the display. The array size must - // be equal to what GetDisplaySize() last returned for this connection. - virtual bool WriteDots(const unsigned char* cells) = 0; + // be equal to what GetDisplaySize() last returned for this connection, + // that is, cells must have a size of rows x columns. + virtual bool WriteDots(const std::vector<unsigned char>& cells) = 0; // Reads the next keyboard command, returning true on success. // Returns < 0 on error, 0 if no more keys are pending and > 0 diff --git a/chromium/chrome/browser/extensions/api/braille_display_private/brlapi_keycode_map.cc b/chromium/chrome/browser/extensions/api/braille_display_private/brlapi_keycode_map.cc index 1e8a9530699..aa4e913a4fc 100644 --- a/chromium/chrome/browser/extensions/api/braille_display_private/brlapi_keycode_map.cc +++ b/chromium/chrome/browser/extensions/api/braille_display_private/brlapi_keycode_map.cc @@ -142,8 +142,14 @@ void MapCommand(brlapi_keyCode_t code, KeyEvent* event) { event->display_position.reset(new int(argument)); break; case BRLAPI_KEY_CMD_PASSDOTS: - event->command = KEY_COMMAND_DOTS; - event->braille_dots.reset(new int(argument & kAllDots)); + unsigned int dots = argument & kAllDots; + event->braille_dots.reset(new int(dots)); + + // BRLAPI_DOTC represents when the braille space key is pressed. + if (dots && (argument & BRLAPI_DOTC)) + event->command = KEY_COMMAND_CHORD; + else + event->command = KEY_COMMAND_DOTS; MapModifierFlags(code, event); break; } diff --git a/chromium/chrome/browser/extensions/api/braille_display_private/mock_braille_controller.cc b/chromium/chrome/browser/extensions/api/braille_display_private/mock_braille_controller.cc index 0bfd5f9c0dd..0e07e7aa2e6 100644 --- a/chromium/chrome/browser/extensions/api/braille_display_private/mock_braille_controller.cc +++ b/chromium/chrome/browser/extensions/api/braille_display_private/mock_braille_controller.cc @@ -14,8 +14,10 @@ MockBrailleController::MockBrailleController() std::unique_ptr<DisplayState> MockBrailleController::GetDisplayState() { std::unique_ptr<DisplayState> state(new DisplayState()); state->available = available_; - if (available_) - state->text_cell_count.reset(new int(18)); + if (available_) { + state->text_column_count.reset(new int(18)); + state->text_row_count.reset(new int(18)); + } return state; } diff --git a/chromium/chrome/browser/extensions/api/braille_display_private/stub_braille_controller.cc b/chromium/chrome/browser/extensions/api/braille_display_private/stub_braille_controller.cc index ac30bdd0038..5e8a8c5be24 100644 --- a/chromium/chrome/browser/extensions/api/braille_display_private/stub_braille_controller.cc +++ b/chromium/chrome/browser/extensions/api/braille_display_private/stub_braille_controller.cc @@ -15,8 +15,9 @@ std::unique_ptr<DisplayState> StubBrailleController::GetDisplayState() { return std::unique_ptr<DisplayState>(new DisplayState); } -void StubBrailleController::WriteDots(const std::vector<char>& cells) { -} +void StubBrailleController::WriteDots(const std::vector<char>& cells, + unsigned int cols, + unsigned int rows) {} void StubBrailleController::AddObserver(BrailleObserver* observer) { } diff --git a/chromium/chrome/browser/extensions/api/braille_display_private/stub_braille_controller.h b/chromium/chrome/browser/extensions/api/braille_display_private/stub_braille_controller.h index 4184d04abe7..cc159125575 100644 --- a/chromium/chrome/browser/extensions/api/braille_display_private/stub_braille_controller.h +++ b/chromium/chrome/browser/extensions/api/braille_display_private/stub_braille_controller.h @@ -17,7 +17,9 @@ class StubBrailleController : public BrailleController { public: StubBrailleController(); std::unique_ptr<DisplayState> GetDisplayState() override; - void WriteDots(const std::vector<char>& cells) override; + void WriteDots(const std::vector<char>& cells, + unsigned int cols, + unsigned int rows) override; void AddObserver(BrailleObserver* observer) override; void RemoveObserver(BrailleObserver* observer) override; diff --git a/chromium/chrome/browser/extensions/api/cast_devices_private/cast_devices_private_api.cc b/chromium/chrome/browser/extensions/api/cast_devices_private/cast_devices_private_api.cc deleted file mode 100644 index 8537677e546..00000000000 --- a/chromium/chrome/browser/extensions/api/cast_devices_private/cast_devices_private_api.cc +++ /dev/null @@ -1,108 +0,0 @@ -// 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. - -#include "chrome/browser/extensions/api/cast_devices_private/cast_devices_private_api.h" - -#include "base/lazy_instance.h" -#include "base/strings/utf_string_conversions.h" -#include "chrome/common/extensions/api/cast_devices_private.h" - -namespace extensions { - -namespace { - -ash::CastConfigDelegate::Receiver ConvertReceiverType( - const api::cast_devices_private::Receiver& receiver) { - ash::CastConfigDelegate::Receiver result; - result.id = receiver.id; - result.name = base::UTF8ToUTF16(receiver.name); - return result; -} - -ash::CastConfigDelegate::Activity ConvertActivityType( - const api::cast_devices_private::Activity& activity) { - ash::CastConfigDelegate::Activity result; - result.id = activity.id; - result.title = base::UTF8ToUTF16(activity.title); - if (activity.tab_id) - result.tab_id = *activity.tab_id; - else - result.tab_id = ash::CastConfigDelegate::Activity::TabId::UNKNOWN; - return result; -} - -ash::CastConfigDelegate::ReceiverAndActivity ConvertReceiverAndActivityType( - const api::cast_devices_private::Receiver& receiver, - const api::cast_devices_private::Activity* activity) { - ash::CastConfigDelegate::ReceiverAndActivity result; - result.receiver = ConvertReceiverType(receiver); - if (activity) - result.activity = ConvertActivityType(*activity); - return result; -} - -} // namespace - -static base::LazyInstance< - BrowserContextKeyedAPIFactory<CastDeviceUpdateListeners>> g_factory = - LAZY_INSTANCE_INITIALIZER; - -// static -BrowserContextKeyedAPIFactory<CastDeviceUpdateListeners>* -CastDeviceUpdateListeners::GetFactoryInstance() { - return g_factory.Pointer(); -} - -// static -CastDeviceUpdateListeners* CastDeviceUpdateListeners::Get( - content::BrowserContext* context) { - return BrowserContextKeyedAPIFactory<CastDeviceUpdateListeners>::Get(context); -} - -CastDeviceUpdateListeners::CastDeviceUpdateListeners( - content::BrowserContext* context) {} - -CastDeviceUpdateListeners::~CastDeviceUpdateListeners() {} - -void CastDeviceUpdateListeners::AddObserver( - ash::CastConfigDelegate::Observer* observer) { - observer_list_.AddObserver(observer); -} - -void CastDeviceUpdateListeners::RemoveObserver( - ash::CastConfigDelegate::Observer* observer) { - observer_list_.RemoveObserver(observer); -} - -void CastDeviceUpdateListeners::NotifyCallbacks( - const ReceiverAndActivityList& devices) { - FOR_EACH_OBSERVER(ash::CastConfigDelegate::Observer, observer_list_, - OnDevicesUpdated(devices)); -} - -CastDevicesPrivateUpdateDevicesFunction:: - CastDevicesPrivateUpdateDevicesFunction() {} - -CastDevicesPrivateUpdateDevicesFunction:: - ~CastDevicesPrivateUpdateDevicesFunction() {} - -ExtensionFunction::ResponseAction -CastDevicesPrivateUpdateDevicesFunction::Run() { - auto params = - api::cast_devices_private::UpdateDevices::Params::Create(*args_); - - CastDeviceUpdateListeners::ReceiverAndActivityList devices; - for (const api::cast_devices_private::ReceiverActivity& device : - params->devices) { - devices.push_back( - ConvertReceiverAndActivityType(device.receiver, device.activity.get())); - } - - auto* listeners = CastDeviceUpdateListeners::Get(browser_context()); - listeners->NotifyCallbacks(devices); - - return RespondNow(NoArguments()); -} - -} // namespace extensions diff --git a/chromium/chrome/browser/extensions/api/cast_devices_private/cast_devices_private_api.h b/chromium/chrome/browser/extensions/api/cast_devices_private/cast_devices_private_api.h deleted file mode 100644 index 97b21ea7db3..00000000000 --- a/chromium/chrome/browser/extensions/api/cast_devices_private/cast_devices_private_api.h +++ /dev/null @@ -1,72 +0,0 @@ -// 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. - -#ifndef CHROME_BROWSER_EXTENSIONS_API_CAST_DEVICES_PRIVATE_CAST_DEVICES_PRIVATE_API_H_ -#define CHROME_BROWSER_EXTENSIONS_API_CAST_DEVICES_PRIVATE_CAST_DEVICES_PRIVATE_API_H_ - -#include <vector> - -#include "ash/common/cast_config_delegate.h" -#include "base/callback_list.h" -#include "base/macros.h" -#include "base/observer_list.h" -#include "extensions/browser/browser_context_keyed_api_factory.h" -#include "extensions/browser/extension_function.h" - -namespace extensions { - -class CastDeviceUpdateListeners : public BrowserContextKeyedAPI { - public: - explicit CastDeviceUpdateListeners(content::BrowserContext* context); - ~CastDeviceUpdateListeners() override; - - // Fetches an instance for the given context. - static CastDeviceUpdateListeners* Get(content::BrowserContext* context); - - // Adds an observer that will be invoked when new device data is available. - void AddObserver(ash::CastConfigDelegate::Observer* observer); - void RemoveObserver(ash::CastConfigDelegate::Observer* observer); - - // BrowserContextKeyedAPI implementation: - static BrowserContextKeyedAPIFactory<CastDeviceUpdateListeners>* - GetFactoryInstance(); - static const bool kServiceIsCreatedWithBrowserContext = false; - - private: - using ReceiverAndActivityList = - std::vector<ash::CastConfigDelegate::ReceiverAndActivity>; - - friend class CastDevicesPrivateUpdateDevicesFunction; // For NotifyCallbacks. - void NotifyCallbacks(const ReceiverAndActivityList& devices); - - base::ObserverList<ash::CastConfigDelegate::Observer> observer_list_; - - friend class BrowserContextKeyedAPIFactory<CastDeviceUpdateListeners>; - - // BrowserContextKeyedAPI implementation: - static const char* service_name() { return "CastDeviceUpdateListeners"; } - - DISALLOW_COPY_AND_ASSIGN(CastDeviceUpdateListeners); -}; - -// static void updateDeviceState(ReceiverActivity[] devices); -class CastDevicesPrivateUpdateDevicesFunction : - public UIThreadExtensionFunction { - public: - CastDevicesPrivateUpdateDevicesFunction(); - - private: - ~CastDevicesPrivateUpdateDevicesFunction() override; - - // ExtensionFunction: - ResponseAction Run() override; - - DECLARE_EXTENSION_FUNCTION("cast.devicesPrivate.updateDevices", - CASTDEVICESPRIVATE_UPDATEDEVICES); - DISALLOW_COPY_AND_ASSIGN(CastDevicesPrivateUpdateDevicesFunction); -}; - -} // namespace extensions - -#endif // CHROME_BROWSER_EXTENSIONS_API_CAST_DEVICES_PRIVATE_CAST_DEVICES_PRIVATE_API_H_ diff --git a/chromium/chrome/browser/extensions/api/cast_streaming/cast_streaming_apitest.cc b/chromium/chrome/browser/extensions/api/cast_streaming/cast_streaming_apitest.cc index 848aa5cca59..df4109dae74 100644 --- a/chromium/chrome/browser/extensions/api/cast_streaming/cast_streaming_apitest.cc +++ b/chromium/chrome/browser/extensions/api/cast_streaming/cast_streaming_apitest.cc @@ -32,7 +32,7 @@ #include "net/base/net_errors.h" #include "net/base/rand_callback.h" #include "net/log/net_log_source.h" -#include "net/udp/udp_server_socket.h" +#include "net/socket/udp_server_socket.h" #include "testing/gtest/include/gtest/gtest.h" using media::cast::test::GetFreeLocalPort; diff --git a/chromium/chrome/browser/extensions/api/cast_streaming/performance_test.cc b/chromium/chrome/browser/extensions/api/cast_streaming/performance_test.cc index 52697efe24c..81bf52b83ff 100644 --- a/chromium/chrome/browser/extensions/api/cast_streaming/performance_test.cc +++ b/chromium/chrome/browser/extensions/api/cast_streaming/performance_test.cc @@ -48,7 +48,7 @@ #include "net/base/net_errors.h" #include "net/base/rand_callback.h" #include "net/log/net_log_source.h" -#include "net/udp/udp_server_socket.h" +#include "net/socket/udp_server_socket.h" #include "testing/gtest/include/gtest/gtest.h" #include "testing/perf/perf_test.h" #include "ui/compositor/compositor_switches.h" diff --git a/chromium/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc b/chromium/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc index f4b3aa3c022..e6c94df4e2b 100644 --- a/chromium/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc +++ b/chromium/chrome/browser/extensions/api/certificate_provider/certificate_provider_apitest.cc @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include <openssl/evp.h> -#include <openssl/rsa.h> #include <stddef.h> #include <stdint.h> #include <stdlib.h> @@ -33,11 +31,12 @@ #include "content/public/test/test_navigation_observer.h" #include "content/public/test/test_utils.h" #include "crypto/rsa_private_key.h" -#include "crypto/scoped_openssl_types.h" #include "extensions/common/extension.h" #include "extensions/test/result_catcher.h" #include "net/test/spawned_test_server/spawned_test_server.h" #include "testing/gmock/include/gmock/gmock.h" +#include "third_party/boringssl/src/include/openssl/evp.h" +#include "third_party/boringssl/src/include/openssl/rsa.h" using testing::Return; using testing::_; @@ -82,7 +81,7 @@ void StoreDigest(std::vector<uint8_t>* digest, bool RsaSign(const std::vector<uint8_t>& digest, crypto::RSAPrivateKey* key, std::vector<uint8_t>* signature) { - crypto::ScopedRSA rsa_key(EVP_PKEY_get1_RSA(key->key())); + RSA* rsa_key = EVP_PKEY_get0_RSA(key->key()); if (!rsa_key) return false; @@ -94,9 +93,9 @@ bool RsaSign(const std::vector<uint8_t>& digest, return false; } size_t len = 0; - signature->resize(RSA_size(rsa_key.get())); + signature->resize(RSA_size(rsa_key)); const int rv = - RSA_sign_raw(rsa_key.get(), &len, signature->data(), signature->size(), + RSA_sign_raw(rsa_key, &len, signature->data(), signature->size(), prefixed_digest, prefixed_digest_len, RSA_PKCS1_PADDING); if (is_alloced) free(prefixed_digest); diff --git a/chromium/chrome/browser/extensions/api/chrome_extensions_api_client.cc b/chromium/chrome/browser/extensions/api/chrome_extensions_api_client.cc index 0e02af7f010..d65c7b41f03 100644 --- a/chromium/chrome/browser/extensions/api/chrome_extensions_api_client.cc +++ b/chromium/chrome/browser/extensions/api/chrome_extensions_api_client.cc @@ -32,19 +32,20 @@ #include "extensions/browser/api/virtual_keyboard_private/virtual_keyboard_delegate.h" #include "extensions/browser/guest_view/web_view/web_view_guest.h" #include "extensions/browser/guest_view/web_view/web_view_permission_helper.h" +#include "printing/features/features.h" #if defined(OS_CHROMEOS) #include "chrome/browser/extensions/api/virtual_keyboard_private/chrome_virtual_keyboard_delegate.h" #endif -#if defined(ENABLE_PRINTING) -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINTING) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) #include "chrome/browser/printing/print_preview_message_handler.h" #include "chrome/browser/printing/print_view_manager.h" #else #include "chrome/browser/printing/print_view_manager_basic.h" -#endif // defined(ENABLE_PRINT_PREVIEW) -#endif // defined(ENABLE_PRINTING) +#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW) +#endif // BUILDFLAG(ENABLE_PRINTING) namespace extensions { @@ -70,14 +71,14 @@ void ChromeExtensionsAPIClient::AddAdditionalValueStoreCaches( void ChromeExtensionsAPIClient::AttachWebContentsHelpers( content::WebContents* web_contents) const { favicon::CreateContentFaviconDriverForWebContents(web_contents); -#if defined(ENABLE_PRINTING) -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINTING) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) printing::PrintViewManager::CreateForWebContents(web_contents); printing::PrintPreviewMessageHandler::CreateForWebContents(web_contents); #else printing::PrintViewManagerBasic::CreateForWebContents(web_contents); -#endif // defined(ENABLE_PRINT_PREVIEW) -#endif // defined(ENABLE_PRINTING) +#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW) +#endif // BUILDFLAG(ENABLE_PRINTING) pdf::PDFWebContentsHelper::CreateForWebContentsWithClient( web_contents, std::unique_ptr<pdf::PDFWebContentsHelperClient>( new ChromePDFWebContentsHelperClient())); diff --git a/chromium/chrome/browser/extensions/api/cloud_print_private/cloud_print_private_api.cc b/chromium/chrome/browser/extensions/api/cloud_print_private/cloud_print_private_api.cc index 9ee429c8562..a3b40642e23 100644 --- a/chromium/chrome/browser/extensions/api/cloud_print_private/cloud_print_private_api.cc +++ b/chromium/chrome/browser/extensions/api/cloud_print_private/cloud_print_private_api.cc @@ -13,12 +13,13 @@ #include "chrome/common/extensions/api/cloud_print_private.h" #include "google_apis/google_api_keys.h" #include "net/base/network_interfaces.h" +#include "printing/features/features.h" namespace extensions { namespace { -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) const char kErrorIncognito[] = "Cannot access in incognito mode"; #endif @@ -47,7 +48,7 @@ CloudPrintPrivateSetupConnectorFunction:: } bool CloudPrintPrivateSetupConnectorFunction::RunAsync() { -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) using api::cloud_print_private::SetupConnector::Params; std::unique_ptr<Params> params(Params::Create(*args_)); if (CloudPrintTestsDelegate::Get()) { @@ -101,7 +102,7 @@ void CloudPrintPrivateGetPrintersFunction::SendResults( } bool CloudPrintPrivateGetPrintersFunction::RunAsync() { -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) if (CloudPrintTestsDelegate::Get()) { SendResults(CloudPrintTestsDelegate::Get()->GetPrinters()); } else { diff --git a/chromium/chrome/browser/extensions/api/commands/command_service.cc b/chromium/chrome/browser/extensions/api/commands/command_service.cc index 960bf41cd64..1e1c25ad08e 100644 --- a/chromium/chrome/browser/extensions/api/commands/command_service.cc +++ b/chromium/chrome/browser/extensions/api/commands/command_service.cc @@ -294,11 +294,10 @@ bool CommandService::AddKeybindingPref( std::move(suggested_key_prefs)); // Fetch the newly-updated command, and notify the observers. - FOR_EACH_OBSERVER( - Observer, - observers_, - OnExtensionCommandAdded(extension_id, - FindCommandByName(extension_id, command_name))); + for (auto& observer : observers_) { + observer.OnExtensionCommandAdded( + extension_id, FindCommandByName(extension_id, command_name)); + } // TODO(devlin): Deprecate this notification in favor of the observers. std::pair<const std::string, const std::string> details = @@ -849,10 +848,8 @@ void CommandService::RemoveKeybindingPrefs(const std::string& extension_id, } for (const Command& removed_command : removed_commands) { - FOR_EACH_OBSERVER( - Observer, - observers_, - OnExtensionCommandRemoved(extension_id, removed_command)); + for (auto& observer : observers_) + observer.OnExtensionCommandRemoved(extension_id, removed_command); } } diff --git a/chromium/chrome/browser/extensions/api/content_settings/content_settings_store.cc b/chromium/chrome/browser/extensions/api/content_settings/content_settings_store.cc index ec745236e3a..3df22217d4e 100644 --- a/chromium/chrome/browser/extensions/api/content_settings/content_settings_store.cc +++ b/chromium/chrome/browser/extensions/api/content_settings/content_settings_store.cc @@ -116,10 +116,9 @@ void ContentSettingsStore::SetExtensionContentSetting( } } - // Send notification that content settings changed. - // TODO(markusheintz): Notifications should only be sent if the set content - // setting is effective and not hidden by another setting of another - // extension installed more recently. + // Send notification that content settings changed. (Note: This is responsible + // for updating the pref store, so cannot be skipped even if the setting would + // be masked by another extension.) NotifyOfContentSettingChanged(ext_id, scope != kExtensionPrefsScopeRegular); } @@ -320,7 +319,18 @@ void ContentSettingsStore::SetExtensionContentSettingFromList( dict->GetString(keys::kContentSettingsTypeKey, &content_settings_type_str); ContentSettingsType content_settings_type = helpers::StringToContentSettingsType(content_settings_type_str); - DCHECK_NE(CONTENT_SETTINGS_TYPE_DEFAULT, content_settings_type); + if (content_settings_type == CONTENT_SETTINGS_TYPE_DEFAULT) { + // We'll end up with DEFAULT here if the type string isn't recognised. + // This could be if it's a string from an old settings type that has been + // deleted. DCHECK to make sure this is the case (not some random string). + DCHECK(content_settings_type_str == "fullscreen" || + content_settings_type_str == "mouselock"); + + // In this case, we just skip over that setting, effectively deleting it + // from the in-memory model. This will implicitly delete these old + // settings from the pref store when it is written back. + continue; + } std::string resource_identifier; dict->GetString(keys::kResourceIdentifierKey, &resource_identifier); @@ -355,10 +365,8 @@ void ContentSettingsStore::RemoveObserver(Observer* observer) { void ContentSettingsStore::NotifyOfContentSettingChanged( const std::string& extension_id, bool incognito) { - FOR_EACH_OBSERVER( - ContentSettingsStore::Observer, - observers_, - OnContentSettingChanged(extension_id, incognito)); + for (auto& observer : observers_) + observer.OnContentSettingChanged(extension_id, incognito); } bool ContentSettingsStore::OnCorrectThread() { diff --git a/chromium/chrome/browser/extensions/api/content_settings/content_settings_store_unittest.cc b/chromium/chrome/browser/extensions/api/content_settings/content_settings_store_unittest.cc index 9986d4e2436..02ab848ffdf 100644 --- a/chromium/chrome/browser/extensions/api/content_settings/content_settings_store_unittest.cc +++ b/chromium/chrome/browser/extensions/api/content_settings/content_settings_store_unittest.cc @@ -8,6 +8,10 @@ #include <memory> +#include "base/memory/ptr_util.h" +#include "base/values.h" +#include "chrome/browser/extensions/api/content_settings/content_settings_api_constants.h" +#include "components/content_settings/core/browser/content_settings_registry.h" #include "components/content_settings/core/browser/content_settings_rule.h" #include "components/content_settings/core/browser/content_settings_utils.h" #include "components/content_settings/core/test/content_settings_test_utils.h" @@ -19,6 +23,8 @@ using ::testing::Mock; namespace extensions { +namespace keys = content_settings_api_constants; + namespace { void CheckRule(const content_settings::Rule& rule, @@ -255,4 +261,74 @@ TEST_F(ContentSettingsStoreTest, GetAllSettings) { ASSERT_EQ(0u, rules.size()); } +TEST_F(ContentSettingsStoreTest, SetFromList) { + // Force creation of ContentSettingsRegistry, so that the string to content + // setting type lookup can succeed. + content_settings::ContentSettingsRegistry::GetInstance(); + + ::testing::StrictMock<MockContentSettingsStoreObserver> observer; + store()->AddObserver(&observer); + + GURL url("http://www.youtube.com"); + + EXPECT_EQ(CONTENT_SETTING_DEFAULT, + GetContentSettingFromStore(store(), + url, + url, + CONTENT_SETTINGS_TYPE_COOKIES, + std::string(), + false)); + + // Register first extension + std::string ext_id("my_extension"); + RegisterExtension(ext_id); + + // Set setting via a list + ContentSettingsPattern pattern = + ContentSettingsPattern::FromURL(GURL("http://www.youtube.com")); + EXPECT_CALL(observer, OnContentSettingChanged(ext_id, false)); + + // Build a preference list in JSON format. + base::ListValue pref_list; + // {"primaryPattern": pattern, "secondaryPattern": pattern, "type": "cookies", + // "setting": "allow"} + auto dict_value = base::MakeUnique<base::DictionaryValue>(); + dict_value->SetString(keys::kPrimaryPatternKey, pattern.ToString()); + dict_value->SetString(keys::kSecondaryPatternKey, pattern.ToString()); + dict_value->SetString(keys::kContentSettingsTypeKey, "cookies"); + dict_value->SetString(keys::kContentSettingKey, "allow"); + pref_list.Append(std::move(dict_value)); + // Test content settings types that have been removed. Should be ignored. + // {"primaryPattern": pattern, "secondaryPattern": pattern, + // "type": "fullscreen", "setting": "allow"} + dict_value = base::MakeUnique<base::DictionaryValue>(); + dict_value->SetString(keys::kPrimaryPatternKey, pattern.ToString()); + dict_value->SetString(keys::kSecondaryPatternKey, pattern.ToString()); + dict_value->SetString(keys::kContentSettingsTypeKey, "fullscreen"); + dict_value->SetString(keys::kContentSettingKey, "allow"); + pref_list.Append(std::move(dict_value)); + // {"primaryPattern": pattern, "secondaryPattern": pattern, + // "type": "mouselock", "setting": "allow"} + dict_value = base::MakeUnique<base::DictionaryValue>(); + dict_value->SetString(keys::kPrimaryPatternKey, pattern.ToString()); + dict_value->SetString(keys::kSecondaryPatternKey, pattern.ToString()); + dict_value->SetString(keys::kContentSettingsTypeKey, "mouselock"); + dict_value->SetString(keys::kContentSettingKey, "allow"); + pref_list.Append(std::move(dict_value)); + + store()->SetExtensionContentSettingFromList(ext_id, &pref_list, + kExtensionPrefsScopeRegular); + Mock::VerifyAndClear(&observer); + + EXPECT_EQ(CONTENT_SETTING_ALLOW, + GetContentSettingFromStore(store(), + url, + url, + CONTENT_SETTINGS_TYPE_COOKIES, + std::string(), + false)); + + store()->RemoveObserver(&observer); +} + } // namespace extensions diff --git a/chromium/chrome/browser/extensions/api/context_menus/context_menus_api_helpers.h b/chromium/chrome/browser/extensions/api/context_menus/context_menus_api_helpers.h index 4fc44ebaa25..19b793cd2d0 100644 --- a/chromium/chrome/browser/extensions/api/context_menus/context_menus_api_helpers.h +++ b/chromium/chrome/browser/extensions/api/context_menus/context_menus_api_helpers.h @@ -148,9 +148,9 @@ bool CreateMenuItem(const PropertyWithEnumT& create_properties, MenuItem* parent = GetParent(*parent_id, menu_manager, error); if (!parent) return false; - success = menu_manager->AddChildItem(parent->id(), item.release()); + success = menu_manager->AddChildItem(parent->id(), std::move(item)); } else { - success = menu_manager->AddContextItem(extension, item.release()); + success = menu_manager->AddContextItem(extension, std::move(item)); } if (!success) diff --git a/chromium/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc b/chromium/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc index cc2363c7173..d4934900be0 100644 --- a/chromium/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc +++ b/chromium/chrome/browser/extensions/api/declarative_content/declarative_content_apitest.cc @@ -749,20 +749,12 @@ class ShowPageActionWithoutPageActionTest : public DeclarativeContentApiTest { private: void SetUpCommandLine(base::CommandLine* command_line) override { DeclarativeContentApiTest::SetUpCommandLine(command_line); - // If disabling the redesign, we need to disable Media Router since having - // Media Router enabled will result in auto-enabling the redesign and - // breaking the test. - if (!enable_redesign_) { - override_media_router_.reset(new FeatureSwitch::ScopedOverride( - FeatureSwitch::media_router(), false)); - } override_toolbar_redesign_.reset(new FeatureSwitch::ScopedOverride( FeatureSwitch::extension_action_redesign(), enable_redesign_)); } bool enable_redesign_; std::unique_ptr<FeatureSwitch::ScopedOverride> override_toolbar_redesign_; - std::unique_ptr<FeatureSwitch::ScopedOverride> override_media_router_; DISALLOW_COPY_AND_ASSIGN(ShowPageActionWithoutPageActionTest); }; diff --git a/chromium/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc b/chromium/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc index 5a799942067..348d2c8462d 100644 --- a/chromium/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc +++ b/chromium/chrome/browser/extensions/api/declarative_webrequest/webrequest_action_unittest.cc @@ -150,7 +150,8 @@ bool WebRequestActionWithThreadsTest::ActionWorksOnRequest( std::list<LinkedPtrEventResponseDelta> deltas; scoped_refptr<net::HttpResponseHeaders> headers( new net::HttpResponseHeaders("")); - WebRequestData request_data(regular_request.get(), stage, headers.get()); + WebRequestData request_data(regular_request.get(), stage, nullptr, + headers.get()); std::set<std::string> ignored_tags; WebRequestAction::ApplyInfo apply_info = { extension_info_map_.get(), request_data, diff --git a/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc b/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc index 3326d47532a..a2f5a65bda7 100644 --- a/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc +++ b/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.cc @@ -88,7 +88,7 @@ bool DesktopCaptureChooseDesktopMediaFunction::RunAsync() { DCHECK(web_contents); } else { origin = extension()->url(); - target_name = base::UTF8ToUTF16(extension()->name()); + target_name = base::UTF8ToUTF16(GetExtensionTargetName()); web_contents = GetSenderWebContents(); DCHECK(web_contents); } @@ -96,6 +96,11 @@ bool DesktopCaptureChooseDesktopMediaFunction::RunAsync() { return Execute(params->sources, web_contents, origin, target_name); } +std::string DesktopCaptureChooseDesktopMediaFunction::GetExtensionTargetName() + const { + return GetCallerDisplayName(); +} + DesktopCaptureCancelChooseDesktopMediaFunction:: DesktopCaptureCancelChooseDesktopMediaFunction() {} diff --git a/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.h b/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.h index 4a507e44344..82cc4fc3c59 100644 --- a/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.h +++ b/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_api.h @@ -22,6 +22,10 @@ class DesktopCaptureChooseDesktopMediaFunction // ExtensionFunction overrides. bool RunAsync() override; + + // Returns the target name to show in the picker when capture is requested for + // an extension. Currently this is the same as the application name. + std::string GetExtensionTargetName() const; }; class DesktopCaptureCancelChooseDesktopMediaFunction diff --git a/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc b/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc index 049a56b160d..da43435a1b9 100644 --- a/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc +++ b/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.cc @@ -17,14 +17,17 @@ #include "chrome/browser/media/webrtc/media_capture_devices_dispatcher.h" #include "chrome/browser/media/webrtc/native_desktop_media_list.h" #include "chrome/browser/media/webrtc/tab_desktop_media_list.h" -#include "components/version_info/version_info.h" +#include "chrome/browser/ui/browser_finder.h" +#include "chrome/browser/ui/browser_window.h" +#include "chrome/grit/chromium_strings.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents.h" +#include "extensions/common/manifest.h" #include "extensions/common/switches.h" #include "third_party/webrtc/modules/desktop_capture/desktop_capture_options.h" -#include "third_party/webrtc/modules/desktop_capture/screen_capturer.h" -#include "third_party/webrtc/modules/desktop_capture/window_capturer.h" +#include "third_party/webrtc/modules/desktop_capture/desktop_capturer.h" +#include "ui/base/l10n/l10n_util.h" namespace extensions { @@ -116,8 +119,17 @@ bool DesktopCaptureChooseDesktopMediaFunctionBase::Execute( return false; } - const gfx::NativeWindow parent_window = - web_contents->GetTopLevelNativeWindow(); + gfx::NativeWindow parent_window = web_contents->GetTopLevelNativeWindow(); + // In case of coming from background extension page, |parent_window| will + // be null. We are going to make the picker modal to the current browser + // window. + if (!parent_window) { + Browser* target_browser = chrome::FindLastActiveWithProfile( + Profile::FromBrowserContext(web_contents->GetBrowserContext())); + + if (target_browser) + parent_window = target_browser->window()->GetNativeWindow(); + } std::unique_ptr<DesktopMediaList> screen_list; std::unique_ptr<DesktopMediaList> window_list; std::unique_ptr<DesktopMediaList> tab_list; @@ -140,8 +152,8 @@ bool DesktopCaptureChooseDesktopMediaFunctionBase::Execute( webrtc::DesktopCaptureOptions options = webrtc::DesktopCaptureOptions::CreateDefault(); options.set_disable_effects(false); - std::unique_ptr<webrtc::ScreenCapturer> screen_capturer( - webrtc::ScreenCapturer::Create(options)); + std::unique_ptr<webrtc::DesktopCapturer> screen_capturer( + webrtc::DesktopCapturer::CreateScreenCapturer(options)); screen_list = base::MakeUnique<NativeDesktopMediaList>( std::move(screen_capturer), nullptr); @@ -158,8 +170,8 @@ bool DesktopCaptureChooseDesktopMediaFunctionBase::Execute( webrtc::DesktopCaptureOptions options = webrtc::DesktopCaptureOptions::CreateDefault(); options.set_disable_effects(false); - std::unique_ptr<webrtc::WindowCapturer> window_capturer( - webrtc::WindowCapturer::Create(options)); + std::unique_ptr<webrtc::DesktopCapturer> window_capturer( + webrtc::DesktopCapturer::CreateWindowCapturer(options)); window_list = base::MakeUnique<NativeDesktopMediaList>( nullptr, std::move(window_capturer)); @@ -186,13 +198,23 @@ bool DesktopCaptureChooseDesktopMediaFunctionBase::Execute( this); picker_->Show(web_contents, parent_window, parent_window, - base::UTF8ToUTF16(extension()->name()), target_name, + base::UTF8ToUTF16(GetCallerDisplayName()), target_name, std::move(screen_list), std::move(window_list), std::move(tab_list), request_audio, callback); origin_ = origin; return true; } +std::string DesktopCaptureChooseDesktopMediaFunctionBase::GetCallerDisplayName() + const { + if (extension()->location() == Manifest::COMPONENT || + extension()->location() == Manifest::EXTERNAL_COMPONENT) { + return l10n_util::GetStringUTF8(IDS_SHORT_PRODUCT_NAME); + } else { + return extension()->name(); + } +} + void DesktopCaptureChooseDesktopMediaFunctionBase::WebContentsDestroyed() { Cancel(); } diff --git a/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.h b/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.h index 38b803d2b15..f4f03f04fd4 100644 --- a/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.h +++ b/chromium/chrome/browser/extensions/api/desktop_capture/desktop_capture_base.h @@ -7,6 +7,7 @@ #include <array> #include <map> +#include <string> #include "base/macros.h" #include "base/memory/singleton.h" @@ -36,7 +37,11 @@ class DesktopCaptureChooseDesktopMediaFunctionBase virtual std::unique_ptr<DesktopMediaPicker> CreatePicker() = 0; protected: + PickerFactory() = default; virtual ~PickerFactory() {} + + private: + DISALLOW_COPY_AND_ASSIGN(PickerFactory); }; // Used to set PickerFactory used to create mock DesktopMediaPicker instances @@ -62,6 +67,9 @@ class DesktopCaptureChooseDesktopMediaFunctionBase const GURL& origin, const base::string16 target_name); + // Returns the calling application name to show in the picker. + std::string GetCallerDisplayName() const; + int request_id_; private: diff --git a/chromium/chrome/browser/extensions/api/device_permissions_manager_unittest.cc b/chromium/chrome/browser/extensions/api/device_permissions_manager_unittest.cc index eacf06e698a..6ff4e53cc25 100644 --- a/chromium/chrome/browser/extensions/api/device_permissions_manager_unittest.cc +++ b/chromium/chrome/browser/extensions/api/device_permissions_manager_unittest.cc @@ -10,7 +10,7 @@ #include "build/build_config.h" #include "chrome/browser/extensions/test_extension_environment.h" #include "chrome/test/base/testing_profile.h" -#include "device/core/mock_device_client.h" +#include "device/base/mock_device_client.h" #include "device/hid/hid_device_info.h" #include "device/hid/mock_hid_service.h" #include "device/usb/mock_usb_device.h" diff --git a/chromium/chrome/browser/extensions/api/dial/dial_service.cc b/chromium/chrome/browser/extensions/api/dial/dial_service.cc index 06c7398d3cd..1fe6dae2af0 100644 --- a/chromium/chrome/browser/extensions/api/dial/dial_service.cc +++ b/chromium/chrome/browser/extensions/api/dial/dial_service.cc @@ -562,7 +562,8 @@ void DialServiceImpl::NotifyOnDiscoveryRequest() { } VLOG(2) << "Notifying observers of discovery request"; - FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryRequest(this)); + for (auto& observer : observer_list_) + observer.OnDiscoveryRequest(this); // If we need to send additional requests, schedule a timer to do so. if (num_requests_sent_ < max_requests_ && num_requests_sent_ == 1) { VLOG(2) << "Scheduling timer to send additional requests"; @@ -582,18 +583,18 @@ void DialServiceImpl::NotifyOnDeviceDiscovered( VLOG(2) << "Got response after discovery finished. Ignoring."; return; } - FOR_EACH_OBSERVER(Observer, observer_list_, - OnDeviceDiscovered(this, device_data)); + for (auto& observer : observer_list_) + observer.OnDeviceDiscovered(this, device_data); } void DialServiceImpl::NotifyOnError() { DCHECK_CURRENTLY_ON(BrowserThread::IO); // TODO(imcheng): Modify upstream so that the device list is not cleared // when it could still potentially discover devices on other sockets. - FOR_EACH_OBSERVER(Observer, observer_list_, - OnError(this, - HasOpenSockets() ? DIAL_SERVICE_SOCKET_ERROR - : DIAL_SERVICE_NO_INTERFACES)); + for (auto& observer : observer_list_) { + observer.OnError(this, HasOpenSockets() ? DIAL_SERVICE_SOCKET_ERROR + : DIAL_SERVICE_NO_INTERFACES); + } } void DialServiceImpl::FinishDiscovery() { @@ -606,7 +607,8 @@ void DialServiceImpl::FinishDiscovery() { request_timer_.Stop(); discovery_active_ = false; num_requests_sent_ = 0; - FOR_EACH_OBSERVER(Observer, observer_list_, OnDiscoveryFinished(this)); + for (auto& observer : observer_list_) + observer.OnDiscoveryFinished(this); } bool DialServiceImpl::HasOpenSockets() { diff --git a/chromium/chrome/browser/extensions/api/dial/dial_service.h b/chromium/chrome/browser/extensions/api/dial/dial_service.h index fa9809e8f6e..bbf2fdec126 100644 --- a/chromium/chrome/browser/extensions/api/dial/dial_service.h +++ b/chromium/chrome/browser/extensions/api/dial/dial_service.h @@ -16,7 +16,7 @@ #include "base/timer/timer.h" #include "net/base/ip_address.h" #include "net/log/net_log_source.h" -#include "net/udp/udp_socket.h" +#include "net/socket/udp_socket.h" namespace net { class IOBuffer; diff --git a/chromium/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc b/chromium/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc index 5d1cfcf59e6..a8a9eca778b 100644 --- a/chromium/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc +++ b/chromium/chrome/browser/extensions/api/downloads/downloads_api_browsertest.cc @@ -15,8 +15,8 @@ #include "base/guid.h" #include "base/json/json_reader.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/message_loop/message_loop.h" -#include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "base/synchronization/waitable_event.h" #include "build/build_config.h" @@ -95,10 +95,9 @@ class DownloadsEventsListener : public content::NotificationObserver { registrar_.Remove(this, extensions::NOTIFICATION_EXTENSION_DOWNLOADS_EVENT, content::NotificationService::AllSources()); - base::STLDeleteElements(&events_); } - void ClearEvents() { base::STLDeleteElements(&events_); } + void ClearEvents() { events_.clear(); } class Event { public: @@ -186,7 +185,7 @@ class DownloadsEventsListener : public content::NotificationObserver { Event* new_event = new Event( dns->profile, dns->event_name, *content::Details<std::string>(details).ptr(), base::Time::Now()); - events_.push_back(new_event); + events_.push_back(base::WrapUnique(new_event)); if (waiting_ && waiting_for_.get() && new_event->Satisfies(*waiting_for_)) { @@ -204,9 +203,8 @@ class DownloadsEventsListener : public content::NotificationObserver { const std::string& event_name, const std::string& json_args) { waiting_for_.reset(new Event(profile, event_name, json_args, base::Time())); - for (std::deque<Event*>::const_iterator iter = events_.begin(); - iter != events_.end(); ++iter) { - if ((*iter)->Satisfies(*waiting_for_)) { + for (const auto& event : events_) { + if (event->Satisfies(*waiting_for_)) { return true; } } @@ -217,10 +215,9 @@ class DownloadsEventsListener : public content::NotificationObserver { // Print the events that were caught since the last WaitFor() call to help // find the erroneous event. // TODO(benjhayden) Fuzzy-match and highlight the erroneous event. - for (std::deque<Event*>::const_iterator iter = events_.begin(); - iter != events_.end(); ++iter) { - if ((*iter)->caught() > last_wait_) { - LOG(INFO) << "Caught " << (*iter)->Debug(); + for (const auto& event : events_) { + if (event->caught() > last_wait_) { + LOG(INFO) << "Caught " << event->Debug(); } } if (waiting_for_.get()) { @@ -238,7 +235,7 @@ class DownloadsEventsListener : public content::NotificationObserver { base::Time last_wait_; std::unique_ptr<Event> waiting_for_; content::NotificationRegistrar registrar_; - std::deque<Event*> events_; + std::deque<std::unique_ptr<Event>> events_; DISALLOW_COPY_AND_ASSIGN(DownloadsEventsListener); }; diff --git a/chromium/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api_chromeos_unittest.cc b/chromium/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api_chromeos_unittest.cc index bf6a85b225a..bbf17ca5113 100644 --- a/chromium/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api_chromeos_unittest.cc +++ b/chromium/chrome/browser/extensions/api/easy_unlock_private/easy_unlock_private_api_chromeos_unittest.cc @@ -264,8 +264,7 @@ TEST_F(EasyUnlockPrivateApiTest, CreateSecureMessage) { std::unique_ptr<base::ListValue> args(new base::ListValue); args->Append(StringToBinaryValue("PAYLOAD")); args->Append(StringToBinaryValue("KEY")); - base::DictionaryValue* options = new base::DictionaryValue(); - args->Append(options); + auto options = base::MakeUnique<base::DictionaryValue>(); options->Set("associatedData", StringToBinaryValue("ASSOCIATED_DATA")); options->Set("publicMetadata", StringToBinaryValue("PUBLIC_METADATA")); options->Set("verificationKeyId", @@ -278,6 +277,7 @@ TEST_F(EasyUnlockPrivateApiTest, CreateSecureMessage) { options->SetString( "signType", api::ToString(api::SIGNATURE_TYPE_HMAC_SHA256)); + args->Append(std::move(options)); ASSERT_TRUE(extension_function_test_utils::RunFunction( function.get(), std::move(args), browser(), @@ -338,8 +338,7 @@ TEST_F(EasyUnlockPrivateApiTest, CreateSecureMessage_AsymmetricSign) { std::unique_ptr<base::ListValue> args(new base::ListValue); args->Append(StringToBinaryValue("PAYLOAD")); args->Append(StringToBinaryValue("KEY")); - base::DictionaryValue* options = new base::DictionaryValue(); - args->Append(options); + auto options = base::MakeUnique<base::DictionaryValue>(); options->Set("associatedData", StringToBinaryValue("ASSOCIATED_DATA")); options->Set("verificationKeyId", @@ -347,6 +346,7 @@ TEST_F(EasyUnlockPrivateApiTest, CreateSecureMessage_AsymmetricSign) { options->SetString( "signType", api::ToString(api::SIGNATURE_TYPE_ECDSA_P256_SHA256)); + args->Append(std::move(options)); ASSERT_TRUE(extension_function_test_utils::RunFunction( function.get(), std::move(args), browser(), @@ -376,8 +376,7 @@ TEST_F(EasyUnlockPrivateApiTest, UnwrapSecureMessage) { std::unique_ptr<base::ListValue> args(new base::ListValue); args->Append(StringToBinaryValue("MESSAGE")); args->Append(StringToBinaryValue("KEY")); - base::DictionaryValue* options = new base::DictionaryValue(); - args->Append(options); + auto options = base::MakeUnique<base::DictionaryValue>(); options->Set("associatedData", StringToBinaryValue("ASSOCIATED_DATA")); options->SetString( "encryptType", @@ -385,6 +384,7 @@ TEST_F(EasyUnlockPrivateApiTest, UnwrapSecureMessage) { options->SetString( "signType", api::ToString(api::SIGNATURE_TYPE_HMAC_SHA256)); + args->Append(std::move(options)); ASSERT_TRUE(extension_function_test_utils::RunFunction( function.get(), std::move(args), browser(), @@ -444,13 +444,13 @@ TEST_F(EasyUnlockPrivateApiTest, UnwrapSecureMessage_AsymmetricSign) { std::unique_ptr<base::ListValue> args(new base::ListValue); args->Append(StringToBinaryValue("MESSAGE")); args->Append(StringToBinaryValue("KEY")); - base::DictionaryValue* options = new base::DictionaryValue(); - args->Append(options); + auto options = base::MakeUnique<base::DictionaryValue>(); options->Set("associatedData", StringToBinaryValue("ASSOCIATED_DATA")); options->SetString( "signType", api::ToString(api::SIGNATURE_TYPE_ECDSA_P256_SHA256)); + args->Append(std::move(options)); ASSERT_TRUE(extension_function_test_utils::RunFunction( function.get(), std::move(args), browser(), diff --git a/chromium/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc b/chromium/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc index 329d1cccfee..8a40a6bcab6 100644 --- a/chromium/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc +++ b/chromium/chrome/browser/extensions/api/enterprise_device_attributes/enterprise_device_attributes_apitest.cc @@ -13,7 +13,6 @@ #include "chrome/browser/net/url_request_mock_util.h" #include "chrome/test/base/ui_test_utils.h" #include "chromeos/dbus/fake_session_manager_client.h" -#include "chromeos/login/user_names.h" #include "components/policy/core/common/cloud/device_management_service.h" #include "components/policy/core/common/mock_configuration_policy_provider.h" #include "components/policy/policy_constants.h" @@ -100,7 +99,7 @@ class EnterpriseDeviceAttributesTest : std::unique_ptr<chromeos::StubInstallAttributes> attributes = base::MakeUnique<chromeos::StubInstallAttributes>(); - attributes->SetRegistrationUser(affiliated_account_id_.GetUserEmail()); + attributes->SetEnterprise("fake-domain", "fake-id"); policy::BrowserPolicyConnectorChromeOS::SetInstallAttributesForTesting( attributes.release()); diff --git a/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc b/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc index 01e847957bb..4a71583f67a 100644 --- a/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc +++ b/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_api_unittest.cc @@ -161,11 +161,7 @@ class EPKChallengeKeyTestBase : public BrowserWithTestWindowTest { ON_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _)) .WillByDefault(Invoke(GetCertificateCallbackTrue)); - // Set the Enterprise install attributes. - stub_install_attributes_.SetDomain("google.com"); - stub_install_attributes_.SetRegistrationUser(kUserEmail); - stub_install_attributes_.SetDeviceId("device_id"); - stub_install_attributes_.SetMode(policy::DEVICE_MODE_ENTERPRISE); + stub_install_attributes_.SetEnterprise("google.com", "device_id"); settings_helper_.ReplaceProvider(chromeos::kDeviceAttestationEnabled); settings_helper_.SetBoolean(chromeos::kDeviceAttestationEnabled, true); @@ -277,7 +273,7 @@ class EPKChallengeMachineKeyTest : public EPKChallengeKeyTestBase { }; TEST_F(EPKChallengeMachineKeyTest, NonEnterpriseDevice) { - stub_install_attributes_.SetRegistrationUser(""); + stub_install_attributes_.SetConsumer(); EXPECT_EQ(EPKPChallengeMachineKey::kNonEnterpriseDeviceError, RunFunctionAndReturnError(func_.get(), CreateArgs(), browser())); @@ -496,7 +492,7 @@ TEST_F(EPKChallengeUserKeyTest, KeyNotRegistered) { } TEST_F(EPKChallengeUserKeyTest, PersonalDevice) { - stub_install_attributes_.SetRegistrationUser(""); + stub_install_attributes_.SetConsumer(); // Currently personal devices are not supported. EXPECT_EQ(GetCertificateError(kUserRejected), diff --git a/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc b/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc index 3adc4ec10df..436584a9f4e 100644 --- a/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc +++ b/chromium/chrome/browser/extensions/api/enterprise_platform_keys/enterprise_platform_keys_apitest_nss.cc @@ -25,7 +25,6 @@ #include "chromeos/dbus/dbus_thread_manager.h" #include "chromeos/dbus/fake_session_manager_client.h" #include "chromeos/dbus/session_manager_client.h" -#include "chromeos/login/user_names.h" #include "components/policy/core/browser/browser_policy_connector.h" #include "components/policy/core/common/mock_configuration_policy_provider.h" #include "components/policy/core/common/policy_map.h" diff --git a/chromium/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc b/chromium/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc index b3c78fbe3ca..6d9e2699010 100644 --- a/chromium/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc +++ b/chromium/chrome/browser/extensions/api/enterprise_platform_keys_private/enterprise_platform_keys_private_api_unittest.cc @@ -170,11 +170,7 @@ class EPKPChallengeKeyTestBase : public BrowserWithTestWindowTest { ON_CALL(mock_attestation_flow_, GetCertificate(_, _, _, _, _)) .WillByDefault(Invoke(GetCertificateCallbackTrue)); - // Set the Enterprise install attributes. - stub_install_attributes_.SetDomain("google.com"); - stub_install_attributes_.SetRegistrationUser(kUserEmail); - stub_install_attributes_.SetDeviceId("device_id"); - stub_install_attributes_.SetMode(policy::DEVICE_MODE_ENTERPRISE); + stub_install_attributes_.SetEnterprise("google.com", "device_id"); settings_helper_.ReplaceProvider(chromeos::kDeviceAttestationEnabled); settings_helper_.SetBoolean(chromeos::kDeviceAttestationEnabled, true); @@ -262,7 +258,7 @@ TEST_F(EPKPChallengeMachineKeyTest, ChallengeBadBase64) { } TEST_F(EPKPChallengeMachineKeyTest, NonEnterpriseDevice) { - stub_install_attributes_.SetRegistrationUser(""); + stub_install_attributes_.SetConsumer(); EXPECT_EQ(EPKPChallengeMachineKey::kNonEnterpriseDeviceError, utils::RunFunctionAndReturnError(func_.get(), kArgs, browser())); @@ -477,7 +473,7 @@ TEST_F(EPKPChallengeUserKeyTest, KeyNotRegistered) { } TEST_F(EPKPChallengeUserKeyTest, PersonalDevice) { - stub_install_attributes_.SetRegistrationUser(""); + stub_install_attributes_.SetConsumer(); // Currently personal devices are not supported. EXPECT_EQ(GetCertificateError(kUserRejected), diff --git a/chromium/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc b/chromium/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc index 7b2e7dd11dd..876abcc72a4 100644 --- a/chromium/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc +++ b/chromium/chrome/browser/extensions/api/extension_action/browser_action_apitest.cc @@ -4,6 +4,9 @@ #include <stdint.h> +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/files/scoped_temp_dir.h" #include "base/macros.h" #include "build/build_config.h" #include "chrome/browser/extensions/api/extension_action/extension_action_api.h" @@ -23,8 +26,10 @@ #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/extensions/extension_process_policy.h" +#include "chrome/common/pref_names.h" #include "chrome/common/url_constants.h" #include "chrome/test/base/ui_test_utils.h" +#include "components/prefs/pref_service.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/render_frame_host.h" @@ -64,6 +69,18 @@ void ExecuteExtensionAction(Browser* browser, const Extension* extension) { ->RunAction(extension, true); } +std::unique_ptr<base::ScopedTempDir> CreateAndSetDownloadsDirectory( + PrefService* pref_service) { + std::unique_ptr<base::ScopedTempDir> dir(new base::ScopedTempDir); + + if (!dir->CreateUniqueTempDir()) + return nullptr; + + pref_service->SetFilePath(prefs::kDownloadDefaultDirectory, dir->GetPath()); + pref_service->SetFilePath(prefs::kSaveFileDefaultDirectory, dir->GetPath()); + return dir; +} + // An ImageSkia source that will do nothing (i.e., have a blank skia). We need // this because we need a blank canvas at a certain size, and that can't be done // by just using a null ImageSkia. @@ -992,6 +1009,14 @@ IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest, // TODO(lukasza): https://crbug.com/650694: Add a "Get" flavour of the test once // the download works both for GET and POST requests. IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest, DownloadViaPost) { + // Override the default downloads directory, so that the test can cleanup + // after itself. This section is based on CreateAndSetDownloadsDirectory + // method defined in a few other source files with tests. + std::unique_ptr<base::ScopedTempDir> downloads_directory = + CreateAndSetDownloadsDirectory(browser()->profile()->GetPrefs()); + ASSERT_TRUE(downloads_directory); + + // Setup monitoring of the downloads. content::DownloadTestObserverTerminal downloads_observer( content::BrowserContext::GetDownloadManager(browser()->profile()), 1, // == wait_count (only waiting for "download-test3.gif"). @@ -1009,6 +1034,8 @@ IN_PROC_BROWSER_TEST_F(NavigatingExtensionPopupBrowserTest, DownloadViaPost) { EXPECT_EQ(0u, downloads_observer.NumDangerousDownloadsSeen()); EXPECT_EQ(1u, downloads_observer.NumDownloadsSeenInState( content::DownloadItem::COMPLETE)); + EXPECT_TRUE(base::PathExists(downloads_directory->GetPath().AppendASCII( + "download-test3-attachment.gif"))); // The test verification below is applicable only to scenarios where the // download shelf is supported - on ChromeOS, instead of the download shelf, diff --git a/chromium/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc b/chromium/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc index 35b9de583a7..1c0ffcdd78f 100644 --- a/chromium/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc +++ b/chromium/chrome/browser/extensions/api/extension_action/browser_action_interactive_test.cc @@ -19,8 +19,10 @@ #include "chrome/test/base/interactive_test_utils.h" #include "chrome/test/base/ui_test_utils.h" #include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_types.h" #include "extensions/browser/extension_registry.h" #include "extensions/browser/extension_system.h" +#include "extensions/browser/notification_types.h" #include "extensions/common/extension.h" #include "extensions/common/extension_set.h" #include "extensions/common/permissions/permissions_data.h" diff --git a/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.cc b/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.cc index 754d1542518..91555cbfd61 100644 --- a/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.cc +++ b/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.cc @@ -167,8 +167,8 @@ void ExtensionActionAPI::SetBrowserActionVisibility( GetExtensionPrefs()->UpdateExtensionPref(extension_id, kBrowserActionVisible, new base::FundamentalValue(visible)); - FOR_EACH_OBSERVER(Observer, observers_, OnExtensionActionVisibilityChanged( - extension_id, visible)); + for (auto& observer : observers_) + observer.OnExtensionActionVisibilityChanged(extension_id, visible); } bool ExtensionActionAPI::ShowExtensionActionPopup( @@ -205,10 +205,8 @@ bool ExtensionActionAPI::ShowExtensionActionPopup( void ExtensionActionAPI::NotifyChange(ExtensionAction* extension_action, content::WebContents* web_contents, content::BrowserContext* context) { - FOR_EACH_OBSERVER( - Observer, - observers_, - OnExtensionActionUpdated(extension_action, web_contents, context)); + for (auto& observer : observers_) + observer.OnExtensionActionUpdated(extension_action, web_contents, context); if (extension_action->action_type() == ActionInfo::TYPE_PAGE) NotifyPageActionsChanged(web_contents); @@ -302,11 +300,13 @@ void ExtensionActionAPI::NotifyPageActionsChanged( return; location_bar->UpdatePageActions(); - FOR_EACH_OBSERVER(Observer, observers_, OnPageActionsUpdated(web_contents)); + for (auto& observer : observers_) + observer.OnPageActionsUpdated(web_contents); } void ExtensionActionAPI::Shutdown() { - FOR_EACH_OBSERVER(Observer, observers_, OnExtensionActionAPIShuttingDown()); + for (auto& observer : observers_) + observer.OnExtensionActionAPIShuttingDown(); } // @@ -323,8 +323,9 @@ ExtensionActionFunction::ExtensionActionFunction() ExtensionActionFunction::~ExtensionActionFunction() { } -bool ExtensionActionFunction::RunSync() { - ExtensionActionManager* manager = ExtensionActionManager::Get(GetProfile()); +ExtensionFunction::ResponseAction ExtensionActionFunction::Run() { + ExtensionActionManager* manager = + ExtensionActionManager::Get(browser_context()); if (base::StartsWith(name(), "systemIndicator.", base::CompareCase::INSENSITIVE_ASCII)) { extension_action_ = manager->GetSystemIndicator(*extension()); @@ -338,8 +339,7 @@ bool ExtensionActionFunction::RunSync() { // TODO(kalman): ideally the browserAction/pageAction APIs wouldn't event // exist for extensions that don't have one declared. This should come as // part of the Feature system. - error_ = kNoExtensionActionError; - return false; + return RespondNow(Error(kNoExtensionActionError)); } // Populates the tab_id_ and details_ members. @@ -347,18 +347,11 @@ bool ExtensionActionFunction::RunSync() { // Find the WebContents that contains this tab id if one is required. if (tab_id_ != ExtensionAction::kDefaultTabId) { - ExtensionTabUtil::GetTabById(tab_id_, - GetProfile(), - include_incognito(), - NULL, - NULL, - &contents_, - NULL); - if (!contents_) { - error_ = ErrorUtils::FormatErrorMessage( - kNoTabError, base::IntToString(tab_id_)); - return false; - } + ExtensionTabUtil::GetTabById(tab_id_, browser_context(), + include_incognito(), nullptr, nullptr, + &contents_, nullptr); + if (!contents_) + return RespondNow(Error(kNoTabError, base::IntToString(tab_id_))); } else { // Only browser actions and system indicators have a default tabId. ActionInfo::Type action_type = extension_action_->action_type(); @@ -417,27 +410,31 @@ bool ExtensionActionFunction::ExtractDataFromArguments() { } void ExtensionActionFunction::NotifyChange() { - ExtensionActionAPI::Get(GetProfile())->NotifyChange( - extension_action_, contents_, GetProfile()); + ExtensionActionAPI::Get(browser_context()) + ->NotifyChange(extension_action_, contents_, browser_context()); } -bool ExtensionActionFunction::SetVisible(bool visible) { +void ExtensionActionFunction::SetVisible(bool visible) { if (extension_action_->GetIsVisible(tab_id_) == visible) - return true; + return; extension_action_->SetIsVisible(tab_id_, visible); NotifyChange(); - return true; } -bool ExtensionActionShowFunction::RunExtensionAction() { - return SetVisible(true); +ExtensionFunction::ResponseAction +ExtensionActionShowFunction::RunExtensionAction() { + SetVisible(true); + return RespondNow(NoArguments()); } -bool ExtensionActionHideFunction::RunExtensionAction() { - return SetVisible(false); +ExtensionFunction::ResponseAction +ExtensionActionHideFunction::RunExtensionAction() { + SetVisible(false); + return RespondNow(NoArguments()); } -bool ExtensionActionSetIconFunction::RunExtensionAction() { +ExtensionFunction::ResponseAction +ExtensionActionSetIconFunction::RunExtensionAction() { EXTENSION_FUNCTION_VALIDATE(details_); // setIcon can take a variant argument: either a dictionary of canvas @@ -450,32 +447,32 @@ bool ExtensionActionSetIconFunction::RunExtensionAction() { EXTENSION_FUNCTION_VALIDATE( ExtensionAction::ParseIconFromCanvasDictionary(*canvas_set, &icon)); - if (icon.isNull()) { - error_ = "Icon invalid."; - return false; - } + if (icon.isNull()) + return RespondNow(Error("Icon invalid.")); extension_action_->SetIcon(tab_id_, gfx::Image(icon)); } else if (details_->GetInteger("iconIndex", &icon_index)) { // Obsolete argument: ignore it. - return true; + return RespondNow(NoArguments()); } else { EXTENSION_FUNCTION_VALIDATE(false); } NotifyChange(); - return true; + return RespondNow(NoArguments()); } -bool ExtensionActionSetTitleFunction::RunExtensionAction() { +ExtensionFunction::ResponseAction +ExtensionActionSetTitleFunction::RunExtensionAction() { EXTENSION_FUNCTION_VALIDATE(details_); std::string title; EXTENSION_FUNCTION_VALIDATE(details_->GetString("title", &title)); extension_action_->SetTitle(tab_id_, title); NotifyChange(); - return true; + return RespondNow(NoArguments()); } -bool ExtensionActionSetPopupFunction::RunExtensionAction() { +ExtensionFunction::ResponseAction +ExtensionActionSetPopupFunction::RunExtensionAction() { EXTENSION_FUNCTION_VALIDATE(details_); std::string popup_string; EXTENSION_FUNCTION_VALIDATE(details_->GetString("popup", &popup_string)); @@ -486,19 +483,21 @@ bool ExtensionActionSetPopupFunction::RunExtensionAction() { extension_action_->SetPopupUrl(tab_id_, popup_url); NotifyChange(); - return true; + return RespondNow(NoArguments()); } -bool ExtensionActionSetBadgeTextFunction::RunExtensionAction() { +ExtensionFunction::ResponseAction +ExtensionActionSetBadgeTextFunction::RunExtensionAction() { EXTENSION_FUNCTION_VALIDATE(details_); std::string badge_text; EXTENSION_FUNCTION_VALIDATE(details_->GetString("text", &badge_text)); extension_action_->SetBadgeText(tab_id_, badge_text); NotifyChange(); - return true; + return RespondNow(NoArguments()); } -bool ExtensionActionSetBadgeBackgroundColorFunction::RunExtensionAction() { +ExtensionFunction::ResponseAction +ExtensionActionSetBadgeBackgroundColorFunction::RunExtensionAction() { EXTENSION_FUNCTION_VALIDATE(details_); base::Value* color_value = NULL; EXTENSION_FUNCTION_VALIDATE(details_->Get("color", &color_value)); @@ -518,44 +517,42 @@ bool ExtensionActionSetBadgeBackgroundColorFunction::RunExtensionAction() { } else if (color_value->IsType(base::Value::TYPE_STRING)) { std::string color_string; EXTENSION_FUNCTION_VALIDATE(details_->GetString("color", &color_string)); - if (!image_util::ParseCssColorString(color_string, &color)) { - error_ = kInvalidColorError; - return false; - } + if (!image_util::ParseCssColorString(color_string, &color)) + return RespondNow(Error(kInvalidColorError)); } extension_action_->SetBadgeBackgroundColor(tab_id_, color); NotifyChange(); - return true; + return RespondNow(NoArguments()); } -bool ExtensionActionGetTitleFunction::RunExtensionAction() { - SetResult(base::MakeUnique<base::StringValue>( - extension_action_->GetTitle(tab_id_))); - return true; +ExtensionFunction::ResponseAction +ExtensionActionGetTitleFunction::RunExtensionAction() { + return RespondNow(OneArgument(base::MakeUnique<base::StringValue>( + extension_action_->GetTitle(tab_id_)))); } -bool ExtensionActionGetPopupFunction::RunExtensionAction() { - SetResult(base::MakeUnique<base::StringValue>( - extension_action_->GetPopupUrl(tab_id_).spec())); - return true; +ExtensionFunction::ResponseAction +ExtensionActionGetPopupFunction::RunExtensionAction() { + return RespondNow(OneArgument(base::MakeUnique<base::StringValue>( + extension_action_->GetPopupUrl(tab_id_).spec()))); } -bool ExtensionActionGetBadgeTextFunction::RunExtensionAction() { - SetResult(base::MakeUnique<base::StringValue>( - extension_action_->GetBadgeText(tab_id_))); - return true; +ExtensionFunction::ResponseAction +ExtensionActionGetBadgeTextFunction::RunExtensionAction() { + return RespondNow(OneArgument(base::MakeUnique<base::StringValue>( + extension_action_->GetBadgeText(tab_id_)))); } -bool ExtensionActionGetBadgeBackgroundColorFunction::RunExtensionAction() { +ExtensionFunction::ResponseAction +ExtensionActionGetBadgeBackgroundColorFunction::RunExtensionAction() { std::unique_ptr<base::ListValue> list(new base::ListValue()); SkColor color = extension_action_->GetBadgeBackgroundColor(tab_id_); list->AppendInteger(static_cast<int>(SkColorGetR(color))); list->AppendInteger(static_cast<int>(SkColorGetG(color))); list->AppendInteger(static_cast<int>(SkColorGetB(color))); list->AppendInteger(static_cast<int>(SkColorGetA(color))); - SetResult(std::move(list)); - return true; + return RespondNow(OneArgument(std::move(list))); } BrowserActionOpenPopupFunction::BrowserActionOpenPopupFunction() diff --git a/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.h b/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.h index 070b6686b80..b1ad1fc0fc7 100644 --- a/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.h +++ b/chromium/chrome/browser/extensions/api/extension_action/extension_action_api.h @@ -140,7 +140,7 @@ class ExtensionActionAPI : public BrowserContextKeyedAPI { // tabIds while browserAction's are optional, they have different internal // browser notification requirements, and not all functions are defined for all // APIs). -class ExtensionActionFunction : public ChromeSyncExtensionFunction { +class ExtensionActionFunction : public UIThreadExtensionFunction { public: static bool ParseCSSColorString(const std::string& color_string, SkColor* result); @@ -148,12 +148,13 @@ class ExtensionActionFunction : public ChromeSyncExtensionFunction { protected: ExtensionActionFunction(); ~ExtensionActionFunction() override; - bool RunSync() override; - virtual bool RunExtensionAction() = 0; + ResponseAction Run() override; + + virtual ResponseAction RunExtensionAction() = 0; bool ExtractDataFromArguments(); void NotifyChange(); - bool SetVisible(bool visible); + void SetVisible(bool visible); // All the extension action APIs take a single argument called details that // is a dictionary. @@ -181,42 +182,42 @@ class ExtensionActionFunction : public ChromeSyncExtensionFunction { class ExtensionActionShowFunction : public ExtensionActionFunction { protected: ~ExtensionActionShowFunction() override {} - bool RunExtensionAction() override; + ResponseAction RunExtensionAction() override; }; // hide class ExtensionActionHideFunction : public ExtensionActionFunction { protected: ~ExtensionActionHideFunction() override {} - bool RunExtensionAction() override; + ResponseAction RunExtensionAction() override; }; // setIcon class ExtensionActionSetIconFunction : public ExtensionActionFunction { protected: ~ExtensionActionSetIconFunction() override {} - bool RunExtensionAction() override; + ResponseAction RunExtensionAction() override; }; // setTitle class ExtensionActionSetTitleFunction : public ExtensionActionFunction { protected: ~ExtensionActionSetTitleFunction() override {} - bool RunExtensionAction() override; + ResponseAction RunExtensionAction() override; }; // setPopup class ExtensionActionSetPopupFunction : public ExtensionActionFunction { protected: ~ExtensionActionSetPopupFunction() override {} - bool RunExtensionAction() override; + ResponseAction RunExtensionAction() override; }; // setBadgeText class ExtensionActionSetBadgeTextFunction : public ExtensionActionFunction { protected: ~ExtensionActionSetBadgeTextFunction() override {} - bool RunExtensionAction() override; + ResponseAction RunExtensionAction() override; }; // setBadgeBackgroundColor @@ -224,28 +225,28 @@ class ExtensionActionSetBadgeBackgroundColorFunction : public ExtensionActionFunction { protected: ~ExtensionActionSetBadgeBackgroundColorFunction() override {} - bool RunExtensionAction() override; + ResponseAction RunExtensionAction() override; }; // getTitle class ExtensionActionGetTitleFunction : public ExtensionActionFunction { protected: ~ExtensionActionGetTitleFunction() override {} - bool RunExtensionAction() override; + ResponseAction RunExtensionAction() override; }; // getPopup class ExtensionActionGetPopupFunction : public ExtensionActionFunction { protected: ~ExtensionActionGetPopupFunction() override {} - bool RunExtensionAction() override; + ResponseAction RunExtensionAction() override; }; // getBadgeText class ExtensionActionGetBadgeTextFunction : public ExtensionActionFunction { protected: ~ExtensionActionGetBadgeTextFunction() override {} - bool RunExtensionAction() override; + ResponseAction RunExtensionAction() override; }; // getBadgeBackgroundColor @@ -253,7 +254,7 @@ class ExtensionActionGetBadgeBackgroundColorFunction : public ExtensionActionFunction { protected: ~ExtensionActionGetBadgeBackgroundColorFunction() override {} - bool RunExtensionAction() override; + ResponseAction RunExtensionAction() override; }; // diff --git a/chromium/chrome/browser/extensions/api/font_settings/font_settings_api.cc b/chromium/chrome/browser/extensions/api/font_settings/font_settings_api.cc index 9d60a6ce23c..1d3420a8276 100644 --- a/chromium/chrome/browser/extensions/api/font_settings/font_settings_api.cc +++ b/chromium/chrome/browser/extensions/api/font_settings/font_settings_api.cc @@ -26,6 +26,7 @@ #include "chrome/browser/extensions/api/preference/preference_helpers.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/profiles/profile.h" +#include "chrome/browser/ui/webui/options/font_settings_utils.h" #include "chrome/common/extensions/api/font_settings.h" #include "chrome/common/pref_names.h" #include "chrome/common/pref_names_util.h" @@ -36,14 +37,10 @@ #include "extensions/browser/extension_system.h" #include "extensions/common/error_utils.h" -#if defined(OS_WIN) -#include "ui/gfx/font.h" -#include "ui/gfx/platform_font_win.h" -#endif - namespace extensions { namespace fonts = api::font_settings; +using options::FontSettingsUtilities; namespace { @@ -73,20 +70,6 @@ std::string GetFontNamePrefPath(fonts::GenericFamily generic_family_enum, script.c_str()); } -// Returns the localized name of a font so that it can be matched within the -// list of system fonts. On Windows, the list of system fonts has names only -// for the system locale, but the pref value may be in the English name. -std::string MaybeGetLocalizedFontName(const std::string& font_name) { -#if defined(OS_WIN) - if (!font_name.empty()) { - gfx::Font font(font_name, 12); // dummy font size - return static_cast<gfx::PlatformFontWin*>(font.platform_font())-> - GetLocalizedFontName(); - } -#endif - return font_name; -} - // Registers |obs| to observe per-script font prefs under the path |map_name|. void RegisterFontFamilyMapObserver( PrefChangeRegistrar* registrar, @@ -177,7 +160,7 @@ void FontSettingsEventRouter::OnFontNamePrefChanged( NOTREACHED(); return; } - font_name = MaybeGetLocalizedFontName(font_name); + font_name = FontSettingsUtilities::MaybeGetLocalizedFontName(font_name); base::ListValue args; std::unique_ptr<base::DictionaryValue> dict(new base::DictionaryValue()); @@ -263,7 +246,7 @@ ExtensionFunction::ResponseAction FontSettingsGetFontFunction::Run() { std::string font_name; EXTENSION_FUNCTION_VALIDATE( pref && pref->GetValue()->GetAsString(&font_name)); - font_name = MaybeGetLocalizedFontName(font_name); + font_name = FontSettingsUtilities::MaybeGetLocalizedFontName(font_name); // We don't support incognito-specific font prefs, so don't consider them when // getting level of control. diff --git a/chromium/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc b/chromium/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc index 9541d0efa5c..d21dc8f19f6 100644 --- a/chromium/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc +++ b/chromium/chrome/browser/extensions/api/gcd_private/gcd_private_api.cc @@ -4,9 +4,10 @@ #include "chrome/browser/extensions/api/gcd_private/gcd_private_api.h" +#include <memory> + #include "base/lazy_instance.h" #include "base/macros.h" -#include "base/memory/linked_ptr.h" #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/extensions/api/gcd_private/privet_v3_context_getter.h" #include "chrome/browser/extensions/api/gcd_private/privet_v3_session.h" @@ -93,8 +94,8 @@ class GcdPrivateAPIImpl { service_discovery_client_; struct SessionInfo { - linked_ptr<PrivetV3Session> session; - linked_ptr<local_discovery::EndpointResolver> resolver; + std::unique_ptr<PrivetV3Session> session; + std::unique_ptr<local_discovery::EndpointResolver> resolver; }; std::map<int, SessionInfo> sessions_; diff --git a/chromium/chrome/browser/extensions/api/hotword_private/hotword_private_apitest.cc b/chromium/chrome/browser/extensions/api/hotword_private/hotword_private_apitest.cc index 3c89ec4410a..fd8a8ae3281 100644 --- a/chromium/chrome/browser/extensions/api/hotword_private/hotword_private_apitest.cc +++ b/chromium/chrome/browser/extensions/api/hotword_private/hotword_private_apitest.cc @@ -379,7 +379,12 @@ IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest, OnHotwordTriggered) { EXPECT_TRUE(listenerNotification.WaitUntilSatisfied()); } -IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest, OnDeleteSpeakerModel) { +#if defined(OS_LINUX) +#define MAYBE_OnDeleteSpeakerModel DISABLED_OnDeleteSpeakerModel +#else +#define MAYBE_OnDeleteSpeakerModel OnDeleteSpeakerModel +#endif +IN_PROC_BROWSER_TEST_F(HotwordPrivateApiTest, MAYBE_OnDeleteSpeakerModel) { MockWebHistoryService* web_history = new MockWebHistoryService(profile()); MockAudioHistoryHandler* handler = new MockAudioHistoryHandler(profile(), web_history); diff --git a/chromium/chrome/browser/extensions/api/identity/identity_api.cc b/chromium/chrome/browser/extensions/api/identity/identity_api.cc index e4c15c1f896..f76f95d3f30 100644 --- a/chromium/chrome/browser/extensions/api/identity/identity_api.cc +++ b/chromium/chrome/browser/extensions/api/identity/identity_api.cc @@ -225,7 +225,8 @@ std::string IdentityAPI::FindAccountKeyByGaiaId(const std::string& gaia_id) { } void IdentityAPI::Shutdown() { - FOR_EACH_OBSERVER(ShutdownObserver, shutdown_observer_list_, OnShutdown()); + for (auto& observer : shutdown_observer_list_) + observer.OnShutdown(); account_tracker_.RemoveObserver(this); account_tracker_.Shutdown(); } diff --git a/chromium/chrome/browser/extensions/api/identity/identity_apitest.cc b/chromium/chrome/browser/extensions/api/identity/identity_apitest.cc index 06d8037fab1..22f056d2618 100644 --- a/chromium/chrome/browser/extensions/api/identity/identity_apitest.cc +++ b/chromium/chrome/browser/extensions/api/identity/identity_apitest.cc @@ -1597,8 +1597,7 @@ class GetAuthTokenFunctionPublicSessionTest : public GetAuthTokenFunctionTest { // enterprise-managed. std::unique_ptr<chromeos::StubInstallAttributes> attributes = base::MakeUnique<chromeos::StubInstallAttributes>(); - attributes->SetDomain("example.com"); - attributes->SetRegistrationUser("user@example.com"); + attributes->SetEnterprise("example.com", "fake-id"); policy::BrowserPolicyConnectorChromeOS::SetInstallAttributesForTesting( attributes.release()); } diff --git a/chromium/chrome/browser/extensions/api/identity/web_auth_flow.h b/chromium/chrome/browser/extensions/api/identity/web_auth_flow.h index 0f61451cbc6..1264bdca993 100644 --- a/chromium/chrome/browser/extensions/api/identity/web_auth_flow.h +++ b/chromium/chrome/browser/extensions/api/identity/web_auth_flow.h @@ -21,8 +21,6 @@ class WebAuthFlowTest; namespace content { class NotificationDetails; class NotificationSource; -class RenderViewHost; -class WebContents; } namespace extensions { diff --git a/chromium/chrome/browser/extensions/api/image_writer_private/operation.h b/chromium/chrome/browser/extensions/api/image_writer_private/operation.h index 6710298ca94..98412b700a7 100644 --- a/chromium/chrome/browser/extensions/api/image_writer_private/operation.h +++ b/chromium/chrome/browser/extensions/api/image_writer_private/operation.h @@ -19,7 +19,7 @@ #include "build/build_config.h" #include "chrome/browser/extensions/api/image_writer_private/image_writer_utility_client.h" #include "chrome/common/extensions/api/image_writer_private.h" - +#include "extensions/common/extension_id.h" namespace image_writer_api = extensions::api::image_writer_private; @@ -59,7 +59,6 @@ class Operation : public base::RefCountedThreadSafe<Operation> { public: typedef base::Callback<void(bool, const std::string&)> StartWriteCallback; typedef base::Callback<void(bool, const std::string&)> CancelWriteCallback; - typedef std::string ExtensionId; Operation(base::WeakPtr<OperationManager> manager, const ExtensionId& extension_id, diff --git a/chromium/chrome/browser/extensions/api/image_writer_private/operation_manager.h b/chromium/chrome/browser/extensions/api/image_writer_private/operation_manager.h index 60d25a6760f..993019bdc67 100644 --- a/chromium/chrome/browser/extensions/api/image_writer_private/operation_manager.h +++ b/chromium/chrome/browser/extensions/api/image_writer_private/operation_manager.h @@ -19,6 +19,7 @@ #include "content/public/browser/notification_registrar.h" #include "extensions/browser/browser_context_keyed_api_factory.h" #include "extensions/browser/extension_registry_observer.h" +#include "extensions/common/extension_id.h" #include "url/gurl.h" namespace image_writer_api = extensions::api::image_writer_private; @@ -43,8 +44,6 @@ class OperationManager : public BrowserContextKeyedAPI, public extensions::ExtensionRegistryObserver, public base::SupportsWeakPtr<OperationManager> { public: - typedef std::string ExtensionId; - explicit OperationManager(content::BrowserContext* context); ~OperationManager() override; diff --git a/chromium/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc b/chromium/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc index 6069e113960..4f1d60f8d60 100644 --- a/chromium/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc +++ b/chromium/chrome/browser/extensions/api/input_ime/input_ime_api_chromeos.cc @@ -180,7 +180,7 @@ class ImeObserverChromeOS : public ui::ImeObserver { // first composition character, so for backward compatibility, add it here. base::Value* first_value = NULL; if (bounds_list->Get(0, &first_value)) - args->Append(first_value->DeepCopy()); + args->Append(first_value->CreateDeepCopy()); args->Append(std::move(bounds_list)); DispatchEventToExtension( diff --git a/chromium/chrome/browser/extensions/api/log_private/log_private_api_chromeos.cc b/chromium/chrome/browser/extensions/api/log_private/log_private_api_chromeos.cc index 227a38e0db1..4d6598d9a6a 100644 --- a/chromium/chrome/browser/extensions/api/log_private/log_private_api_chromeos.cc +++ b/chromium/chrome/browser/extensions/api/log_private/log_private_api_chromeos.cc @@ -244,16 +244,15 @@ void LogPrivateAPI::PostPendingEntries() { void LogPrivateAPI::AddEntriesOnUI(std::unique_ptr<base::ListValue> value) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - for (std::set<std::string>::iterator ix = net_internal_watches_.begin(); - ix != net_internal_watches_.end(); ++ix) { + for (const std::string& extension_id : net_internal_watches_) { // Create the event's arguments value. std::unique_ptr<base::ListValue> event_args(new base::ListValue()); - event_args->Append(value->DeepCopy()); + event_args->Append(value->CreateDeepCopy()); std::unique_ptr<Event> event( new Event(::extensions::events::LOG_PRIVATE_ON_CAPTURED_EVENTS, ::events::kOnCapturedEvents, std::move(event_args))); EventRouter::Get(browser_context_) - ->DispatchEventToExtension(*ix, std::move(event)); + ->DispatchEventToExtension(extension_id, std::move(event)); } } diff --git a/chromium/chrome/browser/extensions/api/mdns/dns_sd_registry.cc b/chromium/chrome/browser/extensions/api/mdns/dns_sd_registry.cc index 76496987eea..6664d2a026c 100644 --- a/chromium/chrome/browser/extensions/api/mdns/dns_sd_registry.cc +++ b/chromium/chrome/browser/extensions/api/mdns/dns_sd_registry.cc @@ -6,9 +6,11 @@ #include <utility> +#include "base/memory/ptr_util.h" #include "base/stl_util.h" #include "chrome/browser/extensions/api/mdns/dns_sd_device_lister.h" #include "chrome/browser/local_discovery/service_discovery_shared_client.h" +#include "chrome/common/features.h" using local_discovery::ServiceDiscoveryClient; using local_discovery::ServiceDiscoverySharedClient; @@ -107,7 +109,7 @@ DnsSdRegistry::ServiceTypeData::GetServiceList() { } DnsSdRegistry::DnsSdRegistry() { -#if defined(ENABLE_SERVICE_DISCOVERY) +#if BUILDFLAG(ENABLE_SERVICE_DISCOVERY) service_discovery_client_ = ServiceDiscoverySharedClient::GetInstance(); #endif } @@ -159,16 +161,14 @@ void DnsSdRegistry::RegisterDnsSdListener(const std::string& service_type) { CreateDnsSdDeviceLister(this, service_type, service_discovery_client_.get())); dns_sd_device_lister->Discover(false); - linked_ptr<ServiceTypeData> service_type_data( - new ServiceTypeData(std::move(dns_sd_device_lister))); - service_data_map_[service_type] = service_type_data; + service_data_map_[service_type] = + base::MakeUnique<ServiceTypeData>(std::move(dns_sd_device_lister)); DispatchApiEvent(service_type); } void DnsSdRegistry::UnregisterDnsSdListener(const std::string& service_type) { VLOG(1) << "UnregisterDnsSdListener: " << service_type; - DnsSdRegistry::DnsSdServiceTypeDataMap::iterator it = - service_data_map_.find(service_type); + auto it = service_data_map_.find(service_type); if (it == service_data_map_.end()) return; @@ -229,8 +229,10 @@ void DnsSdRegistry::ServicesFlushed(const std::string& service_type) { void DnsSdRegistry::DispatchApiEvent(const std::string& service_type) { VLOG(1) << "DispatchApiEvent: service_type: " << service_type; - FOR_EACH_OBSERVER(DnsSdObserver, observers_, OnDnsSdEvent( - service_type, service_data_map_[service_type]->GetServiceList())); + for (auto& observer : observers_) { + observer.OnDnsSdEvent(service_type, + service_data_map_[service_type]->GetServiceList()); + } } bool DnsSdRegistry::IsRegistered(const std::string& service_type) { diff --git a/chromium/chrome/browser/extensions/api/mdns/dns_sd_registry.h b/chromium/chrome/browser/extensions/api/mdns/dns_sd_registry.h index d85f297fdc5..4f342684288 100644 --- a/chromium/chrome/browser/extensions/api/mdns/dns_sd_registry.h +++ b/chromium/chrome/browser/extensions/api/mdns/dns_sd_registry.h @@ -12,7 +12,6 @@ #include <vector> #include "base/macros.h" -#include "base/memory/linked_ptr.h" #include "base/observer_list.h" #include "chrome/browser/extensions/api/mdns/dns_sd_delegate.h" @@ -94,10 +93,6 @@ class DnsSdRegistry : public DnsSdDelegate { DISALLOW_COPY_AND_ASSIGN(ServiceTypeData); }; - // Maps service types to associated data such as listers and service lists. - typedef std::map<std::string, linked_ptr<ServiceTypeData> > - DnsSdServiceTypeDataMap; - virtual DnsSdDeviceLister* CreateDnsSdDeviceLister( DnsSdDelegate* delegate, const std::string& service_type, @@ -111,7 +106,7 @@ class DnsSdRegistry : public DnsSdDelegate { const std::string& service_name) override; void ServicesFlushed(const std::string& service_type) override; - DnsSdServiceTypeDataMap service_data_map_; + std::map<std::string, std::unique_ptr<ServiceTypeData>> service_data_map_; private: void DispatchApiEvent(const std::string& service_type); diff --git a/chromium/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc b/chromium/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc index 8d52332152d..9a0409a0c76 100644 --- a/chromium/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc +++ b/chromium/chrome/browser/extensions/api/media_galleries/media_galleries_apitest.cc @@ -13,6 +13,7 @@ #include "base/path_service.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "base/test/test_timeouts.h" #include "base/values.h" #include "build/build_config.h" #include "chrome/browser/apps/app_browsertest_util.h" @@ -29,6 +30,7 @@ #include "content/public/browser/web_contents.h" #include "content/public/test/test_utils.h" #include "extensions/browser/extension_system.h" +#include "extensions/browser/process_manager.h" #include "extensions/common/constants.h" #include "extensions/common/extension.h" #include "extensions/test/result_catcher.h" @@ -78,6 +80,11 @@ class MediaGalleriesPlatformAppBrowserTest : public PlatformAppBrowserTest { void SetUpOnMainThread() override { PlatformAppBrowserTest::SetUpOnMainThread(); ensure_media_directories_exists_.reset(new EnsureMediaDirectoriesExists); + // Prevent the ProcessManager from suspending the chrome-test app. Needed + // because the writer.onerror and writer.onwriteend events do not qualify as + // pending callbacks, so the app looks dormant. + extensions::ProcessManager::SetEventPageIdleTimeForTesting( + TestTimeouts::action_max_timeout().InMilliseconds()); int64_t file_size; ASSERT_TRUE(base::GetFileSize(GetCommonDataDir().AppendASCII("test.jpg"), diff --git a/chromium/chrome/browser/extensions/api/messaging/message_service.h b/chromium/chrome/browser/extensions/api/messaging/message_service.h index 2c6b52d0b24..667594eb6cf 100644 --- a/chromium/chrome/browser/extensions/api/messaging/message_service.h +++ b/chromium/chrome/browser/extensions/api/messaging/message_service.h @@ -19,6 +19,7 @@ #include "extensions/browser/api/messaging/native_message_host.h" #include "extensions/browser/browser_context_keyed_api_factory.h" #include "extensions/common/api/messaging/message.h" +#include "extensions/common/extension_id.h" class GURL; class Profile; @@ -195,9 +196,8 @@ class MessageService : public BrowserContextKeyedAPI { // A map of channel ID to information about the extension that is waiting // for that channel to open. Used for lazy background pages. - using ExtensionID = std::string; using PendingLazyBackgroundPageChannel = - std::pair<content::BrowserContext*, ExtensionID>; + std::pair<content::BrowserContext*, ExtensionId>; using PendingLazyBackgroundPageChannelMap = std::map<int, PendingLazyBackgroundPageChannel>; diff --git a/chromium/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc b/chromium/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc index 031aa73aec5..9d2da8fdc07 100644 --- a/chromium/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc +++ b/chromium/chrome/browser/extensions/api/messaging/native_message_host_chromeos.cc @@ -17,7 +17,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "base/values.h" #include "chrome/browser/browser_process.h" -#include "chrome/browser/chromeos/arc/arc_support_host.h" +#include "chrome/browser/chromeos/arc/extensions/arc_support_message_host.h" #include "components/policy/core/common/policy_service.h" #include "content/public/browser/browser_thread.h" #include "extensions/common/constants.h" @@ -129,18 +129,13 @@ const char* const kRemotingIt2MeOrigins[] = { "chrome-extension://hpodccmdligbeohchckkeajbfohibipg/"}; static const BuiltInHost kBuiltInHost[] = { - {"com.google.chrome.test.echo", // ScopedTestNativeMessagingHost::kHostName - kEchoHostOrigins, - arraysize(kEchoHostOrigins), - &EchoHost::Create}, - {"com.google.chrome.remote_assistance", - kRemotingIt2MeOrigins, - arraysize(kRemotingIt2MeOrigins), - &CreateIt2MeHost}, - {ArcSupportHost::kHostName, - ArcSupportHost::kHostOrigin, - 1, - &ArcSupportHost::Create}, + {"com.google.chrome.test.echo", // ScopedTestNativeMessagingHost::kHostName + kEchoHostOrigins, arraysize(kEchoHostOrigins), &EchoHost::Create}, + {"com.google.chrome.remote_assistance", kRemotingIt2MeOrigins, + arraysize(kRemotingIt2MeOrigins), &CreateIt2MeHost}, + {arc::ArcSupportMessageHost::kHostName, + arc::ArcSupportMessageHost::kHostOrigin, 1, + &arc::ArcSupportMessageHost::Create}, }; bool MatchesSecurityOrigin(const BuiltInHost& host, diff --git a/chromium/chrome/browser/extensions/api/metrics_private/metrics_private_api.cc b/chromium/chrome/browser/extensions/api/metrics_private/metrics_private_api.cc deleted file mode 100644 index f761f5a9fc3..00000000000 --- a/chromium/chrome/browser/extensions/api/metrics_private/metrics_private_api.cc +++ /dev/null @@ -1,215 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "chrome/browser/extensions/api/metrics_private/metrics_private_api.h" - -#include <limits.h> - -#include <algorithm> - -#include "base/memory/ptr_util.h" -#include "base/metrics/field_trial.h" -#include "base/metrics/histogram_macros.h" -#include "base/metrics/sparse_histogram.h" -#include "chrome/common/extensions/api/metrics_private.h" -#include "components/variations/variations_associated_data.h" -#include "content/public/browser/user_metrics.h" -#include "extensions/browser/api/extensions_api_client.h" -#include "extensions/browser/api/metrics_private/metrics_private_delegate.h" -#include "extensions/common/extension.h" - -namespace extensions { - -namespace GetVariationParams = api::metrics_private::GetVariationParams; -namespace RecordUserAction = api::metrics_private::RecordUserAction; -namespace RecordValue = api::metrics_private::RecordValue; -namespace RecordSparseValue = api::metrics_private::RecordSparseValue; -namespace RecordPercentage = api::metrics_private::RecordPercentage; -namespace RecordCount = api::metrics_private::RecordCount; -namespace RecordSmallCount = api::metrics_private::RecordSmallCount; -namespace RecordMediumCount = api::metrics_private::RecordMediumCount; -namespace RecordTime = api::metrics_private::RecordTime; -namespace RecordMediumTime = api::metrics_private::RecordMediumTime; -namespace RecordLongTime = api::metrics_private::RecordLongTime; - -namespace { - -const size_t kMaxBuckets = 10000; // We don't ever want more than these many - // buckets; there is no real need for them - // and would cause crazy memory usage -} // namespace - -ExtensionFunction::ResponseAction -MetricsPrivateGetIsCrashReportingEnabledFunction::Run() { - MetricsPrivateDelegate* delegate = - ExtensionsAPIClient::Get()->GetMetricsPrivateDelegate(); - return RespondNow(OneArgument(base::MakeUnique<base::FundamentalValue>( - delegate && delegate->IsCrashReportingEnabled()))); -} - -ExtensionFunction::ResponseAction MetricsPrivateGetFieldTrialFunction::Run() { - std::string name; - EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &name)); - - return RespondNow(OneArgument(base::MakeUnique<base::StringValue>( - base::FieldTrialList::FindFullName(name)))); -} - -ExtensionFunction::ResponseAction -MetricsPrivateGetVariationParamsFunction::Run() { - std::unique_ptr<GetVariationParams::Params> params( - GetVariationParams::Params::Create(*args_)); - EXTENSION_FUNCTION_VALIDATE(params.get()); - - GetVariationParams::Results::Params result; - std::unique_ptr<base::DictionaryValue> dict; - if (variations::GetVariationParams(params->name, - &result.additional_properties)) { - dict = result.ToValue(); - } - return RespondNow(dict ? OneArgument(std::move(dict)) : NoArguments()); -} - -ExtensionFunction::ResponseAction -MetricsPrivateRecordUserActionFunction::Run() { - std::unique_ptr<RecordUserAction::Params> params( - RecordUserAction::Params::Create(*args_)); - EXTENSION_FUNCTION_VALIDATE(params.get()); - - content::RecordComputedAction(params->name); - return RespondNow(NoArguments()); -} - -void MetricsHistogramHelperFunction::RecordValue(const std::string& name, - base::HistogramType type, - int min, - int max, - size_t buckets, - int sample) { - // Make sure toxic values don't get to internal code. - // Fix for maximums - min = std::min(min, INT_MAX - 3); - max = std::min(max, INT_MAX - 3); - buckets = std::min(buckets, kMaxBuckets); - // Fix for minimums. - min = std::max(min, 1); - max = std::max(max, min + 1); - buckets = std::max(buckets, static_cast<size_t>(3)); - // Trim buckets down to a maximum of the given range + over/underflow buckets - if (buckets > static_cast<size_t>(max - min + 2)) - buckets = max - min + 2; - - base::HistogramBase* counter; - if (type == base::LINEAR_HISTOGRAM) { - counter = base::LinearHistogram::FactoryGet( - name, min, max, buckets, - base::HistogramBase::kUmaTargetedHistogramFlag); - } else { - counter = base::Histogram::FactoryGet( - name, min, max, buckets, - base::HistogramBase::kUmaTargetedHistogramFlag); - } - - // The histogram can be NULL if it is constructed with bad arguments. Ignore - // that data for this API. An error message will be logged. - if (counter) - counter->Add(sample); -} - -ExtensionFunction::ResponseAction MetricsPrivateRecordValueFunction::Run() { - std::unique_ptr<RecordValue::Params> params( - RecordValue::Params::Create(*args_)); - EXTENSION_FUNCTION_VALIDATE(params.get()); - - // Get the histogram parameters from the metric type object. - std::string type = api::metrics_private::ToString(params->metric.type); - - base::HistogramType histogram_type(type == "histogram-linear" ? - base::LINEAR_HISTOGRAM : base::HISTOGRAM); - RecordValue(params->metric.metric_name, histogram_type, params->metric.min, - params->metric.max, params->metric.buckets, params->value); - return RespondNow(NoArguments()); -} - -ExtensionFunction::ResponseAction -MetricsPrivateRecordSparseValueFunction::Run() { - std::unique_ptr<RecordSparseValue::Params> params( - RecordSparseValue::Params::Create(*args_)); - EXTENSION_FUNCTION_VALIDATE(params.get()); - // This particular UMA_HISTOGRAM_ macro is okay for - // non-runtime-constant strings. - UMA_HISTOGRAM_SPARSE_SLOWLY(params->metric_name, params->value); - return RespondNow(NoArguments()); -} - -ExtensionFunction::ResponseAction -MetricsPrivateRecordPercentageFunction::Run() { - std::unique_ptr<RecordPercentage::Params> params( - RecordPercentage::Params::Create(*args_)); - EXTENSION_FUNCTION_VALIDATE(params.get()); - RecordValue(params->metric_name, base::LINEAR_HISTOGRAM, 1, 101, 102, - params->value); - return RespondNow(NoArguments()); -} - -ExtensionFunction::ResponseAction MetricsPrivateRecordCountFunction::Run() { - std::unique_ptr<RecordCount::Params> params( - RecordCount::Params::Create(*args_)); - EXTENSION_FUNCTION_VALIDATE(params.get()); - RecordValue(params->metric_name, base::HISTOGRAM, 1, 1000000, 50, - params->value); - return RespondNow(NoArguments()); -} - -ExtensionFunction::ResponseAction -MetricsPrivateRecordSmallCountFunction::Run() { - std::unique_ptr<RecordSmallCount::Params> params( - RecordSmallCount::Params::Create(*args_)); - EXTENSION_FUNCTION_VALIDATE(params.get()); - RecordValue(params->metric_name, base::HISTOGRAM, 1, 100, 50, params->value); - return RespondNow(NoArguments()); -} - -ExtensionFunction::ResponseAction -MetricsPrivateRecordMediumCountFunction::Run() { - std::unique_ptr<RecordMediumCount::Params> params( - RecordMediumCount::Params::Create(*args_)); - EXTENSION_FUNCTION_VALIDATE(params.get()); - RecordValue(params->metric_name, base::HISTOGRAM, 1, 10000, 50, - params->value); - return RespondNow(NoArguments()); -} - -ExtensionFunction::ResponseAction MetricsPrivateRecordTimeFunction::Run() { - std::unique_ptr<RecordTime::Params> params( - RecordTime::Params::Create(*args_)); - EXTENSION_FUNCTION_VALIDATE(params.get()); - static const int kTenSecMs = 10 * 1000; - RecordValue(params->metric_name, base::HISTOGRAM, 1, kTenSecMs, 50, - params->value); - return RespondNow(NoArguments()); -} - -ExtensionFunction::ResponseAction -MetricsPrivateRecordMediumTimeFunction::Run() { - std::unique_ptr<RecordMediumTime::Params> params( - RecordMediumTime::Params::Create(*args_)); - EXTENSION_FUNCTION_VALIDATE(params.get()); - static const int kThreeMinMs = 3 * 60 * 1000; - RecordValue(params->metric_name, base::HISTOGRAM, 1, kThreeMinMs, 50, - params->value); - return RespondNow(NoArguments()); -} - -ExtensionFunction::ResponseAction MetricsPrivateRecordLongTimeFunction::Run() { - std::unique_ptr<RecordLongTime::Params> params( - RecordLongTime::Params::Create(*args_)); - EXTENSION_FUNCTION_VALIDATE(params.get()); - static const int kOneHourMs = 60 * 60 * 1000; - RecordValue(params->metric_name, base::HISTOGRAM, 1, kOneHourMs, 50, - params->value); - return RespondNow(NoArguments()); -} - -} // namespace extensions diff --git a/chromium/chrome/browser/extensions/api/metrics_private/metrics_private_api.h b/chromium/chrome/browser/extensions/api/metrics_private/metrics_private_api.h deleted file mode 100644 index 21e1e7ba7fb..00000000000 --- a/chromium/chrome/browser/extensions/api/metrics_private/metrics_private_api.h +++ /dev/null @@ -1,197 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef CHROME_BROWSER_EXTENSIONS_API_METRICS_PRIVATE_METRICS_PRIVATE_API_H_ -#define CHROME_BROWSER_EXTENSIONS_API_METRICS_PRIVATE_METRICS_PRIVATE_API_H_ - -#include <stddef.h> - -#include <string> - -#include "base/metrics/histogram.h" -#include "extensions/browser/extension_function.h" - -namespace extensions { - -class MetricsPrivateGetIsCrashReportingEnabledFunction - : public UIThreadExtensionFunction { - public: - DECLARE_EXTENSION_FUNCTION("metricsPrivate.getIsCrashReportingEnabled", - METRICSPRIVATE_GETISCRASHRECORDINGENABLED) - - protected: - ~MetricsPrivateGetIsCrashReportingEnabledFunction() override {} - - // ExtensionFunction: - ResponseAction Run() override; -}; - -class MetricsPrivateGetFieldTrialFunction : public UIThreadExtensionFunction { - public: - DECLARE_EXTENSION_FUNCTION("metricsPrivate.getFieldTrial", - METRICSPRIVATE_GETFIELDTRIAL) - - protected: - ~MetricsPrivateGetFieldTrialFunction() override {} - - // ExtensionFunction: - ResponseAction Run() override; -}; - -class MetricsPrivateGetVariationParamsFunction - : public UIThreadExtensionFunction { - public: - DECLARE_EXTENSION_FUNCTION("metricsPrivate.getVariationParams", - METRICSPRIVATE_GETVARIATIONPARAMS) - - protected: - ~MetricsPrivateGetVariationParamsFunction() override {} - - // ExtensionFunction: - ResponseAction Run() override; -}; - -class MetricsPrivateRecordUserActionFunction - : public UIThreadExtensionFunction { - public: - DECLARE_EXTENSION_FUNCTION("metricsPrivate.recordUserAction", - METRICSPRIVATE_RECORDUSERACTION) - - protected: - ~MetricsPrivateRecordUserActionFunction() override {} - - // ExtensionFunction: - ResponseAction Run() override; -}; - -class MetricsHistogramHelperFunction : public UIThreadExtensionFunction { - protected: - ~MetricsHistogramHelperFunction() override {} - void RecordValue(const std::string& name, - base::HistogramType type, - int min, - int max, - size_t buckets, - int sample); -}; - -class MetricsPrivateRecordValueFunction - : public MetricsHistogramHelperFunction { - public: - DECLARE_EXTENSION_FUNCTION("metricsPrivate.recordValue", - METRICSPRIVATE_RECORDVALUE) - - protected: - ~MetricsPrivateRecordValueFunction() override {} - - // ExtensionFunction: - ResponseAction Run() override; -}; - -class MetricsPrivateRecordSparseValueFunction - : public MetricsHistogramHelperFunction { - public: - DECLARE_EXTENSION_FUNCTION("metricsPrivate.recordSparseValue", - METRICSPRIVATE_RECORDSPARSEVALUE) - - protected: - ~MetricsPrivateRecordSparseValueFunction() override {} - - // ExtensionFunction: - ResponseAction Run() override; -}; - -class MetricsPrivateRecordPercentageFunction - : public MetricsHistogramHelperFunction { - public: - DECLARE_EXTENSION_FUNCTION("metricsPrivate.recordPercentage", - METRICSPRIVATE_RECORDPERCENTAGE) - - protected: - ~MetricsPrivateRecordPercentageFunction() override {} - - // ExtensionFunction: - ResponseAction Run() override; -}; - -class MetricsPrivateRecordCountFunction - : public MetricsHistogramHelperFunction { - public: - DECLARE_EXTENSION_FUNCTION("metricsPrivate.recordCount", - METRICSPRIVATE_RECORDCOUNT) - - protected: - ~MetricsPrivateRecordCountFunction() override {} - - // ExtensionFunction: - ResponseAction Run() override; -}; - -class MetricsPrivateRecordSmallCountFunction - : public MetricsHistogramHelperFunction { - public: - DECLARE_EXTENSION_FUNCTION("metricsPrivate.recordSmallCount", - METRICSPRIVATE_RECORDSMALLCOUNT) - - protected: - ~MetricsPrivateRecordSmallCountFunction() override {} - - // ExtensionFunction: - ResponseAction Run() override; -}; - -class MetricsPrivateRecordMediumCountFunction - : public MetricsHistogramHelperFunction { - public: - DECLARE_EXTENSION_FUNCTION("metricsPrivate.recordMediumCount", - METRICSPRIVATE_RECORDMEDIUMCOUNT) - - protected: - ~MetricsPrivateRecordMediumCountFunction() override {} - - // ExtensionFunction: - ResponseAction Run() override; -}; - -class MetricsPrivateRecordTimeFunction : public MetricsHistogramHelperFunction { - public: - DECLARE_EXTENSION_FUNCTION("metricsPrivate.recordTime", - METRICSPRIVATE_RECORDTIME) - - protected: - ~MetricsPrivateRecordTimeFunction() override {} - - // ExtensionFunction: - ResponseAction Run() override; -}; - -class MetricsPrivateRecordMediumTimeFunction - : public MetricsHistogramHelperFunction { - public: - DECLARE_EXTENSION_FUNCTION("metricsPrivate.recordMediumTime", - METRICSPRIVATE_RECORDMEDIUMTIME) - - protected: - ~MetricsPrivateRecordMediumTimeFunction() override {} - - // ExtensionFunction: - ResponseAction Run() override; -}; - -class MetricsPrivateRecordLongTimeFunction - : public MetricsHistogramHelperFunction { - public: - DECLARE_EXTENSION_FUNCTION("metricsPrivate.recordLongTime", - METRICSPRIVATE_RECORDLONGTIME) - - protected: - ~MetricsPrivateRecordLongTimeFunction() override {} - - // ExtensionFunction: - ResponseAction Run() override; -}; - -} // namespace extensions - -#endif // CHROME_BROWSER_EXTENSIONS_API_METRICS_PRIVATE_METRICS_PRIVATE_API_H_ diff --git a/chromium/chrome/browser/extensions/api/networking_private/crypto_verify_impl.cc b/chromium/chrome/browser/extensions/api/networking_private/crypto_verify_impl.cc index c3654438472..1fc8b48d1b7 100644 --- a/chromium/chrome/browser/extensions/api/networking_private/crypto_verify_impl.cc +++ b/chromium/chrome/browser/extensions/api/networking_private/crypto_verify_impl.cc @@ -15,7 +15,7 @@ #include "base/threading/sequenced_worker_pool.h" #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/extensions/api/networking_private/networking_private_credentials_getter.h" -#include "chrome/common/extensions/api/networking_private/networking_private_crypto.h" +#include "chrome/browser/extensions/api/networking_private/networking_private_crypto.h" #include "content/public/browser/browser_thread.h" #include "extensions/browser/api/networking_private/networking_private_api.h" #include "extensions/browser/api/networking_private/networking_private_service_client.h" diff --git a/chromium/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc b/chromium/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc index 740406b8872..6d22232e525 100644 --- a/chromium/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc +++ b/chromium/chrome/browser/extensions/api/networking_private/networking_private_chromeos_apitest.cc @@ -24,7 +24,6 @@ #include "chromeos/dbus/shill_manager_client.h" #include "chromeos/dbus/shill_profile_client.h" #include "chromeos/dbus/shill_service_client.h" -#include "chromeos/login/user_names.h" #include "chromeos/network/network_handler.h" #include "chromeos/network/network_state_handler.h" #include "chromeos/network/onc/onc_utils.h" @@ -38,6 +37,7 @@ #include "components/policy/policy_constants.h" #include "components/user_manager/user.h" #include "components/user_manager/user_manager.h" +#include "components/user_manager/user_names.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" #include "content/public/browser/notification_service.h" @@ -199,9 +199,8 @@ class NetworkingPrivateChromeOSApiTest : public ExtensionApiTest { // uses the ProfileHelper to obtain the userhash crbug/238623. const cryptohome::Identification login_user = cryptohome::Identification::FromString( - chromeos::login::CanonicalizeUserID( - command_line->GetSwitchValueNative( - chromeos::switches::kLoginUser))); + user_manager::CanonicalizeUserID(command_line->GetSwitchValueNative( + chromeos::switches::kLoginUser))); const std::string sanitized_user = CryptohomeClient::GetStubSanitizedUsername(login_user); command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, diff --git a/chromium/chrome/browser/extensions/api/networking_private/networking_private_credentials_getter_mac.cc b/chromium/chrome/browser/extensions/api/networking_private/networking_private_credentials_getter_mac.cc index 15176cc7320..76629767a53 100644 --- a/chromium/chrome/browser/extensions/api/networking_private/networking_private_credentials_getter_mac.cc +++ b/chromium/chrome/browser/extensions/api/networking_private/networking_private_credentials_getter_mac.cc @@ -12,7 +12,7 @@ #include "base/base64.h" #include "base/bind.h" #include "base/macros.h" -#include "chrome/common/extensions/api/networking_private/networking_private_crypto.h" +#include "chrome/browser/extensions/api/networking_private/networking_private_crypto.h" #include "components/wifi/wifi_service.h" #include "content/public/browser/browser_thread.h" diff --git a/chromium/chrome/browser/extensions/api/networking_private/networking_private_credentials_getter_win.cc b/chromium/chrome/browser/extensions/api/networking_private/networking_private_credentials_getter_win.cc index 1157ba146e0..b5a047d769f 100644 --- a/chromium/chrome/browser/extensions/api/networking_private/networking_private_credentials_getter_win.cc +++ b/chromium/chrome/browser/extensions/api/networking_private/networking_private_credentials_getter_win.cc @@ -13,7 +13,7 @@ #include "base/strings/stringprintf.h" #include "base/threading/sequenced_worker_pool.h" #include "base/threading/thread_task_runner_handle.h" -#include "chrome/common/extensions/api/networking_private/networking_private_crypto.h" +#include "chrome/browser/extensions/api/networking_private/networking_private_crypto.h" #include "chrome/common/extensions/chrome_utility_extensions_messages.h" #include "chrome/grit/generated_resources.h" #include "content/public/browser/browser_thread.h" diff --git a/chromium/chrome/browser/extensions/api/networking_private/networking_private_crypto.cc b/chromium/chrome/browser/extensions/api/networking_private/networking_private_crypto.cc new file mode 100644 index 00000000000..bf05b1d6312 --- /dev/null +++ b/chromium/chrome/browser/extensions/api/networking_private/networking_private_crypto.cc @@ -0,0 +1,187 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/extensions/api/networking_private/networking_private_crypto.h" + +#include <stddef.h> + +#include <memory> + +#include "base/logging.h" +#include "base/strings/string_util.h" +#include "components/cast_certificate/cast_cert_validator.h" +#include "crypto/openssl_util.h" +#include "crypto/rsa_private_key.h" +#include "net/cert/pem_tokenizer.h" +#include "third_party/boringssl/src/include/openssl/digest.h" +#include "third_party/boringssl/src/include/openssl/evp.h" +#include "third_party/boringssl/src/include/openssl/rsa.h" +#include "third_party/boringssl/src/include/openssl/x509.h" + +namespace { + +namespace cast_crypto = ::cast_certificate; + +// Parses |pem_data| for a PEM block of |pem_type|. +// Returns true if a |pem_type| block is found, storing the decoded result in +// |der_output|. +bool GetDERFromPEM(const std::string& pem_data, + const std::string& pem_type, + std::vector<uint8_t>* der_output) { + std::vector<std::string> headers; + headers.push_back(pem_type); + net::PEMTokenizer pem_tokenizer(pem_data, headers); + if (!pem_tokenizer.GetNext()) { + return false; + } + + der_output->assign(pem_tokenizer.data().begin(), pem_tokenizer.data().end()); + return true; +} + +} // namespace + +namespace networking_private_crypto { + +bool VerifyCredentials( + const std::string& certificate, + const std::vector<std::string>& intermediate_certificates, + const std::string& signature, + const std::string& data, + const std::string& connected_mac) { + base::Time now = base::Time::Now(); + return VerifyCredentialsAtTime(certificate, intermediate_certificates, + signature, data, connected_mac, now); +} + +bool VerifyCredentialsAtTime( + const std::string& certificate, + const std::vector<std::string>& intermediate_certificates, + const std::string& signature, + const std::string& data, + const std::string& connected_mac, + const base::Time& time) { + static const char kErrorPrefix[] = "Device verification failed. "; + + std::vector<std::string> headers; + headers.push_back("CERTIFICATE"); + + // Convert certificate from PEM to raw DER + net::PEMTokenizer pem_tokenizer(certificate, headers); + if (!pem_tokenizer.GetNext()) { + LOG(ERROR) << kErrorPrefix << "Failed to parse device certificate."; + return false; + } + + // |certs| is a vector with the DER for all the certificates. + std::vector<std::string> certs; + certs.push_back(pem_tokenizer.data()); + + // Convert intermediate certificates from PEM to raw DER + for (size_t idx = 0; idx < intermediate_certificates.size(); ++idx) { + net::PEMTokenizer ica_pem_tokenizer(intermediate_certificates[idx], + headers); + if (ica_pem_tokenizer.GetNext()) { + certs.push_back(ica_pem_tokenizer.data()); + } else { + LOG(WARNING) << "Failed to parse intermediate certificates."; + } + } + + // Note that the device certificate's policy is not enforced here. The goal + // is simply to verify that the device belongs to the Cast ecosystem. + cast_crypto::CastDeviceCertPolicy unused_policy; + + std::unique_ptr<cast_crypto::CertVerificationContext> verification_context; + if (!cast_crypto::VerifyDeviceCert(certs, time, &verification_context, + &unused_policy, nullptr, + cast_crypto::CRLPolicy::CRL_OPTIONAL)) { + LOG(ERROR) << kErrorPrefix << "Failed verifying cast device cert"; + return false; + } + + // Check that the device listed in the certificate is correct. + // Something like evt_e161 001a11ffacdf + std::string common_name = verification_context->GetCommonName(); + std::string translated_mac; + base::RemoveChars(connected_mac, ":", &translated_mac); + if (!base::EndsWith(common_name, translated_mac, + base::CompareCase::INSENSITIVE_ASCII)) { + LOG(ERROR) << kErrorPrefix << "MAC addresses don't match."; + return false; + } + + // Use the public key from verified certificate to verify |signature| over + // |data|. + if (!verification_context->VerifySignatureOverData(signature, data)) { + LOG(ERROR) << kErrorPrefix + << "Failed verifying signature using cast device cert"; + return false; + } + return true; +} + +bool EncryptByteString(const std::vector<uint8_t>& pub_key_der, + const std::string& data, + std::vector<uint8_t>* encrypted_output) { + crypto::EnsureOpenSSLInit(); + crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); + + bssl::UniquePtr<RSA> rsa( + RSA_public_key_from_bytes(pub_key_der.data(), pub_key_der.size())); + if (!rsa || RSA_size(rsa.get()) == 0) { + LOG(ERROR) << "Failed to parse public key"; + return false; + } + + encrypted_output->resize(RSA_size(rsa.get())); + int encrypted_length = RSA_public_encrypt( + data.size(), reinterpret_cast<const uint8_t*>(data.data()), + encrypted_output->data(), rsa.get(), RSA_PKCS1_PADDING); + if (encrypted_length < 0) { + LOG(ERROR) << "Error during decryption"; + return false; + } + encrypted_output->resize(encrypted_length); + return true; +} + +bool DecryptByteString(const std::string& private_key_pem, + const std::vector<uint8_t>& encrypted_data, + std::string* decrypted_output) { + crypto::EnsureOpenSSLInit(); + crypto::OpenSSLErrStackTracer err_tracer(FROM_HERE); + + std::vector<uint8_t> private_key_data; + if (!GetDERFromPEM(private_key_pem, "PRIVATE KEY", &private_key_data)) { + LOG(ERROR) << "Failed to parse private key PEM."; + return false; + } + std::unique_ptr<crypto::RSAPrivateKey> private_key( + crypto::RSAPrivateKey::CreateFromPrivateKeyInfo(private_key_data)); + if (!private_key || !private_key->key()) { + LOG(ERROR) << "Failed to parse private key DER."; + return false; + } + + RSA* rsa = EVP_PKEY_get0_RSA(private_key->key()); + if (!rsa || RSA_size(rsa) == 0) { + LOG(ERROR) << "Failed to get RSA key."; + return false; + } + + uint8_t* output = reinterpret_cast<uint8_t*>( + base::WriteInto(decrypted_output, RSA_size(rsa) + 1)); + int output_length = + RSA_private_decrypt(encrypted_data.size(), &encrypted_data[0], output, + rsa, RSA_PKCS1_PADDING); + if (output_length < 0) { + LOG(ERROR) << "Error during decryption."; + return false; + } + decrypted_output->resize(output_length); + return true; +} + +} // namespace networking_private_crypto diff --git a/chromium/chrome/browser/extensions/api/networking_private/networking_private_crypto.h b/chromium/chrome/browser/extensions/api/networking_private/networking_private_crypto.h new file mode 100644 index 00000000000..ede765a7d87 --- /dev/null +++ b/chromium/chrome/browser/extensions/api/networking_private/networking_private_crypto.h @@ -0,0 +1,61 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_EXTENSIONS_API_NETWORKING_PRIVATE_NETWORKING_PRIVATE_CRYPTO_H_ +#define CHROME_BROWSER_EXTENSIONS_API_NETWORKING_PRIVATE_NETWORKING_PRIVATE_CRYPTO_H_ + +#include <stdint.h> + +#include <string> +#include <vector> + +#include "base/time/time.h" + +namespace networking_private_crypto { + +// Verify that the credentials described by |certificate| and |signed_data| +// are valid as follows: +// 1) The MAC address listed in the certificate matches |connected_mac|. +// 2) The certificate is a valid PEM encoded certificate signed by trusted CA. +// 3) |signature| is a valid signature for |data|, using the public key in +// |certificate| +bool VerifyCredentials( + const std::string& certificate, + const std::vector<std::string>& intermediate_certificates, + const std::string& signature, + const std::string& data, + const std::string& connected_mac); + +// The same as VerifyCredentials() above, but uses time |time| rather than the +// current time for checking validity. +bool VerifyCredentialsAtTime( + const std::string& certificate, + const std::vector<std::string>& intermediate_certificates, + const std::string& signature, + const std::string& data, + const std::string& connected_mac, + const base::Time& time); + +// Encrypt |data| with |public_key|. |public_key| is a DER-encoded +// RSAPublicKey. |data| is some string of bytes that is smaller than the +// maximum length permissible for PKCS#1 v1.5 with a key of |public_key| size. +// +// Returns true on success, storing the encrypted result in +// |encrypted_output|. +bool EncryptByteString(const std::vector<uint8_t>& public_key, + const std::string& data, + std::vector<uint8_t>* encrypted_output); + +// Decrypt |encrypted_data| with |private_key_pem|. |private_key_pem| is the +// PKCS8 PEM-encoded private key. |encrypted_data| is data encrypted with +// EncryptByteString. Used in NetworkingPrivateCryptoTest::EncryptString test. +// Returns true on success, storing the decrypted result in +// |decrypted_output|. +bool DecryptByteString(const std::string& private_key_pem, + const std::vector<uint8_t>& encrypted_data, + std::string* decrypted_output); + +} // namespace networking_private_crypto + +#endif // CHROME_BROWSER_EXTENSIONS_API_NETWORKING_PRIVATE_NETWORKING_PRIVATE_CRYPTO_H_ diff --git a/chromium/chrome/browser/extensions/api/networking_private/networking_private_crypto_unittest.cc b/chromium/chrome/browser/extensions/api/networking_private/networking_private_crypto_unittest.cc new file mode 100644 index 00000000000..79c790efdde --- /dev/null +++ b/chromium/chrome/browser/extensions/api/networking_private/networking_private_crypto_unittest.cc @@ -0,0 +1,231 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. +#include "chrome/browser/extensions/api/networking_private/networking_private_crypto.h" + +#include <stdint.h> + +#include "base/base64.h" +#include "base/logging.h" +#include "base/strings/stringprintf.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace { + +} // namespace + +// Tests of networking_private_crypto support for Networking Private API. +class NetworkingPrivateCryptoTest : public testing::Test { + protected: + // Verify that decryption of |encrypted| data using |private_key_pem| matches + // |plain| data. + bool VerifyByteString(const std::string& private_key_pem, + const std::string& plain, + const std::vector<uint8_t>& encrypted) { + std::string decrypted; + if (networking_private_crypto::DecryptByteString( + private_key_pem, encrypted, &decrypted)) + return decrypted == plain; + return false; + } +}; + +// Test that networking_private_crypto::VerifyCredentials behaves as expected. +TEST_F(NetworkingPrivateCryptoTest, VerifyCredentials) { + // This certificate chain and signature are duplicated from: + // + // components/test/data/cast_certificate/certificates/chromecast_gen1.pem + // components/test/data/cast_certificate/signeddata/2ZZBG9_FA8FCA3EF91A.pem + // + // TODO(eroman): Avoid duplicating the data. + static const char kCertData[] = + "-----BEGIN CERTIFICATE-----" + "MIIDrDCCApSgAwIBAgIEU8xPLDANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJV" + "UzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzET" + "MBEGA1UECgwKR29vZ2xlIEluYzESMBAGA1UECwwJR29vZ2xlIFRWMRgwFgYDVQQD" + "DA9FdXJla2EgR2VuMSBJQ0EwHhcNMTQwNzIwMjMyMjIwWhcNMzQwNzE1MjMyMjIw" + "WjCBgTELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExEzARBgNVBAoT" + "Ckdvb2dsZSBJbmMxFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxEjAQBgNVBAsTCUdv" + "b2dsZSBUVjEcMBoGA1UEAxMTMlpaQkc5IEZBOEZDQTNFRjkxQTCCASIwDQYJKoZI" + "hvcNAQEBBQADggEPADCCAQoCggEBAKV56Srec2ePlqDP6cqFPuwU4MOs7MOcGDrv" + "da6qy6tWC7BmsqipMA/hn77iUiBZsw3TbUQnVfmM4ZQ2RENzcrAJ68cmc+lPxmRr" + "8x1Xu5FzZ+kcyU8glLLqdiXYEKRboFhC7BM05O1XOLvzCls4zuZuMrGNFBW+YoBm" + "FiXFYWBhapZC3RhhlSEZFuQWbb/MUSDzwr/CRbn4tKHMv4Fkw5HAnhLa+yXfgCGw" + "qOd9GejqUKsO/aajAHkM7lIHmvkthI4MVk0Koc+Ih487pgsOt18LqubZVEkbjCqp" + "Rpx1CGbErWnw2ptPvMCEC6e7mrYHcYgmuzQ7m+eUlhthEUiTYC0CAwEAAaMvMC0w" + "CQYDVR0TBAIwADALBgNVHQ8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwIwDQYJ" + "KoZIhvcNAQEFBQADggEBAGuKgGXHJXQ1M7P4uXB8wPPuT2h6g29YJ62rUvZ7BrlW" + "TknJT0Owaw68zepLhFQ4ydIzbVV3hA2InCmP3U24ZMxMJcA/9qNPAqPrtE1ZIQNI" + "Qh6slAdZa0qM6Us30/5fpUL6lgAfD1RIJxA4RWYZKP78SjJz1Lybx3Zbt0Jist9G" + "tvaJGZjZrdPncnJKayGaIln8gzHd6MVEGZp7aIQZ2h4NDlnrwyhMFTjg1WvnmQJ6" + "3bEvjSyjMGhY0JOUaDp/UMxnExn+1+cYAW9LrosZXtRDNJTl1zX4auAnNMHkt8uC" + "F8Jhy80X2wU0fj85oYbRsm+jBMtRayznY1TR0WoPBAo=" + "-----END CERTIFICATE-----"; + + static const char kICAData[] = + "-----BEGIN CERTIFICATE-----" + "MIIDhzCCAm+gAwIBAgIBATANBgkqhkiG9w0BAQUFADB8MQswCQYDVQQGEwJVUzET" + "MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzETMBEG" + "A1UECgwKR29vZ2xlIEluYzESMBAGA1UECwwJR29vZ2xlIFRWMRcwFQYDVQQDDA5F" + "dXJla2EgUm9vdCBDQTAeFw0xMjEyMTkwMDQ3MTJaFw0zMjEyMTQwMDQ3MTJaMH0x" + "CzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1Nb3Vu" + "dGFpbiBWaWV3MRMwEQYDVQQKDApHb29nbGUgSW5jMRIwEAYDVQQLDAlHb29nbGUg" + "VFYxGDAWBgNVBAMMD0V1cmVrYSBHZW4xIElDQTCCASIwDQYJKoZIhvcNAQEBBQAD" + "ggEPADCCAQoCggEBALwigL2A9johADuudl41fz3DZFxVlIY0LwWHKM33aYwXs1Cn" + "uIL638dDLdZ+q6BvtxNygKRHFcEgmVDN7BRiCVukmM3SQbY2Tv/oLjIwSoGoQqNs" + "mzNuyrL1U2bgJ1OGGoUepzk/SneO+1RmZvtYVMBeOcf1UAYL4IrUzuFqVR+LFwDm" + "aaMn5gglaTwSnY0FLNYuojHetFJQ1iBJ3nGg+a0gQBLx3SXr1ea4NvTWj3/KQ9zX" + "EFvmP1GKhbPz//YDLcsjT5ytGOeTBYysUpr3TOmZer5ufk0K48YcqZP6OqWRXRy9" + "ZuvMYNyGdMrP+JIcmH1X+mFHnquAt+RIgCqSxRsCAwEAAaMTMBEwDwYDVR0TBAgw" + "BgEB/wIBATANBgkqhkiG9w0BAQUFAAOCAQEAi9Shsc9dzXtsSEpBH1MvGC0yRf+e" + "q9NzPh8i1+r6AeZzAw8rxiW7pe7F9UXLJBIqrcJdBfR69cKbEBZa0QpzxRY5oBDK" + "0WiFnvueJoOOWPN3oE7l25e+LQBf9ZTbsZ1la/3w0QRR38ySppktcfVN1SP+Mxyp" + "tKvFvxq40YDvicniH5xMSDui+gIK3IQBiocC+1nup0wEfXSZh2olRK0WquxONRt8" + "e4TJsT/hgnDlDefZbfqVtsXkHugRm9iy86T9E/ODT/cHFCC7IqWmj9a126l0eOKT" + "DeUjLwUX4LKXZzRND5x2Q3umIUpWBfYqfPJ/EpSCJikH8AtsbHkUsHTVbA==" + "-----END CERTIFICATE-----"; + + unsigned char kData[] = {0x53, 0x54, 0x52, 0x49, 0x4e, 0x47}; + + unsigned char kSignature[] = { + 0x0a, 0xda, 0xb5, 0x40, 0x5c, 0x8e, 0x53, 0x89, 0xda, 0x67, 0x47, 0x28, + 0xab, 0x64, 0x0d, 0xec, 0xb8, 0x1f, 0xd6, 0x75, 0x28, 0x97, 0x5f, 0xe0, + 0x11, 0x51, 0x35, 0x2a, 0x70, 0xd8, 0xf6, 0x4d, 0xe8, 0xd0, 0x2e, 0xe0, + 0x79, 0x75, 0x3a, 0x25, 0xbf, 0x40, 0x0f, 0x6d, 0xd1, 0x20, 0xe3, 0x82, + 0xbd, 0x05, 0x87, 0x57, 0x01, 0x1e, 0x76, 0xb7, 0xf4, 0xd7, 0xb3, 0x10, + 0x4a, 0x6c, 0x8a, 0xf9, 0x3d, 0xe7, 0xeb, 0x62, 0xe9, 0x5f, 0x73, 0xab, + 0x6e, 0x22, 0xf5, 0x59, 0x4d, 0xc4, 0xa3, 0x95, 0xc3, 0xbe, 0x7b, 0x04, + 0x5a, 0x36, 0x67, 0xee, 0x71, 0xb2, 0xe8, 0x60, 0xbe, 0xaa, 0x2c, 0x90, + 0x36, 0xd7, 0xf0, 0x42, 0x28, 0xd4, 0x29, 0x9f, 0x30, 0xaa, 0x10, 0x4f, + 0x2a, 0xe1, 0x72, 0x67, 0xcc, 0xb5, 0x44, 0x7b, 0x7f, 0x89, 0x45, 0x9f, + 0xc3, 0x9d, 0x6a, 0xf0, 0x78, 0x77, 0x6d, 0x9f, 0x13, 0x58, 0x35, 0x09, + 0x8c, 0x71, 0xaf, 0x34, 0x4b, 0x18, 0xc7, 0x07, 0xd2, 0xf2, 0x03, 0x48, + 0xe2, 0x40, 0x75, 0x3b, 0xeb, 0x33, 0x74, 0x8d, 0x33, 0xb4, 0x45, 0xe2, + 0x59, 0x56, 0x8b, 0xc7, 0x4e, 0x60, 0xc7, 0xec, 0xc8, 0xd3, 0x32, 0x16, + 0x20, 0xb0, 0xc7, 0x0d, 0x14, 0x4b, 0x68, 0xbf, 0x79, 0xad, 0x7e, 0x47, + 0x5d, 0x5d, 0xb5, 0x8c, 0xb6, 0xc3, 0x27, 0xb9, 0xd8, 0x25, 0x70, 0xc0, + 0x8d, 0x12, 0x26, 0x51, 0xe8, 0xad, 0xde, 0xf8, 0xe8, 0x3e, 0x47, 0xd0, + 0xdf, 0x11, 0x7d, 0x34, 0x50, 0xa8, 0x89, 0x89, 0x59, 0x93, 0x8a, 0x3d, + 0x88, 0xaf, 0xd5, 0x1e, 0xe8, 0x34, 0x2e, 0x98, 0x62, 0x39, 0xc1, 0x22, + 0x06, 0xf7, 0x3e, 0x98, 0xfd, 0x6f, 0x3a, 0x45, 0xd0, 0xb7, 0x3a, 0xe5, + 0xaa, 0x38, 0x35, 0x2c, 0xe9, 0x78, 0x71, 0xe2, 0xf0, 0x6f, 0x60, 0x95, + 0xc0, 0x60, 0x5f, 0xc3, + }; + + static const char kHotspotBssid[] = "FA:8F:CA:3E:F9:1A"; + + static const char kBadCertData[] = "not a certificate"; + static const char kBadHotspotBssid[] = "bad bssid"; + + // April 1, 2016 + base::Time::Exploded time_exploded = {0}; + time_exploded.year = 2016; + time_exploded.month = 4; + time_exploded.day_of_month = 1; + base::Time time; + ASSERT_TRUE(base::Time::FromUTCExploded(time_exploded, &time)); + + // September 1, 2035 + base::Time::Exploded expired_time_exploded = {0}; + expired_time_exploded.year = 2035; + expired_time_exploded.month = 9; + expired_time_exploded.day_of_month = 1; + base::Time expired_time; + ASSERT_TRUE( + base::Time::FromUTCExploded(expired_time_exploded, &expired_time)); + + std::string unsigned_data = std::string(std::begin(kData), std::end(kData)); + std::string signed_data = + std::string(std::begin(kSignature), std::end(kSignature)); + + // Check that verification fails when the intermediaries are not provided. + EXPECT_FALSE(networking_private_crypto::VerifyCredentialsAtTime( + kCertData, std::vector<std::string>(), signed_data, unsigned_data, + kHotspotBssid, time)); + + // Checking basic verification operation. + std::vector<std::string> icas; + icas.push_back(kICAData); + + EXPECT_TRUE(networking_private_crypto::VerifyCredentialsAtTime( + kCertData, icas, signed_data, unsigned_data, kHotspotBssid, time)); + + // Checking that verification fails when the certificate is expired. + EXPECT_FALSE(networking_private_crypto::VerifyCredentialsAtTime( + kCertData, icas, signed_data, unsigned_data, kHotspotBssid, + expired_time)); + + // Checking that verification fails when certificate has invalid format. + EXPECT_FALSE(networking_private_crypto::VerifyCredentialsAtTime( + kBadCertData, icas, signed_data, unsigned_data, kHotspotBssid, time)); + + // Checking that verification fails if we supply a bad ICA. + std::vector<std::string> bad_icas; + bad_icas.push_back(kCertData); + EXPECT_FALSE(networking_private_crypto::VerifyCredentialsAtTime( + kCertData, bad_icas, signed_data, unsigned_data, kHotspotBssid, time)); + + // Checking that verification fails when Hotspot Bssid does not match the + // certificate's common name. + EXPECT_FALSE(networking_private_crypto::VerifyCredentialsAtTime( + kCertData, icas, signed_data, unsigned_data, kBadHotspotBssid, time)); + + // Checking that verification fails when the signature is wrong. + unsigned_data = "bad data"; + EXPECT_FALSE(networking_private_crypto::VerifyCredentialsAtTime( + kCertData, icas, signed_data, unsigned_data, kHotspotBssid, time)); +} + +// Test that networking_private_crypto::EncryptByteString behaves as expected. +TEST_F(NetworkingPrivateCryptoTest, EncryptByteString) { + static const char kPublicKey[] = + "MIGJAoGBANTjeoILNkSKHVkd3my/rSwNi+9t473vPJU0lkM8nn9C7+gmaPvEWg4ZNkMd12aI" + "XDXVHrjgjcS80bPE0ykhN9J7EYkJ+43oulJMrEnyDy5KQo7U3MKBdjaKFTS+OPyohHpI8GqH" + "KM8UMkLPVtAKu1BXgGTSDvEaBAuoVT2PM4XNAgMBAAE="; + static const char kPrivateKey[] = + "-----BEGIN PRIVATE KEY-----" + "MIICdwIBADANBgkqhkiG9w0BAQEFAASCAmEwggJdAgEAAoGBANTjeoILNkSKHVkd" + "3my/rSwNi+9t473vPJU0lkM8nn9C7+gmaPvEWg4ZNkMd12aIXDXVHrjgjcS80bPE" + "0ykhN9J7EYkJ+43oulJMrEnyDy5KQo7U3MKBdjaKFTS+OPyohHpI8GqHKM8UMkLP" + "VtAKu1BXgGTSDvEaBAuoVT2PM4XNAgMBAAECgYEAt91H/2zjj8qhkkhDxDS/wd5p" + "T37fRTmMX2ktpiCC23LadOxHm7p39Nk9jjYFxV5cFXpdsFrw1kwl6VdC8LDp3eGu" + "Ku1GCqj5H2fpnkmL2goD01HRkPR3ro4uBHPtTXDbCIz0qp+NGlGG4gPUysMXxHSb" + "E5FIWeUx6gcPvidwrpkCQQD40FXY46KDJT8JVYJMqY6nFQZvptFl+9BGWfheVVSF" + "KBlTQBx/QA+XcC/W9Q/I+NEhdGcxLlkEMUpihSpYffKbAkEA2wmFfccdheTtoOuY" + "8oTurbnFHsS7gLtcR2IbRJKXw80CJxTQA/LMWz0YuFOAYJNl/9ILMfp6MQiI4L9F" + "l6pbtwJAJqkAXcXo72WvKL0flNfXsYBj0p9h8+2vi+7Y15d8nYAAh13zz5XdllM5" + "K7ZCMKDwpbkXe53O+QbLnwk/7iYLtwJAERT6AygfJk0HNzCIeglh78x4EgE3uj9i" + "X/LHu55PFacMTu3xlw09YLQwFFf2wBFeuAeyddBZ7S8ENbrU+5H+mwJBAO2E6gwG" + "e5ZqY4RmsQmv6K0rn5k+UT4qlPeVp1e6LnvO/PcKWOaUvDK59qFZoX4vN+iFUAbk" + "IuvhmL9u/uPWWck=" + "-----END PRIVATE KEY-----"; + static const std::vector<uint8_t> kBadKeyData(5, 111); + static const char kTestData[] = "disco boy"; + static const char kEmptyData[] = ""; + + std::string public_key_string; + base::Base64Decode(kPublicKey, &public_key_string); + std::vector<uint8_t> public_key(public_key_string.begin(), + public_key_string.end()); + std::string plain; + std::vector<uint8_t> encrypted_output; + + // Checking basic encryption operation. + plain = kTestData; + EXPECT_TRUE(networking_private_crypto::EncryptByteString( + public_key, plain, &encrypted_output)); + EXPECT_TRUE(VerifyByteString(kPrivateKey, plain, encrypted_output)); + + // Checking that we can encrypt the empty string. + plain = kEmptyData; + EXPECT_TRUE(networking_private_crypto::EncryptByteString( + public_key, plain, &encrypted_output)); + + // Checking graceful fail for too much data to encrypt. + EXPECT_FALSE(networking_private_crypto::EncryptByteString( + public_key, std::string(500, 'x'), &encrypted_output)); + + // Checking graceful fail for a bad key format. + EXPECT_FALSE(networking_private_crypto::EncryptByteString( + kBadKeyData, kTestData, &encrypted_output)); +} diff --git a/chromium/chrome/browser/extensions/api/networking_private/networking_private_ui_delegate_chromeos.cc b/chromium/chrome/browser/extensions/api/networking_private/networking_private_ui_delegate_chromeos.cc index ff32e2b258c..fbdbf5de19f 100644 --- a/chromium/chrome/browser/extensions/api/networking_private/networking_private_ui_delegate_chromeos.cc +++ b/chromium/chrome/browser/extensions/api/networking_private/networking_private_ui_delegate_chromeos.cc @@ -4,9 +4,9 @@ #include "chrome/browser/extensions/api/networking_private/networking_private_ui_delegate_chromeos.h" +#include "chromeos/network/network_connect.h" #include "chromeos/network/network_state.h" #include "chromeos/network/network_state_handler.h" -#include "ui/chromeos/network/network_connect.h" namespace chromeos { namespace extensions { @@ -17,24 +17,13 @@ NetworkingPrivateUIDelegateChromeOS::~NetworkingPrivateUIDelegateChromeOS() {} void NetworkingPrivateUIDelegateChromeOS::ShowAccountDetails( const std::string& guid) const { - const NetworkState* network = - NetworkHandler::Get()->network_state_handler()->GetNetworkStateFromGuid( - guid); - if (!network || network->path().empty()) - return; - ui::NetworkConnect::Get()->ShowMobileSetup(network->path()); + chromeos::NetworkConnect::Get()->ShowMobileSetup(guid); } bool NetworkingPrivateUIDelegateChromeOS::HandleConnectFailed( const std::string& guid, const std::string error) const { - const NetworkState* network = - NetworkHandler::Get()->network_state_handler()->GetNetworkStateFromGuid( - guid); - if (!network || network->path().empty()) - return false; - return ui::NetworkConnect::Get()->MaybeShowConfigureUI(network->path(), - error); + return chromeos::NetworkConnect::Get()->MaybeShowConfigureUI(guid, error); } } // namespace extensions diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.cc b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.cc index 796b497b6bf..9fcaabfbfc9 100644 --- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.cc +++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.cc @@ -4,6 +4,10 @@ #include "chrome/browser/extensions/api/passwords_private/passwords_private_api.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/location.h" +#include "base/threading/thread_task_runner_handle.h" #include "base/values.h" #include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate_factory.h" #include "chrome/common/extensions/api/passwords_private.h" @@ -93,12 +97,26 @@ PasswordsPrivateGetSavedPasswordListFunction:: ExtensionFunction::ResponseAction PasswordsPrivateGetSavedPasswordListFunction::Run() { + // GetList() can immediately call GotList() (which would Respond() before + // RespondLater()). So we post a task to preserve order. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&PasswordsPrivateGetSavedPasswordListFunction::GetList, this)); + return RespondLater(); +} + +void PasswordsPrivateGetSavedPasswordListFunction::GetList() { PasswordsPrivateDelegate* delegate = PasswordsPrivateDelegateFactory::GetForBrowserContext(browser_context(), true /* create */); - return RespondNow(ArgumentList( - api::passwords_private::GetSavedPasswordList::Results::Create( - *(delegate->GetSavedPasswordsList())))); + delegate->GetSavedPasswordsList( + base::Bind(&PasswordsPrivateGetSavedPasswordListFunction::GotList, this)); +} + +void PasswordsPrivateGetSavedPasswordListFunction::GotList( + const PasswordsPrivateDelegate::UiEntries& list) { + Respond(ArgumentList( + api::passwords_private::GetSavedPasswordList::Results::Create(list))); } //////////////////////////////////////////////////////////////////////////////// @@ -109,12 +127,27 @@ PasswordsPrivateGetPasswordExceptionListFunction:: ExtensionFunction::ResponseAction PasswordsPrivateGetPasswordExceptionListFunction::Run() { + // GetList() can immediately call GotList() (which would Respond() before + // RespondLater()). So we post a task to preserve order. + base::ThreadTaskRunnerHandle::Get()->PostTask( + FROM_HERE, + base::Bind(&PasswordsPrivateGetPasswordExceptionListFunction::GetList, + this)); + return RespondLater(); +} + +void PasswordsPrivateGetPasswordExceptionListFunction::GetList() { PasswordsPrivateDelegate* delegate = PasswordsPrivateDelegateFactory::GetForBrowserContext(browser_context(), true /* create */); - return RespondNow(ArgumentList( - api::passwords_private::GetPasswordExceptionList::Results::Create( - *(delegate->GetPasswordExceptionsList())))); + delegate->GetPasswordExceptionsList(base::Bind( + &PasswordsPrivateGetPasswordExceptionListFunction::GotList, this)); +} + +void PasswordsPrivateGetPasswordExceptionListFunction::GotList( + const PasswordsPrivateDelegate::ExceptionPairs& list) { + Respond(ArgumentList( + api::passwords_private::GetPasswordExceptionList::Results::Create(list))); } } // namespace extensions diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.h b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.h index b8789f5aca4..6296e8bbe2b 100644 --- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.h +++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_api.h @@ -79,6 +79,9 @@ class PasswordsPrivateGetSavedPasswordListFunction ResponseAction Run() override; private: + void GetList(); + void GotList(const PasswordsPrivateDelegate::UiEntries& entries); + DISALLOW_COPY_AND_ASSIGN(PasswordsPrivateGetSavedPasswordListFunction); }; @@ -96,6 +99,9 @@ class PasswordsPrivateGetPasswordExceptionListFunction ResponseAction Run() override; private: + void GetList(); + void GotList(const PasswordsPrivateDelegate::ExceptionPairs& pairs); + DISALLOW_COPY_AND_ASSIGN(PasswordsPrivateGetPasswordExceptionListFunction); }; diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_apitest.cc b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_apitest.cc index 7ec270b1d33..6ab38ffe123 100644 --- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_apitest.cc +++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_apitest.cc @@ -77,9 +77,8 @@ class TestDelegate : public PasswordsPrivateDelegate { router->OnSavedPasswordsListChanged(current_entries_); } - const std::vector<api::passwords_private::PasswordUiEntry>* - GetSavedPasswordsList() const override { - return ¤t_entries_; + void GetSavedPasswordsList(const UiEntriesCallback& callback) override { + callback.Run(current_entries_); } void SendPasswordExceptionsList() override { @@ -89,9 +88,9 @@ class TestDelegate : public PasswordsPrivateDelegate { router->OnPasswordExceptionsListChanged(current_exceptions_); } - const std::vector<api::passwords_private::ExceptionPair>* - GetPasswordExceptionsList() const override { - return ¤t_exceptions_; + void GetPasswordExceptionsList( + const ExceptionPairsCallback& callback) override { + callback.Run(current_exceptions_); } void RemoveSavedPassword( diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h index 7d5d230abff..7faeddd4f7a 100644 --- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h +++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate.h @@ -42,15 +42,18 @@ class PasswordsPrivateDelegate : public KeyedService { virtual void SendSavedPasswordsList() = 0; // Gets the saved passwords list. - virtual const std::vector<api::passwords_private::PasswordUiEntry>* - GetSavedPasswordsList() const = 0; + using UiEntries = std::vector<api::passwords_private::PasswordUiEntry>; + using UiEntriesCallback = base::Callback<void(const UiEntries&)>; + virtual void GetSavedPasswordsList(const UiEntriesCallback& callback) = 0; // Sends the password exceptions list to the event router. virtual void SendPasswordExceptionsList() = 0; // Gets the password exceptions list. - virtual const std::vector<api::passwords_private::ExceptionPair>* - GetPasswordExceptionsList() const = 0; + using ExceptionPairs = std::vector<api::passwords_private::ExceptionPair>; + using ExceptionPairsCallback = base::Callback<void(const ExceptionPairs&)>; + virtual void GetPasswordExceptionsList( + const ExceptionPairsCallback& callback) = 0; // Removes the saved password entry corresponding to |origin_url| and // |username|. diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc index f332e3ef2d7..ee744580d82 100644 --- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc +++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.cc @@ -32,8 +32,8 @@ namespace extensions { PasswordsPrivateDelegateImpl::PasswordsPrivateDelegateImpl(Profile* profile) : profile_(profile), password_manager_presenter_(new PasswordManagerPresenter(this)), - set_password_list_called_(false), - set_password_exception_list_called_(false), + current_entries_initialized_(false), + current_exceptions_initialized_(false), is_initialized_(false), web_contents_(nullptr) { password_manager_presenter_->Initialize(); @@ -49,9 +49,12 @@ void PasswordsPrivateDelegateImpl::SendSavedPasswordsList() { router->OnSavedPasswordsListChanged(current_entries_); } -const std::vector<api::passwords_private::PasswordUiEntry>* -PasswordsPrivateDelegateImpl::GetSavedPasswordsList() const { - return ¤t_entries_; +void PasswordsPrivateDelegateImpl::GetSavedPasswordsList( + const UiEntriesCallback& callback) { + if (current_entries_initialized_) + callback.Run(current_entries_); + else + get_saved_passwords_list_callbacks_.push_back(callback); } void PasswordsPrivateDelegateImpl::SendPasswordExceptionsList() { @@ -61,9 +64,12 @@ void PasswordsPrivateDelegateImpl::SendPasswordExceptionsList() { router->OnPasswordExceptionsListChanged(current_exceptions_); } -const std::vector<api::passwords_private::ExceptionPair>* -PasswordsPrivateDelegateImpl::GetPasswordExceptionsList() const { - return ¤t_exceptions_; +void PasswordsPrivateDelegateImpl::GetPasswordExceptionsList( + const ExceptionPairsCallback& callback) { + if (current_exceptions_initialized_) + callback.Run(current_exceptions_); + else + get_password_exception_list_callbacks_.push_back(callback); } void PasswordsPrivateDelegateImpl::RemoveSavedPassword( @@ -189,8 +195,15 @@ void PasswordsPrivateDelegateImpl::SetPasswordList( SendSavedPasswordsList(); - set_password_list_called_ = true; + DCHECK(!current_entries_initialized_ || + get_saved_passwords_list_callbacks_.empty()); + + current_entries_initialized_ = true; InitializeIfNecessary(); + + for (const auto& callback : get_saved_passwords_list_callbacks_) + callback.Run(current_entries_); + get_saved_passwords_list_callbacks_.clear(); } void PasswordsPrivateDelegateImpl::SetPasswordExceptionList( @@ -216,8 +229,15 @@ void PasswordsPrivateDelegateImpl::SetPasswordExceptionList( SendPasswordExceptionsList(); - set_password_exception_list_called_ = true; + DCHECK(!current_entries_initialized_ || + get_saved_passwords_list_callbacks_.empty()); + + current_exceptions_initialized_ = true; InitializeIfNecessary(); + + for (const auto& callback : get_password_exception_list_callbacks_) + callback.Run(current_exceptions_); + get_password_exception_list_callbacks_.clear(); } #if !defined(OS_ANDROID) @@ -232,7 +252,7 @@ void PasswordsPrivateDelegateImpl::Shutdown() { } void PasswordsPrivateDelegateImpl::ExecuteFunction( - const base::Callback<void()>& callback) { + const base::Closure& callback) { if (is_initialized_) { callback.Run(); return; @@ -242,16 +262,15 @@ void PasswordsPrivateDelegateImpl::ExecuteFunction( } void PasswordsPrivateDelegateImpl::InitializeIfNecessary() { - if (is_initialized_ || - !set_password_list_called_ || - !set_password_exception_list_called_) + if (is_initialized_ || !current_entries_initialized_ || + !current_exceptions_initialized_) return; is_initialized_ = true; - for (const base::Callback<void()>& callback : pre_initialization_callbacks_) { + for (const base::Closure& callback : pre_initialization_callbacks_) callback.Run(); - } + pre_initialization_callbacks_.clear(); } } // namespace extensions diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h index 55b87f518b9..830e8ba9a98 100644 --- a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h +++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h @@ -40,11 +40,10 @@ class PasswordsPrivateDelegateImpl : public PasswordsPrivateDelegate, // PasswordsPrivateDelegate implementation. void SendSavedPasswordsList() override; - const std::vector<api::passwords_private::PasswordUiEntry>* - GetSavedPasswordsList() const override; + void GetSavedPasswordsList(const UiEntriesCallback& callback) override; void SendPasswordExceptionsList() override; - const std::vector<api::passwords_private::ExceptionPair>* - GetPasswordExceptionsList() const override; + void GetPasswordExceptionsList( + const ExceptionPairsCallback& callback) override; void RemoveSavedPassword( const std::string& origin_url, const std::string& username) override; void RemovePasswordException(const std::string& exception_url) override; @@ -80,7 +79,7 @@ class PasswordsPrivateDelegateImpl : public PasswordsPrivateDelegate, // Executes a given callback by either invoking it immediately if the class // has been initialized or by deferring it until initialization has completed. - void ExecuteFunction(const base::Callback<void()>& callback); + void ExecuteFunction(const base::Closure& callback); void RemoveSavedPasswordInternal( const std::string& origin_url, const std::string& username); @@ -98,20 +97,22 @@ class PasswordsPrivateDelegateImpl : public PasswordsPrivateDelegate, // The current list of entries/exceptions. Cached here so that when new // observers are added, this delegate can send the current lists without // having to request them from |password_manager_presenter_| again. - std::vector<api::passwords_private::PasswordUiEntry> current_entries_; - std::vector<api::passwords_private::ExceptionPair> current_exceptions_; + UiEntries current_entries_; + ExceptionPairs current_exceptions_; // Whether SetPasswordList and SetPasswordExceptionList have been called, and // whether this class has been initialized, meaning both have been called. - bool set_password_list_called_; - bool set_password_exception_list_called_; + bool current_entries_initialized_; + bool current_exceptions_initialized_; bool is_initialized_; // Vector of callbacks which are queued up before the password store has been // initialized. Once both SetPasswordList() and SetPasswordExceptionList() // have been called, this class is considered initialized and can these // callbacks are invoked. - std::vector<base::Callback<void()>> pre_initialization_callbacks_; + std::vector<base::Closure> pre_initialization_callbacks_; + std::vector<UiEntriesCallback> get_saved_passwords_list_callbacks_; + std::vector<ExceptionPairsCallback> get_password_exception_list_callbacks_; // The WebContents used when invoking this API. Used to fetch the // NativeWindow for the window where the API was called. diff --git a/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_unittest.cc b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_unittest.cc new file mode 100644 index 00000000000..87e1a39c2ca --- /dev/null +++ b/chromium/chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl_unittest.cc @@ -0,0 +1,84 @@ +// Copyright 2016 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. + +#include <stddef.h> + +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/macros.h" +#include "base/memory/ptr_util.h" +#include "chrome/browser/extensions/api/passwords_private/passwords_private_delegate_impl.h" +#include "chrome/test/base/testing_profile.h" +#include "components/autofill/core/common/password_form.h" +#include "content/public/test/test_browser_thread_bundle.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace extensions { + +template <typename T> +class CallbackTracker { + public: + CallbackTracker() : callback_( + base::Bind(&CallbackTracker::Callback, base::Unretained(this))) {} + + using TypedCallback = base::Callback<void(const T&)>; + + const TypedCallback& callback() const { return callback_; } + + size_t call_count() const { return call_count_; } + + private: + void Callback(const T& args) { + EXPECT_FALSE(args.empty()); + ++call_count_; + } + + size_t call_count_ = 0; + + TypedCallback callback_; + + DISALLOW_COPY_AND_ASSIGN(CallbackTracker); +}; + +using PasswordFormList = std::vector<std::unique_ptr<autofill::PasswordForm>>; + +TEST(PasswordsPrivateDelegateImplTest, GetSavedPasswordsList) { + CallbackTracker<PasswordsPrivateDelegate::UiEntries> tracker; + + content::TestBrowserThreadBundle thread_bundle; + TestingProfile profile; + PasswordsPrivateDelegateImpl delegate(&profile); + + delegate.GetSavedPasswordsList(tracker.callback()); + EXPECT_EQ(0u, tracker.call_count()); + + PasswordFormList list; + list.push_back(base::MakeUnique<autofill::PasswordForm>()); + delegate.SetPasswordList(list); + EXPECT_EQ(1u, tracker.call_count()); + + delegate.GetSavedPasswordsList(tracker.callback()); + EXPECT_EQ(2u, tracker.call_count()); +} + +TEST(PasswordsPrivateDelegateImplTest, GetPasswordExceptionsList) { + CallbackTracker<PasswordsPrivateDelegate::ExceptionPairs> tracker; + + content::TestBrowserThreadBundle thread_bundle; + TestingProfile profile; + PasswordsPrivateDelegateImpl delegate(&profile); + + delegate.GetPasswordExceptionsList(tracker.callback()); + EXPECT_EQ(0u, tracker.call_count()); + + PasswordFormList list; + list.push_back(base::MakeUnique<autofill::PasswordForm>()); + delegate.SetPasswordExceptionList(list); + EXPECT_EQ(1u, tracker.call_count()); + + delegate.GetPasswordExceptionsList(tracker.callback()); + EXPECT_EQ(2u, tracker.call_count()); +} + +} // namespace extensions diff --git a/chromium/chrome/browser/extensions/api/permissions/permissions_api.cc b/chromium/chrome/browser/extensions/api/permissions/permissions_api.cc index 0a8222f08af..3b52c7334c2 100644 --- a/chromium/chrome/browser/extensions/api/permissions/permissions_api.cc +++ b/chromium/chrome/browser/extensions/api/permissions/permissions_api.cc @@ -54,53 +54,50 @@ bool ignore_user_gesture_for_tests = false; } // namespace -bool PermissionsContainsFunction::RunSync() { +ExtensionFunction::ResponseAction PermissionsContainsFunction::Run() { std::unique_ptr<Contains::Params> params(Contains::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params); // NOTE: |permissions| is not used to make any security decisions. Therefore, // it is entirely fine to set |allow_file_access| to true below. This will // avoid throwing error when extension() doesn't have access to file://. + std::string error; std::unique_ptr<const PermissionSet> permissions = helpers::UnpackPermissionSet(params->permissions, - true /* allow_file_access */, &error_); + true /* allow_file_access */, &error); if (!permissions.get()) - return false; + return RespondNow(Error(error)); - results_ = Contains::Results::Create( + return RespondNow(ArgumentList(Contains::Results::Create( extension()->permissions_data()->active_permissions().Contains( - *permissions)); - return true; + *permissions)))); } -bool PermissionsGetAllFunction::RunSync() { +ExtensionFunction::ResponseAction PermissionsGetAllFunction::Run() { std::unique_ptr<Permissions> permissions = helpers::PackPermissionSet( extension()->permissions_data()->active_permissions()); - results_ = GetAll::Results::Create(*permissions); - return true; + return RespondNow(ArgumentList(GetAll::Results::Create(*permissions))); } -bool PermissionsRemoveFunction::RunSync() { +ExtensionFunction::ResponseAction PermissionsRemoveFunction::Run() { std::unique_ptr<Remove::Params> params(Remove::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params); + std::string error; std::unique_ptr<const PermissionSet> permissions = - helpers::UnpackPermissionSet( - params->permissions, - ExtensionPrefs::Get(GetProfile())->AllowFileAccess(extension_->id()), - &error_); + helpers::UnpackPermissionSet(params->permissions, + ExtensionPrefs::Get(browser_context()) + ->AllowFileAccess(extension_->id()), + &error); + if (!permissions.get()) - return false; + return RespondNow(Error(error)); // Make sure they're only trying to remove permissions supported by this API. APIPermissionSet apis = permissions->apis(); - for (APIPermissionSet::const_iterator i = apis.begin(); - i != apis.end(); ++i) { - if (!i->info()->supports_optional()) { - error_ = ErrorUtils::FormatErrorMessage( - kNotWhitelistedError, i->name()); - return false; - } + for (const APIPermission* permission : apis) { + if (!permission->info()->supports_optional()) + return RespondNow(Error(kNotWhitelistedError, permission->name())); } // Make sure we only remove optional permissions, and not required @@ -116,8 +113,7 @@ bool PermissionsRemoveFunction::RunSync() { !std::unique_ptr<const PermissionSet>( PermissionSet::CreateIntersection(*permissions, required)) ->IsEmpty()) { - error_ = kCantRemoveRequiredPermissionsError; - return false; + return RespondNow(Error(kCantRemoveRequiredPermissionsError)); } // Only try and remove those permissions that are active on the extension. @@ -126,11 +122,10 @@ bool PermissionsRemoveFunction::RunSync() { permissions = PermissionSet::CreateIntersection( *permissions, extension()->permissions_data()->active_permissions()); - PermissionsUpdater(GetProfile()) + PermissionsUpdater(browser_context()) .RemovePermissions(extension(), *permissions, PermissionsUpdater::REMOVE_SOFT); - results_ = Remove::Results::Create(true); - return true; + return RespondNow(ArgumentList(Remove::Results::Create(true))); } // static diff --git a/chromium/chrome/browser/extensions/api/permissions/permissions_api.h b/chromium/chrome/browser/extensions/api/permissions/permissions_api.h index e29074b531d..e780a45199d 100644 --- a/chromium/chrome/browser/extensions/api/permissions/permissions_api.h +++ b/chromium/chrome/browser/extensions/api/permissions/permissions_api.h @@ -16,7 +16,7 @@ namespace extensions { // chrome.permissions.contains -class PermissionsContainsFunction : public ChromeSyncExtensionFunction { +class PermissionsContainsFunction : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("permissions.contains", PERMISSIONS_CONTAINS) @@ -24,11 +24,11 @@ class PermissionsContainsFunction : public ChromeSyncExtensionFunction { ~PermissionsContainsFunction() override {} // ExtensionFunction: - bool RunSync() override; + ResponseAction Run() override; }; // chrome.permissions.getAll -class PermissionsGetAllFunction : public ChromeSyncExtensionFunction { +class PermissionsGetAllFunction : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("permissions.getAll", PERMISSIONS_GETALL) @@ -36,11 +36,11 @@ class PermissionsGetAllFunction : public ChromeSyncExtensionFunction { ~PermissionsGetAllFunction() override {} // ExtensionFunction: - bool RunSync() override; + ResponseAction Run() override; }; // chrome.permissions.remove -class PermissionsRemoveFunction : public ChromeSyncExtensionFunction { +class PermissionsRemoveFunction : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("permissions.remove", PERMISSIONS_REMOVE) @@ -48,7 +48,7 @@ class PermissionsRemoveFunction : public ChromeSyncExtensionFunction { ~PermissionsRemoveFunction() override {} // ExtensionFunction: - bool RunSync() override; + ResponseAction Run() override; }; // chrome.permissions.request diff --git a/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc b/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc index 6b79c87a04d..2a8a5a44605 100644 --- a/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc +++ b/chromium/chrome/browser/extensions/api/platform_keys/platform_keys_apitest_nss.cc @@ -20,9 +20,9 @@ #include "chrome/browser/policy/profile_policy_connector_factory.h" #include "chrome/browser/profiles/profile.h" #include "chromeos/chromeos_switches.h" -#include "chromeos/login/user_names.h" #include "components/policy/policy_constants.h" #include "components/signin/core/account_id/account_id.h" +#include "components/user_manager/user_names.h" #include "content/public/browser/notification_service.h" #include "content/public/test/test_utils.h" #include "crypto/nss_util_internal.h" @@ -65,7 +65,7 @@ class PlatformKeysTest : public ExtensionApiTest { command_line->AppendSwitchASCII( chromeos::switches::kLoginUser, - chromeos::login::StubAccountId().GetUserEmail()); + user_manager::StubAccountId().GetUserEmail()); } void SetUpInProcessBrowserTestFixture() override { @@ -74,7 +74,7 @@ class PlatformKeysTest : public ExtensionApiTest { if (device_status_ == DEVICE_STATUS_ENROLLED) { device_policy_test_helper_.device_policy()->policy_data().set_username( user_status_ == USER_STATUS_MANAGED_AFFILIATED_DOMAIN - ? chromeos::login::StubAccountId().GetUserEmail() + ? user_manager::StubAccountId().GetUserEmail() : "someuser@anydomain.com"); device_policy_test_helper_.device_policy()->Build(); @@ -181,7 +181,7 @@ class PlatformKeysTest : public ExtensionApiTest { private: void SetupInitialEmptyPolicy() { policy_helper_.reset(new policy::UserPolicyTestHelper( - chromeos::login::StubAccountId().GetUserEmail())); + user_manager::StubAccountId().GetUserEmail())); policy_helper_->Init( base::DictionaryValue() /* empty mandatory policy */, base::DictionaryValue() /* empty recommended policy */); diff --git a/chromium/chrome/browser/extensions/api/platform_keys/verify_trust_api.cc b/chromium/chrome/browser/extensions/api/platform_keys/verify_trust_api.cc index 42e21020c3d..4bdc91ea91c 100644 --- a/chromium/chrome/browser/extensions/api/platform_keys/verify_trust_api.cc +++ b/chromium/chrome/browser/extensions/api/platform_keys/verify_trust_api.cc @@ -5,10 +5,10 @@ #include "chrome/browser/extensions/api/platform_keys/verify_trust_api.h" #include <algorithm> +#include <memory> #include "base/lazy_instance.h" #include "base/macros.h" -#include "base/memory/linked_ptr.h" #include "base/memory/ref_counted.h" #include "chrome/browser/extensions/api/platform_keys/platform_keys_api.h" #include "chrome/common/extensions/api/platform_keys_internal.h" @@ -71,7 +71,8 @@ class VerifyTrustAPI::IOPart { // One CertVerifier per extension to verify trust. Each verifier is created on // first usage and deleted when this IOPart is destructed or the respective // extension is unloaded. - std::map<std::string, linked_ptr<net::CertVerifier>> extension_to_verifier_; + std::map<std::string, std::unique_ptr<net::CertVerifier>> + extension_to_verifier_; }; // static @@ -177,8 +178,7 @@ void VerifyTrustAPI::IOPart::Verify(std::unique_ptr<Params> params, } if (!base::ContainsKey(extension_to_verifier_, extension_id)) { - extension_to_verifier_[extension_id] = - make_linked_ptr(net::CertVerifier::CreateDefault().release()); + extension_to_verifier_[extension_id] = net::CertVerifier::CreateDefault(); } net::CertVerifier* verifier = extension_to_verifier_[extension_id].get(); diff --git a/chromium/chrome/browser/extensions/api/preference/preference_api.cc b/chromium/chrome/browser/extensions/api/preference/preference_api.cc index 89d11d66c0d..025bf3a80c9 100644 --- a/chromium/chrome/browser/extensions/api/preference/preference_api.cc +++ b/chromium/chrome/browser/extensions/api/preference/preference_api.cc @@ -32,6 +32,7 @@ #include "components/password_manager/core/common/password_manager_pref_names.h" #include "components/prefs/pref_service.h" #include "components/proxy_config/proxy_config_pref_names.h" +#include "components/safe_browsing_db/safe_browsing_prefs.h" #include "components/spellcheck/browser/pref_names.h" #include "components/translate/core/common/translate_pref_names.h" #include "content/public/browser/notification_details.h" @@ -80,8 +81,7 @@ const char kConversionErrorMessage[] = "properly."; PrefMappingEntry kPrefMapping[] = { - {"spdy_proxy.enabled", - prefs::kDataSaverEnabled, + {"spdy_proxy.enabled", prefs::kDataSaverEnabled, APIPermission::kDataReductionProxy, APIPermission::kDataReductionProxy}, {"data_reduction.daily_original_length", data_reduction_proxy::prefs::kDailyHttpOriginalContentLength, @@ -587,32 +587,9 @@ BrowserContextKeyedAPIFactory<PreferenceAPI>::DeclareFactoryDependencies() { PreferenceFunction::~PreferenceFunction() { } -bool PreferenceFunction::ValidateBrowserPref( - const std::string& extension_pref_key, - PreferenceFunction::PermissionType permission_type, - std::string* browser_pref_key) { - APIPermission::ID read_permission = APIPermission::kInvalid; - APIPermission::ID write_permission = APIPermission::kInvalid; - EXTENSION_FUNCTION_VALIDATE( - PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref( - extension_pref_key, - browser_pref_key, - &read_permission, - &write_permission)); - APIPermission::ID permission = permission_type == PERMISSION_TYPE_READ - ? read_permission - : write_permission; - if (!extension()->permissions_data()->HasAPIPermission(permission)) { - error_ = ErrorUtils::FormatErrorMessage( - keys::kPermissionErrorMessage, extension_pref_key); - return false; - } - return true; -} - GetPreferenceFunction::~GetPreferenceFunction() { } -bool GetPreferenceFunction::RunSync() { +ExtensionFunction::ResponseAction GetPreferenceFunction::Run() { std::string pref_key; EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key)); base::DictionaryValue* details = NULL; @@ -624,19 +601,22 @@ bool GetPreferenceFunction::RunSync() { &incognito)); // Check incognito access. - if (incognito && !include_incognito()) { - error_ = keys::kIncognitoErrorMessage; - return false; - } + if (incognito && !include_incognito()) + return RespondNow(Error(keys::kIncognitoErrorMessage)); // Obtain pref. std::string browser_pref; - if (!ValidateBrowserPref( - pref_key, PreferenceFunction::PERMISSION_TYPE_READ, &browser_pref)) { - return false; - } - PrefService* prefs = incognito ? GetProfile()->GetOffTheRecordPrefs() - : GetProfile()->GetPrefs(); + APIPermission::ID read_permission = APIPermission::kInvalid; + APIPermission::ID write_permission = APIPermission::kInvalid; + EXTENSION_FUNCTION_VALIDATE( + PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref( + pref_key, &browser_pref, &read_permission, &write_permission)); + if (!extension()->permissions_data()->HasAPIPermission(read_permission)) + return RespondNow(Error(keys::kPermissionErrorMessage, pref_key)); + + Profile* profile = Profile::FromBrowserContext(browser_context()); + PrefService* prefs = + incognito ? profile->GetOffTheRecordPrefs() : profile->GetPrefs(); const PrefService::Preference* pref = prefs->FindPreference(browser_pref.c_str()); CHECK(pref); @@ -645,7 +625,7 @@ bool GetPreferenceFunction::RunSync() { // Retrieve level of control. std::string level_of_control = helpers::GetLevelOfControl( - GetProfile(), extension_id(), browser_pref, incognito); + profile, extension_id(), browser_pref, incognito); result->SetString(keys::kLevelOfControl, level_of_control); // Retrieve pref value. @@ -654,27 +634,28 @@ bool GetPreferenceFunction::RunSync() { base::Value* transformed_value = transformer->BrowserToExtensionPref(pref->GetValue()); if (!transformed_value) { + // TODO(devlin): Can this happen? When? Should it be an error, or a bad + // message? LOG(ERROR) << ErrorUtils::FormatErrorMessage(kConversionErrorMessage, pref->name()); - return false; + return RespondNow(Error(kUnknownErrorDoNotUse)); } result->Set(keys::kValue, transformed_value); // Retrieve incognito status. if (incognito) { - ExtensionPrefs* ep = ExtensionPrefs::Get(GetProfile()); + ExtensionPrefs* ep = ExtensionPrefs::Get(browser_context()); result->SetBoolean(keys::kIncognitoSpecific, ep->HasIncognitoPrefValue(browser_pref)); } - SetResult(std::move(result)); - return true; + return RespondNow(OneArgument(std::move(result))); } SetPreferenceFunction::~SetPreferenceFunction() { } -bool SetPreferenceFunction::RunSync() { +ExtensionFunction::ResponseAction SetPreferenceFunction::Run() { std::string pref_key; EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key)); base::DictionaryValue* details = NULL; @@ -698,32 +679,32 @@ bool SetPreferenceFunction::RunSync() { scope == kExtensionPrefsScopeIncognitoSessionOnly); if (incognito) { // Regular profiles can't access incognito unless include_incognito is true. - if (!GetProfile()->IsOffTheRecord() && !include_incognito()) { - error_ = keys::kIncognitoErrorMessage; - return false; - } - } else { + if (!browser_context()->IsOffTheRecord() && !include_incognito()) + return RespondNow(Error(keys::kIncognitoErrorMessage)); + } else if (browser_context()->IsOffTheRecord()) { // Incognito profiles can't access regular mode ever, they only exist in // split mode. - if (GetProfile()->IsOffTheRecord()) { - error_ = "Can't modify regular settings from an incognito context."; - return false; - } + return RespondNow( + Error("Can't modify regular settings from an incognito context.")); } + Profile* profile = Profile::FromBrowserContext(browser_context()); if (scope == kExtensionPrefsScopeIncognitoSessionOnly && - !GetProfile()->HasOffTheRecordProfile()) { - error_ = keys::kIncognitoSessionOnlyErrorMessage; - return false; + !profile->HasOffTheRecordProfile()) { + return RespondNow(Error(keys::kIncognitoSessionOnlyErrorMessage)); } // Obtain pref. std::string browser_pref; - if (!ValidateBrowserPref( - pref_key, PreferenceFunction::PERMISSION_TYPE_WRITE, &browser_pref)) { - return false; - } - ExtensionPrefs* prefs = ExtensionPrefs::Get(GetProfile()); + APIPermission::ID read_permission = APIPermission::kInvalid; + APIPermission::ID write_permission = APIPermission::kInvalid; + EXTENSION_FUNCTION_VALIDATE( + PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref( + pref_key, &browser_pref, &read_permission, &write_permission)); + if (!extension()->permissions_data()->HasAPIPermission(write_permission)) + return RespondNow(Error(keys::kPermissionErrorMessage, pref_key)); + + ExtensionPrefs* prefs = ExtensionPrefs::Get(browser_context()); const PrefService::Preference* pref = prefs->pref_service()->FindPreference(browser_pref.c_str()); CHECK(pref); @@ -736,31 +717,26 @@ bool SetPreferenceFunction::RunSync() { std::unique_ptr<base::Value> browser_pref_value( transformer->ExtensionToBrowserPref(value, &error, &bad_message)); if (!browser_pref_value) { - error_ = error; - set_bad_message(bad_message); - return false; + EXTENSION_FUNCTION_VALIDATE(!bad_message); + return RespondNow(Error(error)); } EXTENSION_FUNCTION_VALIDATE(browser_pref_value->GetType() == pref->GetType()); // Validate also that the stored value can be converted back by the // transformer. - std::unique_ptr<base::Value> extensionPrefValue( + std::unique_ptr<base::Value> extension_pref_value( transformer->BrowserToExtensionPref(browser_pref_value.get())); - if (!extensionPrefValue) { - error_ = ErrorUtils::FormatErrorMessage(kConversionErrorMessage, - pref->name()); - set_bad_message(true); - return false; - } + EXTENSION_FUNCTION_VALIDATE(extension_pref_value); - PreferenceAPI::Get(GetProfile())->SetExtensionControlledPref( - extension_id(), browser_pref, scope, browser_pref_value.release()); - return true; + PreferenceAPI::Get(browser_context()) + ->SetExtensionControlledPref(extension_id(), browser_pref, scope, + browser_pref_value.release()); + return RespondNow(NoArguments()); } ClearPreferenceFunction::~ClearPreferenceFunction() { } -bool ClearPreferenceFunction::RunSync() { +ExtensionFunction::ResponseAction ClearPreferenceFunction::Run() { std::string pref_key; EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &pref_key)); base::DictionaryValue* details = NULL; @@ -782,24 +758,25 @@ bool ClearPreferenceFunction::RunSync() { if (incognito) { // We don't check incognito permissions here, as an extension should be // always allowed to clear its own settings. - } else { + } else if (browser_context()->IsOffTheRecord()) { // Incognito profiles can't access regular mode ever, they only exist in // split mode. - if (GetProfile()->IsOffTheRecord()) { - error_ = "Can't modify regular settings from an incognito context."; - return false; - } + return RespondNow( + Error("Can't modify regular settings from an incognito context.")); } std::string browser_pref; - if (!ValidateBrowserPref( - pref_key, PreferenceFunction::PERMISSION_TYPE_WRITE, &browser_pref)) { - return false; - } + APIPermission::ID read_permission = APIPermission::kInvalid; + APIPermission::ID write_permission = APIPermission::kInvalid; + EXTENSION_FUNCTION_VALIDATE( + PrefMapping::GetInstance()->FindBrowserPrefForExtensionPref( + pref_key, &browser_pref, &read_permission, &write_permission)); + if (!extension()->permissions_data()->HasAPIPermission(write_permission)) + return RespondNow(Error(keys::kPermissionErrorMessage, pref_key)); - PreferenceAPI::Get(GetProfile()) + PreferenceAPI::Get(browser_context()) ->RemoveExtensionControlledPref(extension_id(), browser_pref, scope); - return true; + return RespondNow(NoArguments()); } } // namespace extensions diff --git a/chromium/chrome/browser/extensions/api/preference/preference_api.h b/chromium/chrome/browser/extensions/api/preference/preference_api.h index f82bb8eba1a..47d68b4a576 100644 --- a/chromium/chrome/browser/extensions/api/preference/preference_api.h +++ b/chromium/chrome/browser/extensions/api/preference/preference_api.h @@ -166,20 +166,11 @@ class PrefTransformerInterface { // A base class to provide functionality common to the other *PreferenceFunction // classes. -class PreferenceFunction : public ChromeSyncExtensionFunction { +class PreferenceFunction : public UIThreadExtensionFunction { protected: enum PermissionType { PERMISSION_TYPE_READ, PERMISSION_TYPE_WRITE }; ~PreferenceFunction() override; - - // Given an |extension_pref_key|, provides its |browser_pref_key| from the - // static map in preference_api.cc. Returns true if the corresponding - // browser pref exists and the extension has the API permission needed to - // modify that pref. Sets |error_| if the extension doesn't have the needed - // permission. - bool ValidateBrowserPref(const std::string& extension_pref_key, - PermissionType permission_type, - std::string* browser_pref_key); }; class GetPreferenceFunction : public PreferenceFunction { @@ -190,7 +181,7 @@ class GetPreferenceFunction : public PreferenceFunction { ~GetPreferenceFunction() override; // ExtensionFunction: - bool RunSync() override; + ResponseAction Run() override; }; class SetPreferenceFunction : public PreferenceFunction { @@ -201,7 +192,7 @@ class SetPreferenceFunction : public PreferenceFunction { ~SetPreferenceFunction() override; // ExtensionFunction: - bool RunSync() override; + ResponseAction Run() override; }; class ClearPreferenceFunction : public PreferenceFunction { @@ -213,7 +204,7 @@ class ClearPreferenceFunction : public PreferenceFunction { ~ClearPreferenceFunction() override; // ExtensionFunction: - bool RunSync() override; + ResponseAction Run() override; }; } // namespace extensions diff --git a/chromium/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.cc b/chromium/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.cc index 4504d3c9240..02e97473912 100644 --- a/chromium/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.cc +++ b/chromium/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.cc @@ -96,7 +96,8 @@ ScreenlockPrivateAcceptAuthAttemptFunction:: ScreenlockPrivateAcceptAuthAttemptFunction:: ~ScreenlockPrivateAcceptAuthAttemptFunction() {} -bool ScreenlockPrivateAcceptAuthAttemptFunction::RunSync() { +ExtensionFunction::ResponseAction +ScreenlockPrivateAcceptAuthAttemptFunction::Run() { std::unique_ptr<screenlock::AcceptAuthAttempt::Params> params( screenlock::AcceptAuthAttempt::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); @@ -105,7 +106,7 @@ bool ScreenlockPrivateAcceptAuthAttemptFunction::RunSync() { EasyUnlockService* service = EasyUnlockService::Get(profile); if (service) service->FinalizeUnlock(params->accept); - return true; + return RespondNow(NoArguments()); } ScreenlockPrivateEventRouter::ScreenlockPrivateEventRouter( diff --git a/chromium/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.h b/chromium/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.h index b08d043a087..8be74e50597 100644 --- a/chromium/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.h +++ b/chromium/chrome/browser/extensions/api/screenlock_private/screenlock_private_api.h @@ -41,12 +41,12 @@ class ScreenlockPrivateSetLockedFunction : public ChromeAsyncExtensionFunction { }; class ScreenlockPrivateAcceptAuthAttemptFunction - : public ChromeSyncExtensionFunction { + : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("screenlockPrivate.acceptAuthAttempt", SCREENLOCKPRIVATE_ACCEPTAUTHATTEMPT) ScreenlockPrivateAcceptAuthAttemptFunction(); - bool RunSync() override; + ResponseAction Run() override; private: ~ScreenlockPrivateAcceptAuthAttemptFunction() override; diff --git a/chromium/chrome/browser/extensions/api/sessions/sessions_api.cc b/chromium/chrome/browser/extensions/api/sessions/sessions_api.cc index b568021ab66..6ac96677064 100644 --- a/chromium/chrome/browser/extensions/api/sessions/sessions_api.cc +++ b/chromium/chrome/browser/extensions/api/sessions/sessions_api.cc @@ -76,7 +76,6 @@ bool SortTabsByRecency(const sessions::SessionTab* t1, } tabs::Tab CreateTabModelHelper( - Profile* profile, const sessions::SerializedNavigationEntry& current_navigation, const std::string& session_id, int index, @@ -146,8 +145,7 @@ bool is_window_entry(const sessions::TabRestoreService::Entry& entry) { tabs::Tab SessionsGetRecentlyClosedFunction::CreateTabModel( const sessions::TabRestoreService::Tab& tab, bool active) { - return CreateTabModelHelper(GetProfile(), - tab.navigations[tab.current_navigation_index], + return CreateTabModelHelper(tab.navigations[tab.current_navigation_index], base::IntToString(tab.id), tab.tabstrip_index, tab.pinned, active, extension()); } @@ -188,7 +186,7 @@ SessionsGetRecentlyClosedFunction::CreateSessionModel( std::move(window)); } -bool SessionsGetRecentlyClosedFunction::RunSync() { +ExtensionFunction::ResponseAction SessionsGetRecentlyClosedFunction::Run() { std::unique_ptr<GetRecentlyClosed::Params> params( GetRecentlyClosed::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params); @@ -200,15 +198,15 @@ bool SessionsGetRecentlyClosedFunction::RunSync() { std::vector<api::sessions::Session> result; sessions::TabRestoreService* tab_restore_service = - TabRestoreServiceFactory::GetForProfile(GetProfile()); + TabRestoreServiceFactory::GetForProfile( + Profile::FromBrowserContext(browser_context())); // TabRestoreServiceFactory::GetForProfile() can return NULL (i.e., when in // incognito mode) if (!tab_restore_service) { - DCHECK_NE(GetProfile(), GetProfile()->GetOriginalProfile()) + DCHECK(browser_context()->IsOffTheRecord()) << "sessions::TabRestoreService expected for normal profiles"; - results_ = GetRecentlyClosed::Results::Create(result); - return true; + return RespondNow(ArgumentList(GetRecentlyClosed::Results::Create(result))); } // List of entries. They are ordered from most to least recent. @@ -218,8 +216,7 @@ bool SessionsGetRecentlyClosedFunction::RunSync() { result.push_back(std::move(*CreateSessionModel(*entry))); } - results_ = GetRecentlyClosed::Results::Create(result); - return true; + return RespondNow(ArgumentList(GetRecentlyClosed::Results::Create(result))); } tabs::Tab SessionsGetDevicesFunction::CreateTabModel( @@ -229,8 +226,8 @@ tabs::Tab SessionsGetDevicesFunction::CreateTabModel( bool active) { std::string session_id = SessionId(session_tag, tab.tab_id.id()).ToString(); return CreateTabModelHelper( - GetProfile(), tab.navigations[tab.normalized_navigation_index()], - session_id, tab_index, tab.pinned, active, extension()); + tab.navigations[tab.normalized_navigation_index()], session_id, tab_index, + tab.pinned, active, extension()); } std::unique_ptr<windows::Window> SessionsGetDevicesFunction::CreateWindowModel( @@ -247,7 +244,8 @@ std::unique_ptr<windows::Window> SessionsGetDevicesFunction::CreateWindowModel( continue; const sessions::SerializedNavigationEntry& current_navigation = tab->navigations.at(tab->normalized_navigation_index()); - if (search::IsNTPURL(current_navigation.virtual_url(), GetProfile())) { + if (search::IsNTPURL(current_navigation.virtual_url(), + Profile::FromBrowserContext(browser_context()))) { continue; } tabs_in_window.push_back(tab); @@ -347,23 +345,22 @@ api::sessions::Device SessionsGetDevicesFunction::CreateDeviceModel( return device_struct; } -bool SessionsGetDevicesFunction::RunSync() { +ExtensionFunction::ResponseAction SessionsGetDevicesFunction::Run() { browser_sync::ProfileSyncService* service = - ProfileSyncServiceFactory::GetInstance()->GetForProfile(GetProfile()); + ProfileSyncServiceFactory::GetInstance()->GetForProfile( + Profile::FromBrowserContext(browser_context())); if (!(service && service->GetPreferredDataTypes().Has(syncer::SESSIONS))) { // Sync not enabled. - results_ = - GetDevices::Results::Create(std::vector<api::sessions::Device>()); - return true; + return RespondNow(ArgumentList( + GetDevices::Results::Create(std::vector<api::sessions::Device>()))); } sync_sessions::OpenTabsUIDelegate* open_tabs = service->GetOpenTabsUIDelegate(); std::vector<const sync_sessions::SyncedSession*> sessions; if (!(open_tabs && open_tabs->GetAllForeignSessions(&sessions))) { - results_ = - GetDevices::Results::Create(std::vector<api::sessions::Device>()); - return true; + return RespondNow(ArgumentList( + GetDevices::Results::Create(std::vector<api::sessions::Device>()))); } std::unique_ptr<GetDevices::Params> params( @@ -380,51 +377,46 @@ bool SessionsGetDevicesFunction::RunSync() { for (size_t i = 0; i < sessions.size(); ++i) result.push_back(CreateDeviceModel(sessions[i])); - results_ = GetDevices::Results::Create(result); - return true; + return RespondNow(ArgumentList(GetDevices::Results::Create(result))); } -void SessionsRestoreFunction::SetInvalidIdError(const std::string& invalid_id) { - SetError(ErrorUtils::FormatErrorMessage(kInvalidSessionIdError, invalid_id)); -} - - -void SessionsRestoreFunction::SetResultRestoredTab( +ExtensionFunction::ResponseValue SessionsRestoreFunction::GetRestoredTabResult( content::WebContents* contents) { std::unique_ptr<tabs::Tab> tab( ExtensionTabUtil::CreateTabObject(contents, extension())); std::unique_ptr<api::sessions::Session> restored_session( CreateSessionModelHelper(base::Time::Now().ToTimeT(), std::move(tab), std::unique_ptr<windows::Window>())); - results_ = Restore::Results::Create(*restored_session); + return ArgumentList(Restore::Results::Create(*restored_session)); } -bool SessionsRestoreFunction::SetResultRestoredWindow(int window_id) { +ExtensionFunction::ResponseValue +SessionsRestoreFunction::GetRestoredWindowResult(int window_id) { WindowController* controller = NULL; + std::string error; if (!windows_util::GetWindowFromWindowID(this, window_id, 0, &controller, - &error_)) { - return false; + &error)) { + return Error(error); } std::unique_ptr<base::DictionaryValue> window_value( controller->CreateWindowValueWithTabs(extension())); std::unique_ptr<windows::Window> window( windows::Window::FromValue(*window_value)); - results_ = Restore::Results::Create(*CreateSessionModelHelper( + return ArgumentList(Restore::Results::Create(*CreateSessionModelHelper( base::Time::Now().ToTimeT(), std::unique_ptr<tabs::Tab>(), - std::move(window))); - return true; + std::move(window)))); } -bool SessionsRestoreFunction::RestoreMostRecentlyClosed(Browser* browser) { +ExtensionFunction::ResponseValue +SessionsRestoreFunction::RestoreMostRecentlyClosed(Browser* browser) { sessions::TabRestoreService* tab_restore_service = - TabRestoreServiceFactory::GetForProfile(GetProfile()); + TabRestoreServiceFactory::GetForProfile( + Profile::FromBrowserContext(browser_context())); const sessions::TabRestoreService::Entries& entries = tab_restore_service->entries(); - if (entries.empty()) { - SetError(kNoRecentlyClosedSessionsError); - return false; - } + if (entries.empty()) + return Error(kNoRecentlyClosedSessionsError); bool is_window = is_window_entry(*entries.front()); sessions::LiveTabContext* context = @@ -437,25 +429,24 @@ bool SessionsRestoreFunction::RestoreMostRecentlyClosed(Browser* browser) { sessions::ContentLiveTab* first_tab = static_cast<sessions::ContentLiveTab*>(restored_tabs[0]); if (is_window) { - return SetResultRestoredWindow( + return GetRestoredWindowResult( ExtensionTabUtil::GetWindowIdOfTab(first_tab->web_contents())); } - SetResultRestoredTab(first_tab->web_contents()); - return true; + return GetRestoredTabResult(first_tab->web_contents()); } -bool SessionsRestoreFunction::RestoreLocalSession(const SessionId& session_id, - Browser* browser) { +ExtensionFunction::ResponseValue SessionsRestoreFunction::RestoreLocalSession( + const SessionId& session_id, + Browser* browser) { sessions::TabRestoreService* tab_restore_service = - TabRestoreServiceFactory::GetForProfile(GetProfile()); + TabRestoreServiceFactory::GetForProfile( + Profile::FromBrowserContext(browser_context())); const sessions::TabRestoreService::Entries& entries = tab_restore_service->entries(); - if (entries.empty()) { - SetInvalidIdError(session_id.ToString()); - return false; - } + if (entries.empty()) + return Error(kInvalidSessionIdError, session_id.ToString()); // Check if the recently closed list contains an entry with the provided id. bool is_window = false; @@ -475,38 +466,33 @@ bool SessionsRestoreFunction::RestoreLocalSession(const SessionId& session_id, tab_restore_service->RestoreEntryById(context, session_id.id(), WindowOpenDisposition::UNKNOWN); // If the ID is invalid, restored_tabs will be empty. - if (restored_tabs.empty()) { - SetInvalidIdError(session_id.ToString()); - return false; - } + if (restored_tabs.empty()) + return Error(kInvalidSessionIdError, session_id.ToString()); sessions::ContentLiveTab* first_tab = static_cast<sessions::ContentLiveTab*>(restored_tabs[0]); // Retrieve the window through any of the tabs in restored_tabs. if (is_window) { - return SetResultRestoredWindow( + return GetRestoredWindowResult( ExtensionTabUtil::GetWindowIdOfTab(first_tab->web_contents())); } - SetResultRestoredTab(first_tab->web_contents()); - return true; + return GetRestoredTabResult(first_tab->web_contents()); } -bool SessionsRestoreFunction::RestoreForeignSession(const SessionId& session_id, - Browser* browser) { +ExtensionFunction::ResponseValue SessionsRestoreFunction::RestoreForeignSession( + const SessionId& session_id, + Browser* browser) { + Profile* profile = Profile::FromBrowserContext(browser_context()); browser_sync::ProfileSyncService* service = - ProfileSyncServiceFactory::GetInstance()->GetForProfile(GetProfile()); - if (!(service && service->GetPreferredDataTypes().Has(syncer::SESSIONS))) { - SetError(kSessionSyncError); - return false; - } + ProfileSyncServiceFactory::GetInstance()->GetForProfile(profile); + if (!(service && service->GetPreferredDataTypes().Has(syncer::SESSIONS))) + return Error(kSessionSyncError); sync_sessions::OpenTabsUIDelegate* open_tabs = service->GetOpenTabsUIDelegate(); - if (!open_tabs) { - SetError(kSessionSyncError); - return false; - } + if (!open_tabs) + return Error(kSessionSyncError); const sessions::SessionTab* tab = NULL; if (open_tabs->GetForeignTab(session_id.session_tag(), @@ -518,16 +504,13 @@ bool SessionsRestoreFunction::RestoreForeignSession(const SessionId& session_id, content::WebContents* tab_contents = SessionRestore::RestoreForeignSessionTab( contents, *tab, WindowOpenDisposition::NEW_FOREGROUND_TAB); - SetResultRestoredTab(tab_contents); - return true; + return GetRestoredTabResult(tab_contents); } // Restoring a full window. std::vector<const sessions::SessionWindow*> windows; - if (!open_tabs->GetForeignSession(session_id.session_tag(), &windows)) { - SetInvalidIdError(session_id.ToString()); - return false; - } + if (!open_tabs->GetForeignSession(session_id.session_tag(), &windows)) + return Error(kInvalidSessionIdError, session_id.ToString()); std::vector<const sessions::SessionWindow*>::const_iterator window = windows.begin(); @@ -535,46 +518,39 @@ bool SessionsRestoreFunction::RestoreForeignSession(const SessionId& session_id, && (*window)->window_id.id() != session_id.id()) { ++window; } - if (window == windows.end()) { - SetInvalidIdError(session_id.ToString()); - return false; - } + if (window == windows.end()) + return Error(kInvalidSessionIdError, session_id.ToString()); // Only restore one window at a time. - std::vector<Browser*> browsers = SessionRestore::RestoreForeignSessionWindows( - GetProfile(), window, window + 1); + std::vector<Browser*> browsers = + SessionRestore::RestoreForeignSessionWindows(profile, window, window + 1); // Will always create one browser because we only restore one window per call. DCHECK_EQ(1u, browsers.size()); - return SetResultRestoredWindow(ExtensionTabUtil::GetWindowId(browsers[0])); + return GetRestoredWindowResult(ExtensionTabUtil::GetWindowId(browsers[0])); } -bool SessionsRestoreFunction::RunSync() { +ExtensionFunction::ResponseAction SessionsRestoreFunction::Run() { std::unique_ptr<Restore::Params> params(Restore::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params); - Browser* browser = chrome::FindBrowserWithProfile(GetProfile()); - if (!browser) { - SetError(kNoBrowserToRestoreSession); - return false; - } + Profile* profile = Profile::FromBrowserContext(browser_context()); + Browser* browser = chrome::FindBrowserWithProfile(profile); + if (!browser) + return RespondNow(Error(kNoBrowserToRestoreSession)); - if (GetProfile() != GetProfile()->GetOriginalProfile()) { - SetError(kRestoreInIncognitoError); - return false; - } + if (profile != profile->GetOriginalProfile()) + return RespondNow(Error(kRestoreInIncognitoError)); if (!params->session_id) - return RestoreMostRecentlyClosed(browser); + return RespondNow(RestoreMostRecentlyClosed(browser)); std::unique_ptr<SessionId> session_id(SessionId::Parse(*params->session_id)); - if (!session_id) { - SetInvalidIdError(*params->session_id); - return false; - } + if (!session_id) + return RespondNow(Error(kInvalidSessionIdError, *params->session_id)); - return session_id->IsForeign() ? - RestoreForeignSession(*session_id, browser) - : RestoreLocalSession(*session_id, browser); + return RespondNow(session_id->IsForeign() + ? RestoreForeignSession(*session_id, browser) + : RestoreLocalSession(*session_id, browser)); } SessionsEventRouter::SessionsEventRouter(Profile* profile) diff --git a/chromium/chrome/browser/extensions/api/sessions/sessions_api.h b/chromium/chrome/browser/extensions/api/sessions/sessions_api.h index 6f8480581b6..d859f6434bb 100644 --- a/chromium/chrome/browser/extensions/api/sessions/sessions_api.h +++ b/chromium/chrome/browser/extensions/api/sessions/sessions_api.h @@ -27,10 +27,10 @@ namespace extensions { class SessionId; -class SessionsGetRecentlyClosedFunction : public ChromeSyncExtensionFunction { +class SessionsGetRecentlyClosedFunction : public UIThreadExtensionFunction { protected: ~SessionsGetRecentlyClosedFunction() override {} - bool RunSync() override; + ResponseAction Run() override; DECLARE_EXTENSION_FUNCTION("sessions.getRecentlyClosed", SESSIONS_GETRECENTLYCLOSED) @@ -43,10 +43,10 @@ class SessionsGetRecentlyClosedFunction : public ChromeSyncExtensionFunction { const sessions::TabRestoreService::Entry& entry); }; -class SessionsGetDevicesFunction : public ChromeSyncExtensionFunction { +class SessionsGetDevicesFunction : public UIThreadExtensionFunction { protected: ~SessionsGetDevicesFunction() override {} - bool RunSync() override; + ResponseAction Run() override; DECLARE_EXTENSION_FUNCTION("sessions.getDevices", SESSIONS_GETDEVICES) private: @@ -64,20 +64,20 @@ class SessionsGetDevicesFunction : public ChromeSyncExtensionFunction { const sync_sessions::SyncedSession* session); }; -class SessionsRestoreFunction : public ChromeSyncExtensionFunction { +class SessionsRestoreFunction : public UIThreadExtensionFunction { protected: ~SessionsRestoreFunction() override {} - bool RunSync() override; + ResponseAction Run() override; DECLARE_EXTENSION_FUNCTION("sessions.restore", SESSIONS_RESTORE) private: - void SetInvalidIdError(const std::string& invalid_id); - void SetResultRestoredTab(content::WebContents* contents); - bool SetResultRestoredWindow(int window_id); - bool RestoreMostRecentlyClosed(Browser* browser); - bool RestoreLocalSession(const SessionId& session_id, Browser* browser); - bool RestoreForeignSession(const SessionId& session_id, - Browser* browser); + ResponseValue GetRestoredTabResult(content::WebContents* contents); + ResponseValue GetRestoredWindowResult(int window_id); + ResponseValue RestoreMostRecentlyClosed(Browser* browser); + ResponseValue RestoreLocalSession(const SessionId& session_id, + Browser* browser); + ResponseValue RestoreForeignSession(const SessionId& session_id, + Browser* browser); }; class SessionsEventRouter : public sessions::TabRestoreServiceObserver { diff --git a/chromium/chrome/browser/extensions/api/sessions/sessions_apitest.cc b/chromium/chrome/browser/extensions/api/sessions/sessions_apitest.cc index b510b29b875..9abe2efa2d9 100644 --- a/chromium/chrome/browser/extensions/api/sessions/sessions_apitest.cc +++ b/chromium/chrome/browser/extensions/api/sessions/sessions_apitest.cc @@ -27,12 +27,12 @@ #include "chrome/test/base/testing_browser_process.h" #include "components/browser_sync/profile_sync_service.h" #include "components/browser_sync/profile_sync_service_mock.h" -#include "components/sync/api/attachments/attachment_id.h" -#include "components/sync/api/fake_sync_change_processor.h" -#include "components/sync/api/sync_error_factory_mock.h" -#include "components/sync/core/attachments/attachment_service_proxy_for_test.h" #include "components/sync/device_info/local_device_info_provider_mock.h" #include "components/sync/driver/sync_api_component_factory_mock.h" +#include "components/sync/model/attachments/attachment_id.h" +#include "components/sync/model/attachments/attachment_service_proxy_for_test.h" +#include "components/sync/model/fake_sync_change_processor.h" +#include "components/sync/model/sync_error_factory_mock.h" #include "components/sync_sessions/sessions_sync_manager.h" #include "extensions/browser/api_test_utils.h" @@ -217,11 +217,12 @@ void ExtensionSessionsTest::CreateTestProfileSyncService() { ProfileSyncServiceFactory::GetInstance()->SetTestingFactoryAndUse( profile, &ExtensionSessionsTest::BuildProfileSyncService)); - syncer::ModelTypeSet preferred_types; - preferred_types.Put(syncer::SESSIONS); + syncer::ModelTypeSet preferred_types(syncer::SESSIONS, syncer::PROXY_TABS); GoogleServiceAuthError no_error(GoogleServiceAuthError::NONE); ON_CALL(*service, IsDataTypeControllerRunning(syncer::SESSIONS)) .WillByDefault(testing::Return(true)); + ON_CALL(*service, IsDataTypeControllerRunning(syncer::PROXY_TABS)) + .WillByDefault(testing::Return(true)); ON_CALL(*service, GetRegisteredDataTypes()) .WillByDefault(testing::Return(syncer::UserTypes())); ON_CALL(*service, GetPreferredDataTypes()).WillByDefault( diff --git a/chromium/chrome/browser/extensions/api/settings_private/OWNERS b/chromium/chrome/browser/extensions/api/settings_private/OWNERS index 057813143a1..e07a545d3ee 100644 --- a/chromium/chrome/browser/extensions/api/settings_private/OWNERS +++ b/chromium/chrome/browser/extensions/api/settings_private/OWNERS @@ -1,2 +1,3 @@ michaelpg@chromium.org stevenjb@chromium.org +dbeam@chromium.org diff --git a/chromium/chrome/browser/extensions/api/settings_private/prefs_util.cc b/chromium/chrome/browser/extensions/api/settings_private/prefs_util.cc index e64b8ece704..e2f86c70b4a 100644 --- a/chromium/chrome/browser/extensions/api/settings_private/prefs_util.cc +++ b/chromium/chrome/browser/extensions/api/settings_private/prefs_util.cc @@ -7,14 +7,29 @@ #include "build/build_config.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/chrome_extension_function.h" +#include "chrome/browser/extensions/settings_api_helpers.h" +#include "chrome/browser/prefs/session_startup_pref.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/pref_names.h" +#include "components/autofill/core/common/autofill_pref_names.h" +#include "components/bookmarks/common/bookmark_pref_names.h" +#include "components/browsing_data/core/pref_names.h" +#include "components/content_settings/core/common/pref_names.h" +#include "components/drive/drive_pref_names.h" +#include "components/password_manager/core/common/password_manager_pref_names.h" #include "components/prefs/pref_service.h" #include "components/proxy_config/proxy_config_pref_names.h" +#include "components/safe_browsing_db/safe_browsing_prefs.h" +#include "components/search_engines/search_engines_pref_names.h" +#include "components/spellcheck/browser/pref_names.h" +#include "components/translate/core/browser/translate_prefs.h" +#include "components/translate/core/common/translate_pref_names.h" #include "components/url_formatter/url_fixer.h" #include "extensions/browser/extension_pref_value_map.h" #include "extensions/browser/extension_pref_value_map_factory.h" #include "extensions/browser/extension_registry.h" +#include "extensions/browser/extension_system.h" +#include "extensions/browser/management_policy.h" #include "extensions/common/extension.h" #if defined(OS_CHROMEOS) @@ -59,260 +74,267 @@ const PrefsUtil::TypedPrefMap& PrefsUtil::GetWhitelistedKeys() { static PrefsUtil::TypedPrefMap* s_whitelist = nullptr; if (s_whitelist) return *s_whitelist; - // TODO(dbeam): why aren't we using kPrefName from pref_names.h? s_whitelist = new PrefsUtil::TypedPrefMap(); - (*s_whitelist)["alternate_error_pages.enabled"] = + + // Miscellaneous + (*s_whitelist)[::prefs::kAlternateErrorPagesEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["autofill.enabled"] = + (*s_whitelist)[autofill::prefs::kAutofillEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["bookmark_bar.show_on_all_tabs"] = + (*s_whitelist)[bookmarks::prefs::kShowBookmarkBar] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["browser.custom_chrome_frame"] = +#if defined(OS_LINUX) && !defined(OS_CHROMEOS) + (*s_whitelist)[::prefs::kUseCustomChromeFrame] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["browser.show_home_button"] = +#endif + (*s_whitelist)[::prefs::kShowHomeButton] = settings_private::PrefType::PREF_TYPE_BOOLEAN; // Appearance settings. - (*s_whitelist)["extensions.theme.id"] = + (*s_whitelist)[::prefs::kCurrentThemeID] = settings_private::PrefType::PREF_TYPE_STRING; - (*s_whitelist)["webkit.webprefs.default_fixed_font_size"] = +#if defined(OS_LINUX) && !defined(OS_CHROMEOS) + (*s_whitelist)[::prefs::kUsesSystemTheme] = + settings_private::PrefType::PREF_TYPE_BOOLEAN; +#endif + (*s_whitelist)[::prefs::kHomePage] = + settings_private::PrefType::PREF_TYPE_URL; + (*s_whitelist)[::prefs::kHomePageIsNewTabPage] = + settings_private::PrefType::PREF_TYPE_BOOLEAN; + (*s_whitelist)[::prefs::kWebKitDefaultFixedFontSize] = settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["webkit.webprefs.default_font_size"] = + (*s_whitelist)[::prefs::kWebKitDefaultFontSize] = settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["webkit.webprefs.minimum_font_size"] = + (*s_whitelist)[::prefs::kWebKitMinimumFontSize] = settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["webkit.webprefs.fonts.fixed.Zyyy"] = + (*s_whitelist)[::prefs::kWebKitFixedFontFamily] = settings_private::PrefType::PREF_TYPE_STRING; - (*s_whitelist)["webkit.webprefs.fonts.sansserif.Zyyy"] = + (*s_whitelist)[::prefs::kWebKitSansSerifFontFamily] = settings_private::PrefType::PREF_TYPE_STRING; - (*s_whitelist)["webkit.webprefs.fonts.serif.Zyyy"] = + (*s_whitelist)[::prefs::kWebKitSerifFontFamily] = settings_private::PrefType::PREF_TYPE_STRING; - (*s_whitelist)["webkit.webprefs.fonts.standard.Zyyy"] = + (*s_whitelist)[::prefs::kWebKitStandardFontFamily] = settings_private::PrefType::PREF_TYPE_STRING; - (*s_whitelist)["intl.charset_default"] = + (*s_whitelist)[::prefs::kDefaultCharset] = settings_private::PrefType::PREF_TYPE_STRING; + // On startup. + (*s_whitelist)[::prefs::kRestoreOnStartup] = + settings_private::PrefType::PREF_TYPE_NUMBER; + (*s_whitelist)[::prefs::kURLsToRestoreOnStartup] = + settings_private::PrefType::PREF_TYPE_LIST; + // Downloads settings. - (*s_whitelist)["download.default_directory"] = + (*s_whitelist)[::prefs::kDownloadDefaultDirectory] = settings_private::PrefType::PREF_TYPE_STRING; - (*s_whitelist)["download.prompt_for_download"] = + (*s_whitelist)[::prefs::kPromptForDownload] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["gdata.disabled"] = + (*s_whitelist)[drive::prefs::kDisableDrive] = settings_private::PrefType::PREF_TYPE_BOOLEAN; // Printing settings. - (*s_whitelist)["local_discovery.notifications_enabled"] = + (*s_whitelist)[::prefs::kLocalDiscoveryNotificationsEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["enable_do_not_track"] = - settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["homepage"] = settings_private::PrefType::PREF_TYPE_URL; - (*s_whitelist)["homepage_is_newtabpage"] = + // Miscellaneous. TODO(stevenjb): categorize. + (*s_whitelist)[::prefs::kEnableDoNotTrack] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["intl.app_locale"] = + (*s_whitelist)[::prefs::kApplicationLocale] = settings_private::PrefType::PREF_TYPE_STRING; - (*s_whitelist)["net.network_prediction_options"] = + (*s_whitelist)[::prefs::kNetworkPredictionOptions] = settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["profile.password_manager_enabled"] = + (*s_whitelist)[password_manager::prefs::kPasswordManagerSavingEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["credentials_enable_autosignin"] = + (*s_whitelist)[password_manager::prefs::kCredentialsEnableAutosignin] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["safebrowsing.enabled"] = + (*s_whitelist)[::prefs::kSafeBrowsingEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["safebrowsing.extended_reporting_enabled"] = + (*s_whitelist)[::prefs::kSafeBrowsingExtendedReportingEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["search.suggest_enabled"] = + (*s_whitelist)[::prefs::kSearchSuggestEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["session.restore_on_startup"] = - settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["session.startup_urls"] = + (*s_whitelist)[spellcheck::prefs::kSpellCheckDictionaries] = settings_private::PrefType::PREF_TYPE_LIST; - (*s_whitelist)["spellcheck.dictionaries"] = - settings_private::PrefType::PREF_TYPE_LIST; - (*s_whitelist)["spellcheck.use_spelling_service"] = + (*s_whitelist)[spellcheck::prefs::kSpellCheckUseSpellingService] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["translate.enabled"] = + (*s_whitelist)[::prefs::kEnableTranslate] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["translate_blocked_languages"] = + (*s_whitelist)[translate::TranslatePrefs::kPrefTranslateBlockedLanguages] = settings_private::PrefType::PREF_TYPE_LIST; // Site Settings prefs. - (*s_whitelist)["profile.block_third_party_cookies"] = + (*s_whitelist)[::prefs::kBlockThirdPartyCookies] = + settings_private::PrefType::PREF_TYPE_BOOLEAN; + (*s_whitelist)[::prefs::kPluginsAlwaysOpenPdfExternally] = settings_private::PrefType::PREF_TYPE_BOOLEAN; // Clear browsing data settings. - (*s_whitelist)["browser.clear_data.browsing_history"] = + (*s_whitelist)[browsing_data::prefs::kDeleteBrowsingHistory] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["browser.clear_data.download_history"] = + (*s_whitelist)[browsing_data::prefs::kDeleteDownloadHistory] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["browser.clear_data.cache"] = + (*s_whitelist)[browsing_data::prefs::kDeleteCache] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["browser.clear_data.cookies"] = + (*s_whitelist)[browsing_data::prefs::kDeleteCookies] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["browser.clear_data.passwords"] = + (*s_whitelist)[browsing_data::prefs::kDeletePasswords] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["browser.clear_data.form_data"] = + (*s_whitelist)[browsing_data::prefs::kDeleteFormData] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["browser.clear_data.hosted_apps_data"] = + (*s_whitelist)[browsing_data::prefs::kDeleteHostedAppsData] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["browser.clear_data.media_licenses"] = + (*s_whitelist)[browsing_data::prefs::kDeleteMediaLicenses] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["browser.clear_data.time_period"] = - settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["profile.default_content_setting_values.cookies"] = + (*s_whitelist)[browsing_data::prefs::kDeleteTimePeriod] = settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["profile.default_content_setting_values.fullscreen"] = - settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["profile.default_content_setting_values.geolocation"] = - settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["profile.default_content_setting_values.images"] = - settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["profile.default_content_setting_values.javascript"] = - settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["profile.default_content_setting_values.media_stream_camera"] = - settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["profile.default_content_setting_values.media_stream_mic"] = - settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["profile.default_content_setting_values.notifications"] = - settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["profile.default_content_setting_values.popups"] = - settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["profile.content_settings.exceptions.cookies"] = - settings_private::PrefType::PREF_TYPE_DICTIONARY; - (*s_whitelist)["profile.content_settings.exceptions.fullscreen"] = - settings_private::PrefType::PREF_TYPE_DICTIONARY; - (*s_whitelist)["profile.content_settings.exceptions.geolocation"] = - settings_private::PrefType::PREF_TYPE_DICTIONARY; - (*s_whitelist)["profile.content_settings.exceptions.images"] = - settings_private::PrefType::PREF_TYPE_DICTIONARY; - (*s_whitelist)["profile.content_settings.exceptions.javascript"] = - settings_private::PrefType::PREF_TYPE_DICTIONARY; - (*s_whitelist)["profile.content_settings.exceptions.media_stream_camera"] = - settings_private::PrefType::PREF_TYPE_DICTIONARY; - (*s_whitelist)["profile.content_settings.exceptions.media_stream_mic"] = - settings_private::PrefType::PREF_TYPE_DICTIONARY; - (*s_whitelist)["profile.content_settings.exceptions.notifications"] = - settings_private::PrefType::PREF_TYPE_DICTIONARY; - (*s_whitelist)["profile.content_settings.exceptions.popups"] = - settings_private::PrefType::PREF_TYPE_DICTIONARY; #if defined(OS_CHROMEOS) - (*s_whitelist)["cros.accounts.allowBWSI"] = + // Accounts / Users / People. + (*s_whitelist)[chromeos::kAccountsPrefAllowGuest] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["cros.accounts.supervisedUsersEnabled"] = + (*s_whitelist)[chromeos::kAccountsPrefSupervisedUsersEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["cros.accounts.showUserNamesOnSignIn"] = + (*s_whitelist)[chromeos::kAccountsPrefShowUserNamesOnSignIn] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["cros.accounts.allowGuest"] = + (*s_whitelist)[chromeos::kAccountsPrefAllowNewUser] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["cros.accounts.users"] = + (*s_whitelist)[chromeos::kAccountsPrefUsers] = settings_private::PrefType::PREF_TYPE_LIST; - (*s_whitelist)["settings.accessibility"] = + (*s_whitelist)[::prefs::kEnableAutoScreenLock] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.a11y.autoclick"] = + + // Accessibility. + (*s_whitelist)[::prefs::kAccessibilitySpokenFeedbackEnabled] = + settings_private::PrefType::PREF_TYPE_BOOLEAN; + (*s_whitelist)[::prefs::kAccessibilityAutoclickEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.a11y.autoclick_delay_ms"] = + (*s_whitelist)[::prefs::kAccessibilityAutoclickDelayMs] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.a11y.caret_highlight"] = + (*s_whitelist)[::prefs::kAccessibilityCaretHighlightEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.a11y.cursor_highlight"] = + (*s_whitelist)[::prefs::kAccessibilityCursorHighlightEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.a11y.enable_menu"] = + (*s_whitelist)[::prefs::kShouldAlwaysShowAccessibilityMenu] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.a11y.focus_highlight"] = + (*s_whitelist)[::prefs::kAccessibilityFocusHighlightEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.a11y.high_contrast_enabled"] = + (*s_whitelist)[::prefs::kAccessibilityHighContrastEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.a11y.large_cursor_enabled"] = + (*s_whitelist)[::prefs::kAccessibilityLargeCursorEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.a11y.screen_magnifier"] = + (*s_whitelist)[::prefs::kAccessibilityScreenMagnifierEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.a11y.select_to_speak"] = + (*s_whitelist)[::prefs::kAccessibilitySelectToSpeakEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.a11y.sticky_keys_enabled"] = + (*s_whitelist)[::prefs::kAccessibilityStickyKeysEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.a11y.switch_access"] = + (*s_whitelist)[::prefs::kAccessibilitySwitchAccessEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.a11y.virtual_keyboard"] = + (*s_whitelist)[::prefs::kAccessibilityVirtualKeyboardEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.a11y.mono_audio"] = + (*s_whitelist)[::prefs::kAccessibilityMonoAudioEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.clock.use_24hour_clock"] = + + // Misc. + (*s_whitelist)[::prefs::kUse24HourClock] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.language.preferred_languages"] = + (*s_whitelist)[::prefs::kLanguagePreferredLanguages] = settings_private::PrefType::PREF_TYPE_STRING; - (*s_whitelist)["settings.touchpad.enable_tap_dragging"] = + (*s_whitelist)[::prefs::kTapDraggingEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["cros.metrics.reportingEnabled"] = + (*s_whitelist)[chromeos::kStatsReportingPref] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["cros.device.allow_bluetooth"] = + (*s_whitelist)[chromeos::kAttestationForContentProtectionEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["cros.device.attestation_for_content_protection_enabled"] = + + // Bluetooth & Internet settings. + (*s_whitelist)[chromeos::kAllowBluetooth] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.internet.wake_on_wifi_darkconnect"] = + (*s_whitelist)[proxy_config::prefs::kUseSharedProxies] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.enable_screen_lock"] = + (*s_whitelist)[::prefs::kWakeOnWifiDarkConnect] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - // Time zone settings. - (*s_whitelist)["settings.resolve_timezone_by_geolocation"] = + // Timezone settings. + (*s_whitelist)[chromeos::kSystemTimezone] = + settings_private::PrefType::PREF_TYPE_BOOLEAN; + (*s_whitelist)[::prefs::kResolveTimezoneByGeolocation] = settings_private::PrefType::PREF_TYPE_BOOLEAN; // Ash settings. - (*s_whitelist)["settings.enable_stylus_tools"] = + (*s_whitelist)[::prefs::kEnableStylusTools] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.launch_palette_on_eject_event"] = + (*s_whitelist)[::prefs::kLaunchPaletteOnEjectEvent] = settings_private::PrefType::PREF_TYPE_BOOLEAN; // Input method settings. - (*s_whitelist)["settings.language.preload_engines"] = + (*s_whitelist)[::prefs::kLanguagePreloadEngines] = settings_private::PrefType::PREF_TYPE_STRING; - (*s_whitelist)["settings.language.enabled_extension_imes"] = + (*s_whitelist)[::prefs::kLanguageEnabledExtensionImes] = settings_private::PrefType::PREF_TYPE_STRING; // Device settings. - (*s_whitelist)["settings.touchpad.enable_tap_to_click"] = + (*s_whitelist)[::prefs::kTapToClickEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.touchpad.natural_scroll"] = + (*s_whitelist)[::prefs::kNaturalScroll] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.touchpad.sensitivity2"] = + (*s_whitelist)[::prefs::kTouchpadSensitivity] = settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["settings.mouse.primary_right"] = + (*s_whitelist)[::prefs::kPrimaryMouseButtonRight] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.mouse.sensitivity2"] = + (*s_whitelist)[::prefs::kMouseSensitivity] = + settings_private::PrefType::PREF_TYPE_NUMBER; + (*s_whitelist)[::prefs::kLanguageRemapSearchKeyTo] = settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["settings.language.xkb_remap_search_key_to"] = + (*s_whitelist)[::prefs::kLanguageRemapControlKeyTo] = settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["settings.language.xkb_remap_control_key_to"] = + (*s_whitelist)[::prefs::kLanguageRemapAltKeyTo] = settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["settings.language.xkb_remap_alt_key_to"] = + (*s_whitelist)[::prefs::kLanguageRemapCapsLockKeyTo] = settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["settings.language.remap_caps_lock_key_to"] = + (*s_whitelist)[::prefs::kLanguageRemapBackspaceKeyTo] = settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["settings.language.remap_diamond_key_to"] = + (*s_whitelist)[::prefs::kLanguageRemapEscapeKeyTo] = settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["settings.language.send_function_keys"] = + (*s_whitelist)[::prefs::kLanguageRemapDiamondKeyTo] = + settings_private::PrefType::PREF_TYPE_NUMBER; + (*s_whitelist)[::prefs::kLanguageSendFunctionKeys] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.language.xkb_auto_repeat_enabled_r2"] = + (*s_whitelist)[::prefs::kLanguageXkbAutoRepeatEnabled] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["settings.language.xkb_auto_repeat_delay_r2"] = + (*s_whitelist)[::prefs::kLanguageXkbAutoRepeatDelay] = settings_private::PrefType::PREF_TYPE_NUMBER; - (*s_whitelist)["settings.language.xkb_auto_repeat_interval_r2"] = + (*s_whitelist)[::prefs::kLanguageXkbAutoRepeatInterval] = settings_private::PrefType::PREF_TYPE_NUMBER; #else - (*s_whitelist)["intl.accept_languages"] = + (*s_whitelist)[::prefs::kAcceptLanguages] = settings_private::PrefType::PREF_TYPE_STRING; // System settings. - (*s_whitelist)["background_mode.enabled"] = + (*s_whitelist)[::prefs::kBackgroundModeEnabled] = + settings_private::PrefType::PREF_TYPE_BOOLEAN; + (*s_whitelist)[::prefs::kHardwareAccelerationModeEnabled] = + settings_private::PrefType::PREF_TYPE_BOOLEAN; + + // Import data + (*s_whitelist)[::prefs::kImportAutofillFormData] = + settings_private::PrefType::PREF_TYPE_BOOLEAN; + (*s_whitelist)[::prefs::kImportBookmarks] = + settings_private::PrefType::PREF_TYPE_BOOLEAN; + (*s_whitelist)[::prefs::kImportHistory] = + settings_private::PrefType::PREF_TYPE_BOOLEAN; + (*s_whitelist)[::prefs::kImportSavedPasswords] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["hardware_acceleration_mode.enabled"] = + (*s_whitelist)[::prefs::kImportSearchEngine] = settings_private::PrefType::PREF_TYPE_BOOLEAN; - (*s_whitelist)["proxy"] = settings_private::PrefType::PREF_TYPE_DICTIONARY; #endif + // Proxy settings. + (*s_whitelist)[proxy_config::prefs::kProxy] = + settings_private::PrefType::PREF_TYPE_DICTIONARY; + #if defined(GOOGLE_CHROME_BUILD) - (*s_whitelist)["media_router.cloudservices.enabled"] = + (*s_whitelist)[::prefs::kMediaRouterEnableCloudServices] = settings_private::PrefType::PREF_TYPE_BOOLEAN; #endif // defined(GOOGLE_CHROME_BUILD) @@ -374,37 +396,42 @@ std::unique_ptr<settings_private::PrefObject> PrefsUtil::GetPref( #if defined(OS_CHROMEOS) if (IsPrefPrimaryUserControlled(name)) { - pref_object->policy_source = - settings_private::PolicySource::POLICY_SOURCE_PRIMARY_USER; - pref_object->policy_enforcement = - settings_private::PolicyEnforcement::POLICY_ENFORCEMENT_ENFORCED; - pref_object->policy_source_name.reset(new std::string( - user_manager::UserManager::Get()->GetPrimaryUser()->email())); + pref_object->controlled_by = + settings_private::ControlledBy::CONTROLLED_BY_PRIMARY_USER; + pref_object->enforcement = + settings_private::Enforcement::ENFORCEMENT_ENFORCED; + pref_object->controlled_by_name.reset( + new std::string(user_manager::UserManager::Get() + ->GetPrimaryUser() + ->GetAccountId() + .GetUserEmail())); return pref_object; } + if (IsPrefEnterpriseManaged(name)) { // Enterprise managed prefs are treated the same as device policy restricted // prefs in the UI. - pref_object->policy_source = - settings_private::PolicySource::POLICY_SOURCE_DEVICE_POLICY; - pref_object->policy_enforcement = - settings_private::PolicyEnforcement::POLICY_ENFORCEMENT_ENFORCED; + pref_object->controlled_by = + settings_private::ControlledBy::CONTROLLED_BY_DEVICE_POLICY; + pref_object->enforcement = + settings_private::Enforcement::ENFORCEMENT_ENFORCED; return pref_object; } #endif if (pref && pref->IsManaged()) { - pref_object->policy_source = - settings_private::PolicySource::POLICY_SOURCE_USER_POLICY; - pref_object->policy_enforcement = - settings_private::PolicyEnforcement::POLICY_ENFORCEMENT_ENFORCED; + pref_object->controlled_by = + settings_private::ControlledBy::CONTROLLED_BY_USER_POLICY; + pref_object->enforcement = + settings_private::Enforcement::ENFORCEMENT_ENFORCED; return pref_object; } + if (pref && pref->IsRecommended()) { - pref_object->policy_source = - settings_private::PolicySource::POLICY_SOURCE_USER_POLICY; - pref_object->policy_enforcement = - settings_private::PolicyEnforcement::POLICY_ENFORCEMENT_RECOMMENDED; + pref_object->controlled_by = + settings_private::ControlledBy::CONTROLLED_BY_USER_POLICY; + pref_object->enforcement = + settings_private::Enforcement::ENFORCEMENT_RECOMMENDED; pref_object->recommended_value.reset( pref->GetRecommendedValue()->DeepCopy()); return pref_object; @@ -416,38 +443,32 @@ std::unique_ptr<settings_private::PrefObject> PrefsUtil::GetPref( // device policy there is no "owner". (In the unlikely case that both // situations apply, either badge is potentially relevant, so the order // is somewhat arbitrary). - pref_object->policy_source = - settings_private::PolicySource::POLICY_SOURCE_OWNER; - pref_object->policy_enforcement = - settings_private::PolicyEnforcement::POLICY_ENFORCEMENT_ENFORCED; - pref_object->policy_source_name.reset(new std::string( + pref_object->controlled_by = + settings_private::ControlledBy::CONTROLLED_BY_OWNER; + pref_object->enforcement = + settings_private::Enforcement::ENFORCEMENT_ENFORCED; + pref_object->controlled_by_name.reset(new std::string( user_manager::UserManager::Get()->GetOwnerAccountId().GetUserEmail())); return pref_object; } #endif - if (pref && pref->IsExtensionControlled()) { - std::string extension_id = - ExtensionPrefValueMapFactory::GetForBrowserContext(profile_) - ->GetExtensionControllingPref(pref->name()); - const Extension* extension = ExtensionRegistry::Get(profile_)-> - GetExtensionById(extension_id, ExtensionRegistry::ENABLED); - if (extension) { - pref_object->policy_source = - settings_private::PolicySource::POLICY_SOURCE_EXTENSION; - pref_object->policy_enforcement = - settings_private::PolicyEnforcement::POLICY_ENFORCEMENT_ENFORCED; - pref_object->extension_id.reset(new std::string(extension_id)); - pref_object->policy_source_name.reset(new std::string(extension->name())); - return pref_object; - } - } - if (pref && (!pref->IsUserModifiable() || IsPrefSupervisorControlled(name))) { - // TODO(stevenjb): Investigate whether either of these should be badged. - pref_object->read_only.reset(new bool(true)); + const Extension* extension = GetExtensionControllingPref(*pref_object); + if (extension) { + pref_object->controlled_by = + settings_private::ControlledBy::CONTROLLED_BY_EXTENSION; + pref_object->enforcement = + settings_private::Enforcement::ENFORCEMENT_ENFORCED; + pref_object->extension_id.reset(new std::string(extension->id())); + pref_object->controlled_by_name.reset(new std::string(extension->name())); + bool can_be_disabled = !ExtensionSystem::Get(profile_)->management_policy() + ->MustRemainEnabled(extension, nullptr); + pref_object->extension_can_be_disabled.reset(new bool(can_be_disabled)); return pref_object; } + // TODO(dbeam): surface !IsUserModifiable or IsPrefSupervisorControlled? + return pref_object; } @@ -603,7 +624,8 @@ bool PrefsUtil::IsPrefPrimaryUserControlled(const std::string& pref_name) { user_manager::UserManager* user_manager = user_manager::UserManager::Get(); const user_manager::User* user = chromeos::ProfileHelper::Get()->GetUserByProfile(profile_); - if (user && user->email() != user_manager->GetPrimaryUser()->email()) + if (user && + user->GetAccountId() != user_manager->GetPrimaryUser()->GetAccountId()) return true; } return false; @@ -668,4 +690,19 @@ bool PrefsUtil::IsCrosSetting(const std::string& pref_name) { #endif } +const Extension* PrefsUtil::GetExtensionControllingPref( + const settings_private::PrefObject& pref_object) { + // Look for specific prefs that might be extension controlled. This generally + // corresponds with some indiciator that should be shown in the settings UI. + if (pref_object.key == ::prefs::kHomePage) + return GetExtensionOverridingHomepage(profile_); + if (pref_object.key == ::prefs::kURLsToRestoreOnStartup) + return GetExtensionOverridingStartupPages(profile_); + if (pref_object.key == ::prefs::kDefaultSearchProviderEnabled) + return GetExtensionOverridingSearchEngine(profile_); + if (pref_object.key == proxy_config::prefs::kProxy) + return GetExtensionOverridingProxy(profile_); + return nullptr; +} + } // namespace extensions diff --git a/chromium/chrome/browser/extensions/api/settings_private/prefs_util.h b/chromium/chrome/browser/extensions/api/settings_private/prefs_util.h index 321a5c9e88f..a2f229e0862 100644 --- a/chromium/chrome/browser/extensions/api/settings_private/prefs_util.h +++ b/chromium/chrome/browser/extensions/api/settings_private/prefs_util.h @@ -17,6 +17,7 @@ class PrefService; class Profile; namespace extensions { +class Extension; class PrefsUtil { @@ -102,6 +103,10 @@ class PrefsUtil { SetPrefResult SetCrosSettingsPref(const std::string& name, const base::Value* value); + private: + const Extension* GetExtensionControllingPref( + const api::settings_private::PrefObject& pref_object); + Profile* profile_; // weak }; diff --git a/chromium/chrome/browser/extensions/api/settings_private/settings_private_api.cc b/chromium/chrome/browser/extensions/api/settings_private/settings_private_api.cc index e2b23743721..a73f78f8d83 100644 --- a/chromium/chrome/browser/extensions/api/settings_private/settings_private_api.cc +++ b/chromium/chrome/browser/extensions/api/settings_private/settings_private_api.cc @@ -106,37 +106,36 @@ ExtensionFunction::ResponseAction SettingsPrivateGetPrefFunction::Run() { } //////////////////////////////////////////////////////////////////////////////// -// SettingsPrivateGetDefaultZoomPercentFunction +// SettingsPrivateGetDefaultZoomFunction //////////////////////////////////////////////////////////////////////////////// -SettingsPrivateGetDefaultZoomPercentFunction:: - ~SettingsPrivateGetDefaultZoomPercentFunction() { +SettingsPrivateGetDefaultZoomFunction:: + ~SettingsPrivateGetDefaultZoomFunction() { } ExtensionFunction::ResponseAction - SettingsPrivateGetDefaultZoomPercentFunction::Run() { + SettingsPrivateGetDefaultZoomFunction::Run() { SettingsPrivateDelegate* delegate = SettingsPrivateDelegateFactory::GetForBrowserContext(browser_context()); if (delegate == nullptr) return RespondNow(Error(kDelegateIsNull)); else - return RespondNow(OneArgument(delegate->GetDefaultZoomPercent())); + return RespondNow(OneArgument(delegate->GetDefaultZoom())); } //////////////////////////////////////////////////////////////////////////////// -// SettingsPrivateSetDefaultZoomPercentFunction +// SettingsPrivateSetDefaultZoomFunction //////////////////////////////////////////////////////////////////////////////// -SettingsPrivateSetDefaultZoomPercentFunction:: - ~SettingsPrivateSetDefaultZoomPercentFunction() { +SettingsPrivateSetDefaultZoomFunction:: + ~SettingsPrivateSetDefaultZoomFunction() { } ExtensionFunction::ResponseAction - SettingsPrivateSetDefaultZoomPercentFunction::Run() { - std::unique_ptr<api::settings_private::SetDefaultZoomPercent::Params> - parameters = - api::settings_private::SetDefaultZoomPercent::Params::Create(*args_); + SettingsPrivateSetDefaultZoomFunction::Run() { + std::unique_ptr<api::settings_private::SetDefaultZoom::Params> parameters = + api::settings_private::SetDefaultZoom::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(parameters.get()); SettingsPrivateDelegate* delegate = @@ -144,7 +143,7 @@ ExtensionFunction::ResponseAction if (delegate == nullptr) return RespondNow(Error(kDelegateIsNull)); - delegate->SetDefaultZoomPercent(parameters->percent); + delegate->SetDefaultZoom(parameters->zoom); return RespondNow( OneArgument(base::MakeUnique<base::FundamentalValue>(true))); } diff --git a/chromium/chrome/browser/extensions/api/settings_private/settings_private_api.h b/chromium/chrome/browser/extensions/api/settings_private/settings_private_api.h index 07a03ece7f6..e61e09a458a 100644 --- a/chromium/chrome/browser/extensions/api/settings_private/settings_private_api.h +++ b/chromium/chrome/browser/extensions/api/settings_private/settings_private_api.h @@ -60,38 +60,38 @@ class SettingsPrivateGetPrefFunction : public UIThreadExtensionFunction { DISALLOW_COPY_AND_ASSIGN(SettingsPrivateGetPrefFunction); }; -// Implements the chrome.settingsPrivate.getDefaultZoomPercent method. -class SettingsPrivateGetDefaultZoomPercentFunction +// Implements the chrome.settingsPrivate.getDefaultZoom method. +class SettingsPrivateGetDefaultZoomFunction : public UIThreadExtensionFunction { public: - SettingsPrivateGetDefaultZoomPercentFunction() {} - DECLARE_EXTENSION_FUNCTION("settingsPrivate.getDefaultZoomPercent", - SETTINGSPRIVATE_GETDEFAULTZOOMPERCENTFUNCTION); + SettingsPrivateGetDefaultZoomFunction() {} + DECLARE_EXTENSION_FUNCTION("settingsPrivate.getDefaultZoom", + SETTINGSPRIVATE_GETDEFAULTZOOMFUNCTION); protected: - ~SettingsPrivateGetDefaultZoomPercentFunction() override; + ~SettingsPrivateGetDefaultZoomFunction() override; // AsyncExtensionFunction overrides. ResponseAction Run() override; - DISALLOW_COPY_AND_ASSIGN(SettingsPrivateGetDefaultZoomPercentFunction); + DISALLOW_COPY_AND_ASSIGN(SettingsPrivateGetDefaultZoomFunction); }; -// Implements the chrome.settingsPrivate.setDefaultZoomPercent method. -class SettingsPrivateSetDefaultZoomPercentFunction +// Implements the chrome.settingsPrivate.setDefaultZoom method. +class SettingsPrivateSetDefaultZoomFunction : public UIThreadExtensionFunction { public: - SettingsPrivateSetDefaultZoomPercentFunction() {} - DECLARE_EXTENSION_FUNCTION("settingsPrivate.setDefaultZoomPercent", - SETTINGSPRIVATE_SETDEFAULTZOOMPERCENTFUNCTION); + SettingsPrivateSetDefaultZoomFunction() {} + DECLARE_EXTENSION_FUNCTION("settingsPrivate.setDefaultZoom", + SETTINGSPRIVATE_SETDEFAULTZOOMFUNCTION); protected: - ~SettingsPrivateSetDefaultZoomPercentFunction() override; + ~SettingsPrivateSetDefaultZoomFunction() override; // AsyncExtensionFunction overrides. ResponseAction Run() override; - DISALLOW_COPY_AND_ASSIGN(SettingsPrivateSetDefaultZoomPercentFunction); + DISALLOW_COPY_AND_ASSIGN(SettingsPrivateSetDefaultZoomFunction); }; } // namespace extensions diff --git a/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate.cc b/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate.cc index 1b5f72ea522..13ed8a8ddbe 100644 --- a/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate.cc +++ b/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate.cc @@ -58,16 +58,16 @@ PrefsUtil::SetPrefResult SettingsPrivateDelegate::SetPref( return prefs_util_->SetPref(pref_name, value); } -std::unique_ptr<base::Value> SettingsPrivateDelegate::GetDefaultZoomPercent() { +std::unique_ptr<base::Value> SettingsPrivateDelegate::GetDefaultZoom() { double zoom = content::ZoomLevelToZoomFactor( - profile_->GetZoomLevelPrefs()->GetDefaultZoomLevelPref()) * 100; + profile_->GetZoomLevelPrefs()->GetDefaultZoomLevelPref()); std::unique_ptr<base::Value> value(new base::FundamentalValue(zoom)); return value; } -PrefsUtil::SetPrefResult SettingsPrivateDelegate::SetDefaultZoomPercent( - int percent) { - double zoom_factor = content::ZoomFactorToZoomLevel(percent * 0.01); +PrefsUtil::SetPrefResult SettingsPrivateDelegate::SetDefaultZoom( + double zoom) { + double zoom_factor = content::ZoomFactorToZoomLevel(zoom); profile_->GetZoomLevelPrefs()->SetDefaultZoomLevelPref(zoom_factor); return PrefsUtil::SetPrefResult::SUCCESS; } diff --git a/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate.h b/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate.h index 66c71532ebd..752c2f005e1 100644 --- a/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate.h +++ b/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate.h @@ -45,10 +45,10 @@ class SettingsPrivateDelegate : public KeyedService { virtual std::unique_ptr<base::Value> GetAllPrefs(); // Gets the value. - virtual std::unique_ptr<base::Value> GetDefaultZoomPercent(); + virtual std::unique_ptr<base::Value> GetDefaultZoom(); // Sets the pref. - virtual PrefsUtil::SetPrefResult SetDefaultZoomPercent(int percent); + virtual PrefsUtil::SetPrefResult SetDefaultZoom(double zoom); protected: Profile* profile_; // weak; not owned by us diff --git a/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate_factory.cc b/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate_factory.cc index fc56bc34f9f..e855cac044a 100644 --- a/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate_factory.cc +++ b/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate_factory.cc @@ -6,6 +6,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/extensions/api/settings_private/settings_private_delegate.h" +#include "chrome/browser/profiles/incognito_helpers.h" #include "chrome/browser/profiles/profile.h" #include "components/keyed_service/content/browser_context_dependency_manager.h" #include "extensions/browser/extension_system_provider.h" @@ -35,6 +36,14 @@ SettingsPrivateDelegateFactory::SettingsPrivateDelegateFactory() SettingsPrivateDelegateFactory::~SettingsPrivateDelegateFactory() { } +content::BrowserContext* SettingsPrivateDelegateFactory::GetBrowserContextToUse( + content::BrowserContext* context) const { + // Use the incognito profile when in Guest mode. + if (context->IsOffTheRecord()) + return chrome::GetBrowserContextRedirectedInIncognito(context); + return context; +} + KeyedService* SettingsPrivateDelegateFactory::BuildServiceInstanceFor( content::BrowserContext* profile) const { return new SettingsPrivateDelegate(static_cast<Profile*>(profile)); diff --git a/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate_factory.h b/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate_factory.h index 3564810082c..a69bf7f7c18 100644 --- a/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate_factory.h +++ b/chromium/chrome/browser/extensions/api/settings_private/settings_private_delegate_factory.h @@ -34,6 +34,8 @@ class SettingsPrivateDelegateFactory // BrowserContextKeyedBaseFactory implementation. KeyedService* BuildServiceInstanceFor( content::BrowserContext* profile) const override; + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; DISALLOW_COPY_AND_ASSIGN(SettingsPrivateDelegateFactory); }; diff --git a/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc b/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc index 4b0db6660fe..f42e2ef98f9 100644 --- a/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc +++ b/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router.cc @@ -94,15 +94,13 @@ void SettingsPrivateEventRouter::StartOrStopListeningForPrefsChanges() { std::string pref_name = it.first; if (prefs_util_->IsCrosSetting(pref_name)) { #if defined(OS_CHROMEOS) - std::unique_ptr<chromeos::CrosSettings::ObserverSubscription> observer = - chromeos::CrosSettings::Get()->AddSettingsObserver( + std::unique_ptr<chromeos::CrosSettings::ObserverSubscription> + subscription = chromeos::CrosSettings::Get()->AddSettingsObserver( pref_name.c_str(), base::Bind(&SettingsPrivateEventRouter::OnPreferenceChanged, base::Unretained(this), pref_name)); - linked_ptr<chromeos::CrosSettings::ObserverSubscription> subscription( - observer.release()); cros_settings_subscription_map_.insert( - make_pair(pref_name, subscription)); + make_pair(pref_name, std::move(subscription))); #endif } else { FindRegistrarForPref(it.first) diff --git a/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router.h b/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router.h index 7738b978a72..06477b50893 100644 --- a/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router.h +++ b/chromium/chrome/browser/extensions/api/settings_private/settings_private_event_router.h @@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_EXTENSIONS_API_SETTINGS_PRIVATE_SETTINGS_PRIVATE_EVENT_ROUTER_H_ #define CHROME_BROWSER_EXTENSIONS_API_SETTINGS_PRIVATE_SETTINGS_PRIVATE_EVENT_ROUTER_H_ +#include <memory> + #include "base/macros.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/extensions/api/settings_private/prefs_util.h" @@ -57,9 +59,9 @@ class SettingsPrivateEventRouter : public KeyedService, PrefChangeRegistrar* FindRegistrarForPref(const std::string& pref_name); - typedef std::map<std::string, - linked_ptr<chromeos::CrosSettings::ObserverSubscription>> - SubscriptionMap; + using SubscriptionMap = + std::map<std::string, + std::unique_ptr<chromeos::CrosSettings::ObserverSubscription>>; SubscriptionMap cros_settings_subscription_map_; content::BrowserContext* context_; diff --git a/chromium/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api.cc b/chromium/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api.cc index c1023b80edf..096316a5caa 100644 --- a/chromium/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api.cc +++ b/chromium/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api.cc @@ -113,34 +113,33 @@ std::unique_ptr<DeviceInfo> GetLocalDeviceInfo(const std::string& extension_id, return device; } -bool SignedInDevicesGetFunction::RunSync() { +ExtensionFunction::ResponseAction SignedInDevicesGetFunction::Run() { std::unique_ptr<api::signed_in_devices::Get::Params> params( api::signed_in_devices::Get::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); bool is_local = params->is_local.get() ? *params->is_local : false; + Profile* profile = Profile::FromBrowserContext(browser_context()); if (is_local) { std::unique_ptr<DeviceInfo> device = - GetLocalDeviceInfo(extension_id(), GetProfile()); + GetLocalDeviceInfo(extension_id(), profile); std::unique_ptr<base::ListValue> result(new base::ListValue()); if (device.get()) { result->Append(device->ToValue()); } - SetResult(std::move(result)); - return true; + return RespondNow(OneArgument(std::move(result))); } std::vector<std::unique_ptr<DeviceInfo>> devices = - GetAllSignedInDevices(extension_id(), GetProfile()); + GetAllSignedInDevices(extension_id(), profile); std::unique_ptr<base::ListValue> result(new base::ListValue()); for (const std::unique_ptr<DeviceInfo>& device : devices) result->Append(device->ToValue()); - SetResult(std::move(result)); - return true; + return RespondNow(OneArgument(std::move(result))); } } // namespace extensions diff --git a/chromium/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api.h b/chromium/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api.h index 264600c4b9c..b24066be1e8 100644 --- a/chromium/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api.h +++ b/chromium/chrome/browser/extensions/api/signed_in_devices/signed_in_devices_api.h @@ -37,12 +37,12 @@ std::vector<std::unique_ptr<syncer::DeviceInfo>> GetAllSignedInDevices( syncer::DeviceInfoTracker* device_tracker, ExtensionPrefs* extension_prefs); -class SignedInDevicesGetFunction : public ChromeSyncExtensionFunction { +class SignedInDevicesGetFunction : public UIThreadExtensionFunction { protected: ~SignedInDevicesGetFunction() override {} // ExtensionFunction: - bool RunSync() override; + ResponseAction Run() override; DECLARE_EXTENSION_FUNCTION("signedInDevices.get", SIGNED_IN_DEVICES_GET) }; diff --git a/chromium/chrome/browser/extensions/api/socket/combined_socket_unittest.cc b/chromium/chrome/browser/extensions/api/socket/combined_socket_unittest.cc index e6d2595d487..14de64940ae 100644 --- a/chromium/chrome/browser/extensions/api/socket/combined_socket_unittest.cc +++ b/chromium/chrome/browser/extensions/api/socket/combined_socket_unittest.cc @@ -107,7 +107,9 @@ class CombinedSocketTest : public testing::Test { EXPECT_EQ(buffer, io_buffer_); } - void OnRead(int count, scoped_refptr<net::IOBuffer> io_buffer) { + void OnRead(int count, + scoped_refptr<net::IOBuffer> io_buffer, + bool socket_destroying) { count_ = count; io_buffer_ = io_buffer.get(); } diff --git a/chromium/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc b/chromium/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc index dd435b25afb..ac8a6fda363 100644 --- a/chromium/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc +++ b/chromium/chrome/browser/extensions/api/socket/tcp_socket_unittest.cc @@ -58,8 +58,10 @@ class CompleteHandler { public: CompleteHandler() {} MOCK_METHOD1(OnComplete, void(int result_code)); - MOCK_METHOD2(OnReadComplete, void(int result_code, - scoped_refptr<net::IOBuffer> io_buffer)); + MOCK_METHOD3(OnReadComplete, + void(int result_code, + scoped_refptr<net::IOBuffer> io_buffer, + bool socket_destroying)); // MOCK_METHOD cannot mock a scoped_ptr argument. MOCK_METHOD2(OnAcceptMock, void(int, net::TCPClientSocket*)); @@ -81,8 +83,7 @@ TEST(SocketTest, TestTCPSocketRead) { EXPECT_CALL(*tcp_client_socket, Read(_, _, _)) .Times(1); - EXPECT_CALL(handler, OnReadComplete(_, _)) - .Times(1); + EXPECT_CALL(handler, OnReadComplete(_, _, _)).Times(1); std::unique_ptr<TCPSocket> socket(TCPSocket::CreateSocketForTesting( std::move(tcp_client_socket), FAKE_ID, true)); diff --git a/chromium/chrome/browser/extensions/api/socket/tls_socket_unittest.cc b/chromium/chrome/browser/extensions/api/socket/tls_socket_unittest.cc index 1b5663a653c..2e19965cbba 100644 --- a/chromium/chrome/browser/extensions/api/socket/tls_socket_unittest.cc +++ b/chromium/chrome/browser/extensions/api/socket/tls_socket_unittest.cc @@ -112,8 +112,10 @@ class CompleteHandler { public: CompleteHandler() {} MOCK_METHOD1(OnComplete, void(int result_code)); - MOCK_METHOD2(OnReadComplete, - void(int result_code, scoped_refptr<net::IOBuffer> io_buffer)); + MOCK_METHOD3(OnReadComplete, + void(int result_code, + scoped_refptr<net::IOBuffer> io_buffer, + bool socket_destroying)); MOCK_METHOD2(OnAccept, void(int, net::TCPClientSocket*)); private: @@ -150,7 +152,7 @@ TEST_F(TLSSocketTest, TestTLSSocketRead) { CompleteHandler handler; EXPECT_CALL(*ssl_socket_, Read(_, _, _)).Times(1); - EXPECT_CALL(handler, OnReadComplete(_, _)).Times(1); + EXPECT_CALL(handler, OnReadComplete(_, _, _)).Times(1); const int count = 512; socket_->Read( diff --git a/chromium/chrome/browser/extensions/api/socket/udp_socket_unittest.cc b/chromium/chrome/browser/extensions/api/socket/udp_socket_unittest.cc index 9c4e5213872..915d6766d6b 100644 --- a/chromium/chrome/browser/extensions/api/socket/udp_socket_unittest.cc +++ b/chromium/chrome/browser/extensions/api/socket/udp_socket_unittest.cc @@ -33,6 +33,7 @@ static void OnConnected(int result) { static void OnCompleted(int bytes_read, scoped_refptr<net::IOBuffer> io_buffer, + bool socket_destroying, const std::string& address, uint16_t port) { // Do nothing; don't care. @@ -114,7 +115,8 @@ static void SendMulticastPacket(const base::Closure& quit_run_loop, static void OnMulticastReadCompleted(const base::Closure& quit_run_loop, bool* packet_received, int count, - scoped_refptr<net::IOBuffer> io_buffer) { + scoped_refptr<net::IOBuffer> io_buffer, + bool socket_destroying) { EXPECT_EQ(test_message_length, count); EXPECT_EQ(0, strncmp(io_buffer->data(), test_message, test_message_length)); *packet_received = true; diff --git a/chromium/chrome/browser/extensions/api/storage/managed_value_store_cache.cc b/chromium/chrome/browser/extensions/api/storage/managed_value_store_cache.cc index 46e3228024b..2864c75d6bf 100644 --- a/chromium/chrome/browser/extensions/api/storage/managed_value_store_cache.cc +++ b/chromium/chrome/browser/extensions/api/storage/managed_value_store_cache.cc @@ -21,7 +21,6 @@ #include "chrome/browser/policy/schema_registry_service_factory.h" #include "chrome/browser/profiles/profile.h" #include "chrome/common/extensions/api/storage/storage_schema_manifest_handler.h" -#include "components/policy/core/common/policy_namespace.h" #include "components/policy/core/common/schema.h" #include "components/policy/core/common/schema_map.h" #include "components/policy/core/common/schema_registry.h" @@ -40,6 +39,10 @@ #include "extensions/common/manifest_constants.h" #include "extensions/common/one_shot_event.h" +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/profiles/profile_helper.h" +#endif + using content::BrowserContext; using content::BrowserThread; @@ -67,7 +70,7 @@ const ValueStoreFactory::ModelType kManagedModelType = class ManagedValueStoreCache::ExtensionTracker : public ExtensionRegistryObserver { public: - explicit ExtensionTracker(Profile* profile); + ExtensionTracker(Profile* profile, policy::PolicyDomain policy_domain); ~ExtensionTracker() override {} private: @@ -96,6 +99,7 @@ class ManagedValueStoreCache::ExtensionTracker void Register(const policy::ComponentMap* components); Profile* profile_; + policy::PolicyDomain policy_domain_; ScopedObserver<ExtensionRegistry, ExtensionRegistryObserver> extension_registry_observer_; policy::SchemaRegistry* schema_registry_; @@ -104,11 +108,15 @@ class ManagedValueStoreCache::ExtensionTracker DISALLOW_COPY_AND_ASSIGN(ExtensionTracker); }; -ManagedValueStoreCache::ExtensionTracker::ExtensionTracker(Profile* profile) +ManagedValueStoreCache::ExtensionTracker::ExtensionTracker( + Profile* profile, + policy::PolicyDomain policy_domain) : profile_(profile), + policy_domain_(policy_domain), extension_registry_observer_(this), - schema_registry_(policy::SchemaRegistryServiceFactory::GetForContext( - profile)->registry()), + schema_registry_( + policy::SchemaRegistryServiceFactory::GetForContext(profile) + ->registry()), weak_factory_(this) { extension_registry_observer_.Add(ExtensionRegistry::Get(profile_)); // Load schemas when the extension system is ready. It might be ready now. @@ -141,8 +149,8 @@ void ManagedValueStoreCache::ExtensionTracker::OnExtensionUninstalled( if (!ExtensionSystem::Get(profile_)->ready().is_signaled()) return; if (extension && UsesManagedStorage(extension)) { - schema_registry_->UnregisterComponent(policy::PolicyNamespace( - policy::POLICY_DOMAIN_EXTENSIONS, extension->id())); + schema_registry_->UnregisterComponent( + policy::PolicyNamespace(policy_domain_, extension->id())); } } @@ -214,16 +222,19 @@ void ManagedValueStoreCache::ExtensionTracker::LoadSchemasOnBlockingPool( void ManagedValueStoreCache::ExtensionTracker::Register( const policy::ComponentMap* components) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - schema_registry_->RegisterComponents(policy::POLICY_DOMAIN_EXTENSIONS, - *components); - - // The first SetReady() call is performed after the ExtensionSystem is ready, - // even if there are no managed extensions. It will trigger a loading of the - // initial policy for any managed extensions, and eventually the PolicyService - // will become ready for POLICY_DOMAIN_EXTENSIONS, and - // OnPolicyServiceInitialized() will be invoked. - // Subsequent calls to SetReady() are ignored. - schema_registry_->SetReady(policy::POLICY_DOMAIN_EXTENSIONS); + schema_registry_->RegisterComponents(policy_domain_, *components); + + // The first SetExtensionsDomainsReady() call is performed after the + // ExtensionSystem is ready, even if there are no managed extensions. It will + // trigger a loading of the initial policy for any managed extensions, and + // eventually the PolicyService will become ready for policy for extensions, + // and OnPolicyServiceInitialized() will be invoked. + // Subsequent calls to SetExtensionsDomainsReady() are ignored. + // + // Note that there is only ever one |ManagedValueStoreCache| instance for each + // profile, regardless of its type, therefore all extensions policy domains + // are marked as ready here. + schema_registry_->SetExtensionsDomainsReady(); } ManagedValueStoreCache::ManagedValueStoreCache( @@ -231,6 +242,7 @@ ManagedValueStoreCache::ManagedValueStoreCache( const scoped_refptr<ValueStoreFactory>& factory, const scoped_refptr<SettingsObserverList>& observers) : profile_(Profile::FromBrowserContext(context)), + policy_domain_(GetPolicyDomain(profile_)), policy_service_( policy::ProfilePolicyConnectorFactory::GetForBrowserContext(context) ->policy_service()), @@ -238,14 +250,12 @@ ManagedValueStoreCache::ManagedValueStoreCache( observers_(observers) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - policy_service_->AddObserver(policy::POLICY_DOMAIN_EXTENSIONS, this); + policy_service_->AddObserver(policy_domain_, this); - extension_tracker_.reset(new ExtensionTracker(profile_)); + extension_tracker_.reset(new ExtensionTracker(profile_, policy_domain_)); - if (policy_service_->IsInitializationComplete( - policy::POLICY_DOMAIN_EXTENSIONS)) { - OnPolicyServiceInitialized(policy::POLICY_DOMAIN_EXTENSIONS); - } + if (policy_service_->IsInitializationComplete(policy_domain_)) + OnPolicyServiceInitialized(policy_domain_); } ManagedValueStoreCache::~ManagedValueStoreCache() { @@ -256,7 +266,7 @@ ManagedValueStoreCache::~ManagedValueStoreCache() { void ManagedValueStoreCache::ShutdownOnUI() { DCHECK_CURRENTLY_ON(BrowserThread::UI); - policy_service_->RemoveObserver(policy::POLICY_DOMAIN_EXTENSIONS, this); + policy_service_->RemoveObserver(policy_domain_, this); extension_tracker_.reset(); } @@ -283,23 +293,22 @@ void ManagedValueStoreCache::OnPolicyServiceInitialized( policy::PolicyDomain domain) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (domain != policy::POLICY_DOMAIN_EXTENSIONS) + if (domain != policy_domain_) return; // The PolicyService now has all the initial policies ready. Send policy // for all the managed extensions to their backing stores now. policy::SchemaRegistry* registry = policy::SchemaRegistryServiceFactory::GetForContext(profile_)->registry(); - const policy::ComponentMap* map = registry->schema_map()->GetComponents( - policy::POLICY_DOMAIN_EXTENSIONS); + const policy::ComponentMap* map = + registry->schema_map()->GetComponents(policy_domain_); if (!map) return; const policy::PolicyMap empty_map; for (policy::ComponentMap::const_iterator it = map->begin(); it != map->end(); ++it) { - const policy::PolicyNamespace ns(policy::POLICY_DOMAIN_EXTENSIONS, - it->first); + const policy::PolicyNamespace ns(policy_domain_, it->first); // If there is no policy for |ns| then this will clear the previous store, // if there is one. OnPolicyUpdated(ns, empty_map, policy_service_->GetPolicies(ns)); @@ -311,8 +320,7 @@ void ManagedValueStoreCache::OnPolicyUpdated(const policy::PolicyNamespace& ns, const policy::PolicyMap& current) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (!policy_service_->IsInitializationComplete( - policy::POLICY_DOMAIN_EXTENSIONS)) { + if (!policy_service_->IsInitializationComplete(policy_domain_)) { // OnPolicyUpdated is called whenever a policy changes, but it doesn't // mean that all the policy providers are ready; wait until we get the // final policy values before passing them to the store. @@ -327,6 +335,17 @@ void ManagedValueStoreCache::OnPolicyUpdated(const policy::PolicyNamespace& ns, base::Passed(current.DeepCopy()))); } +// static +policy::PolicyDomain ManagedValueStoreCache::GetPolicyDomain(Profile* profile) { +#if defined(OS_CHROMEOS) + return chromeos::ProfileHelper::IsSigninProfile(profile) + ? policy::POLICY_DOMAIN_SIGNIN_EXTENSIONS + : policy::POLICY_DOMAIN_EXTENSIONS; +#else + return policy::POLICY_DOMAIN_EXTENSIONS; +#endif +} + void ManagedValueStoreCache::UpdatePolicyOnFILE( const std::string& extension_id, std::unique_ptr<policy::PolicyMap> current_policy) { @@ -346,19 +365,20 @@ PolicyValueStore* ManagedValueStoreCache::GetStoreFor( const std::string& extension_id) { DCHECK_CURRENTLY_ON(BrowserThread::FILE); - PolicyValueStoreMap::iterator it = store_map_.find(extension_id); + auto it = store_map_.find(extension_id); if (it != store_map_.end()) return it->second.get(); // Create the store now, and serve the cached policy until the PolicyService // sends updated values. - PolicyValueStore* store = new PolicyValueStore( + std::unique_ptr<PolicyValueStore> store(new PolicyValueStore( extension_id, observers_, storage_factory_->CreateSettingsStore(settings_namespace::MANAGED, - kManagedModelType, extension_id)); - store_map_[extension_id] = make_linked_ptr(store); + kManagedModelType, extension_id))); + PolicyValueStore* raw_store = store.get(); + store_map_[extension_id] = std::move(store); - return store; + return raw_store; } bool ManagedValueStoreCache::HasStore(const std::string& extension_id) const { diff --git a/chromium/chrome/browser/extensions/api/storage/managed_value_store_cache.h b/chromium/chrome/browser/extensions/api/storage/managed_value_store_cache.h index f0d5beffa23..72fd865906f 100644 --- a/chromium/chrome/browser/extensions/api/storage/managed_value_store_cache.h +++ b/chromium/chrome/browser/extensions/api/storage/managed_value_store_cache.h @@ -12,8 +12,8 @@ #include "base/compiler_specific.h" #include "base/files/file_path.h" #include "base/macros.h" -#include "base/memory/linked_ptr.h" #include "base/memory/ref_counted.h" +#include "components/policy/core/common/policy_namespace.h" #include "components/policy/core/common/policy_service.h" #include "extensions/browser/api/storage/settings_observer.h" #include "extensions/browser/api/storage/value_store_cache.h" @@ -51,10 +51,6 @@ class ManagedValueStoreCache : public ValueStoreCache, private: class ExtensionTracker; - // Maps an extension ID to its PolicyValueStoreMap. - typedef std::map<std::string, linked_ptr<PolicyValueStore> > - PolicyValueStoreMap; - // ValueStoreCache implementation: void ShutdownOnUI() override; void RunWithValueStoreForExtension( @@ -68,6 +64,9 @@ class ManagedValueStoreCache : public ValueStoreCache, const policy::PolicyMap& previous, const policy::PolicyMap& current) override; + // Returns the policy domain that should be used for the specified profile. + static policy::PolicyDomain GetPolicyDomain(Profile* profile); + // Posted by OnPolicyUpdated() to update a PolicyValueStore on the FILE // thread. void UpdatePolicyOnFILE(const std::string& extension_id, @@ -83,6 +82,10 @@ class ManagedValueStoreCache : public ValueStoreCache, // get the PolicyService, the EventRouter and the ExtensionService. Profile* profile_; + // The policy domain. This is used for both updating the schema registry with + // the list of extensions and for observing the policy updates. + policy::PolicyDomain policy_domain_; + // The |profile_|'s PolicyService. policy::PolicyService* policy_service_; @@ -96,7 +99,7 @@ class ManagedValueStoreCache : public ValueStoreCache, // All the PolicyValueStores live on the FILE thread, and |store_map_| can be // accessed only on the FILE thread as well. - PolicyValueStoreMap store_map_; + std::map<std::string, std::unique_ptr<PolicyValueStore>> store_map_; DISALLOW_COPY_AND_ASSIGN(ManagedValueStoreCache); }; diff --git a/chromium/chrome/browser/extensions/api/storage/setting_sync_data.cc b/chromium/chrome/browser/extensions/api/storage/setting_sync_data.cc index 6819f6fbe16..a704db7603d 100644 --- a/chromium/chrome/browser/extensions/api/storage/setting_sync_data.cc +++ b/chromium/chrome/browser/extensions/api/storage/setting_sync_data.cc @@ -8,7 +8,7 @@ #include "base/json/json_reader.h" #include "base/json/json_writer.h" -#include "components/sync/api/sync_data.h" +#include "components/sync/model/sync_data.h" #include "components/sync/protocol/app_setting_specifics.pb.h" #include "components/sync/protocol/extension_setting_specifics.pb.h" #include "components/sync/protocol/sync.pb.h" diff --git a/chromium/chrome/browser/extensions/api/storage/setting_sync_data.h b/chromium/chrome/browser/extensions/api/storage/setting_sync_data.h index fd843fbdab2..c98db37b9c2 100644 --- a/chromium/chrome/browser/extensions/api/storage/setting_sync_data.h +++ b/chromium/chrome/browser/extensions/api/storage/setting_sync_data.h @@ -10,7 +10,7 @@ #include "base/macros.h" #include "base/values.h" -#include "components/sync/api/sync_change.h" +#include "components/sync/model/sync_change.h" namespace syncer { class SyncData; diff --git a/chromium/chrome/browser/extensions/api/storage/settings_apitest.cc b/chromium/chrome/browser/extensions/api/storage/settings_apitest.cc index 3eb1437be2e..b934a9b55e0 100644 --- a/chromium/chrome/browser/extensions/api/storage/settings_apitest.cc +++ b/chromium/chrome/browser/extensions/api/storage/settings_apitest.cc @@ -25,13 +25,13 @@ #include "components/policy/core/common/schema.h" #include "components/policy/core/common/schema_map.h" #include "components/policy/core/common/schema_registry.h" -#include "components/sync/api/fake_sync_change_processor.h" -#include "components/sync/api/sync_change.h" -#include "components/sync/api/sync_change_processor.h" -#include "components/sync/api/sync_change_processor_wrapper_for_test.h" -#include "components/sync/api/sync_error_factory.h" -#include "components/sync/api/sync_error_factory_mock.h" -#include "components/sync/api/syncable_service.h" +#include "components/sync/model/fake_sync_change_processor.h" +#include "components/sync/model/sync_change.h" +#include "components/sync/model/sync_change_processor.h" +#include "components/sync/model/sync_change_processor_wrapper_for_test.h" +#include "components/sync/model/sync_error_factory.h" +#include "components/sync/model/sync_error_factory_mock.h" +#include "components/sync/model/syncable_service.h" #include "extensions/browser/api/storage/settings_namespace.h" #include "extensions/browser/api/storage/storage_frontend.h" #include "extensions/browser/extension_system.h" diff --git a/chromium/chrome/browser/extensions/api/storage/settings_sync_processor.cc b/chromium/chrome/browser/extensions/api/storage/settings_sync_processor.cc index 62bb164c0f5..02f3f6f9266 100644 --- a/chromium/chrome/browser/extensions/api/storage/settings_sync_processor.cc +++ b/chromium/chrome/browser/extensions/api/storage/settings_sync_processor.cc @@ -4,8 +4,8 @@ #include "chrome/browser/extensions/api/storage/settings_sync_processor.h" #include "chrome/browser/extensions/api/storage/settings_sync_util.h" -#include "components/sync/api/sync_change_processor.h" -#include "components/sync/api/sync_data.h" +#include "components/sync/model/sync_change_processor.h" +#include "components/sync/model/sync_data.h" #include "components/sync/protocol/extension_setting_specifics.pb.h" #include "content/public/browser/browser_thread.h" #include "extensions/browser/api/storage/settings_namespace.h" diff --git a/chromium/chrome/browser/extensions/api/storage/settings_sync_processor.h b/chromium/chrome/browser/extensions/api/storage/settings_sync_processor.h index 93e6349f0f3..bec11ef1267 100644 --- a/chromium/chrome/browser/extensions/api/storage/settings_sync_processor.h +++ b/chromium/chrome/browser/extensions/api/storage/settings_sync_processor.h @@ -9,7 +9,7 @@ #include <string> #include "base/macros.h" -#include "components/sync/api/sync_error.h" +#include "components/sync/model/sync_error.h" #include "extensions/browser/value_store/value_store_change.h" namespace syncer { diff --git a/chromium/chrome/browser/extensions/api/storage/settings_sync_unittest.cc b/chromium/chrome/browser/extensions/api/storage/settings_sync_unittest.cc index 2bd06676574..1f68049384b 100644 --- a/chromium/chrome/browser/extensions/api/storage/settings_sync_unittest.cc +++ b/chromium/chrome/browser/extensions/api/storage/settings_sync_unittest.cc @@ -20,10 +20,10 @@ #include "chrome/browser/extensions/api/storage/sync_value_store_cache.h" #include "chrome/browser/extensions/api/storage/syncable_settings_storage.h" #include "chrome/test/base/testing_profile.h" -#include "components/sync/api/sync_change_processor.h" -#include "components/sync/api/sync_change_processor_wrapper_for_test.h" -#include "components/sync/api/sync_error_factory.h" -#include "components/sync/api/sync_error_factory_mock.h" +#include "components/sync/model/sync_change_processor.h" +#include "components/sync/model/sync_change_processor_wrapper_for_test.h" +#include "components/sync/model/sync_error_factory.h" +#include "components/sync/model/sync_error_factory_mock.h" #include "content/public/test/test_browser_thread.h" #include "extensions/browser/api/storage/settings_test_util.h" #include "extensions/browser/api/storage/storage_frontend.h" diff --git a/chromium/chrome/browser/extensions/api/storage/settings_sync_util.h b/chromium/chrome/browser/extensions/api/storage/settings_sync_util.h index ef702581162..4e23bae0619 100644 --- a/chromium/chrome/browser/extensions/api/storage/settings_sync_util.h +++ b/chromium/chrome/browser/extensions/api/storage/settings_sync_util.h @@ -5,8 +5,8 @@ #ifndef CHROME_BROWSER_EXTENSIONS_API_STORAGE_SETTINGS_SYNC_UTIL_H_ #define CHROME_BROWSER_EXTENSIONS_API_STORAGE_SETTINGS_SYNC_UTIL_H_ -#include "components/sync/api/sync_change.h" -#include "components/sync/api/sync_data.h" +#include "components/sync/model/sync_change.h" +#include "components/sync/model/sync_data.h" namespace base { class Value; diff --git a/chromium/chrome/browser/extensions/api/storage/sync_storage_backend.cc b/chromium/chrome/browser/extensions/api/storage/sync_storage_backend.cc index 21f9747ab56..18d50350578 100644 --- a/chromium/chrome/browser/extensions/api/storage/sync_storage_backend.cc +++ b/chromium/chrome/browser/extensions/api/storage/sync_storage_backend.cc @@ -11,7 +11,7 @@ #include "chrome/browser/extensions/api/storage/settings_sync_processor.h" #include "chrome/browser/extensions/api/storage/settings_sync_util.h" #include "chrome/browser/extensions/api/storage/syncable_settings_storage.h" -#include "components/sync/api/sync_error_factory.h" +#include "components/sync/model/sync_error_factory.h" #include "content/public/browser/browser_thread.h" using content::BrowserThread; @@ -81,7 +81,7 @@ SyncableSettingsStorage* SyncStorageBackend::GetOrCreateStorageWithSyncData( return maybe_storage->second.get(); } - std::unique_ptr<SettingsStorageQuotaEnforcer> storage( + std::unique_ptr<SettingsStorageQuotaEnforcer> settings_storage( new SettingsStorageQuotaEnforcer( quota_, storage_factory_->CreateSettingsStore( settings_namespace::SYNC, ToFactoryModelType(sync_type_), @@ -89,18 +89,20 @@ SyncableSettingsStorage* SyncStorageBackend::GetOrCreateStorageWithSyncData( // It's fine to create the quota enforcer underneath the sync layer, since // sync will only go ahead if each underlying storage operation succeeds. - linked_ptr<SyncableSettingsStorage> syncable_storage( - new SyncableSettingsStorage( - observers_, extension_id, storage.release(), sync_type_, flare_)); - storage_objs_[extension_id] = syncable_storage; + std::unique_ptr<SyncableSettingsStorage> syncable_storage( + new SyncableSettingsStorage(observers_, extension_id, + settings_storage.release(), sync_type_, + flare_)); + SyncableSettingsStorage* raw_syncable_storage = syncable_storage.get(); + storage_objs_[extension_id] = std::move(syncable_storage); if (sync_processor_.get()) { - syncer::SyncError error = syncable_storage->StartSyncing( + syncer::SyncError error = raw_syncable_storage->StartSyncing( std::move(sync_data), CreateSettingsSyncProcessor(extension_id)); if (error.IsSet()) - syncable_storage->StopSyncing(); + raw_syncable_storage->StopSyncing(); } - return syncable_storage.get(); + return raw_syncable_storage; } void SyncStorageBackend::DeleteStorage(const std::string& extension_id) { diff --git a/chromium/chrome/browser/extensions/api/storage/sync_storage_backend.h b/chromium/chrome/browser/extensions/api/storage/sync_storage_backend.h index 9a854d9c14a..e3b61ed4fdd 100644 --- a/chromium/chrome/browser/extensions/api/storage/sync_storage_backend.h +++ b/chromium/chrome/browser/extensions/api/storage/sync_storage_backend.h @@ -13,9 +13,8 @@ #include "base/compiler_specific.h" #include "base/files/file_path.h" #include "base/macros.h" -#include "base/memory/linked_ptr.h" #include "base/memory/ref_counted.h" -#include "components/sync/api/syncable_service.h" +#include "components/sync/model/syncable_service.h" #include "extensions/browser/api/storage/settings_observer.h" #include "extensions/browser/api/storage/settings_storage_quota_enforcer.h" #include "extensions/browser/value_store/value_store_factory.h" @@ -87,8 +86,8 @@ class SyncStorageBackend : public syncer::SyncableService { // A cache of ValueStore objects that have already been created. // Ensure that there is only ever one created per extension. - typedef std::map<std::string, linked_ptr<SyncableSettingsStorage> > - StorageObjMap; + using StorageObjMap = + std::map<std::string, std::unique_ptr<SyncableSettingsStorage>>; mutable StorageObjMap storage_objs_; // Current sync model type. Either EXTENSION_SETTINGS or APP_SETTINGS. diff --git a/chromium/chrome/browser/extensions/api/storage/sync_value_store_cache.h b/chromium/chrome/browser/extensions/api/storage/sync_value_store_cache.h index 94f53b27a9b..62805823865 100644 --- a/chromium/chrome/browser/extensions/api/storage/sync_value_store_cache.h +++ b/chromium/chrome/browser/extensions/api/storage/sync_value_store_cache.h @@ -10,7 +10,7 @@ #include "base/compiler_specific.h" #include "base/macros.h" #include "base/memory/ref_counted.h" -#include "components/sync/api/syncable_service.h" +#include "components/sync/model/syncable_service.h" #include "extensions/browser/api/storage/settings_observer.h" #include "extensions/browser/api/storage/value_store_cache.h" diff --git a/chromium/chrome/browser/extensions/api/storage/syncable_settings_storage.cc b/chromium/chrome/browser/extensions/api/storage/syncable_settings_storage.cc index 102e2b343cc..e6668ec8294 100644 --- a/chromium/chrome/browser/extensions/api/storage/syncable_settings_storage.cc +++ b/chromium/chrome/browser/extensions/api/storage/syncable_settings_storage.cc @@ -10,7 +10,7 @@ #include "base/strings/stringprintf.h" #include "chrome/browser/extensions/api/storage/settings_sync_processor.h" #include "chrome/browser/extensions/api/storage/settings_sync_util.h" -#include "components/sync/api/sync_data.h" +#include "components/sync/model/sync_data.h" #include "components/sync/protocol/extension_setting_specifics.pb.h" #include "content/public/browser/browser_thread.h" #include "extensions/browser/api/storage/settings_namespace.h" diff --git a/chromium/chrome/browser/extensions/api/storage/syncable_settings_storage.h b/chromium/chrome/browser/extensions/api/storage/syncable_settings_storage.h index c903f23b4fa..f382dd13490 100644 --- a/chromium/chrome/browser/extensions/api/storage/syncable_settings_storage.h +++ b/chromium/chrome/browser/extensions/api/storage/syncable_settings_storage.h @@ -17,8 +17,8 @@ #include "base/observer_list_threadsafe.h" #include "base/values.h" #include "chrome/browser/extensions/api/storage/setting_sync_data.h" -#include "components/sync/api/sync_change.h" -#include "components/sync/api/syncable_service.h" +#include "components/sync/model/sync_change.h" +#include "components/sync/model/syncable_service.h" #include "extensions/browser/api/storage/settings_observer.h" #include "extensions/browser/value_store/value_store.h" diff --git a/chromium/chrome/browser/extensions/api/streams_private/streams_private_api.cc b/chromium/chrome/browser/extensions/api/streams_private/streams_private_api.cc index 199a16323ef..dc12dac808f 100644 --- a/chromium/chrome/browser/extensions/api/streams_private/streams_private_api.cc +++ b/chromium/chrome/browser/extensions/api/streams_private/streams_private_api.cc @@ -135,7 +135,7 @@ void StreamsPrivateAPI::ExecuteMimeTypeHandler( ->DispatchEventToExtension(extension_id, std::move(event)); GURL url = stream->handle->GetURL(); - streams_[extension_id][url] = make_linked_ptr(stream->handle.release()); + streams_[extension_id][url] = std::move(stream->handle); } void StreamsPrivateAPI::AbortStream(const std::string& extension_id, diff --git a/chromium/chrome/browser/extensions/api/streams_private/streams_private_api.h b/chromium/chrome/browser/extensions/api/streams_private/streams_private_api.h index e2e2ab84aa3..3d987d480d8 100644 --- a/chromium/chrome/browser/extensions/api/streams_private/streams_private_api.h +++ b/chromium/chrome/browser/extensions/api/streams_private/streams_private_api.h @@ -62,9 +62,6 @@ class StreamsPrivateAPI : public BrowserContextKeyedAPI, private: friend class BrowserContextKeyedAPIFactory<StreamsPrivateAPI>; - typedef std::map<std::string, - std::map<GURL, - linked_ptr<content::StreamHandle> > > StreamMap; // ExtensionRegistryObserver implementation. void OnExtensionUnloaded(content::BrowserContext* browser_context, @@ -79,6 +76,9 @@ class StreamsPrivateAPI : public BrowserContextKeyedAPI, static const bool kServiceRedirectedInIncognito = true; content::BrowserContext* const browser_context_; + using StreamMap = + std::map<std::string, + std::map<GURL, std::unique_ptr<content::StreamHandle>>>; StreamMap streams_; // Listen to extension unloaded notifications. diff --git a/chromium/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.cc b/chromium/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.cc index c89dad722b3..f8dd6452639 100644 --- a/chromium/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.cc +++ b/chromium/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.cc @@ -46,7 +46,8 @@ const char kUnsupportedConflictResolutionPolicy[] = "Policy %s is not supported."; sync_file_system::SyncFileSystemService* GetSyncFileSystemService( - Profile* profile) { + content::BrowserContext* browser_context) { + Profile* profile = Profile::FromBrowserContext(browser_context); sync_file_system::SyncFileSystemService* service = SyncFileSystemServiceFactory::GetForProfile(profile); if (!service) @@ -355,33 +356,35 @@ void SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota( SendResponse(true); } -bool SyncFileSystemSetConflictResolutionPolicyFunction::RunSync() { +ExtensionFunction::ResponseAction +SyncFileSystemSetConflictResolutionPolicyFunction::Run() { std::string policy_string; EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &policy_string)); ConflictResolutionPolicy policy = ExtensionEnumToConflictResolutionPolicy( api::sync_file_system::ParseConflictResolutionPolicy(policy_string)); if (policy != sync_file_system::CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN) { - SetError(base::StringPrintf(kUnsupportedConflictResolutionPolicy, - policy_string.c_str())); - return false; + return RespondNow(Error(base::StringPrintf( + kUnsupportedConflictResolutionPolicy, policy_string.c_str()))); } - return true; + return RespondNow(NoArguments()); } -bool SyncFileSystemGetConflictResolutionPolicyFunction::RunSync() { - SetResult(base::MakeUnique<base::StringValue>(api::sync_file_system::ToString( - api::sync_file_system::CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN))); - return true; +ExtensionFunction::ResponseAction +SyncFileSystemGetConflictResolutionPolicyFunction::Run() { + return RespondNow(OneArgument( + base::MakeUnique<base::StringValue>(api::sync_file_system::ToString( + api::sync_file_system::CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN)))); } -bool SyncFileSystemGetServiceStatusFunction::RunSync() { +ExtensionFunction::ResponseAction +SyncFileSystemGetServiceStatusFunction::Run() { sync_file_system::SyncFileSystemService* service = - GetSyncFileSystemService(GetProfile()); + GetSyncFileSystemService(browser_context()); if (!service) - return false; - results_ = api::sync_file_system::GetServiceStatus::Results::Create( - SyncServiceStateToExtensionEnum(service->GetSyncServiceState())); - return true; + return RespondNow(Error(kUnknownErrorDoNotUse)); + return RespondNow( + ArgumentList(api::sync_file_system::GetServiceStatus::Results::Create( + SyncServiceStateToExtensionEnum(service->GetSyncServiceState())))); } } // namespace extensions diff --git a/chromium/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.h b/chromium/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.h index 38dc817049d..9863c8f95a7 100644 --- a/chromium/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.h +++ b/chromium/chrome/browser/extensions/api/sync_file_system/sync_file_system_api.h @@ -120,36 +120,36 @@ class SyncFileSystemRequestFileSystemFunction }; class SyncFileSystemSetConflictResolutionPolicyFunction - : public ChromeSyncExtensionFunction { + : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("syncFileSystem.setConflictResolutionPolicy", SYNCFILESYSTEM_SETCONFLICTRESOLUTIONPOLICY) protected: ~SyncFileSystemSetConflictResolutionPolicyFunction() override {} - bool RunSync() override; + ResponseAction Run() override; }; class SyncFileSystemGetConflictResolutionPolicyFunction - : public ChromeSyncExtensionFunction { + : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("syncFileSystem.getConflictResolutionPolicy", SYNCFILESYSTEM_GETCONFLICTRESOLUTIONPOLICY) protected: ~SyncFileSystemGetConflictResolutionPolicyFunction() override {} - bool RunSync() override; + ResponseAction Run() override; }; class SyncFileSystemGetServiceStatusFunction - : public ChromeSyncExtensionFunction { + : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("syncFileSystem.getServiceStatus", SYNCFILESYSTEM_GETSERVICESTATUS) protected: ~SyncFileSystemGetServiceStatusFunction() override {} - bool RunSync() override; + ResponseAction Run() override; }; } // namespace extensions diff --git a/chromium/chrome/browser/extensions/api/tab_capture/tab_capture_api.cc b/chromium/chrome/browser/extensions/api/tab_capture/tab_capture_api.cc index 1afbe59eb3e..17987c1481d 100644 --- a/chromium/chrome/browser/extensions/api/tab_capture/tab_capture_api.cc +++ b/chromium/chrome/browser/extensions/api/tab_capture/tab_capture_api.cc @@ -199,25 +199,21 @@ const char* const kMediaRouterExtensionIds[] = { "ekpaaapppgpmolpcldedioblbkmijaca", // Beta }; -bool TabCaptureCaptureFunction::RunSync() { +ExtensionFunction::ResponseAction TabCaptureCaptureFunction::Run() { std::unique_ptr<api::tab_capture::Capture::Params> params = TabCapture::Capture::Params::Create(*args_); EXTENSION_FUNCTION_VALIDATE(params); // Figure out the active WebContents and retrieve the needed ids. - Browser* target_browser = - chrome::FindAnyBrowser(GetProfile(), include_incognito()); - if (!target_browser) { - error_ = kFindingTabError; - return false; - } + Browser* target_browser = chrome::FindAnyBrowser( + Profile::FromBrowserContext(browser_context()), include_incognito()); + if (!target_browser) + return RespondNow(Error(kFindingTabError)); content::WebContents* target_contents = target_browser->tab_strip_model()->GetActiveWebContents(); - if (!target_contents) { - error_ = kFindingTabError; - return false; - } + if (!target_contents) + return RespondNow(Error(kFindingTabError)); const std::string& extension_id = extension()->id(); @@ -232,21 +228,17 @@ bool TabCaptureCaptureFunction::RunSync() { arraysize(kChromecastExtensionIds)) && !SimpleFeature::IsIdInArray(extension_id, kMediaRouterExtensionIds, arraysize(kMediaRouterExtensionIds))) { - error_ = kGrantError; - return false; + return RespondNow(Error(kGrantError)); } - if (!OptionsSpecifyAudioOrVideo(params->options)) { - error_ = kNoAudioOrVideo; - return false; - } + if (!OptionsSpecifyAudioOrVideo(params->options)) + return RespondNow(Error(kNoAudioOrVideo)); - TabCaptureRegistry* registry = TabCaptureRegistry::Get(GetProfile()); + TabCaptureRegistry* registry = TabCaptureRegistry::Get(browser_context()); if (!registry->AddRequest(target_contents, extension_id, false)) { // TODO(miu): Allow multiple consumers of single tab capture. // http://crbug.com/535336 - error_ = kCapturingSameTab; - return false; + return RespondNow(Error(kCapturingSameTab)); } FilterDeprecatedGoogConstraints(¶ms->options); AddMediaStreamSourceConstraints(target_contents, ¶ms->options); @@ -261,17 +253,15 @@ bool TabCaptureCaptureFunction::RunSync() { // chrome/renderer/resources/extensions/tab_capture_custom_bindings.js std::unique_ptr<base::DictionaryValue> result(new base::DictionaryValue()); result->MergeDictionary(params->options.ToValue().get()); - SetResult(std::move(result)); - return true; + return RespondNow(OneArgument(std::move(result))); } -bool TabCaptureGetCapturedTabsFunction::RunSync() { - TabCaptureRegistry* registry = TabCaptureRegistry::Get(GetProfile()); +ExtensionFunction::ResponseAction TabCaptureGetCapturedTabsFunction::Run() { + TabCaptureRegistry* registry = TabCaptureRegistry::Get(browser_context()); std::unique_ptr<base::ListValue> list(new base::ListValue()); if (registry) registry->GetCapturedTabs(extension()->id(), list.get()); - SetResult(std::move(list)); - return true; + return RespondNow(OneArgument(std::move(list))); } ExtensionFunction::ResponseAction TabCaptureCaptureOffscreenTabFunction::Run() { diff --git a/chromium/chrome/browser/extensions/api/tab_capture/tab_capture_api.h b/chromium/chrome/browser/extensions/api/tab_capture/tab_capture_api.h index 8e9675f1c61..b035882611a 100644 --- a/chromium/chrome/browser/extensions/api/tab_capture/tab_capture_api.h +++ b/chromium/chrome/browser/extensions/api/tab_capture/tab_capture_api.h @@ -22,7 +22,7 @@ extern const char* const kStableChromecastExtensionId; // Extension ids for the chromecast. extern const char* const kChromecastExtensionIds[6]; -class TabCaptureCaptureFunction : public ChromeSyncExtensionFunction { +class TabCaptureCaptureFunction : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("tabCapture.capture", TABCAPTURE_CAPTURE) @@ -30,10 +30,10 @@ class TabCaptureCaptureFunction : public ChromeSyncExtensionFunction { ~TabCaptureCaptureFunction() final {} // ExtensionFunction: - bool RunSync() final; + ResponseAction Run() final; }; -class TabCaptureGetCapturedTabsFunction : public ChromeSyncExtensionFunction { +class TabCaptureGetCapturedTabsFunction : public UIThreadExtensionFunction { public: DECLARE_EXTENSION_FUNCTION("tabCapture.getCapturedTabs", TABCAPTURE_GETCAPTUREDTABS) @@ -42,7 +42,7 @@ class TabCaptureGetCapturedTabsFunction : public ChromeSyncExtensionFunction { ~TabCaptureGetCapturedTabsFunction() final {} // ExtensionFunction: - bool RunSync() final; + ResponseAction Run() final; }; class TabCaptureCaptureOffscreenTabFunction : public UIThreadExtensionFunction { diff --git a/chromium/chrome/browser/extensions/api/tabs/ash_panel_contents.h b/chromium/chrome/browser/extensions/api/tabs/ash_panel_contents.h index 442051dc784..78299ec947c 100644 --- a/chromium/chrome/browser/extensions/api/tabs/ash_panel_contents.h +++ b/chromium/chrome/browser/extensions/api/tabs/ash_panel_contents.h @@ -16,14 +16,6 @@ class GURL; -namespace content { -class RenderViewHost; -} - -namespace extensions { -struct DraggableRegion; -} - // extensions::AppWindowContents class specific to panel windows created by v1 // extenstions. This class maintains a WebContents instance and observes it for // the purpose of passing messages to the extensions system. It also creates diff --git a/chromium/chrome/browser/extensions/api/tabs/tabs_api.cc b/chromium/chrome/browser/extensions/api/tabs/tabs_api.cc index 28d77b098a3..f882148ceb7 100644 --- a/chromium/chrome/browser/extensions/api/tabs/tabs_api.cc +++ b/chromium/chrome/browser/extensions/api/tabs/tabs_api.cc @@ -225,9 +225,7 @@ bool IsValidStateForWindowsCreateFunction( bool has_bound = create_data->left || create_data->top || create_data->width || create_data->height; - bool is_panel = - create_data->type == windows::CreateType::CREATE_TYPE_PANEL || - create_data->type == windows::CreateType::CREATE_TYPE_DETACHED_PANEL; + bool is_panel = create_data->type == windows::CreateType::CREATE_TYPE_PANEL; switch (create_data->state) { case windows::WINDOW_STATE_MINIMIZED: @@ -500,8 +498,7 @@ ExtensionFunction::ResponseAction WindowsCreateFunction::Run() { extension_id = extension()->id(); break; - case windows::CREATE_TYPE_PANEL: - case windows::CREATE_TYPE_DETACHED_PANEL: { + case windows::CREATE_TYPE_PANEL: { extension_id = extension()->id(); #if defined(USE_ASH) // Only ChromeOS' version of chrome.windows.create would create a panel diff --git a/chromium/chrome/browser/extensions/api/tabs/tabs_constants.cc b/chromium/chrome/browser/extensions/api/tabs/tabs_constants.cc index 8d4392b3f7a..8df23c8d14f 100644 --- a/chromium/chrome/browser/extensions/api/tabs/tabs_constants.cc +++ b/chromium/chrome/browser/extensions/api/tabs/tabs_constants.cc @@ -67,7 +67,6 @@ const char kStatusValueLoading[] = "loading"; const char kWindowTypeValueNormal[] = "normal"; const char kWindowTypeValuePopup[] = "popup"; const char kWindowTypeValuePanel[] = "panel"; -const char kWindowTypeValueDetachedPanel[] = "detached_panel"; const char kWindowTypeValueApp[] = "app"; const char kWindowTypeValueDevTools[] = "devtools"; diff --git a/chromium/chrome/browser/extensions/api/tabs/tabs_constants.h b/chromium/chrome/browser/extensions/api/tabs/tabs_constants.h index f9b633b326a..92f66619bc4 100644 --- a/chromium/chrome/browser/extensions/api/tabs/tabs_constants.h +++ b/chromium/chrome/browser/extensions/api/tabs/tabs_constants.h @@ -73,7 +73,6 @@ extern const char kStatusValueLoading[]; extern const char kWindowTypeValueNormal[]; extern const char kWindowTypeValuePopup[]; extern const char kWindowTypeValuePanel[]; -extern const char kWindowTypeValueDetachedPanel[]; extern const char kWindowTypeValueApp[]; extern const char kWindowTypeValueDevTools[]; diff --git a/chromium/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc b/chromium/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc index 879acfef8de..f27be745923 100644 --- a/chromium/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc +++ b/chromium/chrome/browser/extensions/api/tabs/tabs_interactive_test.cc @@ -12,18 +12,17 @@ #include "chrome/browser/extensions/extension_function_test_utils.h" #include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/ui/browser.h" -#include "chrome/browser/ui/browser_window.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/interactive_test_utils.h" -#include "chrome/test/base/ui_test_utils.h" #include "extensions/browser/api_test_utils.h" #include "extensions/common/test_util.h" -namespace api_test_utils = extensions::api_test_utils; -namespace keys = extensions::tabs_constants; +namespace extensions { + +namespace keys = tabs_constants; namespace utils = extension_function_test_utils; -typedef InProcessBrowserTest ExtensionTabsTest; +using ExtensionTabsTest = InProcessBrowserTest; // http://crbug.com/154081 for Aura specific // http://crbug.com/179063 for other general failures on try bots. @@ -37,6 +36,11 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, MAYBE_GetLastFocusedWindow) { // Create a new window which making it the "last focused" window. // Note that "last focused" means the "top" most window. Browser* new_browser = CreateBrowser(browser()->profile()); + ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(new_browser)); + + GURL url("about:blank"); + AddTabAtIndexToBrowser(new_browser, 0, url, ui::PAGE_TRANSITION_LINK, true); + int focused_window_id = extensions::ExtensionTabUtil::GetWindowId(new_browser); @@ -69,24 +73,15 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, MAYBE_GetLastFocusedWindow) { EXPECT_TRUE(result.get()->GetList(keys::kTabsKey, &tabs)); } -// Flaky: http://crbug.com/136562 -IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DISABLED_QueryLastFocusedWindowTabs) { +IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, QueryLastFocusedWindowTabs) { const size_t kExtraWindows = 2; for (size_t i = 0; i < kExtraWindows; ++i) CreateBrowser(browser()->profile()); Browser* focused_window = CreateBrowser(browser()->profile()); -#if defined(OS_MACOSX) - // See BrowserWindowCocoa::Show. In tests, Browser::window()->IsActive won't - // work unless we fake the browser being launched by the user. - ASSERT_TRUE(ui_test_utils::ShowAndFocusNativeWindow( - focused_window->window()->GetNativeWindow())); -#endif - - // Needed on Mac and Linux so that the BrowserWindow::IsActive calls work. - content::RunAllPendingInMessageLoop(); + ASSERT_TRUE(ui_test_utils::BringBrowserWindowToFront(focused_window)); - GURL url; + GURL url("about:blank"); AddTabAtIndexToBrowser(focused_window, 0, url, ui::PAGE_TRANSITION_LINK, true); int focused_window_id = @@ -95,6 +90,9 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DISABLED_QueryLastFocusedWindowTabs) { // Get tabs in the 'last focused' window called from non-focused browser. scoped_refptr<extensions::TabsQueryFunction> function = new extensions::TabsQueryFunction(); + scoped_refptr<extensions::Extension> extension( + extensions::test_util::CreateEmptyExtension()); + function->set_extension(extension.get()); std::unique_ptr<base::ListValue> result( utils::ToList(utils::RunFunctionAndReturnSingleResult( function.get(), "[{\"lastFocusedWindow\":true}]", browser()))); @@ -111,6 +109,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DISABLED_QueryLastFocusedWindowTabs) { // Get tabs NOT in the 'last focused' window called from the focused browser. function = new extensions::TabsQueryFunction(); + function->set_extension(extension.get()); result.reset(utils::ToList( utils::RunFunctionAndReturnSingleResult(function.get(), "[{\"lastFocusedWindow\":false}]", @@ -135,3 +134,5 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsTest, DISABLED_QueryLastFocusedWindowTabs) { IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MAYBE_TabCurrentWindow) { ASSERT_TRUE(RunExtensionTest("tabs/current_window")) << message_; } + +} // namespace extensions diff --git a/chromium/chrome/browser/extensions/api/tabs/tabs_test.cc b/chromium/chrome/browser/extensions/api/tabs/tabs_test.cc index 1ca713ac39a..9e33edf72d9 100644 --- a/chromium/chrome/browser/extensions/api/tabs/tabs_test.cc +++ b/chromium/chrome/browser/extensions/api/tabs/tabs_test.cc @@ -1059,6 +1059,8 @@ IN_PROC_BROWSER_TEST_F(ExtensionWindowLastFocusedTest, IN_PROC_BROWSER_TEST_F(ExtensionWindowCreateTest, AcceptState) { #if defined(OS_MACOSX) + if (base::mac::IsOS10_10()) + return; // Fails when swarmed. http://crbug.com/660582 ui::test::ScopedFakeNSWindowFullscreen fake_fullscreen; #endif @@ -2116,4 +2118,33 @@ IN_PROC_BROWSER_TEST_F(ExtensionTabsZoomTest, CannotZoomInvalidTab) { base::MatchPattern(error, manifest_errors::kCannotAccessChromeUrl)); } +// Regression test for crbug.com/660498. +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Foo) { + ASSERT_TRUE(StartEmbeddedTestServer()); + content::WebContents* first_web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + ASSERT_TRUE(first_web_contents); + chrome::NewTab(browser()); + content::WebContents* second_web_contents = + browser()->tab_strip_model()->GetActiveWebContents(); + ASSERT_NE(first_web_contents, second_web_contents); + GURL url = embedded_test_server()->GetURL( + "/extensions/api_test/tabs/pdf_extension_test.html"); + content::TestNavigationManager navigation_manager( + second_web_contents, GURL("http://www.facebook.com:83")); + ui_test_utils::NavigateToURLWithDisposition( + browser(), url, WindowOpenDisposition::CURRENT_TAB, + ui_test_utils::BROWSER_TEST_WAIT_FOR_NAVIGATION); + EXPECT_TRUE(navigation_manager.WaitForRequestStart()); + + browser()->tab_strip_model()->ActivateTabAt(0, true); + EXPECT_EQ(first_web_contents, + browser()->tab_strip_model()->GetActiveWebContents()); + browser()->tab_strip_model()->ActivateTabAt(1, true); + EXPECT_EQ(second_web_contents, + browser()->tab_strip_model()->GetActiveWebContents()); + + EXPECT_EQ(url, second_web_contents->GetVisibleURL()); +} + } // namespace extensions diff --git a/chromium/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc b/chromium/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc index a04ffa1a176..fe50acfe062 100644 --- a/chromium/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc +++ b/chromium/chrome/browser/extensions/api/web_navigation/frame_navigation_state.cc @@ -77,7 +77,7 @@ void FrameNavigationState::StartTrackingDocumentLoad( frame_state.error_occurred = is_error_page; frame_state.url = url; frame_state.is_iframe_srcdoc = is_iframe_srcdoc; - DCHECK(!is_iframe_srcdoc || url == GURL(url::kAboutBlankURL)); + DCHECK(!is_iframe_srcdoc || url == url::kAboutBlankURL); if (!is_same_page) { frame_state.is_loading = true; frame_state.is_parsing = true; diff --git a/chromium/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h b/chromium/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h index aa9347b7699..1647dad0db4 100644 --- a/chromium/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h +++ b/chromium/chrome/browser/extensions/api/web_navigation/frame_navigation_state.h @@ -14,7 +14,6 @@ namespace content { class RenderFrameHost; -class RenderViewHost; } namespace extensions { diff --git a/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc b/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc index 165da220b19..6d45ec58562 100644 --- a/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc +++ b/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_api.cc @@ -30,8 +30,6 @@ #include "extensions/browser/view_type_utils.h" #include "net/base/net_errors.h" -using content::ResourceType; - namespace GetFrame = extensions::api::web_navigation::GetFrame; namespace GetAllFrames = extensions::api::web_navigation::GetAllFrames; @@ -268,7 +266,7 @@ void WebNavigationTabObserver::RenderFrameHostChanged( void WebNavigationTabObserver::DidStartNavigation( content::NavigationHandle* navigation_handle) { - if (navigation_handle->IsSynchronousNavigation() || + if (navigation_handle->IsSamePage() || !FrameNavigationState::IsValidUrl(navigation_handle->GetURL())) { return; } @@ -325,8 +323,8 @@ void WebNavigationTabObserver::DidFinishLoad( // srcdoc iframes will report a url of about:blank, still let it through. if (navigation_state_.GetUrl(render_frame_host) != validated_url && (navigation_state_.GetUrl(render_frame_host) != - GURL(content::kAboutSrcDocURL) || - validated_url != GURL(url::kAboutBlankURL))) { + content::kAboutSrcDocURL || + validated_url != url::kAboutBlankURL)) { return; } @@ -446,24 +444,18 @@ bool WebNavigationTabObserver::IsReferenceFragmentNavigation( url.ReplaceComponents(replacements); } -bool WebNavigationGetFrameFunction::RunSync() { +ExtensionFunction::ResponseAction WebNavigationGetFrameFunction::Run() { std::unique_ptr<GetFrame::Params> params(GetFrame::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); int tab_id = params->details.tab_id; int frame_id = params->details.frame_id; - SetResult(base::Value::CreateNullValue()); - content::WebContents* web_contents; - if (!ExtensionTabUtil::GetTabById(tab_id, - GetProfile(), - include_incognito(), - NULL, - NULL, - &web_contents, - NULL) || + if (!ExtensionTabUtil::GetTabById(tab_id, browser_context(), + include_incognito(), nullptr, nullptr, + &web_contents, nullptr) || !web_contents) { - return true; + return RespondNow(OneArgument(base::Value::CreateNullValue())); } WebNavigationTabObserver* observer = @@ -477,11 +469,11 @@ bool WebNavigationGetFrameFunction::RunSync() { ExtensionApiFrameIdMap::Get()->GetRenderFrameHostById(web_contents, frame_id); if (!frame_navigation_state.IsValidFrame(render_frame_host)) - return true; + return RespondNow(OneArgument(base::Value::CreateNullValue())); GURL frame_url = frame_navigation_state.GetUrl(render_frame_host); if (!frame_navigation_state.IsValidUrl(frame_url)) - return true; + return RespondNow(OneArgument(base::Value::CreateNullValue())); GetFrame::Results::Details frame_details; frame_details.url = frame_url.spec(); @@ -489,28 +481,21 @@ bool WebNavigationGetFrameFunction::RunSync() { frame_navigation_state.GetErrorOccurredInFrame(render_frame_host); frame_details.parent_frame_id = ExtensionApiFrameIdMap::GetFrameId(render_frame_host->GetParent()); - results_ = GetFrame::Results::Create(frame_details); - return true; + return RespondNow(ArgumentList(GetFrame::Results::Create(frame_details))); } -bool WebNavigationGetAllFramesFunction::RunSync() { +ExtensionFunction::ResponseAction WebNavigationGetAllFramesFunction::Run() { std::unique_ptr<GetAllFrames::Params> params( GetAllFrames::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); int tab_id = params->details.tab_id; - SetResult(base::Value::CreateNullValue()); - content::WebContents* web_contents; - if (!ExtensionTabUtil::GetTabById(tab_id, - GetProfile(), - include_incognito(), - NULL, - NULL, - &web_contents, - NULL) || + if (!ExtensionTabUtil::GetTabById(tab_id, browser_context(), + include_incognito(), nullptr, nullptr, + &web_contents, nullptr) || !web_contents) { - return true; + return RespondNow(OneArgument(base::Value::CreateNullValue())); } WebNavigationTabObserver* observer = @@ -535,8 +520,7 @@ bool WebNavigationGetAllFramesFunction::RunSync() { frame.error_occurred = navigation_state.GetErrorOccurredInFrame(*it); result_list.push_back(std::move(frame)); } - results_ = GetAllFrames::Results::Create(result_list); - return true; + return RespondNow(ArgumentList(GetAllFrames::Results::Create(result_list))); } WebNavigationAPI::WebNavigationAPI(content::BrowserContext* context) diff --git a/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_api.h b/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_api.h index e583c357f5c..47a2915470d 100644 --- a/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_api.h +++ b/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_api.h @@ -169,16 +169,16 @@ class WebNavigationEventRouter : public TabStripModelObserver, }; // API function that returns the state of a given frame. -class WebNavigationGetFrameFunction : public ChromeSyncExtensionFunction { +class WebNavigationGetFrameFunction : public UIThreadExtensionFunction { ~WebNavigationGetFrameFunction() override {} - bool RunSync() override; + ResponseAction Run() override; DECLARE_EXTENSION_FUNCTION("webNavigation.getFrame", WEBNAVIGATION_GETFRAME) }; // API function that returns the states of all frames in a given tab. -class WebNavigationGetAllFramesFunction : public ChromeSyncExtensionFunction { +class WebNavigationGetAllFramesFunction : public UIThreadExtensionFunction { ~WebNavigationGetAllFramesFunction() override {} - bool RunSync() override; + ResponseAction Run() override; DECLARE_EXTENSION_FUNCTION("webNavigation.getAllFrames", WEBNAVIGATION_GETALLFRAMES) }; diff --git a/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc b/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc index c542d111c49..0031c798f90 100644 --- a/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc +++ b/chromium/chrome/browser/extensions/api/web_navigation/web_navigation_apitest.cc @@ -41,6 +41,7 @@ #include "content/public/browser/resource_dispatcher_host.h" #include "content/public/browser/resource_throttle.h" #include "content/public/browser/web_contents.h" +#include "content/public/common/browser_side_navigation_policy.h" #include "content/public/common/context_menu_params.h" #include "content/public/common/resource_type.h" #include "content/public/common/url_constants.h" @@ -53,8 +54,8 @@ #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/test/embedded_test_server/http_request.h" #include "net/test/embedded_test_server/http_response.h" +#include "third_party/WebKit/public/platform/WebInputEvent.h" #include "third_party/WebKit/public/web/WebContextMenuData.h" -#include "third_party/WebKit/public/web/WebInputEvent.h" using content::ResourceType; using content::WebContents; @@ -120,8 +121,7 @@ class TestNavigationListener // // Needs to be invoked on the IO thread. content::ResourceThrottle* CreateResourceThrottle( - const GURL& url, - ResourceType resource_type) { + const GURL& url) { DCHECK_CURRENTLY_ON(content::BrowserThread::IO); if (urls_to_delay_.find(url) == urls_to_delay_.end()) return NULL; @@ -320,8 +320,7 @@ class TestResourceDispatcherHostDelegate resource_type, throttles); content::ResourceThrottle* throttle = - test_navigation_listener_->CreateResourceThrottle(request->url(), - resource_type); + test_navigation_listener_->CreateResourceThrottle(request->url()); if (throttle) throttles->push_back(throttle); } @@ -405,7 +404,12 @@ IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, ClientRedirect) { << message_; } -IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, ServerRedirect) { +#if defined(OS_LINUX) // http://crbug.com/660288 +#define MAYBE_ServerRedirect DISABLED_ServerRedirect +#else +#define MAYBE_ServerRedirect ServerRedirect +#endif +IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, MAYBE_ServerRedirect) { ASSERT_TRUE(StartEmbeddedTestServer()); ASSERT_TRUE(RunExtensionTest("webnavigation/serverRedirect")) << message_; @@ -504,7 +508,13 @@ IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, FilteredTest) { ASSERT_TRUE(RunExtensionTest("webnavigation/filtered")) << message_; } -IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, UserAction) { +// Flaky on Windows. See http://crbug.com/662160. +#if defined(OS_WIN) +#define MAYBE_UserAction DISABLED_UserAction +#else +#define MAYBE_UserAction UserAction +#endif +IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, MAYBE_UserAction) { content::IsolateAllSitesForTesting(base::CommandLine::ForCurrentProcess()); ASSERT_TRUE(StartEmbeddedTestServer()); @@ -681,6 +691,11 @@ IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, CrossProcess) { // resumes all URL requests. Instead, the test explicitly delays each URL // and resumes manually at the required time. IN_PROC_BROWSER_TEST_F(WebNavigationApiTest, CrossProcessAbort) { + // This test does not make sense in PlzNavigate mode, as simultanious + // navigations that make network requests are not supported. + if (content::IsBrowserSideNavigationEnabled()) + return; + ASSERT_TRUE(StartEmbeddedTestServer()); // Add the cross-site URL delay early on, as loading the extension will diff --git a/chromium/chrome/browser/extensions/api/web_request/chrome_extension_web_request_event_router_delegate.cc b/chromium/chrome/browser/extensions/api/web_request/chrome_extension_web_request_event_router_delegate.cc index 96f2a1c76d7..e473d02dd0f 100644 --- a/chromium/chrome/browser/extensions/api/web_request/chrome_extension_web_request_event_router_delegate.cc +++ b/chromium/chrome/browser/extensions/api/web_request/chrome_extension_web_request_event_router_delegate.cc @@ -22,6 +22,11 @@ void NotifyWebRequestWithheldOnUI(int render_process_id, content::RenderFrameHost::FromID(render_process_id, render_frame_id); if (!rfh) return; + // We don't count subframe blocked actions as yet, since there's no way to + // surface this to the user. Ignore these (which is also what we do for + // content scripts). + if (rfh->GetParent()) + return; content::WebContents* web_contents = content::WebContents::FromRenderFrameHost(rfh); if (!web_contents) diff --git a/chromium/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc b/chromium/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc index c007c13476e..004116e4948 100644 --- a/chromium/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc +++ b/chromium/chrome/browser/extensions/api/web_request/web_request_api_unittest.cc @@ -29,6 +29,7 @@ #include "base/time/time.h" #include "chrome/browser/content_settings/cookie_settings_factory.h" #include "chrome/browser/extensions/event_router_forwarder.h" +#include "chrome/browser/net/chrome_extensions_network_delegate.h" #include "chrome/browser/net/chrome_network_delegate.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" @@ -36,7 +37,7 @@ #include "components/about_handler/about_protocol_handler.h" #include "components/content_settings/core/browser/cookie_settings.h" #include "components/prefs/pref_member.h" -#include "components/syncable_prefs/testing_pref_service_syncable.h" +#include "components/sync_preferences/testing_pref_service_syncable.h" #include "content/public/common/url_constants.h" #include "content/public/test/test_browser_thread_bundle.h" #include "extensions/browser/api/web_request/upload_data_presenter.h" @@ -125,19 +126,15 @@ bool HasWarning(const WarningSet& warnings, } // Parses the JSON data attached to the |message| and tries to return it. -// |param| must outlive |out|. Returns NULL on failure. +// |param| must outlive |out|. void GetPartOfMessageArguments(IPC::Message* message, const base::DictionaryValue** out, - ExtensionMsg_MessageInvoke::Param* param) { - ASSERT_EQ(ExtensionMsg_MessageInvoke::ID, message->type()); - ASSERT_TRUE(ExtensionMsg_MessageInvoke::Read(message, param)); - ASSERT_GE(std::get<3>(*param).GetSize(), 2u); - const base::Value* value = NULL; - ASSERT_TRUE(std::get<3>(*param).Get(1, &value)); - const base::ListValue* list = NULL; - ASSERT_TRUE(value->GetAsList(&list)); - ASSERT_EQ(1u, list->GetSize()); - ASSERT_TRUE(list->GetDictionary(0, out)); + ExtensionMsg_DispatchEvent::Param* param) { + ASSERT_EQ(ExtensionMsg_DispatchEvent::ID, message->type()); + ASSERT_TRUE(ExtensionMsg_DispatchEvent::Read(message, param)); + const base::ListValue& list = std::get<1>(*param); + ASSERT_EQ(1u, list.GetSize()); + ASSERT_TRUE(list.GetDictionary(0, out)); } } // namespace @@ -167,7 +164,7 @@ class TestIPCSender : public IPC::Sender { private: // IPC::Sender bool Send(IPC::Message* message) override { - EXPECT_EQ(ExtensionMsg_MessageInvoke::ID, message->type()); + EXPECT_EQ(ExtensionMsg_DispatchEvent::ID, message->type()); EXPECT_FALSE(task_queue_.empty()); base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE, @@ -196,8 +193,7 @@ class ExtensionWebRequestTest : public testing::Test { &enable_referrers_, nullptr, nullptr, nullptr, nullptr, profile_.GetTestingPrefService()); network_delegate_.reset( - new ChromeNetworkDelegate(event_router_.get(), &enable_referrers_, - metrics::UpdateUsagePrefCallbackType())); + new ChromeNetworkDelegate(event_router_.get(), &enable_referrers_)); network_delegate_->set_profile(&profile_); network_delegate_->set_cookie_settings( CookieSettingsFactory::GetForProfile(&profile_).get()); @@ -299,8 +295,7 @@ TEST_F(ExtensionWebRequestTest, BlockingEventPrecedenceRedirect) { base::RunLoop().Run(); EXPECT_TRUE(!request->is_pending()); - EXPECT_EQ(net::URLRequestStatus::SUCCESS, request->status().status()); - EXPECT_EQ(0, request->status().error()); + EXPECT_EQ(net::OK, delegate_.request_status()); EXPECT_EQ(redirect_url, request->url()); EXPECT_EQ(2U, request->url_chain().size()); EXPECT_EQ(0U, ipc_sender_.GetNumTasks()); @@ -350,8 +345,7 @@ TEST_F(ExtensionWebRequestTest, BlockingEventPrecedenceRedirect) { base::RunLoop().Run(); EXPECT_TRUE(!request2->is_pending()); - EXPECT_EQ(net::URLRequestStatus::SUCCESS, request2->status().status()); - EXPECT_EQ(0, request2->status().error()); + EXPECT_EQ(net::OK, delegate_.request_status()); EXPECT_EQ(redirect_url, request2->url()); EXPECT_EQ(2U, request2->url_chain().size()); EXPECT_EQ(0U, ipc_sender_.GetNumTasks()); @@ -419,8 +413,7 @@ TEST_F(ExtensionWebRequestTest, BlockingEventPrecedenceCancel) { base::RunLoop().Run(); EXPECT_TRUE(!request->is_pending()); - EXPECT_EQ(net::URLRequestStatus::FAILED, request->status().status()); - EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, request->status().error()); + EXPECT_EQ(net::ERR_BLOCKED_BY_CLIENT, delegate_.request_status()); EXPECT_EQ(request_url, request->url()); EXPECT_EQ(1U, request->url_chain().size()); EXPECT_EQ(0U, ipc_sender_.GetNumTasks()); @@ -483,12 +476,11 @@ TEST_F(ExtensionWebRequestTest, SimulateChancelWhileBlocked) { request->Start(); // request->Start() will have submitted OnBeforeRequest by the time we cancel. - request->Cancel(); + int net_error = request->Cancel(); run_loop.Run(); + EXPECT_EQ(net::ERR_ABORTED, net_error); EXPECT_TRUE(!request->is_pending()); - EXPECT_EQ(net::URLRequestStatus::CANCELED, request->status().status()); - EXPECT_EQ(net::ERR_ABORTED, request->status().error()); EXPECT_EQ(request_url, request->url()); EXPECT_EQ(1U, request->url_chain().size()); EXPECT_EQ(0U, ipc_sender_.GetNumTasks()); @@ -702,8 +694,8 @@ TEST_F(ExtensionWebRequestTest, AccessRequestBodyData) { SCOPED_TRACE(testing::Message("iteration number ") << test); EXPECT_NE(i, ipc_sender_.sent_end()); message = (i++)->get(); - const base::DictionaryValue* details; - ExtensionMsg_MessageInvoke::Param param; + const base::DictionaryValue* details = nullptr; + ExtensionMsg_DispatchEvent::Param param; GetPartOfMessageArguments(message, &details, ¶m); ASSERT_TRUE(details != NULL); const base::Value* result = NULL; @@ -794,7 +786,7 @@ TEST_F(ExtensionWebRequestTest, MinimalAccessRequestBodyData) { EXPECT_NE(i, ipc_sender_.sent_end()); IPC::Message* message = i->get(); const base::DictionaryValue* details = nullptr; - ExtensionMsg_MessageInvoke::Param param; + ExtensionMsg_DispatchEvent::Param param; GetPartOfMessageArguments(message, &details, ¶m); ASSERT_TRUE(details != nullptr); EXPECT_EQ(kExpected[test], details->HasKey(keys::kRequestBodyKey)); @@ -850,8 +842,8 @@ TEST_F(ExtensionWebRequestTest, NoAccessRequestBodyData) { SCOPED_TRACE(testing::Message("iteration number ") << test); EXPECT_NE(i, ipc_sender_.sent_end()); IPC::Message* message = i->get(); - const base::DictionaryValue* details = NULL; - ExtensionMsg_MessageInvoke::Param param; + const base::DictionaryValue* details = nullptr; + ExtensionMsg_DispatchEvent::Param param; GetPartOfMessageArguments(message, &details, ¶m); ASSERT_TRUE(details != NULL); EXPECT_FALSE(details->HasKey(keys::kRequestBodyKey)); @@ -1007,8 +999,7 @@ class ExtensionWebRequestHeaderModificationTest &enable_referrers_, nullptr, nullptr, nullptr, nullptr, profile_.GetTestingPrefService()); network_delegate_.reset( - new ChromeNetworkDelegate(event_router_.get(), &enable_referrers_, - metrics::UpdateUsagePrefCallbackType())); + new ChromeNetworkDelegate(event_router_.get(), &enable_referrers_)); network_delegate_->set_profile(&profile_); network_delegate_->set_cookie_settings( CookieSettingsFactory::GetForProfile(&profile_).get()); @@ -1121,7 +1112,7 @@ TEST_P(ExtensionWebRequestHeaderModificationTest, TestModifications) { EXPECT_TRUE(!request->is_pending()); // This cannot succeed as we send the request to a server that does not exist. - EXPECT_EQ(net::URLRequestStatus::FAILED, request->status().status()); + EXPECT_EQ(net::ERR_NAME_NOT_RESOLVED, delegate_.request_status()); EXPECT_EQ(request_url, request->url()); EXPECT_EQ(1U, request->url_chain().size()); EXPECT_EQ(0U, ipc_sender_.GetNumTasks()); @@ -1141,31 +1132,27 @@ TEST_P(ExtensionWebRequestHeaderModificationTest, TestModifications) { TestIPCSender::SentMessages::const_iterator i; for (i = ipc_sender_.sent_begin(); i != ipc_sender_.sent_end(); ++i) { IPC::Message* message = i->get(); - if (ExtensionMsg_MessageInvoke::ID != message->type()) + if (ExtensionMsg_DispatchEvent::ID != message->type()) continue; - ExtensionMsg_MessageInvoke::Param message_tuple; - ExtensionMsg_MessageInvoke::Read(message, &message_tuple); - base::ListValue& args = std::get<3>(message_tuple); + ExtensionMsg_DispatchEvent::Param message_tuple; + ExtensionMsg_DispatchEvent::Read(message, &message_tuple); + const ExtensionMsg_DispatchEvent_Params& params = + std::get<0>(message_tuple); - std::string event_name; - if (!args.GetString(0, &event_name) || - event_name != std::string(keys::kOnSendHeadersEvent) + "/3") { + if (params.event_name != std::string(keys::kOnSendHeadersEvent) + "/3") continue; - } - - base::ListValue* event_arg = NULL; - ASSERT_TRUE(args.GetList(1, &event_arg)); - base::DictionaryValue* event_arg_dict = NULL; - ASSERT_TRUE(event_arg->GetDictionary(0, &event_arg_dict)); + const base::ListValue& event_args = std::get<1>(message_tuple); + const base::DictionaryValue* event_arg_dict = nullptr; + ASSERT_TRUE(event_args.GetDictionary(0, &event_arg_dict)); - base::ListValue* request_headers = NULL; + const base::ListValue* request_headers = nullptr; ASSERT_TRUE(event_arg_dict->GetList(keys::kRequestHeadersKey, &request_headers)); net::HttpRequestHeaders observed_headers; for (size_t j = 0; j < request_headers->GetSize(); ++j) { - base::DictionaryValue* header = NULL; + const base::DictionaryValue* header = nullptr; ASSERT_TRUE(request_headers->GetDictionary(j, &header)); std::string key; std::string value; diff --git a/chromium/chrome/browser/extensions/api/web_request/web_request_apitest.cc b/chromium/chrome/browser/extensions/api/web_request/web_request_apitest.cc index a0ea8893dbb..6c145daf861 100644 --- a/chromium/chrome/browser/extensions/api/web_request/web_request_apitest.cc +++ b/chromium/chrome/browser/extensions/api/web_request/web_request_apitest.cc @@ -22,8 +22,10 @@ #include "chrome/common/extensions/extension_process_policy.h" #include "chrome/test/base/search_test_utils.h" #include "chrome/test/base/ui_test_utils.h" +#include "chromeos/login/login_state.h" #include "content/public/browser/notification_registrar.h" #include "content/public/browser/notification_service.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host.h" #include "content/public/browser/web_contents.h" @@ -37,7 +39,7 @@ #include "extensions/test/result_catcher.h" #include "net/dns/mock_host_resolver.h" #include "net/test/embedded_test_server/embedded_test_server.h" -#include "third_party/WebKit/public/web/WebInputEvent.h" +#include "third_party/WebKit/public/platform/WebInputEvent.h" using content::WebContents; @@ -83,14 +85,14 @@ const char kPerformXhrJs[] = "};\n" "xhr.send();\n"; -// Performs an XHR in the given |web_contents|, replying when complete. -void PerformXhrInPage(content::WebContents* web_contents, +// Performs an XHR in the given |frame|, replying when complete. +void PerformXhrInFrame(content::RenderFrameHost* frame, const std::string& host, int port, const std::string& page) { bool success = false; EXPECT_TRUE(ExecuteScriptAndExtractBool( - web_contents, + frame, base::StringPrintf(kPerformXhrJs, host.c_str(), port, page.c_str()), &success)); EXPECT_TRUE(success); @@ -161,6 +163,23 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestTypes) { ASSERT_TRUE(RunExtensionSubtest("webrequest", "test_types.html")) << message_; } +#if defined(OS_CHROMEOS) +IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestPublicSession) { + ASSERT_TRUE(StartEmbeddedTestServer()); + // Set Public Session state. + chromeos::LoginState::Get()->SetLoggedInState( + chromeos::LoginState::LOGGED_IN_ACTIVE, + chromeos::LoginState::LOGGED_IN_USER_PUBLIC_ACCOUNT); + // Disable a CHECK while doing api tests. + WebRequestPermissions::AllowAllExtensionLocationsInPublicSessionForTesting( + true); + ASSERT_TRUE(RunExtensionSubtest("webrequest_public_session", "test.html")) << + message_; + WebRequestPermissions::AllowAllExtensionLocationsInPublicSessionForTesting( + false); +} +#endif // defined(OS_CHROMEOS) + // Test that a request to an OpenSearch description document (OSDD) generates // an event with the expected details. IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestTestOSDD) { @@ -529,7 +548,11 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, WebRequestWithWithheldPermissions) { FeatureSwitch::ScopedOverride enable_scripts_require_action( FeatureSwitch::scripts_require_action(), true); - ASSERT_TRUE(StartEmbeddedTestServer()); + + host_resolver()->AddRule("*", "127.0.0.1"); + ASSERT_TRUE(embedded_test_server()->Start()); + content::SetupCrossSiteRedirector(embedded_test_server()); + // Load an extension that registers a listener for webRequest events, and // wait 'til it's initialized. ExtensionTestMessageListener listener("ready", false); @@ -539,8 +562,9 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, EXPECT_TRUE(listener.WaitUntilSatisfied()); // Navigate the browser to a page in a new tab. - const std::string kHost = "example.com"; - GURL url = embedded_test_server()->GetURL(kHost, "/empty.html"); + GURL url = embedded_test_server()->GetURL( + "/cross-site/a.com/iframe_cross_site.html"); + const std::string kHost = "a.com"; chrome::NavigateParams params(browser(), url, ui::PAGE_TRANSITION_LINK); params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB; ui_test_utils::NavigateToURL(¶ms); @@ -558,12 +582,32 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, // The extension shouldn't have currently received any webRequest events, // since it doesn't have permission (and shouldn't receive any from an XHR). EXPECT_EQ(0, GetWebRequestCountFromBackgroundPage(extension, profile())); - PerformXhrInPage(web_contents, kHost, port, kXhrPath); + + content::RenderFrameHost* main_frame = nullptr; + content::RenderFrameHost* child_frame = nullptr; + auto get_main_and_child_frame = [](content::WebContents* web_contents, + content::RenderFrameHost** main_frame, + content::RenderFrameHost** child_frame) { + *child_frame = nullptr; + *main_frame = web_contents->GetMainFrame(); + std::vector<content::RenderFrameHost*> all_frames = + web_contents->GetAllFrames(); + ASSERT_EQ(3u, all_frames.size()); + *child_frame = all_frames[0] == *main_frame ? all_frames[1] : all_frames[0]; + ASSERT_TRUE(*child_frame); + }; + + get_main_and_child_frame(web_contents, &main_frame, &child_frame); + const std::string kMainHost = main_frame->GetLastCommittedURL().host(); + const std::string kChildHost = child_frame->GetLastCommittedURL().host(); + + PerformXhrInFrame(main_frame, kHost, port, kXhrPath); + PerformXhrInFrame(child_frame, kChildHost, port, kXhrPath); EXPECT_EQ(0, GetWebRequestCountFromBackgroundPage(extension, profile())); + EXPECT_EQ(BLOCKED_ACTION_WEB_REQUEST, runner->GetBlockedActions(extension)); // Grant activeTab permission, and perform another XHR. The extension should // receive the event. - EXPECT_EQ(BLOCKED_ACTION_WEB_REQUEST, runner->GetBlockedActions(extension)); runner->set_default_bubble_close_action_for_testing( base::WrapUnique(new ToolbarActionsBarBubbleDelegate::CloseAction( ToolbarActionsBarBubbleDelegate::CLOSE_EXECUTE))); @@ -571,16 +615,27 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, base::RunLoop().RunUntilIdle(); EXPECT_TRUE(content::WaitForLoadStop(web_contents)); // The runner will have refreshed the page... + get_main_and_child_frame(web_contents, &main_frame, &child_frame); EXPECT_EQ(BLOCKED_ACTION_NONE, runner->GetBlockedActions(extension)); + int xhr_count = GetWebRequestCountFromBackgroundPage(extension, profile()); - // ... which means that we should have a non-zero xhr count. + // ... which means that we should have a non-zero xhr count... EXPECT_GT(xhr_count, 0); - // And the extension should receive future events. - PerformXhrInPage(web_contents, kHost, port, kXhrPath); + // ... and the extension should receive future events. + PerformXhrInFrame(main_frame, kHost, port, kXhrPath); ++xhr_count; EXPECT_EQ(xhr_count, GetWebRequestCountFromBackgroundPage(extension, profile())); + // However, activeTab only grants access to the main frame, not to child + // frames. As such, trying to XHR in the child frame should still fail. + PerformXhrInFrame(child_frame, kChildHost, port, kXhrPath); + EXPECT_EQ(xhr_count, + GetWebRequestCountFromBackgroundPage(extension, profile())); + // But since there's no way for the user to currently grant access to child + // frames, this shouldn't show up as a blocked action. + EXPECT_EQ(BLOCKED_ACTION_NONE, runner->GetBlockedActions(extension)); + // If we revoke the extension's tab permissions, it should no longer receive // webRequest events. ActiveTabPermissionGranter* granter = @@ -588,7 +643,7 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebRequestApiTest, ASSERT_TRUE(granter); granter->RevokeForTesting(); base::RunLoop().RunUntilIdle(); - PerformXhrInPage(web_contents, kHost, port, kXhrPath); + PerformXhrInFrame(main_frame, kHost, port, kXhrPath); EXPECT_EQ(xhr_count, GetWebRequestCountFromBackgroundPage(extension, profile())); EXPECT_EQ(BLOCKED_ACTION_WEB_REQUEST, runner->GetBlockedActions(extension)); diff --git a/chromium/chrome/browser/extensions/api/web_request/web_request_event_details_unittest.cc b/chromium/chrome/browser/extensions/api/web_request/web_request_event_details_unittest.cc new file mode 100644 index 00000000000..4501c524845 --- /dev/null +++ b/chromium/chrome/browser/extensions/api/web_request/web_request_event_details_unittest.cc @@ -0,0 +1,67 @@ +// Copyright 2016 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. + +#include "extensions/browser/api/web_request/web_request_event_details.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace extensions { + +TEST(WebRequestEventDetailsTest, WhitelistedCopyForPublicSession) { + // Create original and copy, and populate them with some values. + std::unique_ptr<WebRequestEventDetails> orig(new WebRequestEventDetails); + std::unique_ptr<WebRequestEventDetails> copy(new WebRequestEventDetails); + + const char* const safe_attributes[] = { + "method", "requestId", "timeStamp", "type", "tabId", "frameId", + "parentFrameId", "fromCache", "error", "ip", "statusLine", "statusCode" + }; + + for (WebRequestEventDetails* ptr : {orig.get(), copy.get()}) { + ptr->render_process_id_ = 1; + ptr->render_frame_id_ = 2; + ptr->extra_info_spec_ = 3; + + ptr->request_body_.reset(new base::DictionaryValue); + ptr->request_headers_.reset(new base::ListValue); + ptr->response_headers_.reset(new base::ListValue); + + for (const char* safe_attr : safe_attributes) { + ptr->dict_.SetString(safe_attr, safe_attr); + } + + ptr->dict_.SetString("url", "http://www.foo.bar/baz"); + + // Add some extra dict_ values that should be filtered out. + ptr->dict_.SetString("requestBody", "request body value"); + ptr->dict_.SetString("requestHeaders", "request headers value"); + } + + // Filter the copy out then check that filtering really works. + copy->FilterForPublicSession(); + + EXPECT_EQ(orig->render_process_id_, copy->render_process_id_); + EXPECT_EQ(orig->render_frame_id_, copy->render_frame_id_); + EXPECT_EQ(0, copy->extra_info_spec_); + + EXPECT_EQ(nullptr, copy->request_body_); + EXPECT_EQ(nullptr, copy->request_headers_); + EXPECT_EQ(nullptr, copy->response_headers_); + + for (const char* safe_attr : safe_attributes) { + std::string copy_str; + copy->dict_.GetString(safe_attr, ©_str); + EXPECT_EQ(safe_attr, copy_str); + } + + // URL is stripped down to origin. + std::string url; + copy->dict_.GetString("url", &url); + EXPECT_EQ("http://www.foo.bar/", url); + + // Extras are filtered out (+1 for url). + EXPECT_EQ(arraysize(safe_attributes) + 1, copy->dict_.size()); +} + +} // namespace extensions diff --git a/chromium/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc b/chromium/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc index 6addaada357..af28138ea03 100644 --- a/chromium/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc +++ b/chromium/chrome/browser/extensions/api/web_request/web_request_permissions_unittest.cc @@ -9,6 +9,7 @@ #include "base/macros.h" #include "base/message_loop/message_loop.h" #include "chrome/common/extensions/extension_test_util.h" +#include "chromeos/login/login_state.h" #include "content/public/browser/resource_request_info.h" #include "content/public/test/test_browser_thread_bundle.h" #include "extensions/browser/api/web_request/web_request_permissions.h" @@ -22,7 +23,6 @@ #include "testing/gtest/include/gtest/gtest.h" using content::ResourceRequestInfo; -using content::ResourceType; using extensions::Extension; using extensions::Manifest; using extensions::PermissionsData; @@ -46,6 +46,9 @@ class ExtensionWebRequestHelpersTestWithThreadsTest : public testing::Test { scoped_refptr<Extension> permissionless_extension_; // This extension has Web Request permissions, and *.com a host permission. scoped_refptr<Extension> com_extension_; + // This extension is the same as com_extension, except it's installed from + // Manifest::EXTERNAL_POLICY_DOWNLOAD. + scoped_refptr<Extension> com_policy_extension_; scoped_refptr<extensions::InfoMap> extension_info_map_; }; @@ -68,16 +71,29 @@ void ExtensionWebRequestHelpersTestWithThreadsTest::SetUp() { "ext_id_2", &error); ASSERT_TRUE(com_extension_.get()) << error; + com_policy_extension_ = + LoadManifestUnchecked("permissions", + "web_request_com_host_permissions.json", + Manifest::EXTERNAL_POLICY_DOWNLOAD, + Extension::NO_FLAGS, + "ext_id_3", + &error); + ASSERT_TRUE(com_policy_extension_.get()) << error; extension_info_map_ = new extensions::InfoMap; extension_info_map_->AddExtension(permissionless_extension_.get(), base::Time::Now(), - false /*incognito_enabled*/, - false /*notifications_disabled*/); + false, // incognito_enabled + false); // notifications_disabled extension_info_map_->AddExtension( com_extension_.get(), base::Time::Now(), - false /*incognito_enabled*/, - false /*notifications_disabled*/); + false, // incognito_enabled + false); // notifications_disabled + extension_info_map_->AddExtension( + com_policy_extension_.get(), + base::Time::Now(), + false, // incognito_enabled + false); // notifications_disabled } TEST_F(ExtensionWebRequestHelpersTestWithThreadsTest, TestHideRequestForURL) { @@ -107,7 +123,8 @@ TEST_F(ExtensionWebRequestHelpersTestWithThreadsTest, TestHideRequestForURL) { std::unique_ptr<net::URLRequest> request( context.CreateRequest(sensitive_url, net::DEFAULT_PRIORITY, NULL)); EXPECT_TRUE(WebRequestPermissions::HideRequest( - extension_info_map_.get(), request.get())) << sensitive_urls[i]; + extension_info_map_.get(), request.get(), nullptr)) << + sensitive_urls[i]; } // Check that requests are accepted if they don't touch sensitive urls. for (size_t i = 0; i < arraysize(non_sensitive_urls); ++i) { @@ -115,7 +132,8 @@ TEST_F(ExtensionWebRequestHelpersTestWithThreadsTest, TestHideRequestForURL) { std::unique_ptr<net::URLRequest> request( context.CreateRequest(non_sensitive_url, net::DEFAULT_PRIORITY, NULL)); EXPECT_FALSE(WebRequestPermissions::HideRequest( - extension_info_map_.get(), request.get())) << non_sensitive_urls[i]; + extension_info_map_.get(), request.get(), nullptr)) << + non_sensitive_urls[i]; } // Check protection of requests originating from the frame showing the Chrome @@ -125,7 +143,7 @@ TEST_F(ExtensionWebRequestHelpersTestWithThreadsTest, TestHideRequestForURL) { std::unique_ptr<net::URLRequest> non_sensitive_request( context.CreateRequest(non_sensitive_url, net::DEFAULT_PRIORITY, NULL)); EXPECT_FALSE(WebRequestPermissions::HideRequest( - extension_info_map_.get(), non_sensitive_request.get())); + extension_info_map_.get(), non_sensitive_request.get(), nullptr)); // If the origin is labeled by the WebStoreAppId, it becomes protected. { int process_id = 42; @@ -147,7 +165,7 @@ TEST_F(ExtensionWebRequestHelpersTestWithThreadsTest, TestHideRequestForURL) { extension_info_map_->RegisterExtensionProcess( extensions::kWebStoreAppId, process_id, site_instance_id); EXPECT_TRUE(WebRequestPermissions::HideRequest( - extension_info_map_.get(), sensitive_request.get())); + extension_info_map_.get(), sensitive_request.get(), nullptr)); } } @@ -161,25 +179,76 @@ TEST_F(ExtensionWebRequestHelpersTestWithThreadsTest, extension_info_map_.get(), permissionless_extension_->id(), request->url(), -1, // No tab id. - false /*crosses_incognito*/, + false, // crosses_incognito WebRequestPermissions::DO_NOT_CHECK_HOST)); EXPECT_EQ(PermissionsData::ACCESS_DENIED, WebRequestPermissions::CanExtensionAccessURL( extension_info_map_.get(), permissionless_extension_->id(), request->url(), -1, // No tab id. - false /*crosses_incognito*/, + false, // crosses_incognito WebRequestPermissions::REQUIRE_HOST_PERMISSION)); EXPECT_EQ(PermissionsData::ACCESS_ALLOWED, WebRequestPermissions::CanExtensionAccessURL( extension_info_map_.get(), com_extension_->id(), request->url(), -1, // No tab id. - false /*crosses_incognito*/, + false, // crosses_incognito WebRequestPermissions::REQUIRE_HOST_PERMISSION)); EXPECT_EQ(PermissionsData::ACCESS_DENIED, WebRequestPermissions::CanExtensionAccessURL( extension_info_map_.get(), com_extension_->id(), request->url(), -1, // No tab id. - false /*crosses_incognito*/, + false, // crosses_incognito WebRequestPermissions::REQUIRE_ALL_URLS)); + + // Public Sessions tests. +#if defined(OS_CHROMEOS) + std::unique_ptr<net::URLRequest> org_request(context.CreateRequest( + GURL("http://example.org"), net::DEFAULT_PRIORITY, nullptr)); + + // com_extension_ doesn't have host permission for .org URLs. + EXPECT_EQ(PermissionsData::ACCESS_DENIED, + WebRequestPermissions::CanExtensionAccessURL( + extension_info_map_.get(), com_policy_extension_->id(), + org_request->url(), + -1, // No tab id. + false, // crosses_incognito + WebRequestPermissions::REQUIRE_HOST_PERMISSION)); + + // Set Public Session state. + chromeos::LoginState::Initialize(); + chromeos::LoginState::Get()->SetLoggedInState( + chromeos::LoginState::LOGGED_IN_ACTIVE, + chromeos::LoginState::LOGGED_IN_USER_PUBLIC_ACCOUNT); + + // Host permission checks are disabled in Public Sessions, instead all URLs + // are whitelisted. + EXPECT_EQ(PermissionsData::ACCESS_ALLOWED, + WebRequestPermissions::CanExtensionAccessURL( + extension_info_map_.get(), com_policy_extension_->id(), + org_request->url(), + -1, // No tab id. + false, // crosses_incognito + WebRequestPermissions::REQUIRE_HOST_PERMISSION)); + + EXPECT_EQ(PermissionsData::ACCESS_ALLOWED, + WebRequestPermissions::CanExtensionAccessURL( + extension_info_map_.get(), com_policy_extension_->id(), + org_request->url(), + -1, // No tab id. + false, // crosses_incognito + WebRequestPermissions::REQUIRE_ALL_URLS)); + + // Make sure that chrome:// URLs cannot be accessed. + std::unique_ptr<net::URLRequest> chrome_request(context.CreateRequest( + GURL("chrome://version/"), net::DEFAULT_PRIORITY, nullptr)); + + EXPECT_EQ(PermissionsData::ACCESS_DENIED, + WebRequestPermissions::CanExtensionAccessURL( + extension_info_map_.get(), com_policy_extension_->id(), + chrome_request->url(), + -1, // No tab id. + false, // crosses_incognito + WebRequestPermissions::REQUIRE_HOST_PERMISSION)); +#endif } diff --git a/chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc b/chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc index 8c3c475fc65..2463eb8f6e8 100644 --- a/chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc +++ b/chromium/chrome/browser/extensions/api/webrtc_audio_private/webrtc_audio_private_browsertest.cc @@ -26,6 +26,7 @@ #include "chrome/browser/media/webrtc/webrtc_log_uploader.h" #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/common/features.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/ui_test_utils.h" #include "content/public/browser/browser_thread.h" @@ -399,7 +400,7 @@ class HangoutServicesBrowserTest : public AudioWaitingExtensionTest { } }; -#if defined(GOOGLE_CHROME_BUILD) || defined(ENABLE_HANGOUT_SERVICES_EXTENSION) +#if BUILDFLAG(ENABLE_HANGOUT_SERVICES_EXTENSION) IN_PROC_BROWSER_TEST_F(HangoutServicesBrowserTest, RunComponentExtensionTest) { // This runs the end-to-end JavaScript test for the Hangout Services @@ -436,6 +437,6 @@ IN_PROC_BROWSER_TEST_F(HangoutServicesBrowserTest, g_browser_process->webrtc_log_uploader()->OverrideUploadWithBufferForTesting( NULL); } -#endif // defined(GOOGLE_CHROME_BUILD) || defined(ENABLE_HANGOUT_SERVICES_EXTENSION) +#endif // BUILDFLAG(ENABLE_HANGOUT_SERVICES_EXTENSION) } // namespace extensions diff --git a/chromium/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc b/chromium/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc index 49ea727195a..b000d228473 100644 --- a/chromium/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc +++ b/chromium/chrome/browser/extensions/api/webrtc_logging_private/webrtc_logging_private_api.cc @@ -469,29 +469,25 @@ bool WebrtcLoggingPrivateStartWebRtcEventLoggingFunction::RunAsync() { std::unique_ptr<StartWebRtcEventLogging::Params> params( StartWebRtcEventLogging::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); - if (params->seconds < 0) { FireErrorCallback("seconds must be greater than or equal to 0"); return true; } - content::RenderProcessHost* host = - RphFromRequest(params->request, params->security_origin); - if (!host) + scoped_refptr<WebRtcLoggingHandlerHost> webrtc_logging_handler_host( + LoggingHandlerFromRequest(params->request, params->security_origin)); + if (!webrtc_logging_handler_host.get()) return false; - scoped_refptr<WebRtcEventLogHandler> webrtc_event_log_handler( - base::UserDataAdapter<WebRtcEventLogHandler>::Get( - host, WebRtcEventLogHandler::kWebRtcEventLogHandlerKey)); - - webrtc_event_log_handler->StartWebRtcEventLogging( - host, base::TimeDelta::FromSeconds(params->seconds), + webrtc_logging_handler_host->StartWebRtcEventLogging( + base::TimeDelta::FromSeconds(params->seconds), base::Bind( - &WebrtcLoggingPrivateStartWebRtcEventLoggingFunction::FireCallback, - this), - base::Bind( - &WebrtcLoggingPrivateStartWebRtcEventLoggingFunction::FireErrorCallback, - this)); + &WebrtcLoggingPrivateStartWebRtcEventLoggingFunction::FireCallback, + this), + base::Bind(&WebrtcLoggingPrivateStartWebRtcEventLoggingFunction:: + FireErrorCallback, + this)); + return true; } @@ -505,23 +501,19 @@ bool WebrtcLoggingPrivateStopWebRtcEventLoggingFunction::RunAsync() { StopWebRtcEventLogging::Params::Create(*args_)); EXTENSION_FUNCTION_VALIDATE(params.get()); - content::RenderProcessHost* host = - RphFromRequest(params->request, params->security_origin); - if (!host) + scoped_refptr<WebRtcLoggingHandlerHost> webrtc_logging_handler_host( + LoggingHandlerFromRequest(params->request, params->security_origin)); + if (!webrtc_logging_handler_host.get()) return false; - scoped_refptr<WebRtcEventLogHandler> webrtc_event_log_handler( - base::UserDataAdapter<WebRtcEventLogHandler>::Get( - host, WebRtcEventLogHandler::kWebRtcEventLogHandlerKey)); - - webrtc_event_log_handler->StopWebRtcEventLogging( - host, - base::Bind( - &WebrtcLoggingPrivateStopWebRtcEventLoggingFunction::FireCallback, - this), + webrtc_logging_handler_host->StopWebRtcEventLogging( base::Bind( - &WebrtcLoggingPrivateStopWebRtcEventLoggingFunction::FireErrorCallback, - this)); + &WebrtcLoggingPrivateStopWebRtcEventLoggingFunction::FireCallback, + this), + base::Bind(&WebrtcLoggingPrivateStopWebRtcEventLoggingFunction:: + FireErrorCallback, + this)); + return true; } diff --git a/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc b/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc index e037c2ed376..8f394423414 100644 --- a/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc +++ b/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_api.cc @@ -41,6 +41,11 @@ #include "net/url_request/url_request.h" #include "url/gurl.h" +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) +#include "chrome/browser/supervised_user/supervised_user_service.h" +#include "chrome/browser/supervised_user/supervised_user_service_factory.h" +#endif + namespace extensions { namespace BeginInstallWithManifest3 = @@ -263,13 +268,32 @@ void WebstorePrivateBeginInstallWithManifest3Function::OnWebstoreParseSuccess( return; } - // Check the management policy before the installation process begins + // Check the management policy before the installation process begins. + Profile* profile = chrome_details_.GetProfile(); base::string16 policy_error; - bool allow = ExtensionSystem::Get(chrome_details_.GetProfile())-> + bool allow = ExtensionSystem::Get(profile)-> management_policy()->UserMayLoad(dummy_extension_.get(), &policy_error); if (!allow) { - Respond(BuildResponse(api::webstore_private::RESULT_BLOCKED_BY_POLICY, - base::UTF16ToUTF8(policy_error))); + bool blocked_for_child = false; +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) + // If the installation was blocked because the user is a child, we send a + // different error code so that the Web Store can adjust the UI accordingly. + // In that case, the CWS will not show the |policy_error|. + if (profile->IsChild()) { + SupervisedUserService* service = + SupervisedUserServiceFactory::GetForProfile(profile); + // Hack: Check that the message matches to make sure installation was + // actually blocked due to the user being a child, as opposed to, say, + // device policy. + if (policy_error == service->GetExtensionsLockedMessage()) + blocked_for_child = true; + } +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) + api::webstore_private::Result code = + blocked_for_child + ? api::webstore_private::RESULT_BLOCKED_FOR_CHILD_ACCOUNT + : api::webstore_private::RESULT_BLOCKED_BY_POLICY; + Respond(BuildResponse(code, base::UTF16ToUTF8(policy_error))); // Matches the AddRef in Run(). Release(); return; diff --git a/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc b/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc index 44c766682bd..0bdcebc704a 100644 --- a/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc +++ b/chromium/chrome/browser/extensions/api/webstore_private/webstore_private_apitest.cc @@ -21,6 +21,7 @@ #include "chrome/browser/ui/browser.h" #include "chrome/browser/ui/tabs/tab_strip_model.h" #include "chrome/common/chrome_switches.h" +#include "chrome/common/features.h" #include "chrome/test/base/ui_test_utils.h" #include "content/public/browser/gpu_data_manager.h" #include "content/public/browser/notification_observer.h" @@ -36,6 +37,10 @@ #include "net/test/embedded_test_server/embedded_test_server.h" #include "ui/gl/gl_switches.h" +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) +#include "chrome/browser/supervised_user/supervised_user_constants.h" +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) + using gpu::GpuFeatureType; namespace utils = extension_function_test_utils; @@ -345,6 +350,44 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTest, EmptyCrx) { ASSERT_TRUE(RunInstallTest("empty.html", "empty.crx")); } +#if BUILDFLAG(ENABLE_SUPERVISED_USERS) + +class ExtensionWebstorePrivateApiTestSupervised + : public ExtensionWebstorePrivateApiTest { + public: + void SetUpCommandLine(base::CommandLine* command_line) override { + ExtensionWebstorePrivateApiTest::SetUpCommandLine(command_line); + command_line->AppendSwitchASCII(switches::kSupervisedUserId, "not_empty"); + } +}; + +// Tests that extension installation is blocked for supervised users. +// Note: This will have to be updated if we enable SU-initiated installs. +IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTestSupervised, + InstallBlocked) { + ASSERT_TRUE( + RunInstallTest("begin_install_fail_supervised.html", "extension.crx")); +} + +class ExtensionWebstorePrivateApiTestChild + : public ExtensionWebstorePrivateApiTest { + public: + void SetUpCommandLine(base::CommandLine* command_line) override { + ExtensionWebstorePrivateApiTest::SetUpCommandLine(command_line); + command_line->AppendSwitchASCII(switches::kSupervisedUserId, + supervised_users::kChildAccountSUID); + } +}; + +// Tests that extension installation is blocked for child accounts, and +// attempting to do so produces a special error code. +// Note: This will have to be updated when we enable child-initiated installs. +IN_PROC_BROWSER_TEST_F(ExtensionWebstorePrivateApiTestChild, InstallBlocked) { + ASSERT_TRUE(RunInstallTest("begin_install_fail_child.html", "extension.crx")); +} + +#endif // BUILDFLAG(ENABLE_SUPERVISED_USERS) + class ExtensionWebstoreGetWebGLStatusTest : public InProcessBrowserTest { protected: void RunTest(bool webgl_allowed) { diff --git a/chromium/chrome/browser/media/router/mojo/media_router.mojom b/chromium/chrome/browser/media/router/mojo/media_router.mojom index 0971cb5b24f..e68a1e09f02 100644 --- a/chromium/chrome/browser/media/router/mojo/media_router.mojom +++ b/chromium/chrome/browser/media/router/mojo/media_router.mojom @@ -49,7 +49,7 @@ struct MediaRoute { // Set to true if this route should be displayed for |media_sink_id| in UI. bool for_display; // Set to true if this route was created by an incognito profile. - bool incognito; + bool is_incognito; }; // Notifications or an actionable events to be shown to the user. diff --git a/chromium/chrome/browser/ntp_snippets/BUILD.gn b/chromium/chrome/browser/ntp_snippets/BUILD.gn new file mode 100644 index 00000000000..474a6f8fb15 --- /dev/null +++ b/chromium/chrome/browser/ntp_snippets/BUILD.gn @@ -0,0 +1,13 @@ +# Copyright 2016 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. + +source_set("test_support") { + testonly = true + sources = [ + "fake_download_item.cc", + "fake_download_item.h", + ] + + deps = [] +} diff --git a/chromium/chrome/browser/printing/background_printing_manager.cc b/chromium/chrome/browser/printing/background_printing_manager.cc index cc7adae4c60..af8ed4cd2cc 100644 --- a/chromium/chrome/browser/printing/background_printing_manager.cc +++ b/chromium/chrome/browser/printing/background_printing_manager.cc @@ -5,6 +5,7 @@ #include "chrome/browser/printing/background_printing_manager.h" #include "base/location.h" +#include "base/memory/ptr_util.h" #include "base/single_thread_task_runner.h" #include "base/stl_util.h" #include "base/threading/thread_task_runner_handle.h" @@ -61,7 +62,6 @@ BackgroundPrintingManager::~BackgroundPrintingManager() { // preview WebContents trying to print). In such a case it will fail to print, // but we should at least clean up the observers. // TODO(thestig): Handle this case better. - base::STLDeleteValues(&printing_contents_map_); } void BackgroundPrintingManager::OwnPrintPreviewDialog( @@ -70,7 +70,8 @@ void BackgroundPrintingManager::OwnPrintPreviewDialog( DCHECK(PrintPreviewDialogController::IsPrintPreviewDialog(preview_dialog)); CHECK(!HasPrintPreviewDialog(preview_dialog)); - printing_contents_map_[preview_dialog] = new Observer(this, preview_dialog); + printing_contents_map_[preview_dialog] = + base::MakeUnique<Observer>(this, preview_dialog); // Watch for print jobs finishing. Everything else is watched for by the // Observer. TODO(avi, cait): finish the job of removing this last @@ -99,8 +100,7 @@ void BackgroundPrintingManager::Observe( void BackgroundPrintingManager::DeletePreviewContents( WebContents* preview_contents) { - WebContentsObserverMap::iterator i = - printing_contents_map_.find(preview_contents); + auto i = printing_contents_map_.find(preview_contents); if (i == printing_contents_map_.end()) { // Everyone is racing to be the first to delete the |preview_contents|. If // this case is hit, someone else won the race, so there is no need to @@ -111,9 +111,7 @@ void BackgroundPrintingManager::DeletePreviewContents( // Stop all observation ... registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_RELEASED, content::Source<WebContents>(preview_contents)); - Observer* observer = i->second; printing_contents_map_.erase(i); - delete observer; // ... and mortally wound the contents. (Deletion immediately is not a good // idea in case this was called from RenderViewGone.) @@ -122,10 +120,9 @@ void BackgroundPrintingManager::DeletePreviewContents( std::set<content::WebContents*> BackgroundPrintingManager::CurrentContentSet() { std::set<content::WebContents*> result; - for (WebContentsObserverMap::iterator i = printing_contents_map_.begin(); - i != printing_contents_map_.end(); ++i) { - result.insert(i->first); - } + for (const auto& entry : printing_contents_map_) + result.insert(entry.first); + return result; } diff --git a/chromium/chrome/browser/printing/background_printing_manager.h b/chromium/chrome/browser/printing/background_printing_manager.h index 0747603b591..c304be0156b 100644 --- a/chromium/chrome/browser/printing/background_printing_manager.h +++ b/chromium/chrome/browser/printing/background_printing_manager.h @@ -6,6 +6,7 @@ #define CHROME_BROWSER_PRINTING_BACKGROUND_PRINTING_MANAGER_H_ #include <map> +#include <memory> #include <set> #include "base/compiler_specific.h" @@ -29,7 +30,6 @@ class BackgroundPrintingManager : public base::NonThreadSafe, public content::NotificationObserver { public: class Observer; - typedef std::map<content::WebContents*, Observer*> WebContentsObserverMap; BackgroundPrintingManager(); ~BackgroundPrintingManager() override; @@ -56,7 +56,8 @@ class BackgroundPrintingManager : public base::NonThreadSafe, // A map from print preview WebContentses (managed by // BackgroundPrintingManager) to the Observers that observe them. - WebContentsObserverMap printing_contents_map_; + std::map<content::WebContents*, std::unique_ptr<Observer>> + printing_contents_map_; content::NotificationRegistrar registrar_; diff --git a/chromium/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc b/chromium/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc index fb3d430bae3..f8d1c524d62 100644 --- a/chromium/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc +++ b/chromium/chrome/browser/printing/cloud_print/cloud_print_proxy_service_unittest.cc @@ -26,7 +26,7 @@ #include "chrome/test/base/testing_profile.h" #include "chrome/test/base/testing_profile_manager.h" #include "components/prefs/testing_pref_service.h" -#include "components/syncable_prefs/testing_pref_service_syncable.h" +#include "components/sync_preferences/testing_pref_service_syncable.h" #include "content/public/browser/browser_thread.h" #include "content/public/test/test_browser_thread.h" #include "testing/gmock/include/gmock/gmock.h" @@ -242,7 +242,7 @@ TEST_F(CloudPrintProxyPolicyTest, StartWithNoPolicyProxyDisabled) { service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations( MockServiceProcessControl::kServiceStateDisabled, false); - syncable_prefs::TestingPrefServiceSyncable* prefs = + sync_preferences::TestingPrefServiceSyncable* prefs = profile_.GetTestingPrefService(); prefs->SetUserPref( prefs::kCloudPrintEmail, @@ -259,7 +259,7 @@ TEST_F(CloudPrintProxyPolicyTest, StartWithNoPolicyProxyEnabled) { service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations( MockServiceProcessControl::kServiceStateEnabled, false); - syncable_prefs::TestingPrefServiceSyncable* prefs = + sync_preferences::TestingPrefServiceSyncable* prefs = profile_.GetTestingPrefService(); prefs->SetUserPref(prefs::kCloudPrintEmail, new base::StringValue(std::string())); @@ -277,7 +277,7 @@ TEST_F(CloudPrintProxyPolicyTest, StartWithPolicySetProxyDisabled) { service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations( MockServiceProcessControl::kServiceStateDisabled, false); - syncable_prefs::TestingPrefServiceSyncable* prefs = + sync_preferences::TestingPrefServiceSyncable* prefs = profile_.GetTestingPrefService(); prefs->SetUserPref(prefs::kCloudPrintEmail, new base::StringValue(std::string())); @@ -296,7 +296,7 @@ TEST_F(CloudPrintProxyPolicyTest, StartWithPolicySetProxyEnabled) { MockServiceProcessControl::kServiceStateEnabled, false); service.GetMockServiceProcessControl()->SetWillBeDisabledExpectations(); - syncable_prefs::TestingPrefServiceSyncable* prefs = + sync_preferences::TestingPrefServiceSyncable* prefs = profile_.GetTestingPrefService(); prefs->SetUserPref(prefs::kCloudPrintEmail, new base::StringValue(std::string())); @@ -314,7 +314,7 @@ TEST_F(CloudPrintProxyPolicyTest, StartWithNoPolicyProxyDisabledThenSetPolicy) { service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations( MockServiceProcessControl::kServiceStateDisabled, false); - syncable_prefs::TestingPrefServiceSyncable* prefs = + sync_preferences::TestingPrefServiceSyncable* prefs = profile_.GetTestingPrefService(); prefs->SetUserPref( prefs::kCloudPrintEmail, @@ -336,7 +336,7 @@ TEST_F(CloudPrintProxyPolicyTest, StartWithNoPolicyProxyEnabledThenSetPolicy) { service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations( MockServiceProcessControl::kServiceStateEnabled, false); - syncable_prefs::TestingPrefServiceSyncable* prefs = + sync_preferences::TestingPrefServiceSyncable* prefs = profile_.GetTestingPrefService(); prefs->SetUserPref(prefs::kCloudPrintEmail, new base::StringValue(std::string())); @@ -361,7 +361,7 @@ TEST_F(CloudPrintProxyPolicyTest, service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations( MockServiceProcessControl::kServiceStateDisabled, false); - syncable_prefs::TestingPrefServiceSyncable* prefs = + sync_preferences::TestingPrefServiceSyncable* prefs = profile_.GetTestingPrefService(); prefs->SetUserPref(prefs::kCloudPrintEmail, new base::StringValue(std::string())); @@ -383,7 +383,7 @@ TEST_F(CloudPrintProxyPolicyTest, MockServiceProcessControl::kServiceStateEnabled, false); service.GetMockServiceProcessControl()->SetWillBeDisabledExpectations(); - syncable_prefs::TestingPrefServiceSyncable* prefs = + sync_preferences::TestingPrefServiceSyncable* prefs = profile_.GetTestingPrefService(); prefs->SetUserPref(prefs::kCloudPrintEmail, new base::StringValue(std::string())); @@ -403,7 +403,7 @@ TEST_F(CloudPrintProxyPolicyTest, StartWithNoPolicyProxyDisabledThenEnable) { service.GetMockServiceProcessControl()->SetConnectSuccessMockExpectations( MockServiceProcessControl::kServiceStateDisabled, false); - syncable_prefs::TestingPrefServiceSyncable* prefs = + sync_preferences::TestingPrefServiceSyncable* prefs = profile_.GetTestingPrefService(); prefs->SetUserPref( prefs::kCloudPrintEmail, @@ -427,7 +427,7 @@ TEST_F(CloudPrintProxyPolicyTest, MockServiceProcessControl::kServiceStateEnabled, false); service.GetMockServiceProcessControl()->SetWillBeDisabledExpectations(); - syncable_prefs::TestingPrefServiceSyncable* prefs = + sync_preferences::TestingPrefServiceSyncable* prefs = profile_.GetTestingPrefService(); prefs->SetUserPref(prefs::kCloudPrintEmail, new base::StringValue(std::string())); diff --git a/chromium/chrome/browser/printing/cloud_print/gcd_api_flow_impl.cc b/chromium/chrome/browser/printing/cloud_print/gcd_api_flow_impl.cc index b7e83620e61..039a0edccfc 100644 --- a/chromium/chrome/browser/printing/cloud_print/gcd_api_flow_impl.cc +++ b/chromium/chrome/browser/printing/cloud_print/gcd_api_flow_impl.cc @@ -16,6 +16,7 @@ #include "chrome/browser/printing/cloud_print/gcd_constants.h" #include "chrome/common/cloud_print/cloud_print_constants.h" #include "components/cloud_devices/common/cloud_devices_urls.h" +#include "components/data_use_measurement/core/data_use_user_data.h" #include "google_apis/gaia/google_service_auth_error.h" #include "net/base/load_flags.h" #include "net/base/url_util.h" @@ -77,6 +78,8 @@ void GCDApiFlowImpl::CreateRequest(const GURL& url) { url_fetcher_->SetUploadData(upload_type, upload_data); } + data_use_measurement::DataUseUserData::AttachToFetcher( + url_fetcher_.get(), data_use_measurement::DataUseUserData::CLOUD_PRINT); url_fetcher_->SetRequestContext(request_context_.get()); std::vector<std::string> extra_headers = request_->GetExtraRequestHeaders(); diff --git a/chromium/chrome/browser/printing/cloud_print/privet_http.h b/chromium/chrome/browser/printing/cloud_print/privet_http.h index 2eeb98007fb..b59743b1a5d 100644 --- a/chromium/chrome/browser/printing/cloud_print/privet_http.h +++ b/chromium/chrome/browser/printing/cloud_print/privet_http.h @@ -21,7 +21,6 @@ class Size; } namespace printing { -class PdfRenderSettings; class PWGRasterConverter; } diff --git a/chromium/chrome/browser/printing/cloud_print/privet_http_impl.cc b/chromium/chrome/browser/printing/cloud_print/privet_http_impl.cc index f62e66d4e02..7ac2cc63d22 100644 --- a/chromium/chrome/browser/printing/cloud_print/privet_http_impl.cc +++ b/chromium/chrome/browser/printing/cloud_print/privet_http_impl.cc @@ -24,9 +24,10 @@ #include "chrome/common/chrome_switches.h" #include "chrome/common/cloud_print/cloud_print_constants.h" #include "net/base/url_util.h" +#include "printing/features/features.h" #include "url/gurl.h" -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) #include "chrome/browser/printing/pwg_raster_converter.h" #include "components/cloud_devices/common/printer_description.h" #include "printing/pdf_render_settings.h" @@ -44,7 +45,7 @@ const char kPrivetRegisterUserArgName[] = "user"; const int kPrivetCancelationTimeoutSeconds = 3; -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) const char kPrivetURLKeyUserName[] = "user_name"; const char kPrivetURLKeyClientName[] = "client_name"; const char kPrivetURLKeyJobname[] = "job_name"; @@ -394,7 +395,7 @@ void PrivetJSONOperationImpl::OnNeedPrivetToken( privet_client_->RefreshPrivetToken(callback); } -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) PrivetLocalPrintOperationImpl::PrivetLocalPrintOperationImpl( PrivetHTTPClient* privet_client, PrivetLocalPrintOperation::Delegate* delegate) @@ -797,7 +798,7 @@ PrivetV1HTTPClientImpl::CreateCapabilitiesOperation( std::unique_ptr<PrivetLocalPrintOperation> PrivetV1HTTPClientImpl::CreateLocalPrintOperation( PrivetLocalPrintOperation::Delegate* delegate) { -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) return std::unique_ptr<PrivetLocalPrintOperation>( new PrivetLocalPrintOperationImpl(info_client(), delegate)); #else diff --git a/chromium/chrome/browser/printing/cloud_print/privet_http_impl.h b/chromium/chrome/browser/printing/cloud_print/privet_http_impl.h index 3b367262d57..d1051c6b89f 100644 --- a/chromium/chrome/browser/printing/cloud_print/privet_http_impl.h +++ b/chromium/chrome/browser/printing/cloud_print/privet_http_impl.h @@ -16,6 +16,7 @@ #include "base/memory/weak_ptr.h" #include "chrome/browser/printing/cloud_print/privet_http.h" #include "components/cloud_devices/common/cloud_device_description.h" +#include "printing/features/features.h" #include "ui/gfx/geometry/size.h" namespace cloud_print { @@ -148,7 +149,7 @@ class PrivetJSONOperationImpl : public PrivetJSONOperation, std::unique_ptr<PrivetURLFetcher> url_fetcher_; }; -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) class PrivetLocalPrintOperationImpl : public PrivetLocalPrintOperation, public PrivetURLFetcher::Delegate { diff --git a/chromium/chrome/browser/printing/cloud_print/privet_http_unittest.cc b/chromium/chrome/browser/printing/cloud_print/privet_http_unittest.cc index 843553b7b0f..97119ad7a81 100644 --- a/chromium/chrome/browser/printing/cloud_print/privet_http_unittest.cc +++ b/chromium/chrome/browser/printing/cloud_print/privet_http_unittest.cc @@ -20,10 +20,11 @@ #include "net/test/embedded_test_server/embedded_test_server.h" #include "net/url_request/test_url_fetcher_factory.h" #include "net/url_request/url_request_test_util.h" +#include "printing/features/features.h" #include "testing/gmock/include/gmock/gmock.h" #include "testing/gtest/include/gtest/gtest.h" -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) #include "chrome/browser/printing/pwg_raster_converter.h" #include "printing/pwg_raster_settings.h" #endif // ENABLE_PRINT_PREVIEW @@ -138,7 +139,7 @@ const char kSampleCapabilitiesResponse[] = "{" "}" "}"; -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) const char kSampleInfoResponseWithCreatejob[] = "{" " \"version\": \"1.0\"," " \"name\": \"Common printer\"," @@ -733,7 +734,7 @@ TEST_P(PrivetCapabilitiesTest, BadToken) { kSampleCapabilitiesResponse)); } -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) // A note on PWG raster conversion: The PWG raster converter used simply // converts strings to file paths based on them by appending "test.pdf", since // it's easier to test that way. Instead of using a mock, we simply check if the diff --git a/chromium/chrome/browser/printing/cloud_print/privet_notifications.cc b/chromium/chrome/browser/printing/cloud_print/privet_notifications.cc index d7eb4e9c691..acd14d025a5 100644 --- a/chromium/chrome/browser/printing/cloud_print/privet_notifications.cc +++ b/chromium/chrome/browser/printing/cloud_print/privet_notifications.cc @@ -39,12 +39,13 @@ #include "content/public/browser/navigation_controller.h" #include "content/public/browser/storage_partition.h" #include "content/public/browser/web_contents.h" +#include "net/net_features.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/page_transition_types.h" #include "ui/base/resource/resource_bundle.h" #include "ui/message_center/notifier_settings.h" -#if defined(ENABLE_MDNS) +#if BUILDFLAG(ENABLE_MDNS) #include "chrome/browser/printing/cloud_print/privet_traffic_detector.h" #endif @@ -255,6 +256,7 @@ void PrivetNotificationService::PrivetNotify(int devices_active, base::string16 product_name = l10n_util::GetStringUTF16(IDS_LOCAL_DISCOVERY_SERVICE_NAME_PRINTER); + Profile* profile = Profile::FromBrowserContext(profile_); Notification notification( message_center::NOTIFICATION_TYPE_SIMPLE, title, body, ui::ResourceBundle::GetSharedInstance().GetImageNamed( @@ -262,10 +264,9 @@ void PrivetNotificationService::PrivetNotify(int devices_active, message_center::NotifierId(message_center::NotifierId::SYSTEM_COMPONENT, kPrivetNotificationID), product_name, GURL(kPrivetNotificationOriginUrl), kPrivetNotificationID, - rich_notification_data, new PrivetNotificationDelegate(profile_)); + rich_notification_data, CreateNotificationDelegate(profile)); auto* notification_ui_manager = g_browser_process->notification_ui_manager(); - Profile* profile = Profile::FromBrowserContext(profile_); bool updated = notification_ui_manager->Update(notification, profile); if (!updated && added && !local_discovery::LocalDiscoveryUIHandler::GetHasVisible()) { @@ -349,11 +350,14 @@ void PrivetNotificationService::StartLister() { new PrivetNotificationsListener(std::move(http_factory), this)); } -PrivetNotificationDelegate::PrivetNotificationDelegate( - content::BrowserContext* profile) - : profile_(profile) { +PrivetNotificationDelegate* +PrivetNotificationService::CreateNotificationDelegate(Profile* profile) { + return new PrivetNotificationDelegate(profile); } +PrivetNotificationDelegate::PrivetNotificationDelegate(Profile* profile) + : profile_(profile) {} + PrivetNotificationDelegate::~PrivetNotificationDelegate() { } @@ -365,26 +369,29 @@ void PrivetNotificationDelegate::ButtonClick(int button_index) { if (button_index == 0) { ReportPrivetUmaEvent(PRIVET_NOTIFICATION_CLICKED); OpenTab(GURL(kPrivetNotificationOriginUrl)); - return; + } else { + DCHECK_EQ(1, button_index); + ReportPrivetUmaEvent(PRIVET_DISABLE_NOTIFICATIONS_CLICKED); + DisableNotifications(); } - - DCHECK_EQ(1, button_index); - ReportPrivetUmaEvent(PRIVET_DISABLE_NOTIFICATIONS_CLICKED); - DisableNotifications(); + CloseNotification(); } void PrivetNotificationDelegate::OpenTab(const GURL& url) { - Profile* profile = Profile::FromBrowserContext(profile_); - chrome::NavigateParams params(profile, url, + chrome::NavigateParams params(profile_, url, ui::PAGE_TRANSITION_AUTO_TOPLEVEL); params.disposition = WindowOpenDisposition::NEW_FOREGROUND_TAB; chrome::Navigate(¶ms); } void PrivetNotificationDelegate::DisableNotifications() { - Profile* profile = Profile::FromBrowserContext(profile_); - profile->GetPrefs()->SetBoolean(prefs::kLocalDiscoveryNotificationsEnabled, - false); + profile_->GetPrefs()->SetBoolean(prefs::kLocalDiscoveryNotificationsEnabled, + false); +} + +void PrivetNotificationDelegate::CloseNotification() { + g_browser_process->notification_ui_manager()->CancelById( + id(), NotificationUIManager::GetProfileID(profile_)); } } // namespace cloud_print diff --git a/chromium/chrome/browser/printing/cloud_print/privet_notifications.h b/chromium/chrome/browser/printing/cloud_print/privet_notifications.h index 2e9df8d1f2e..823a1a36ae3 100644 --- a/chromium/chrome/browser/printing/cloud_print/privet_notifications.h +++ b/chromium/chrome/browser/printing/cloud_print/privet_notifications.h @@ -14,8 +14,10 @@ #include "chrome/browser/printing/cloud_print/privet_http.h" #include "components/keyed_service/core/keyed_service.h" #include "components/prefs/pref_member.h" +#include "net/net_features.h" class NotificationUIManager; +class Profile; namespace content { class BrowserContext; @@ -30,9 +32,10 @@ namespace cloud_print { class PrivetDeviceLister; class PrivetHTTPAsynchronousFactory; class PrivetHTTPResolution; +class PrivetNotificationDelegate; struct DeviceDescription; -#if defined(ENABLE_MDNS) +#if BUILDFLAG(ENABLE_MDNS) class PrivetTrafficDetector; #endif // ENABLE_MDNS @@ -119,6 +122,10 @@ class PrivetNotificationService void OnNotificationsEnabledChanged(); void StartLister(); + // Virtual for testing. The returned delegate is refcounted. + virtual PrivetNotificationDelegate* CreateNotificationDelegate( + Profile* profile); + content::BrowserContext* const profile_; std::unique_ptr<PrivetDeviceLister> device_lister_; scoped_refptr<local_discovery::ServiceDiscoverySharedClient> @@ -126,27 +133,31 @@ class PrivetNotificationService std::unique_ptr<PrivetNotificationsListener> privet_notifications_listener_; BooleanPrefMember enable_privet_notification_member_; -#if defined(ENABLE_MDNS) +#if BUILDFLAG(ENABLE_MDNS) scoped_refptr<PrivetTrafficDetector> traffic_detector_; #endif // ENABLE_MDNS }; class PrivetNotificationDelegate : public NotificationDelegate { public: - explicit PrivetNotificationDelegate(content::BrowserContext* profile); + explicit PrivetNotificationDelegate(Profile* profile); // NotificationDelegate implementation. std::string id() const override; void ButtonClick(int button_index) override; - private: + protected: // Refcounted. ~PrivetNotificationDelegate() override; - void OpenTab(const GURL& url); - void DisableNotifications(); + private: + // ButtonClick() response handlers. Virtual for testing. + virtual void OpenTab(const GURL& url); + virtual void DisableNotifications(); - content::BrowserContext* const profile_; + void CloseNotification(); + + Profile* const profile_; }; } // namespace cloud_print diff --git a/chromium/chrome/browser/printing/cloud_print/privet_notifications_unittest.cc b/chromium/chrome/browser/printing/cloud_print/privet_notifications_unittest.cc index 9a8a2aa2817..18249f8ef7d 100644 --- a/chromium/chrome/browser/printing/cloud_print/privet_notifications_unittest.cc +++ b/chromium/chrome/browser/printing/cloud_print/privet_notifications_unittest.cc @@ -7,10 +7,14 @@ #include <memory> #include "base/memory/ptr_util.h" -#include "base/message_loop/message_loop.h" #include "base/threading/thread_task_runner_handle.h" +#include "chrome/browser/notifications/notification_test_util.h" #include "chrome/browser/printing/cloud_print/privet_http_asynchronous_factory.h" #include "chrome/browser/printing/cloud_print/privet_http_impl.h" +#include "chrome/test/base/testing_browser_process.h" +#include "chrome/test/base/testing_profile.h" +#include "chrome/test/base/testing_profile_manager.h" +#include "content/public/test/test_browser_thread_bundle.h" #include "net/url_request/test_url_fetcher_factory.h" #include "net/url_request/url_request_test_util.h" #include "testing/gmock/include/gmock/gmock.h" @@ -81,7 +85,7 @@ class MockPrivetHttpFactory : public PrivetHTTPAsynchronousFactory { scoped_refptr<net::URLRequestContextGetter> request_context_; }; -class PrivetNotificationsListenerTest : public ::testing::Test { +class PrivetNotificationsListenerTest : public testing::Test { public: PrivetNotificationsListenerTest() : request_context_(new net::TestURLRequestContextGetter( @@ -99,7 +103,7 @@ class PrivetNotificationsListenerTest : public ::testing::Test { bool SuccessfulResponseToInfo(const std::string& response) { net::TestURLFetcher* fetcher = fetcher_factory_.GetFetcherByID(0); - if (!fetcher || GURL(kDeviceInfoURL) != fetcher->GetOriginalURL()) + if (!fetcher || fetcher->GetOriginalURL() != kDeviceInfoURL) return false; fetcher->SetResponseString(response); @@ -180,6 +184,136 @@ TEST_F(PrivetNotificationsListenerTest, DictionaryErrorTest) { SuccessfulResponseToInfo(kInfoResponseNoUptime); } +class TestPrivetNotificationService; + +class TestPrivetNotificationDelegate : public PrivetNotificationDelegate { + public: + TestPrivetNotificationDelegate(TestPrivetNotificationService* service, + Profile* profile) + : PrivetNotificationDelegate(profile), service_(service) {} + + private: + // Refcounted. + ~TestPrivetNotificationDelegate() override {} + + // PrivetNotificationDelegate: + void OpenTab(const GURL& url) override; + void DisableNotifications() override; + + TestPrivetNotificationService* const service_; + + DISALLOW_COPY_AND_ASSIGN(TestPrivetNotificationDelegate); +}; + +class TestPrivetNotificationService : public PrivetNotificationService { + public: + explicit TestPrivetNotificationService(Profile* profile) + : PrivetNotificationService(profile) {} + ~TestPrivetNotificationService() override {} + + const GURL& open_tab_url() const { return open_tab_url_; } + size_t open_tab_count() const { return open_tab_count_; } + size_t disable_notifications_count() const { + return disable_notifications_count_; + } + + void OpenTab(const GURL& url) { + open_tab_url_ = url; + ++open_tab_count_; + } + + void DisableNotifications() { ++disable_notifications_count_; } + + private: + // PrivetNotificationService: + PrivetNotificationDelegate* CreateNotificationDelegate( + Profile* profile) override { + return new TestPrivetNotificationDelegate(this, profile); + } + + GURL open_tab_url_; + size_t open_tab_count_ = 0; + size_t disable_notifications_count_ = 0; + + DISALLOW_COPY_AND_ASSIGN(TestPrivetNotificationService); +}; + +void TestPrivetNotificationDelegate::OpenTab(const GURL& url) { + service_->OpenTab(url); +} + +void TestPrivetNotificationDelegate::DisableNotifications() { + service_->DisableNotifications(); +} + +class PrivetNotificationsNotificationTest : public testing::Test { + public: + PrivetNotificationsNotificationTest() {} + ~PrivetNotificationsNotificationTest() override {} + + void SetUp() override { + testing::Test::SetUp(); + + profile_manager_ = base::MakeUnique<TestingProfileManager>( + TestingBrowserProcess::GetGlobal()); + ASSERT_TRUE(profile_manager_->SetUp()); + profile_ = profile_manager_->CreateTestingProfile("test-user"); + + TestingBrowserProcess::GetGlobal()->SetNotificationUIManager( + base::MakeUnique<StubNotificationUIManager>()); + } + + void TearDown() override { + profile_manager_.reset(); + testing::Test::TearDown(); + } + + protected: + StubNotificationUIManager* ui_manager() const { + return static_cast<StubNotificationUIManager*>( + TestingBrowserProcess::GetGlobal()->notification_ui_manager()); + } + + Profile* profile() { return profile_; } + + private: + // The thread bundle must be first so it is destroyed last. + content::TestBrowserThreadBundle thread_bundle_; + + std::unique_ptr<TestingProfileManager> profile_manager_; + Profile* profile_; + + DISALLOW_COPY_AND_ASSIGN(PrivetNotificationsNotificationTest); +}; + +TEST_F(PrivetNotificationsNotificationTest, AddToCloudPrint) { + TestPrivetNotificationService service(profile()); + service.PrivetNotify(1 /* devices_active */, true /* added */); + + ASSERT_EQ(1U, ui_manager()->GetNotificationCount()); + const auto& notification = ui_manager()->GetNotificationAt(0); + notification.ButtonClick(0 /* add */); + + EXPECT_EQ("chrome://devices/", service.open_tab_url().spec()); + EXPECT_EQ(1U, service.open_tab_count()); + EXPECT_EQ(0U, service.disable_notifications_count()); + EXPECT_EQ(0U, ui_manager()->GetNotificationCount()); +} + +TEST_F(PrivetNotificationsNotificationTest, DontShowAgain) { + TestPrivetNotificationService service(profile()); + service.PrivetNotify(1 /* devices_active */, true /* added */); + + ASSERT_EQ(1U, ui_manager()->GetNotificationCount()); + const auto& notification = ui_manager()->GetNotificationAt(0); + notification.ButtonClick(1 /* don't show again */); + + EXPECT_EQ("", service.open_tab_url().spec()); + EXPECT_EQ(0U, service.open_tab_count()); + EXPECT_EQ(1U, service.disable_notifications_count()); + EXPECT_EQ(0U, ui_manager()->GetNotificationCount()); +} + } // namespace } // namespace cloud_print diff --git a/chromium/chrome/browser/printing/cloud_print/privet_traffic_detector.cc b/chromium/chrome/browser/printing/cloud_print/privet_traffic_detector.cc index a72e5639317..633a74a0ee7 100644 --- a/chromium/chrome/browser/printing/cloud_print/privet_traffic_detector.cc +++ b/chromium/chrome/browser/printing/cloud_print/privet_traffic_detector.cc @@ -19,8 +19,8 @@ #include "net/dns/dns_response.h" #include "net/dns/mdns_client.h" #include "net/log/net_log_source.h" -#include "net/udp/datagram_server_socket.h" -#include "net/udp/udp_server_socket.h" +#include "net/socket/datagram_server_socket.h" +#include "net/socket/udp_server_socket.h" namespace { diff --git a/chromium/chrome/browser/printing/cloud_print/privet_url_fetcher.cc b/chromium/chrome/browser/printing/cloud_print/privet_url_fetcher.cc index 1fdccbdae73..1135e216133 100644 --- a/chromium/chrome/browser/printing/cloud_print/privet_url_fetcher.cc +++ b/chromium/chrome/browser/printing/cloud_print/privet_url_fetcher.cc @@ -21,6 +21,7 @@ #include "base/threading/thread_task_runner_handle.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/printing/cloud_print/privet_constants.h" +#include "components/data_use_measurement/core/data_use_user_data.h" #include "content/public/browser/browser_thread.h" #include "net/base/load_flags.h" #include "net/http/http_status_code.h" @@ -150,6 +151,9 @@ void PrivetURLFetcher::Try() { if (tries_ <= max_retries_) { DVLOG(1) << "Attempt: " << tries_; url_fetcher_ = net::URLFetcher::Create(url_, request_type_, this); + data_use_measurement::DataUseUserData::AttachToFetcher( + url_fetcher_.get(), data_use_measurement::DataUseUserData::CLOUD_PRINT); + // Privet requests are relevant to hosts on local network only. url_fetcher_->SetLoadFlags( url_fetcher_->GetLoadFlags() | net::LOAD_BYPASS_PROXY | diff --git a/chromium/chrome/browser/printing/pdf_to_emf_converter.h b/chromium/chrome/browser/printing/pdf_to_emf_converter.h index f2c0102e266..1f527152740 100644 --- a/chromium/chrome/browser/printing/pdf_to_emf_converter.h +++ b/chromium/chrome/browser/printing/pdf_to_emf_converter.h @@ -10,14 +10,10 @@ #include "base/callback.h" #include "base/memory/ref_counted_memory.h" -namespace base { -class FilePath; -} - namespace printing { class MetafilePlayer; -class PdfRenderSettings; +struct PdfRenderSettings; class PdfToEmfConverter { public: diff --git a/chromium/chrome/browser/printing/print_job_manager.cc b/chromium/chrome/browser/printing/print_job_manager.cc index c47cdb09a32..9074df688ac 100644 --- a/chromium/chrome/browser/printing/print_job_manager.cc +++ b/chromium/chrome/browser/printing/print_job_manager.cc @@ -46,10 +46,9 @@ scoped_refptr<PrinterQuery> PrintQueriesQueue::PopPrinterQuery( scoped_refptr<PrinterQuery> PrintQueriesQueue::CreatePrinterQuery( int render_process_id, - int render_view_id) { - scoped_refptr<PrinterQuery> job = - new printing::PrinterQuery(render_process_id, render_view_id); - return job; + int render_frame_id) { + return make_scoped_refptr( + new PrinterQuery(render_process_id, render_frame_id)); } void PrintQueriesQueue::Shutdown() { diff --git a/chromium/chrome/browser/printing/print_job_manager.h b/chromium/chrome/browser/printing/print_job_manager.h index 3fc7e574965..e4970d41d32 100644 --- a/chromium/chrome/browser/printing/print_job_manager.h +++ b/chromium/chrome/browser/printing/print_job_manager.h @@ -38,7 +38,7 @@ class PrintQueriesQueue : public base::RefCountedThreadSafe<PrintQueriesQueue> { // Creates new query. scoped_refptr<PrinterQuery> CreatePrinterQuery(int render_process_id, - int render_view_id); + int render_frame_id); void Shutdown(); diff --git a/chromium/chrome/browser/printing/print_job_worker.cc b/chromium/chrome/browser/printing/print_job_worker.cc index 0e931183de2..ee4ecf6a9aa 100644 --- a/chromium/chrome/browser/printing/print_job_worker.cc +++ b/chromium/chrome/browser/printing/print_job_worker.cc @@ -24,7 +24,7 @@ #include "chrome/grit/generated_resources.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_service.h" -#include "content/public/browser/render_view_host.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "printing/print_job_constants.h" #include "printing/printed_document.h" @@ -43,14 +43,14 @@ namespace printing { namespace { // Helper function to ensure |owner| is valid until at least |callback| returns. -void HoldRefCallback(const scoped_refptr<printing::PrintJobWorkerOwner>& owner, +void HoldRefCallback(const scoped_refptr<PrintJobWorkerOwner>& owner, const base::Closure& callback) { callback.Run(); } class PrintingContextDelegate : public PrintingContext::Delegate { public: - PrintingContextDelegate(int render_process_id, int render_view_id); + PrintingContextDelegate(int render_process_id, int render_frame_id); ~PrintingContextDelegate() override; gfx::NativeView GetParentView() override; @@ -60,15 +60,14 @@ class PrintingContextDelegate : public PrintingContext::Delegate { content::WebContents* GetWebContents(); private: - int render_process_id_; - int render_view_id_; + const int render_process_id_; + const int render_frame_id_; }; PrintingContextDelegate::PrintingContextDelegate(int render_process_id, - int render_view_id) + int render_frame_id) : render_process_id_(render_process_id), - render_view_id_(render_view_id) { -} + render_frame_id_(render_frame_id) {} PrintingContextDelegate::~PrintingContextDelegate() { } @@ -80,9 +79,9 @@ gfx::NativeView PrintingContextDelegate::GetParentView() { content::WebContents* PrintingContextDelegate::GetWebContents() { DCHECK_CURRENTLY_ON(BrowserThread::UI); - content::RenderViewHost* view = - content::RenderViewHost::FromID(render_process_id_, render_view_id_); - return view ? content::WebContents::FromRenderViewHost(view) : nullptr; + auto* rfh = + content::RenderFrameHost::FromID(render_process_id_, render_frame_id_); + return rfh ? content::WebContents::FromRenderFrameHost(rfh) : nullptr; } std::string PrintingContextDelegate::GetAppLocale() { @@ -111,14 +110,14 @@ void PostOnOwnerThread(const scoped_refptr<PrintJobWorkerOwner>& owner, } // namespace PrintJobWorker::PrintJobWorker(int render_process_id, - int render_view_id, + int render_frame_id, PrintJobWorkerOwner* owner) : owner_(owner), thread_("Printing_Worker"), weak_factory_(this) { // The object is created in the IO thread. DCHECK(owner_->RunsTasksOnCurrentThread()); printing_context_delegate_ = base::MakeUnique<PrintingContextDelegate>( - render_process_id, render_view_id); + render_process_id, render_frame_id); printing_context_ = PrintingContext::Create(printing_context_delegate_.get()); } diff --git a/chromium/chrome/browser/printing/print_job_worker.h b/chromium/chrome/browser/printing/print_job_worker.h index 6ed8885a5ac..e001a86b840 100644 --- a/chromium/chrome/browser/printing/print_job_worker.h +++ b/chromium/chrome/browser/printing/print_job_worker.h @@ -36,14 +36,14 @@ class PrintedPage; class PrintJobWorker { public: PrintJobWorker(int render_process_id, - int render_view_id, + int render_frame_id, PrintJobWorkerOwner* owner); virtual ~PrintJobWorker(); void SetNewOwner(PrintJobWorkerOwner* new_owner); // Initializes the print settings. If |ask_user_for_settings| is true, a - // Print... dialog box will be shown to ask the user his preference. + // Print... dialog box will be shown to ask the user their preference. // |is_scripted| should be true for calls coming straight from window.print(). // |is_modifiable| implies HTML and not other formats like PDF. void GetSettings(bool ask_user_for_settings, diff --git a/chromium/chrome/browser/printing/print_preview_dialog_controller_browsertest.cc b/chromium/chrome/browser/printing/print_preview_dialog_controller_browsertest.cc index e7dd7eab8b8..598a121a912 100644 --- a/chromium/chrome/browser/printing/print_preview_dialog_controller_browsertest.cc +++ b/chromium/chrome/browser/printing/print_preview_dialog_controller_browsertest.cc @@ -58,7 +58,8 @@ class RequestPrintPreviewObserver : public WebContentsObserver { private: // content::WebContentsObserver implementation. - bool OnMessageReceived(const IPC::Message& message) override { + bool OnMessageReceived(const IPC::Message& message, + content::RenderFrameHost* render_frame_host) override { IPC_BEGIN_MESSAGE_MAP(RequestPrintPreviewObserver, message) IPC_MESSAGE_HANDLER(PrintHostMsg_RequestPrintPreview, OnRequestPrintPreview) diff --git a/chromium/chrome/browser/printing/print_preview_dialog_controller_unittest.cc b/chromium/chrome/browser/printing/print_preview_dialog_controller_unittest.cc index 4bb9631f34e..3fd3180c16c 100644 --- a/chromium/chrome/browser/printing/print_preview_dialog_controller_unittest.cc +++ b/chromium/chrome/browser/printing/print_preview_dialog_controller_unittest.cc @@ -70,7 +70,8 @@ TEST_F(PrintPreviewDialogControllerUnitTest, GetOrCreatePreviewDialog) { ASSERT_TRUE(dialog_controller); // Get the preview dialog for initiator. - PrintViewManager::FromWebContents(initiator)->PrintPreviewNow(false); + PrintViewManager::FromWebContents(initiator)->PrintPreviewNow( + initiator->GetMainFrame(), false); WebContents* preview_dialog = dialog_controller->GetOrCreatePreviewDialog(initiator); @@ -116,7 +117,8 @@ TEST_F(PrintPreviewDialogControllerUnitTest, MultiplePreviewDialogs) { ASSERT_TRUE(dialog_controller); // Create preview dialog for |web_contents_1| - PrintViewManager::FromWebContents(web_contents_1)->PrintPreviewNow(false); + PrintViewManager::FromWebContents(web_contents_1) + ->PrintPreviewNow(web_contents_1->GetMainFrame(), false); WebContents* preview_dialog_1 = dialog_controller->GetOrCreatePreviewDialog(web_contents_1); @@ -124,7 +126,8 @@ TEST_F(PrintPreviewDialogControllerUnitTest, MultiplePreviewDialogs) { EXPECT_EQ(2, tab_strip_model->count()); // Create preview dialog for |web_contents_2| - PrintViewManager::FromWebContents(web_contents_2)->PrintPreviewNow(false); + PrintViewManager::FromWebContents(web_contents_2) + ->PrintPreviewNow(web_contents_2->GetMainFrame(), false); WebContents* preview_dialog_2 = dialog_controller->GetOrCreatePreviewDialog(web_contents_2); @@ -172,7 +175,8 @@ TEST_F(PrintPreviewDialogControllerUnitTest, ClearInitiatorDetails) { ASSERT_TRUE(dialog_controller); // Get the preview dialog for the initiator. - PrintViewManager::FromWebContents(initiator)->PrintPreviewNow(false); + PrintViewManager::FromWebContents(initiator)->PrintPreviewNow( + initiator->GetMainFrame(), false); WebContents* preview_dialog = dialog_controller->GetOrCreatePreviewDialog(initiator); @@ -228,7 +232,7 @@ TEST_F(PrintPreviewDialogControllerUnitTest, CloseDialogOnNavigation) { WebContents* tiger_preview_dialog = dialog_controller->GetOrCreatePreviewDialog(web_contents); PrintViewManager* manager = PrintViewManager::FromWebContents(web_contents); - manager->PrintPreviewNow(false); + manager->PrintPreviewNow(web_contents->GetMainFrame(), false); // New print preview dialog is a constrained window, so the number of tabs is // still 1. @@ -247,7 +251,7 @@ TEST_F(PrintPreviewDialogControllerUnitTest, CloseDialogOnNavigation) { // Print preview now should return true as the navigation should have closed // |tiger_preview_dialog| and the previous dialog should have closed. - EXPECT_TRUE(manager->PrintPreviewNow(false)); + EXPECT_TRUE(manager->PrintPreviewNow(web_contents->GetMainFrame(), false)); WebContents* tiger_barb_preview_dialog = dialog_controller->GetOrCreatePreviewDialog(web_contents); ASSERT_TRUE(tiger_barb_preview_dialog); @@ -261,13 +265,13 @@ TEST_F(PrintPreviewDialogControllerUnitTest, CloseDialogOnNavigation) { tiger_barb_preview_dialog); // Now this returns false as |tiger_barb_preview_dialog| is open. - EXPECT_FALSE(manager->PrintPreviewNow(false)); + EXPECT_FALSE(manager->PrintPreviewNow(web_contents->GetMainFrame(), false)); // Navigate with back button or ALT+LEFT ARROW to a similar page. nav_controller.GoBack(); CommitPendingLoad(&nav_controller); EXPECT_EQ(tiger, web_contents->GetLastCommittedURL()); - EXPECT_TRUE(manager->PrintPreviewNow(false)); + EXPECT_TRUE(manager->PrintPreviewNow(web_contents->GetMainFrame(), false)); // Get new dialog WebContents* tiger_preview_dialog_2 = @@ -296,7 +300,7 @@ TEST_F(PrintPreviewDialogControllerUnitTest, CloseDialogOnNavigation) { // preview now should return false, dialog is still alive, and the dialog // returned by GetOrCreatePreviewDialog should be the same as the earlier // dialog. - EXPECT_FALSE(manager->PrintPreviewNow(false)); + EXPECT_FALSE(manager->PrintPreviewNow(web_contents->GetMainFrame(), false)); EXPECT_FALSE(tiger_2_destroyed.dialog_destroyed()); WebContents* tiger_preview_dialog_2b = dialog_controller->GetOrCreatePreviewDialog(web_contents); @@ -326,7 +330,8 @@ TEST_F(PrintPreviewDialogControllerUnitTest, MultiplePreviewDialogsClose) { ASSERT_TRUE(dialog_controller); // Create preview dialog for |web_contents_1|. Should not create a new tab. - PrintViewManager::FromWebContents(web_contents_1)->PrintPreviewNow(false); + PrintViewManager::FromWebContents(web_contents_1) + ->PrintPreviewNow(web_contents_1->GetMainFrame(), false); WebContents* preview_dialog_1 = dialog_controller->GetOrCreatePreviewDialog(web_contents_1); EXPECT_NE(web_contents_1, preview_dialog_1); @@ -339,7 +344,8 @@ TEST_F(PrintPreviewDialogControllerUnitTest, MultiplePreviewDialogsClose) { EXPECT_EQ(2, tab_strip_model->count()); // Create preview dialog for |web_contents_2| - PrintViewManager::FromWebContents(web_contents_2)->PrintPreviewNow(false); + PrintViewManager::FromWebContents(web_contents_2) + ->PrintPreviewNow(web_contents_2->GetMainFrame(), false); WebContents* preview_dialog_2 = dialog_controller->GetOrCreatePreviewDialog(web_contents_2); EXPECT_NE(web_contents_2, preview_dialog_2); diff --git a/chromium/chrome/browser/printing/print_preview_message_handler.cc b/chromium/chrome/browser/printing/print_preview_message_handler.cc index 518f9327e60..c51e72f7338 100644 --- a/chromium/chrome/browser/printing/print_preview_message_handler.cc +++ b/chromium/chrome/browser/printing/print_preview_message_handler.cc @@ -92,9 +92,12 @@ PrintPreviewUI* PrintPreviewMessageHandler::GetPrintPreviewUI() { } void PrintPreviewMessageHandler::OnRequestPrintPreview( + content::RenderFrameHost* render_frame_host, const PrintHostMsg_RequestPrintPreview_Params& params) { - if (params.webnode_only) - PrintViewManager::FromWebContents(web_contents())->PrintPreviewForWebNode(); + if (params.webnode_only) { + PrintViewManager::FromWebContents(web_contents())->PrintPreviewForWebNode( + render_frame_host); + } PrintPreviewDialogController::PrintPreview(web_contents()); PrintPreviewUI::SetInitialParams(GetPrintPreviewDialog(), params); } @@ -206,11 +209,19 @@ void PrintPreviewMessageHandler::OnSetOptionsFromDocument( } bool PrintPreviewMessageHandler::OnMessageReceived( - const IPC::Message& message) { + const IPC::Message& message, + content::RenderFrameHost* render_frame_host) { bool handled = true; - IPC_BEGIN_MESSAGE_MAP(PrintPreviewMessageHandler, message) + IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(PrintPreviewMessageHandler, message, + render_frame_host) IPC_MESSAGE_HANDLER(PrintHostMsg_RequestPrintPreview, OnRequestPrintPreview) + IPC_MESSAGE_UNHANDLED(handled = false) + IPC_END_MESSAGE_MAP() + if (handled) + return true; + + IPC_BEGIN_MESSAGE_MAP(PrintPreviewMessageHandler, message) IPC_MESSAGE_HANDLER(PrintHostMsg_DidGetPreviewPageCount, OnDidGetPreviewPageCount) IPC_MESSAGE_HANDLER(PrintHostMsg_DidPreviewPage, diff --git a/chromium/chrome/browser/printing/print_preview_message_handler.h b/chromium/chrome/browser/printing/print_preview_message_handler.h index 25abc6ad60a..ba7102008ba 100644 --- a/chromium/chrome/browser/printing/print_preview_message_handler.h +++ b/chromium/chrome/browser/printing/print_preview_message_handler.h @@ -18,6 +18,7 @@ struct PrintHostMsg_RequestPrintPreview_Params; struct PrintHostMsg_SetOptionsFromDocument_Params; namespace content { +class RenderFrameHost; class WebContents; } @@ -37,7 +38,8 @@ class PrintPreviewMessageHandler ~PrintPreviewMessageHandler() override; // content::WebContentsObserver implementation. - bool OnMessageReceived(const IPC::Message& message) override; + bool OnMessageReceived(const IPC::Message& message, + content::RenderFrameHost* render_frame_host) override; private: explicit PrintPreviewMessageHandler(content::WebContents* web_contents); @@ -52,6 +54,7 @@ class PrintPreviewMessageHandler // Message handlers. void OnRequestPrintPreview( + content::RenderFrameHost* render_frame_host, const PrintHostMsg_RequestPrintPreview_Params& params); void OnDidGetDefaultPageLayout(const PageSizeMargins& page_layout_in_points, const gfx::Rect& printable_area_in_points, diff --git a/chromium/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc b/chromium/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc index 8d3f3b15d2c..3260bb9c2a8 100644 --- a/chromium/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc +++ b/chromium/chrome/browser/printing/print_preview_pdf_generated_browsertest.cc @@ -342,10 +342,8 @@ class PrintPreviewPdfGeneratedBrowserTest : public InProcessBrowserTest { std::string pdf_data; ASSERT_TRUE(base::ReadFileToString(pdf_file_save_path_, &pdf_data)); - ASSERT_TRUE(chrome_pdf::GetPDFDocInfo(pdf_data.data(), - pdf_data.size(), - &num_pages, - &max_width_in_points)); + ASSERT_TRUE(chrome_pdf::GetPDFDocInfo(pdf_data.data(), pdf_data.size(), + &num_pages, &max_width_in_points)); ASSERT_GT(num_pages, 0); double max_width_in_pixels = @@ -353,11 +351,9 @@ class PrintPreviewPdfGeneratedBrowserTest : public InProcessBrowserTest { for (int i = 0; i < num_pages; ++i) { double width_in_points, height_in_points; - ASSERT_TRUE(chrome_pdf::GetPDFPageSizeByIndex(pdf_data.data(), - pdf_data.size(), - i, - &width_in_points, - &height_in_points)); + ASSERT_TRUE(chrome_pdf::GetPDFPageSizeByIndex( + pdf_data.data(), pdf_data.size(), i, &width_in_points, + &height_in_points)); double width_in_pixels = ConvertUnitDouble( width_in_points, kPointsPerInch, kDpi); @@ -377,29 +373,22 @@ class PrintPreviewPdfGeneratedBrowserTest : public InProcessBrowserTest { PdfRenderSettings settings(rect, kDpi, true); int int_max = std::numeric_limits<int>::max(); - if (settings.area().width() > int_max / kColorChannels || - settings.area().height() > int_max / (kColorChannels * - settings.area().width())) { + if (settings.area.width() > int_max / kColorChannels || + settings.area.height() > + int_max / (kColorChannels * settings.area.width())) { FAIL() << "The dimensions of the image are too large." << "Decrease the DPI or the dimensions of the image."; } - std::vector<uint8_t> page_bitmap_data( - kColorChannels * settings.area().size().GetArea()); + std::vector<uint8_t> page_bitmap_data(kColorChannels * + settings.area.size().GetArea()); ASSERT_TRUE(chrome_pdf::RenderPDFPageToBitmap( - pdf_data.data(), - pdf_data.size(), - i, - page_bitmap_data.data(), - settings.area().size().width(), - settings.area().size().height(), - settings.dpi(), - true)); - FillPng(&page_bitmap_data, - width_in_pixels, - max_width_in_pixels, - settings.area().size().height()); + pdf_data.data(), pdf_data.size(), i, page_bitmap_data.data(), + settings.area.size().width(), settings.area.size().height(), + settings.dpi, settings.autorotate)); + FillPng(&page_bitmap_data, width_in_pixels, max_width_in_pixels, + settings.area.size().height()); bitmap_data.insert(bitmap_data.end(), page_bitmap_data.begin(), page_bitmap_data.end()); diff --git a/chromium/chrome/browser/printing/print_view_manager.cc b/chromium/chrome/browser/printing/print_view_manager.cc index c09c632b060..ea49f9b888e 100644 --- a/chromium/chrome/browser/printing/print_view_manager.cc +++ b/chromium/chrome/browser/printing/print_view_manager.cc @@ -5,9 +5,11 @@ #include "chrome/browser/printing/print_view_manager.h" #include <map> +#include <utility> #include "base/bind.h" #include "base/lazy_instance.h" +#include "base/memory/ptr_util.h" #include "chrome/browser/plugins/chrome_plugin_service_filter.h" #include "chrome/browser/printing/print_preview_dialog_controller.h" #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h" @@ -19,6 +21,7 @@ #include "content/public/browser/render_process_host.h" #include "content/public/browser/web_contents.h" #include "content/public/common/webplugininfo.h" +#include "printing/features/features.h" using content::BrowserThread; @@ -54,6 +57,7 @@ namespace printing { PrintViewManager::PrintViewManager(content::WebContents* web_contents) : PrintViewManagerBase(web_contents), print_preview_state_(NOT_PREVIEWING), + print_preview_rfh_(nullptr), scripted_print_preview_rph_(nullptr) { if (PrintPreviewDialogController::IsPrintPreviewDialog(web_contents)) { EnableInternalPDFPluginForContents( @@ -66,16 +70,20 @@ PrintViewManager::~PrintViewManager() { DCHECK_EQ(NOT_PREVIEWING, print_preview_state_); } -#if defined(ENABLE_BASIC_PRINTING) +#if BUILDFLAG(ENABLE_BASIC_PRINTING) bool PrintViewManager::PrintForSystemDialogNow( const base::Closure& dialog_shown_callback) { DCHECK(!dialog_shown_callback.is_null()); DCHECK(on_print_dialog_shown_callback_.is_null()); on_print_dialog_shown_callback_ = dialog_shown_callback; - return PrintNowInternal(new PrintMsg_PrintForSystemDialog(routing_id())); + + SetPrintingRFH(print_preview_rfh_); + int32_t id = print_preview_rfh_->GetRoutingID(); + return PrintNowInternal(print_preview_rfh_, + base::MakeUnique<PrintMsg_PrintForSystemDialog>(id)); } -bool PrintViewManager::BasicPrint() { +bool PrintViewManager::BasicPrint(content::RenderFrameHost* rfh) { PrintPreviewDialogController* dialog_controller = PrintPreviewDialogController::GetInstance(); if (!dialog_controller) @@ -84,7 +92,7 @@ bool PrintViewManager::BasicPrint() { content::WebContents* print_preview_dialog = dialog_controller->GetPrintPreviewForContents(web_contents()); if (!print_preview_dialog) - return PrintNow(); + return PrintNow(rfh); if (!print_preview_dialog->GetWebUI()) return false; @@ -94,27 +102,34 @@ bool PrintViewManager::BasicPrint() { print_preview_ui->OnShowSystemDialog(); return true; } -#endif // defined(ENABLE_BASIC_PRINTING) +#endif // BUILDFLAG(ENABLE_BASIC_PRINTING) -bool PrintViewManager::PrintPreviewNow(bool selection_only) { +bool PrintViewManager::PrintPreviewNow(content::RenderFrameHost* rfh, + bool has_selection) { // Users can send print commands all they want and it is beyond // PrintViewManager's control. Just ignore the extra commands. // See http://crbug.com/136842 for example. if (print_preview_state_ != NOT_PREVIEWING) return false; - if (!PrintNowInternal(new PrintMsg_InitiatePrintPreview(routing_id(), - selection_only))) { + auto message = base::MakeUnique<PrintMsg_InitiatePrintPreview>( + rfh->GetRoutingID(), has_selection); + if (!PrintNowInternal(rfh, std::move(message))) return false; - } + DCHECK(!print_preview_rfh_); + print_preview_rfh_ = rfh; print_preview_state_ = USER_INITIATED_PREVIEW; return true; } -void PrintViewManager::PrintPreviewForWebNode() { +void PrintViewManager::PrintPreviewForWebNode(content::RenderFrameHost* rfh) { if (print_preview_state_ != NOT_PREVIEWING) return; + + DCHECK(rfh); + DCHECK(!print_preview_rfh_); + print_preview_rfh_ = rfh; print_preview_state_ = USER_INITIATED_PREVIEW; } @@ -131,6 +146,7 @@ void PrintViewManager::PrintPreviewDone() { scripted_print_preview_rph_ = nullptr; } print_preview_state_ = NOT_PREVIEWING; + print_preview_rfh_ = nullptr; } void PrintViewManager::RenderFrameCreated( @@ -141,50 +157,67 @@ void PrintViewManager::RenderFrameCreated( } } -void PrintViewManager::RenderProcessGone(base::TerminationStatus status) { - print_preview_state_ = NOT_PREVIEWING; - PrintViewManagerBase::RenderProcessGone(status); +void PrintViewManager::RenderFrameDeleted( + content::RenderFrameHost* render_frame_host) { + if (render_frame_host == print_preview_rfh_) + print_preview_state_ = NOT_PREVIEWING; + PrintViewManagerBase::RenderFrameDeleted(render_frame_host); } -void PrintViewManager::OnDidShowPrintDialog() { - if (!on_print_dialog_shown_callback_.is_null()) - on_print_dialog_shown_callback_.Run(); +void PrintViewManager::OnDidShowPrintDialog(content::RenderFrameHost* rfh) { + if (rfh != print_preview_rfh_) + return; + + if (on_print_dialog_shown_callback_.is_null()) + return; + + on_print_dialog_shown_callback_.Run(); on_print_dialog_shown_callback_.Reset(); } -void PrintViewManager::OnSetupScriptedPrintPreview(IPC::Message* reply_msg) { +void PrintViewManager::OnSetupScriptedPrintPreview( + content::RenderFrameHost* rfh, + IPC::Message* reply_msg) { DCHECK_CURRENTLY_ON(BrowserThread::UI); auto& map = g_scripted_print_preview_closure_map.Get(); - content::RenderProcessHost* rph = web_contents()->GetRenderProcessHost(); + content::RenderProcessHost* rph = rfh->GetProcess(); if (base::ContainsKey(map, rph)) { - // Renderer already handling window.print() in another View. - Send(reply_msg); + // Renderer already handling window.print(). Abort this attempt to prevent + // the renderer from having multiple nested loops. If multiple nested loops + // existed, then they have to exit in the right order and that is messy. + rfh->Send(reply_msg); return; } if (print_preview_state_ != NOT_PREVIEWING) { - // If a user initiated print dialog is already open, ignore the scripted - // print message. - DCHECK_EQ(USER_INITIATED_PREVIEW, print_preview_state_); - Send(reply_msg); + // If a print dialog is already open for this tab, ignore the scripted print + // message. + rfh->Send(reply_msg); return; } PrintPreviewDialogController* dialog_controller = PrintPreviewDialogController::GetInstance(); if (!dialog_controller) { - Send(reply_msg); + rfh->Send(reply_msg); return; } + DCHECK(!print_preview_rfh_); + print_preview_rfh_ = rfh; print_preview_state_ = SCRIPTED_PREVIEW; map[rph] = base::Bind(&PrintViewManager::OnScriptedPrintPreviewReply, base::Unretained(this), reply_msg); scripted_print_preview_rph_ = rph; } -void PrintViewManager::OnShowScriptedPrintPreview(bool source_is_modifiable) { +void PrintViewManager::OnShowScriptedPrintPreview(content::RenderFrameHost* rfh, + bool source_is_modifiable) { + DCHECK(print_preview_rfh_); + if (rfh != print_preview_rfh_) + return; + PrintPreviewDialogController* dialog_controller = PrintPreviewDialogController::GetInstance(); if (!dialog_controller) { @@ -201,21 +234,24 @@ void PrintViewManager::OnShowScriptedPrintPreview(bool source_is_modifiable) { void PrintViewManager::OnScriptedPrintPreviewReply(IPC::Message* reply_msg) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - Send(reply_msg); + print_preview_rfh_->Send(reply_msg); } -bool PrintViewManager::OnMessageReceived(const IPC::Message& message) { +bool PrintViewManager::OnMessageReceived( + const IPC::Message& message, + content::RenderFrameHost* render_frame_host) { bool handled = true; - IPC_BEGIN_MESSAGE_MAP(PrintViewManager, message) + IPC_BEGIN_MESSAGE_MAP_WITH_PARAM(PrintViewManager, message, render_frame_host) IPC_MESSAGE_HANDLER(PrintHostMsg_DidShowPrintDialog, OnDidShowPrintDialog) - IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_SetupScriptedPrintPreview, - OnSetupScriptedPrintPreview) + IPC_MESSAGE_HANDLER_WITH_PARAM_DELAY_REPLY( + PrintHostMsg_SetupScriptedPrintPreview, OnSetupScriptedPrintPreview) IPC_MESSAGE_HANDLER(PrintHostMsg_ShowScriptedPrintPreview, OnShowScriptedPrintPreview) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() - return handled || PrintViewManagerBase::OnMessageReceived(message); + return handled || + PrintViewManagerBase::OnMessageReceived(message, render_frame_host); } } // namespace printing diff --git a/chromium/chrome/browser/printing/print_view_manager.h b/chromium/chrome/browser/printing/print_view_manager.h index b86c0b6474e..f3572c43e6b 100644 --- a/chromium/chrome/browser/printing/print_view_manager.h +++ b/chromium/chrome/browser/printing/print_view_manager.h @@ -8,8 +8,10 @@ #include "base/macros.h" #include "chrome/browser/printing/print_view_manager_base.h" #include "content/public/browser/web_contents_user_data.h" +#include "printing/features/features.h" namespace content { +class RenderFrameHost; class RenderProcessHost; } @@ -21,7 +23,7 @@ class PrintViewManager : public PrintViewManagerBase, public: ~PrintViewManager() override; -#if defined(ENABLE_BASIC_PRINTING) +#if BUILDFLAG(ENABLE_BASIC_PRINTING) // Same as PrintNow(), but for the case where a user prints with the system // dialog from print preview. // |dialog_shown_callback| is called when the print dialog is shown. @@ -30,32 +32,30 @@ class PrintViewManager : public PrintViewManagerBase, // Same as PrintNow(), but for the case where a user press "ctrl+shift+p" to // show the native system dialog. This can happen from both initiator and // preview dialog. - bool BasicPrint(); + bool BasicPrint(content::RenderFrameHost* rfh); #endif // ENABLE_BASIC_PRINTING // Initiate print preview of the current document by first notifying the // renderer. Since this happens asynchronous, the print preview dialog // creation will not be completed on the return of this function. Returns // false if print preview is impossible at the moment. - bool PrintPreviewNow(bool selection_only); + bool PrintPreviewNow(content::RenderFrameHost* rfh, bool has_selection); // Notify PrintViewManager that print preview is starting in the renderer for // a particular WebNode. - void PrintPreviewForWebNode(); + void PrintPreviewForWebNode(content::RenderFrameHost* rfh); // Notify PrintViewManager that print preview has finished. Unfreeze the // renderer in the case of scripted print preview. void PrintPreviewDone(); // content::WebContentsObserver implementation. - bool OnMessageReceived(const IPC::Message& message) override; - - // content::WebContentsObserver implementation. void RenderFrameCreated(content::RenderFrameHost* render_frame_host) override; + void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override; + bool OnMessageReceived(const IPC::Message& message, + content::RenderFrameHost* render_frame_host) override; - // content::WebContentsObserver implementation. - // Terminates or cancels the print job if one was pending. - void RenderProcessGone(base::TerminationStatus status) override; + content::RenderFrameHost* print_preview_rfh() { return print_preview_rfh_; } private: explicit PrintViewManager(content::WebContents* web_contents); @@ -68,9 +68,11 @@ class PrintViewManager : public PrintViewManagerBase, }; // IPC Message handlers. - void OnDidShowPrintDialog(); - void OnSetupScriptedPrintPreview(IPC::Message* reply_msg); - void OnShowScriptedPrintPreview(bool source_is_modifiable); + void OnDidShowPrintDialog(content::RenderFrameHost* rfh); + void OnSetupScriptedPrintPreview(content::RenderFrameHost* rfh, + IPC::Message* reply_msg); + void OnShowScriptedPrintPreview(content::RenderFrameHost* rfh, + bool source_is_modifiable); void OnScriptedPrintPreviewReply(IPC::Message* reply_msg); base::Closure on_print_dialog_shown_callback_; @@ -78,6 +80,10 @@ class PrintViewManager : public PrintViewManagerBase, // Current state of print preview for this view. PrintPreviewState print_preview_state_; + // The current RFH that is print previewing. It should be a nullptr when + // |print_preview_state_| is NOT_PREVIEWING. + content::RenderFrameHost* print_preview_rfh_; + // Keeps track of the pending callback during scripted print preview. content::RenderProcessHost* scripted_print_preview_rph_; diff --git a/chromium/chrome/browser/printing/print_view_manager_base.cc b/chromium/chrome/browser/printing/print_view_manager_base.cc index 7bc9f77ba3f..33ada8ce7b3 100644 --- a/chromium/chrome/browser/printing/print_view_manager_base.cc +++ b/chromium/chrome/browser/printing/print_view_manager_base.cc @@ -32,13 +32,15 @@ #include "content/public/browser/notification_details.h" #include "content/public/browser/notification_service.h" #include "content/public/browser/notification_source.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" +#include "printing/features/features.h" #include "printing/pdf_metafile_skia.h" #include "printing/printed_document.h" #include "ui/base/l10n/l10n_util.h" -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) #include "chrome/browser/printing/print_error_dialog.h" #endif @@ -69,6 +71,7 @@ void ShowWarningMessageBox(const base::string16& message) { PrintViewManagerBase::PrintViewManagerBase(content::WebContents* web_contents) : PrintManager(web_contents), + printing_rfh_(nullptr), printing_succeeded_(false), inside_inner_message_loop_(false), #if !defined(OS_MACOSX) @@ -79,9 +82,8 @@ PrintViewManagerBase::PrintViewManagerBase(content::WebContents* web_contents) Profile* profile = Profile::FromBrowserContext(web_contents->GetBrowserContext()); printing_enabled_.Init( - prefs::kPrintingEnabled, - profile->GetPrefs(), - base::Bind(&PrintViewManagerBase::UpdateScriptedPrintingBlocked, + prefs::kPrintingEnabled, profile->GetPrefs(), + base::Bind(&PrintViewManagerBase::UpdatePrintingEnabled, base::Unretained(this))); } @@ -90,16 +92,20 @@ PrintViewManagerBase::~PrintViewManagerBase() { DisconnectFromCurrentPrintJob(); } -#if defined(ENABLE_BASIC_PRINTING) -bool PrintViewManagerBase::PrintNow() { - return PrintNowInternal(new PrintMsg_PrintPages(routing_id())); +#if BUILDFLAG(ENABLE_BASIC_PRINTING) +bool PrintViewManagerBase::PrintNow(content::RenderFrameHost* rfh) { + DisconnectFromCurrentPrintJob(); + + SetPrintingRFH(rfh); + int32_t id = rfh->GetRoutingID(); + return PrintNowInternal(rfh, base::MakeUnique<PrintMsg_PrintPages>(id)); } #endif -void PrintViewManagerBase::UpdateScriptedPrintingBlocked() { - Send(new PrintMsg_SetScriptedPrintingBlocked( - routing_id(), - !printing_enabled_.GetValue())); +void PrintViewManagerBase::UpdatePrintingEnabled() { + web_contents()->ForEachFrame( + base::Bind(&PrintViewManagerBase::SendPrintingEnabled, + base::Unretained(this), printing_enabled_.GetValue())); } void PrintViewManagerBase::NavigationStopped() { @@ -107,22 +113,6 @@ void PrintViewManagerBase::NavigationStopped() { TerminatePrintJob(true); } -void PrintViewManagerBase::RenderProcessGone(base::TerminationStatus status) { - PrintManager::RenderProcessGone(status); - ReleasePrinterQuery(); - - if (!print_job_.get()) - return; - - scoped_refptr<PrintedDocument> document(print_job_->document()); - if (document.get()) { - // If IsComplete() returns false, the document isn't completely rendered. - // Since our renderer is gone, there's nothing to do, cancel it. Otherwise, - // the print job may finish without problem. - TerminatePrintJob(!document->IsComplete()); - } -} - base::string16 PrintViewManagerBase::RenderSourceName() { base::string16 name(web_contents()->GetTitle()); if (name.empty()) @@ -192,16 +182,20 @@ void PrintViewManagerBase::OnDidPrintPage( #if defined(OS_WIN) print_job_->AppendPrintedPage(params.page_number); if (metafile_must_be_valid) { + // TODO(thestig): Figure out why rendering text with GDI results in random + // missing characters for some users. https://crbug.com/658606 + bool print_text_with_gdi = + document->settings().print_text_with_gdi() && + !document->settings().printer_is_xps() && + switches::GDITextPrintingEnabled(); scoped_refptr<base::RefCountedBytes> bytes = new base::RefCountedBytes( reinterpret_cast<const unsigned char*>(shared_buf->memory()), params.data_size); document->DebugDumpData(bytes.get(), FILE_PATH_LITERAL(".pdf")); - // TODO(thestig): Figure out why rendering text with GDI results in random - // missing characters for some users. https://crbug.com/658606 print_job_->StartPdfToEmfConversion( bytes, params.page_size, params.content_area, - false /* print_text_with_gdi? */); + print_text_with_gdi); } #else // Update the rendered document. It will send notifications to the listener. @@ -215,7 +209,7 @@ void PrintViewManagerBase::OnDidPrintPage( void PrintViewManagerBase::OnPrintingFailed(int cookie) { PrintManager::OnPrintingFailed(cookie); -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) chrome::ShowPrintErrorDialog(); #endif @@ -235,10 +229,35 @@ void PrintViewManagerBase::OnShowInvalidPrinterSettingsError() { } void PrintViewManagerBase::DidStartLoading() { - UpdateScriptedPrintingBlocked(); + UpdatePrintingEnabled(); +} + +void PrintViewManagerBase::RenderFrameDeleted( + content::RenderFrameHost* render_frame_host) { + // Terminates or cancels the print job if one was pending. + if (render_frame_host != printing_rfh_) + return; + + printing_rfh_ = nullptr; + + PrintManager::PrintingRenderFrameDeleted(); + ReleasePrinterQuery(); + + if (!print_job_.get()) + return; + + scoped_refptr<PrintedDocument> document(print_job_->document()); + if (document.get()) { + // If IsComplete() returns false, the document isn't completely rendered. + // Since our renderer is gone, there's nothing to do, cancel it. Otherwise, + // the print job may finish without problem. + TerminatePrintJob(!document->IsComplete()); + } } -bool PrintViewManagerBase::OnMessageReceived(const IPC::Message& message) { +bool PrintViewManagerBase::OnMessageReceived( + const IPC::Message& message, + content::RenderFrameHost* render_frame_host) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(PrintViewManagerBase, message) IPC_MESSAGE_HANDLER(PrintHostMsg_DidPrintPage, OnDidPrintPage) @@ -246,7 +265,7 @@ bool PrintViewManagerBase::OnMessageReceived(const IPC::Message& message) { OnShowInvalidPrinterSettingsError) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() - return handled || PrintManager::OnMessageReceived(message); + return handled || PrintManager::OnMessageReceived(message, render_frame_host); } void PrintViewManagerBase::Observe( @@ -358,7 +377,7 @@ void PrintViewManagerBase::ShouldQuitFromInnerMessageLoop() { bool PrintViewManagerBase::CreateNewPrintJob(PrintJobWorkerOwner* job) { DCHECK(!inside_inner_message_loop_); - // Disconnect the current print_job_. + // Disconnect the current |print_job_|. DisconnectFromCurrentPrintJob(); // We can't print if there is no renderer. @@ -403,12 +422,6 @@ void PrintViewManagerBase::DisconnectFromCurrentPrintJob() { #endif } -void PrintViewManagerBase::PrintingDone(bool success) { - if (!print_job_.get()) - return; - Send(new PrintMsg_PrintingDone(routing_id(), success)); -} - void PrintViewManagerBase::TerminatePrintJob(bool cancel) { if (!print_job_.get()) return; @@ -430,16 +443,23 @@ void PrintViewManagerBase::TerminatePrintJob(bool cancel) { } void PrintViewManagerBase::ReleasePrintJob() { + content::RenderFrameHost* rfh = printing_rfh_; + printing_rfh_ = nullptr; + if (!print_job_.get()) return; - PrintingDone(printing_succeeded_); + if (rfh) { + auto msg = base::MakeUnique<PrintMsg_PrintingDone>(rfh->GetRoutingID(), + printing_succeeded_); + rfh->Send(msg.release()); + } registrar_.Remove(this, chrome::NOTIFICATION_PRINT_JOB_EVENT, content::Source<PrintJob>(print_job_.get())); print_job_->DisconnectSource(); // Don't close the worker thread. - print_job_ = NULL; + print_job_ = nullptr; } bool PrintViewManagerBase::RunInnerMessageLoop() { @@ -508,14 +528,18 @@ bool PrintViewManagerBase::OpportunisticallyCreatePrintJob(int cookie) { return true; } -bool PrintViewManagerBase::PrintNowInternal(IPC::Message* message) { +bool PrintViewManagerBase::PrintNowInternal( + content::RenderFrameHost* rfh, + std::unique_ptr<IPC::Message> message) { // Don't print / print preview interstitials or crashed tabs. - if (web_contents()->ShowingInterstitialPage() || - web_contents()->IsCrashed()) { - delete message; + if (web_contents()->ShowingInterstitialPage() || web_contents()->IsCrashed()) return false; - } - return Send(message); + return rfh->Send(message.release()); +} + +void PrintViewManagerBase::SetPrintingRFH(content::RenderFrameHost* rfh) { + DCHECK(!printing_rfh_); + printing_rfh_ = rfh; } void PrintViewManagerBase::ReleasePrinterQuery() { @@ -539,4 +563,9 @@ void PrintViewManagerBase::ReleasePrinterQuery() { base::Bind(&PrinterQuery::StopWorker, printer_query)); } +void PrintViewManagerBase::SendPrintingEnabled(bool enabled, + content::RenderFrameHost* rfh) { + rfh->Send(new PrintMsg_SetPrintingEnabled(rfh->GetRoutingID(), enabled)); +} + } // namespace printing diff --git a/chromium/chrome/browser/printing/print_view_manager_base.h b/chromium/chrome/browser/printing/print_view_manager_base.h index 089f9202381..6dac9ddfa3d 100644 --- a/chromium/chrome/browser/printing/print_view_manager_base.h +++ b/chromium/chrome/browser/printing/print_view_manager_base.h @@ -5,6 +5,8 @@ #ifndef CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASE_H_ #define CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_BASE_H_ +#include <memory> + #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/strings/string16.h" @@ -13,12 +15,13 @@ #include "components/printing/browser/print_manager.h" #include "content/public/browser/notification_observer.h" #include "content/public/browser/notification_registrar.h" +#include "printing/features/features.h" #include "printing/printed_pages_source.h" struct PrintHostMsg_DidPrintPage_Params; namespace content { -class RenderViewHost; +class RenderFrameHost; } namespace printing { @@ -36,15 +39,15 @@ class PrintViewManagerBase : public content::NotificationObserver, public: ~PrintViewManagerBase() override; -#if defined(ENABLE_BASIC_PRINTING) +#if BUILDFLAG(ENABLE_BASIC_PRINTING) // Prints the current document immediately. Since the rendering is // asynchronous, the actual printing will not be completed on the return of // this function. Returns false if printing is impossible at the moment. - virtual bool PrintNow(); + virtual bool PrintNow(content::RenderFrameHost* rfh); #endif // ENABLE_BASIC_PRINTING - // Whether to block scripted printing for our tab or not. - void UpdateScriptedPrintingBlocked(); + // Whether printing is enabled or not. + void UpdatePrintingEnabled(); // PrintedPagesSource implementation. base::string16 RenderSourceName() override; @@ -53,13 +56,15 @@ class PrintViewManagerBase : public content::NotificationObserver, explicit PrintViewManagerBase(content::WebContents* web_contents); // Helper method for Print*Now(). - bool PrintNowInternal(IPC::Message* message); + bool PrintNowInternal(content::RenderFrameHost* rfh, + std::unique_ptr<IPC::Message> message); - // Terminates or cancels the print job if one was pending. - void RenderProcessGone(base::TerminationStatus status) override; + void SetPrintingRFH(content::RenderFrameHost* rfh); // content::WebContentsObserver implementation. - bool OnMessageReceived(const IPC::Message& message) override; + void RenderFrameDeleted(content::RenderFrameHost* render_frame_host) override; + bool OnMessageReceived(const IPC::Message& message, + content::RenderFrameHost* render_frame_host) override; private: // content::NotificationObserver implementation. @@ -104,9 +109,6 @@ class PrintViewManagerBase : public content::NotificationObserver, // disconnect from it. void DisconnectFromCurrentPrintJob(); - // Notify that the printing is done. - void PrintingDone(bool success); - // Terminates the print job. No-op if no print job has been created. If // |cancel| is true, cancel it instead of waiting for the job to finish. Will // call ReleasePrintJob(). @@ -130,8 +132,14 @@ class PrintViewManagerBase : public content::NotificationObserver, // Release the PrinterQuery associated with our |cookie_|. void ReleasePrinterQuery(); + // Helper method for UpdatePrintingEnabled(). + void SendPrintingEnabled(bool enabled, content::RenderFrameHost* rfh); + content::NotificationRegistrar registrar_; + // The current RFH that is printing with a system printing dialog. + content::RenderFrameHost* printing_rfh_; + // Manages the low-level talk to the printer. scoped_refptr<PrintJob> print_job_; diff --git a/chromium/chrome/browser/printing/print_view_manager_common.cc b/chromium/chrome/browser/printing/print_view_manager_common.cc index 097220415f1..1832389b903 100644 --- a/chromium/chrome/browser/printing/print_view_manager_common.cc +++ b/chromium/chrome/browser/printing/print_view_manager_common.cc @@ -4,20 +4,25 @@ #include "chrome/browser/printing/print_view_manager_common.h" -#if defined(ENABLE_EXTENSIONS) +#include "content/public/browser/render_frame_host.h" +#include "extensions/features/features.h" +#include "printing/features/features.h" + +#if BUILDFLAG(ENABLE_EXTENSIONS) #include "components/guest_view/browser/guest_view_manager.h" #include "extensions/browser/guest_view/mime_handler_view/mime_handler_view_guest.h" -#endif // defined(ENABLE_EXTENSIONS) +#endif // BUILDFLAG(ENABLE_EXTENSIONS) -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) #include "chrome/browser/printing/print_view_manager.h" #else #include "chrome/browser/printing/print_view_manager_basic.h" -#endif // defined(ENABLE_PRINT_PREVIEW) +#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW) namespace printing { + namespace { -#if defined(ENABLE_EXTENSIONS) +#if BUILDFLAG(ENABLE_EXTENSIONS) // Stores |guest_contents| in |result| and returns true if |guest_contents| is a // full page MimeHandlerViewGuest plugin. Otherwise, returns false. bool StoreFullPagePlugin(content::WebContents** result, @@ -30,12 +35,12 @@ bool StoreFullPagePlugin(content::WebContents** result, } return false; } -#endif // defined(ENABLE_EXTENSIONS) +#endif // BUILDFLAG(ENABLE_EXTENSIONS) // If we have a single full-page embedded mime handler view guest, print the // guest's WebContents instead. content::WebContents* GetWebContentsToUse(content::WebContents* contents) { -#if defined(ENABLE_EXTENSIONS) +#if BUILDFLAG(ENABLE_EXTENSIONS) guest_view::GuestViewManager* guest_view_manager = guest_view::GuestViewManager::FromBrowserContext( contents->GetBrowserContext()); @@ -44,47 +49,77 @@ content::WebContents* GetWebContentsToUse(content::WebContents* contents) { contents, base::Bind(&StoreFullPagePlugin, &contents)); } -#endif // defined(ENABLE_EXTENSIONS) +#endif // BUILDFLAG(ENABLE_EXTENSIONS) return contents; } +// Pick the right RenderFrameHost based on the WebContentses. +content::RenderFrameHost* GetRenderFrameHostToUse( + content::WebContents* original_contents, + content::WebContents* contents_to_use) { + if (original_contents != contents_to_use) + return contents_to_use->GetMainFrame(); + return GetFrameToPrint(contents_to_use); +} + } // namespace void StartPrint(content::WebContents* contents, bool print_preview_disabled, - bool selection_only) { -#if defined(ENABLE_PRINT_PREVIEW) + bool has_selection) { +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) using PrintViewManagerImpl = PrintViewManager; #else using PrintViewManagerImpl = PrintViewManagerBasic; -#endif // defined(ENABLE_PRINT_PREVIEW) +#endif // BUILDFLAG(ENABLE_PRINT_PREVIEW) + content::WebContents* contents_to_use = GetWebContentsToUse(contents); auto* print_view_manager = - PrintViewManagerImpl::FromWebContents(GetWebContentsToUse(contents)); + PrintViewManagerImpl::FromWebContents(contents_to_use); if (!print_view_manager) return; -#if defined(ENABLE_PRINT_PREVIEW) + + content::RenderFrameHost* rfh_to_use = + GetRenderFrameHostToUse(contents, contents_to_use); + if (!rfh_to_use) + return; + +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) if (!print_preview_disabled) { - print_view_manager->PrintPreviewNow(selection_only); + print_view_manager->PrintPreviewNow(rfh_to_use, has_selection); return; } #endif // ENABLE_PRINT_PREVIEW -#if defined(ENABLE_BASIC_PRINTING) - print_view_manager->PrintNow(); +#if BUILDFLAG(ENABLE_BASIC_PRINTING) + print_view_manager->PrintNow(rfh_to_use); #endif // ENABLE_BASIC_PRINTING } -#if defined(ENABLE_BASIC_PRINTING) +#if BUILDFLAG(ENABLE_BASIC_PRINTING) void StartBasicPrint(content::WebContents* contents) { -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) + content::WebContents* contents_to_use = GetWebContentsToUse(contents); PrintViewManager* print_view_manager = - PrintViewManager::FromWebContents(GetWebContentsToUse(contents)); + PrintViewManager::FromWebContents(contents_to_use); if (!print_view_manager) return; - print_view_manager->BasicPrint(); + + content::RenderFrameHost* rfh_to_use = + GetRenderFrameHostToUse(contents, contents_to_use); + if (!rfh_to_use) + return; + + print_view_manager->BasicPrint(rfh_to_use); #endif // ENABLE_PRINT_PREVIEW } #endif // ENABLE_BASIC_PRINTING +content::RenderFrameHost* GetFrameToPrint(content::WebContents* contents) { + auto* focused_frame = contents->GetFocusedFrame(); + return (focused_frame && focused_frame->HasSelection()) + ? focused_frame + : contents->GetMainFrame(); +} + } // namespace printing diff --git a/chromium/chrome/browser/printing/print_view_manager_common.h b/chromium/chrome/browser/printing/print_view_manager_common.h index 6e106404273..da97bc7503d 100644 --- a/chromium/chrome/browser/printing/print_view_manager_common.h +++ b/chromium/chrome/browser/printing/print_view_manager_common.h @@ -5,7 +5,10 @@ #ifndef CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_COMMON_H_ #define CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_COMMON_H_ +#include "printing/features/features.h" + namespace content { +class RenderFrameHost; class WebContents; } @@ -14,13 +17,17 @@ namespace printing { // Start printing using the appropriate PrintViewManagerBase subclass. void StartPrint(content::WebContents* web_contents, bool print_preview_disabled, - bool selection_only); + bool has_selection); -#if defined(ENABLE_BASIC_PRINTING) +#if BUILDFLAG(ENABLE_BASIC_PRINTING) // Start printing using the system print dialog. void StartBasicPrint(content::WebContents* contents); #endif +// If the user has selected text in the currently focused frame, print only that +// frame (this makes print selection work for multiple frames). +content::RenderFrameHost* GetFrameToPrint(content::WebContents* contents); + } // namespace printing #endif // CHROME_BROWSER_PRINTING_PRINT_VIEW_MANAGER_COMMON_H_ diff --git a/chromium/chrome/browser/printing/printer_query.cc b/chromium/chrome/browser/printing/printer_query.cc index 1a097193205..bfaeb574db3 100644 --- a/chromium/chrome/browser/printing/printer_query.cc +++ b/chromium/chrome/browser/printing/printer_query.cc @@ -16,8 +16,8 @@ namespace printing { -PrinterQuery::PrinterQuery(int render_process_id, int render_view_id) - : worker_(new PrintJobWorker(render_process_id, render_view_id, this)), +PrinterQuery::PrinterQuery(int render_process_id, int render_frame_id) + : worker_(new PrintJobWorker(render_process_id, render_frame_id, this)), is_print_dialog_box_shown_(false), cookie_(PrintSettings::NewCookie()), last_status_(PrintingContext::FAILED) { diff --git a/chromium/chrome/browser/printing/printer_query.h b/chromium/chrome/browser/printing/printer_query.h index 13baf17e0d4..9008e19de81 100644 --- a/chromium/chrome/browser/printing/printer_query.h +++ b/chromium/chrome/browser/printing/printer_query.h @@ -31,7 +31,7 @@ class PrinterQuery : public PrintJobWorkerOwner { ASK_USER, }; - PrinterQuery(int render_process_id, int render_view_id); + PrinterQuery(int render_process_id, int render_frame_id); // PrintJobWorkerOwner implementation. void GetSettingsDone(const PrintSettings& new_settings, diff --git a/chromium/chrome/browser/printing/printing_message_filter.cc b/chromium/chrome/browser/printing/printing_message_filter.cc index 6c416b40a0f..a4f25977790 100644 --- a/chromium/chrome/browser/printing/printing_message_filter.cc +++ b/chromium/chrome/browser/printing/printing_message_filter.cc @@ -18,15 +18,17 @@ #include "components/printing/browser/print_manager_utils.h" #include "components/printing/common/print_messages.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/render_view_host.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" #include "content/public/common/child_process_host.h" +#include "printing/features/features.h" -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) #include "chrome/browser/ui/webui/print_preview/print_preview_ui.h" #endif #if defined(OS_ANDROID) +#include "base/file_descriptor_posix.h" #include "base/strings/string_number_conversions.h" #include "chrome/browser/printing/print_view_manager_basic.h" #endif @@ -38,19 +40,19 @@ namespace printing { namespace { #if defined(OS_ANDROID) -content::WebContents* GetWebContentsForRenderView(int render_process_id, - int render_view_id) { +content::WebContents* GetWebContentsForRenderFrame(int render_process_id, + int render_frame_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - content::RenderViewHost* view = content::RenderViewHost::FromID( - render_process_id, render_view_id); - return view ? content::WebContents::FromRenderViewHost(view) : nullptr; + content::RenderFrameHost* frame = + content::RenderFrameHost::FromID(render_process_id, render_frame_id); + return frame ? content::WebContents::FromRenderFrameHost(frame) : nullptr; } PrintViewManagerBasic* GetPrintManager(int render_process_id, - int render_view_id) { + int render_frame_id) { DCHECK_CURRENTLY_ON(BrowserThread::UI); content::WebContents* web_contents = - GetWebContentsForRenderView(render_process_id, render_view_id); + GetWebContentsForRenderFrame(render_process_id, render_frame_id); return web_contents ? PrintViewManagerBasic::FromWebContents(web_contents) : nullptr; } @@ -92,13 +94,12 @@ bool PrintingMessageFilter::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(PrintHostMsg_TempFileForPrintingWritten, OnTempFileForPrintingWritten) #endif - IPC_MESSAGE_HANDLER(PrintHostMsg_IsPrintingEnabled, OnIsPrintingEnabled) IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_GetDefaultPrintSettings, OnGetDefaultPrintSettings) IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrint, OnScriptedPrint) IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_UpdatePrintSettings, OnUpdatePrintSettings) -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) IPC_MESSAGE_HANDLER(PrintHostMsg_CheckForCancel, OnCheckForCancel) #endif IPC_MESSAGE_UNHANDLED(handled = false) @@ -108,35 +109,31 @@ bool PrintingMessageFilter::OnMessageReceived(const IPC::Message& message) { #if defined(OS_ANDROID) void PrintingMessageFilter::OnAllocateTempFileForPrinting( - int render_view_id, + int render_frame_id, base::FileDescriptor* temp_file_fd, int* sequence_number) { DCHECK_CURRENTLY_ON(BrowserThread::UI); PrintViewManagerBasic* print_view_manager = - GetPrintManager(render_process_id_, render_view_id); + GetPrintManager(render_process_id_, render_frame_id); if (!print_view_manager) return; + // The file descriptor is originally created in & passed from the Android // side, and it will handle the closing. temp_file_fd->fd = print_view_manager->file_descriptor().fd; temp_file_fd->auto_close = false; } -void PrintingMessageFilter::OnTempFileForPrintingWritten(int render_view_id, +void PrintingMessageFilter::OnTempFileForPrintingWritten(int render_frame_id, int sequence_number) { DCHECK_CURRENTLY_ON(BrowserThread::UI); PrintViewManagerBasic* print_view_manager = - GetPrintManager(render_process_id_, render_view_id); + GetPrintManager(render_process_id_, render_frame_id); if (print_view_manager) print_view_manager->PdfWritingDone(true); } #endif // defined(OS_ANDROID) -void PrintingMessageFilter::OnIsPrintingEnabled(bool* is_enabled) { - DCHECK_CURRENTLY_ON(BrowserThread::IO); - *is_enabled = is_printing_enabled_->GetValue(); -} - void PrintingMessageFilter::OnGetDefaultPrintSettings(IPC::Message* reply_msg) { DCHECK_CURRENTLY_ON(BrowserThread::IO); scoped_refptr<PrinterQuery> printer_query; @@ -238,10 +235,10 @@ void PrintingMessageFilter::OnScriptedPrintReply( } #if defined(OS_ANDROID) -void PrintingMessageFilter::UpdateFileDescriptor(int render_view_id, int fd) { +void PrintingMessageFilter::UpdateFileDescriptor(int render_frame_id, int fd) { DCHECK_CURRENTLY_ON(BrowserThread::UI); PrintViewManagerBasic* print_view_manager = - GetPrintManager(render_process_id_, render_view_id); + GetPrintManager(render_process_id_, render_frame_id); if (print_view_manager) print_view_manager->set_file_descriptor(base::FileDescriptor(fd, false)); } @@ -260,14 +257,12 @@ void PrintingMessageFilter::OnUpdatePrintSettings( } printer_query = queue_->PopPrinterQuery(document_cookie); if (!printer_query.get()) { - int host_id = render_process_id_; - int routing_id = reply_msg->routing_id(); - if (!new_settings->GetInteger(printing::kPreviewInitiatorHostId, - &host_id) || - !new_settings->GetInteger(printing::kPreviewInitiatorRoutingId, - &routing_id)) { + int host_id; + int routing_id; + if (!new_settings->GetInteger(kPreviewInitiatorHostId, &host_id) || + !new_settings->GetInteger(kPreviewInitiatorRoutingId, &routing_id)) { host_id = content::ChildProcessHost::kInvalidUniqueID; - routing_id = content::ChildProcessHost::kInvalidUniqueID; + routing_id = MSG_ROUTING_NONE; } printer_query = queue_->CreatePrinterQuery(host_id, routing_id); } @@ -289,11 +284,10 @@ void PrintingMessageFilter::OnUpdatePrintSettingsReply( params.params.document_cookie = printer_query->cookie(); params.pages = PageRange::GetPages(printer_query->settings().ranges()); } - PrintHostMsg_UpdatePrintSettings::WriteReplyParams( - reply_msg, - params, - printer_query.get() && - (printer_query->last_status() == printing::PrintingContext::CANCEL)); + bool canceled = printer_query.get() && + (printer_query->last_status() == PrintingContext::CANCEL); + PrintHostMsg_UpdatePrintSettings::WriteReplyParams(reply_msg, params, + canceled); Send(reply_msg); // If user hasn't cancelled. if (printer_query.get()) { @@ -305,7 +299,7 @@ void PrintingMessageFilter::OnUpdatePrintSettingsReply( } } -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) void PrintingMessageFilter::OnCheckForCancel(int32_t preview_ui_id, int preview_request_id, bool* cancel) { diff --git a/chromium/chrome/browser/printing/printing_message_filter.h b/chromium/chrome/browser/printing/printing_message_filter.h index 127f27207b7..86651d47f34 100644 --- a/chromium/chrome/browser/printing/printing_message_filter.h +++ b/chromium/chrome/browser/printing/printing_message_filter.h @@ -10,32 +10,24 @@ #include <memory> #include <string> -#include "base/compiler_specific.h" #include "base/macros.h" #include "build/build_config.h" #include "components/prefs/pref_member.h" #include "content/public/browser/browser_message_filter.h" - -#if defined(OS_WIN) -#include "base/memory/shared_memory.h" -#endif +#include "printing/features/features.h" struct PrintHostMsg_ScriptedPrint_Params; class Profile; -class ProfileIOData; namespace base { class DictionaryValue; -class FilePath; -} - -namespace content { -class WebContents; +#if defined(OS_ANDROID) +struct FileDescriptor; +#endif } namespace printing { -class PrintJobManager; class PrintQueriesQueue; class PrinterQuery; @@ -53,30 +45,19 @@ class PrintingMessageFilter : public content::BrowserMessageFilter { private: ~PrintingMessageFilter() override; -#if defined(OS_CHROMEOS) || defined(OS_ANDROID) +#if defined(OS_ANDROID) // Used to ask the browser allocate a temporary file for the renderer // to fill in resulting PDF in renderer. - void OnAllocateTempFileForPrinting(int render_view_id, + void OnAllocateTempFileForPrinting(int render_frame_id, base::FileDescriptor* temp_file_fd, int* sequence_number); - void OnTempFileForPrintingWritten(int render_view_id, int sequence_number); -#endif + void OnTempFileForPrintingWritten(int render_frame_id, int sequence_number); -#if defined(OS_ANDROID) // Updates the file descriptor for the PrintViewManagerBasic of a given - // render_view_id. - void UpdateFileDescriptor(int render_view_id, int fd); + // |render_frame_id|. + void UpdateFileDescriptor(int render_frame_id, int fd); #endif - // GetPrintSettingsForRenderView must be called via PostTask and - // base::Bind. Collapse the settings-specific params into a - // struct to avoid running into issues with too many params - // to base::Bind. - struct GetPrintSettingsForRenderViewParams; - - // Checks if printing is enabled. - void OnIsPrintingEnabled(bool* is_enabled); - // Get the default print setting. void OnGetDefaultPrintSettings(IPC::Message* reply_msg); void OnGetDefaultPrintSettingsReply(scoped_refptr<PrinterQuery> printer_query, @@ -99,7 +80,7 @@ class PrintingMessageFilter : public content::BrowserMessageFilter { void OnUpdatePrintSettingsReply(scoped_refptr<PrinterQuery> printer_query, IPC::Message* reply_msg); -#if defined(ENABLE_PRINT_PREVIEW) +#if BUILDFLAG(ENABLE_PRINT_PREVIEW) // Check to see if print preview has been cancelled. void OnCheckForCancel(int32_t preview_ui_id, int preview_request_id, diff --git a/chromium/chrome/browser/printing/pwg_raster_converter.cc b/chromium/chrome/browser/printing/pwg_raster_converter.cc index 62b4ac82e91..1a7200fd986 100644 --- a/chromium/chrome/browser/printing/pwg_raster_converter.cc +++ b/chromium/chrome/browser/printing/pwg_raster_converter.cc @@ -16,6 +16,7 @@ #include "base/location.h" #include "base/logging.h" #include "base/macros.h" +#include "base/memory/ptr_util.h" #include "base/single_thread_task_runner.h" #include "base/threading/thread_task_runner_handle.h" #include "chrome/common/chrome_utility_messages.h" @@ -77,14 +78,15 @@ class FileHandlers { base::ScopedTempDir temp_dir_; base::File pdf_file_; base::File pwg_file_; + + DISALLOW_COPY_AND_ASSIGN(FileHandlers); }; void FileHandlers::Init(base::RefCountedMemory* data) { DCHECK_CURRENTLY_ON(BrowserThread::FILE); - if (!temp_dir_.CreateUniqueTempDir()) { + if (!temp_dir_.CreateUniqueTempDir()) return; - } if (static_cast<int>(data->size()) != base::WriteFile(GetPdfPath(), data->front_as<char>(), data->size())) { @@ -150,8 +152,8 @@ class PwgUtilityProcessHostClient : public content::UtilityProcessHostClient { }; PwgUtilityProcessHostClient::PwgUtilityProcessHostClient( - const printing::PdfRenderSettings& settings, - const printing::PwgRasterSettings& bitmap_settings) + const PdfRenderSettings& settings, + const PwgRasterSettings& bitmap_settings) : settings_(settings), bitmap_settings_(bitmap_settings) {} PwgUtilityProcessHostClient::~PwgUtilityProcessHostClient() { @@ -161,9 +163,11 @@ void PwgUtilityProcessHostClient::Convert( base::RefCountedMemory* data, const PWGRasterConverter::ResultCallback& callback) { DCHECK_CURRENTLY_ON(BrowserThread::UI); + callback_ = callback; CHECK(!files_); files_.reset(new FileHandlers()); + BrowserThread::PostTaskAndReply( BrowserThread::FILE, FROM_HERE, base::Bind(&FileHandlers::Init, base::Unretained(files_.get()), @@ -200,6 +204,7 @@ void PwgUtilityProcessHostClient::OnFailed() { void PwgUtilityProcessHostClient::OnFilesReadyOnUIThread() { DCHECK_CURRENTLY_ON(BrowserThread::UI); + if (!files_->IsValid()) { RunCallbackOnUIThread(false); return; @@ -211,6 +216,7 @@ void PwgUtilityProcessHostClient::OnFilesReadyOnUIThread() { void PwgUtilityProcessHostClient::StartProcessOnIOThread() { DCHECK_CURRENTLY_ON(BrowserThread::IO); + content::UtilityProcessHost* utility_process_host = content::UtilityProcessHost::Create(this, base::ThreadTaskRunnerHandle::Get()); @@ -230,23 +236,22 @@ void PwgUtilityProcessHostClient::RunCallback(bool success) { void PwgUtilityProcessHostClient::RunCallbackOnUIThread(bool success) { DCHECK_CURRENTLY_ON(BrowserThread::UI); - if (!callback_.is_null()) { - BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, - base::Bind(callback_, success, - files_->GetPwgPath())); - callback_.Reset(); - } + if (callback_.is_null()) + return; + + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, + base::Bind(callback_, success, files_->GetPwgPath())); + callback_.Reset(); } class PWGRasterConverterImpl : public PWGRasterConverter { public: PWGRasterConverterImpl(); - ~PWGRasterConverterImpl() override; void Start(base::RefCountedMemory* data, - const printing::PdfRenderSettings& conversion_settings, - const printing::PwgRasterSettings& bitmap_settings, + const PdfRenderSettings& conversion_settings, + const PwgRasterSettings& bitmap_settings, const ResultCallback& callback) override; private: @@ -262,11 +267,10 @@ PWGRasterConverterImpl::PWGRasterConverterImpl() { PWGRasterConverterImpl::~PWGRasterConverterImpl() { } -void PWGRasterConverterImpl::Start( - base::RefCountedMemory* data, - const printing::PdfRenderSettings& conversion_settings, - const printing::PwgRasterSettings& bitmap_settings, - const ResultCallback& callback) { +void PWGRasterConverterImpl::Start(base::RefCountedMemory* data, + const PdfRenderSettings& conversion_settings, + const PwgRasterSettings& bitmap_settings, + const ResultCallback& callback) { // Rebind cancelable callback to avoid calling callback if // PWGRasterConverterImpl is destroyed. callback_.Reset(callback); @@ -279,71 +283,64 @@ void PWGRasterConverterImpl::Start( // static std::unique_ptr<PWGRasterConverter> PWGRasterConverter::CreateDefault() { - return std::unique_ptr<PWGRasterConverter>(new PWGRasterConverterImpl()); + return base::MakeUnique<PWGRasterConverterImpl>(); } // static -printing::PdfRenderSettings PWGRasterConverter::GetConversionSettings( +PdfRenderSettings PWGRasterConverter::GetConversionSettings( const cloud_devices::CloudDeviceDescription& printer_capabilities, const gfx::Size& page_size) { - int dpi = printing::kDefaultPdfDpi; + int dpi = kDefaultPdfDpi; cloud_devices::printer::DpiCapability dpis; if (dpis.LoadFrom(printer_capabilities)) dpi = std::max(dpis.GetDefault().horizontal, dpis.GetDefault().vertical); - double scale = dpi; - scale /= printing::kPointsPerInch; + const double scale = static_cast<double>(dpi) / kPointsPerInch; // Make vertical rectangle to optimize streaming to printer. Fix orientation // by autorotate. gfx::Rect area(std::min(page_size.width(), page_size.height()) * scale, std::max(page_size.width(), page_size.height()) * scale); - return printing::PdfRenderSettings(area, dpi, true /* autorotate */); + return PdfRenderSettings(area, dpi, true /* autorotate */); } // static -printing::PwgRasterSettings PWGRasterConverter::GetBitmapSettings( +PwgRasterSettings PWGRasterConverter::GetBitmapSettings( const cloud_devices::CloudDeviceDescription& printer_capabilities, const cloud_devices::CloudDeviceDescription& ticket) { - printing::PwgRasterSettings result; - cloud_devices::printer::PwgRasterConfigCapability raster_capability; - // If the raster capability fails to load, raster_capability will contain - // the default value. - raster_capability.LoadFrom(printer_capabilities); - cloud_devices::printer::DuplexTicketItem duplex_item; cloud_devices::printer::DuplexType duplex_value = cloud_devices::printer::NO_DUPLEX; + if (duplex_item.LoadFrom(ticket)) + duplex_value = duplex_item.value(); + cloud_devices::printer::PwgRasterConfigCapability raster_capability; + // If the raster capability fails to load, |raster_capability| will contain + // the default value. + raster_capability.LoadFrom(printer_capabilities); cloud_devices::printer::DocumentSheetBack document_sheet_back = raster_capability.value().document_sheet_back; - if (duplex_item.LoadFrom(ticket)) { - duplex_value = duplex_item.value(); - } - - result.odd_page_transform = printing::TRANSFORM_NORMAL; + PwgRasterSettings result; + result.odd_page_transform = TRANSFORM_NORMAL; switch (duplex_value) { case cloud_devices::printer::NO_DUPLEX: - result.odd_page_transform = printing::TRANSFORM_NORMAL; break; case cloud_devices::printer::LONG_EDGE: - if (document_sheet_back == cloud_devices::printer::ROTATED) { - result.odd_page_transform = printing::TRANSFORM_ROTATE_180; - } else if (document_sheet_back == cloud_devices::printer::FLIPPED) { - result.odd_page_transform = printing::TRANSFORM_FLIP_VERTICAL; - } + if (document_sheet_back == cloud_devices::printer::ROTATED) + result.odd_page_transform = TRANSFORM_ROTATE_180; + else if (document_sheet_back == cloud_devices::printer::FLIPPED) + result.odd_page_transform = TRANSFORM_FLIP_VERTICAL; break; case cloud_devices::printer::SHORT_EDGE: - if (document_sheet_back == cloud_devices::printer::MANUAL_TUMBLE) { - result.odd_page_transform = printing::TRANSFORM_ROTATE_180; - } else if (document_sheet_back == cloud_devices::printer::FLIPPED) { - result.odd_page_transform = printing::TRANSFORM_FLIP_HORIZONTAL; - } + if (document_sheet_back == cloud_devices::printer::MANUAL_TUMBLE) + result.odd_page_transform = TRANSFORM_ROTATE_180; + else if (document_sheet_back == cloud_devices::printer::FLIPPED) + result.odd_page_transform = TRANSFORM_FLIP_HORIZONTAL; + break; } result.rotate_all_pages = raster_capability.value().rotate_all_pages; - result.reverse_page_order = raster_capability.value().reverse_order_streaming; return result; } diff --git a/chromium/chrome/browser/printing/pwg_raster_converter.h b/chromium/chrome/browser/printing/pwg_raster_converter.h index 18d16524327..c7d6998e077 100644 --- a/chromium/chrome/browser/printing/pwg_raster_converter.h +++ b/chromium/chrome/browser/printing/pwg_raster_converter.h @@ -24,7 +24,7 @@ class Size; namespace printing { -class PdfRenderSettings; +struct PdfRenderSettings; struct PwgRasterSettings; class PWGRasterConverter { @@ -33,9 +33,10 @@ class PWGRasterConverter { // |success| denotes whether the conversion succeeded. // |temp_file| is the path to the temp file (owned by the converter) that // contains the PWG raster data. - typedef base::Callback<void(bool /*success*/, - const base::FilePath& /*temp_file*/)> - ResultCallback; + using ResultCallback = + base::Callback<void(bool /*success*/, + const base::FilePath& /*temp_file*/)>; + virtual ~PWGRasterConverter() {} static std::unique_ptr<PWGRasterConverter> CreateDefault(); diff --git a/chromium/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc b/chromium/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc index 2b42f45645c..0da4a534c0a 100644 --- a/chromium/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc +++ b/chromium/chrome/browser/renderer_host/pepper/chrome_browser_pepper_host_factory.cc @@ -51,7 +51,6 @@ ChromeBrowserPepperHostFactory::CreateResourceHost( return std::unique_ptr<ResourceHost>(new MessageFilterHost( host_->GetPpapiHost(), instance, resource, broker_filter)); } -#if defined(OS_CHROMEOS) case PpapiHostMsg_PlatformVerification_Create::ID: { scoped_refptr<ResourceMessageFilter> pv_filter( new chrome::PepperPlatformVerificationMessageFilter(host_, @@ -59,7 +58,6 @@ ChromeBrowserPepperHostFactory::CreateResourceHost( return std::unique_ptr<ResourceHost>(new MessageFilterHost( host_->GetPpapiHost(), instance, resource, pv_filter)); } -#endif case PpapiHostMsg_OutputProtection_Create::ID: { scoped_refptr<ResourceMessageFilter> output_protection_filter( new chrome::PepperOutputProtectionMessageFilter(host_, instance)); diff --git a/chromium/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.cc b/chromium/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.cc index 5ce66503605..ef35bdaf4e6 100644 --- a/chromium/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.cc +++ b/chromium/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.cc @@ -13,6 +13,7 @@ #include "content/public/browser/browser_ppapi_host.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_process_host.h" +#include "device/power_save_blocker/power_save_blocker.h" #include "ipc/ipc_message_macros.h" #include "ppapi/c/pp_errors.h" #include "ppapi/c/private/ppb_flash.h" @@ -57,6 +58,8 @@ PepperFlashBrowserHost::PepperFlashBrowserHost(BrowserPpapiHost* host, PP_Resource resource) : ResourceHost(host->GetPpapiHost(), instance, resource), host_(host), + delay_timer_(FROM_HERE, base::TimeDelta::FromSeconds(45), this, + &PepperFlashBrowserHost::OnDelayTimerFired), weak_factory_(this) { int unused; host->GetRenderFrameIDsForInstance(instance, &render_process_id_, &unused); @@ -78,21 +81,24 @@ int32_t PepperFlashBrowserHost::OnResourceMessageReceived( return PP_ERROR_FAILED; } +void PepperFlashBrowserHost::OnDelayTimerFired() { + power_save_blocker_.reset(); +} + int32_t PepperFlashBrowserHost::OnUpdateActivity( ppapi::host::HostMessageContext* host_context) { -#if defined(OS_WIN) - // Reading then writing back the same value to the screensaver timeout system - // setting resets the countdown which prevents the screensaver from turning - // on "for a while". As long as the plugin pings us with this message faster - // than the screensaver timeout, it won't go on. - int value = 0; - if (SystemParametersInfo(SPI_GETSCREENSAVETIMEOUT, 0, &value, 0)) - SystemParametersInfo(SPI_SETSCREENSAVETIMEOUT, value, NULL, 0); -#elif defined(OS_MACOSX) - UpdateSystemActivity(OverallAct); -#else -// TODO(brettw) implement this for other platforms. -#endif + if (!power_save_blocker_) { + power_save_blocker_.reset(new device::PowerSaveBlocker( + device::PowerSaveBlocker::kPowerSaveBlockPreventDisplaySleep, + device::PowerSaveBlocker::kReasonOther, "Requested By PepperFlash", + BrowserThread::GetTaskRunnerForThread(BrowserThread::UI), + BrowserThread::GetTaskRunnerForThread(BrowserThread::FILE))); + } + // There is no specification for how long OnUpdateActivity should prevent the + // screen from going to sleep. Empirically, twitch.tv calls this method every + // 10 seconds. Be conservative and allow 45 seconds (set in |delay_timer_|'s + // ctor) before deleting the block. + delay_timer_.Reset(); return PP_OK; } diff --git a/chromium/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.h b/chromium/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.h index 50308a2b618..65f0a61afc9 100644 --- a/chromium/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.h +++ b/chromium/chrome/browser/renderer_host/pepper/pepper_flash_browser_host.h @@ -10,6 +10,7 @@ #include "base/macros.h" #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" +#include "base/timer/timer.h" #include "ppapi/host/host_message_context.h" #include "ppapi/host/resource_host.h" @@ -26,6 +27,10 @@ namespace content_settings { class CookieSettings; } +namespace device { +class PowerSaveBlocker; +} + class GURL; namespace chrome { @@ -43,6 +48,7 @@ class PepperFlashBrowserHost : public ppapi::host::ResourceHost { ppapi::host::HostMessageContext* context) override; private: + void OnDelayTimerFired(); int32_t OnUpdateActivity(ppapi::host::HostMessageContext* host_context); int32_t OnGetLocalTimeZoneOffset( ppapi::host::HostMessageContext* host_context, @@ -57,6 +63,12 @@ class PepperFlashBrowserHost : public ppapi::host::ResourceHost { content::BrowserPpapiHost* host_; int render_process_id_; + + // A power save blocker to prevent going to sleep, and a timer to destroy it + // after a certain amount of time has elapsed without an UpdateActivity. + std::unique_ptr<device::PowerSaveBlocker> power_save_blocker_; + base::DelayTimer delay_timer_; + // For fetching the Flash LSO settings. scoped_refptr<content_settings::CookieSettings> cookie_settings_; base::WeakPtrFactory<PepperFlashBrowserHost> weak_factory_; diff --git a/chromium/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.cc b/chromium/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.cc index 09d7c0b9d61..30a58414fec 100644 --- a/chromium/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.cc +++ b/chromium/chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.cc @@ -16,12 +16,7 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/child_process_security_policy.h" #include "content/public/browser/render_view_host.h" -#if defined(ENABLE_EXTENSIONS) -#include "extensions/browser/extension_registry.h" -#include "extensions/common/constants.h" -#include "extensions/common/extension.h" -#include "extensions/common/extension_set.h" -#endif +#include "extensions/features/features.h" #include "ppapi/c/pp_errors.h" #include "ppapi/host/dispatch_host_message.h" #include "ppapi/host/host_message_context.h" @@ -30,6 +25,13 @@ #include "ppapi/shared_impl/file_system_util.h" #include "storage/browser/fileapi/isolated_context.h" +#if BUILDFLAG(ENABLE_EXTENSIONS) +#include "extensions/browser/extension_registry.h" +#include "extensions/common/constants.h" +#include "extensions/common/extension.h" +#include "extensions/common/extension_set.h" +#endif + namespace chrome { namespace { @@ -102,7 +104,7 @@ Profile* PepperIsolatedFileSystemMessageFilter::GetProfile() { std::string PepperIsolatedFileSystemMessageFilter::CreateCrxFileSystem( Profile* profile) { -#if defined(ENABLE_EXTENSIONS) +#if BUILDFLAG(ENABLE_EXTENSIONS) const extensions::Extension* extension = extensions::ExtensionRegistry::Get(profile)->enabled_extensions().GetByID( document_url_.host()); @@ -140,7 +142,7 @@ int32_t PepperIsolatedFileSystemMessageFilter::OnOpenFileSystem( int32_t PepperIsolatedFileSystemMessageFilter::OpenCrxFileSystem( ppapi::host::HostMessageContext* context) { -#if defined(ENABLE_EXTENSIONS) +#if BUILDFLAG(ENABLE_EXTENSIONS) Profile* profile = GetProfile(); const extensions::ExtensionSet* extension_set = NULL; if (profile) { diff --git a/chromium/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.cc b/chromium/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.cc index 14f1e00cc5c..7bab5693c36 100644 --- a/chromium/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.cc +++ b/chromium/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.cc @@ -15,14 +15,13 @@ #include "ppapi/host/ppapi_host.h" #include "ppapi/proxy/ppapi_messages.h" -using chromeos::attestation::PlatformVerificationFlow; - namespace chrome { PepperPlatformVerificationMessageFilter:: PepperPlatformVerificationMessageFilter(content::BrowserPpapiHost* host, PP_Instance instance) : render_process_id_(0), render_frame_id_(0) { + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); host->GetRenderFrameIDsForInstance( instance, &render_process_id_, &render_frame_id_); } @@ -57,35 +56,35 @@ int32_t PepperPlatformVerificationMessageFilter::OnChallengePlatform( const std::vector<uint8_t>& challenge) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - // Ensure the RenderFrameHost is still alive. +#if defined(OS_CHROMEOS) content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(render_process_id_, render_frame_id_); - if (!rfh) { - ppapi::host::ReplyMessageContext reply_context = - context->MakeReplyMessageContext(); - reply_context.params.set_result(PP_ERROR_FAILED); - SendReply( - reply_context, - PpapiHostMsg_PlatformVerification_ChallengePlatformReply( - std::vector<uint8_t>(), std::vector<uint8_t>(), std::string())); + if (rfh) { + if (!pv_) + pv_ = new chromeos::attestation::PlatformVerificationFlow(); + + pv_->ChallengePlatformKey( + content::WebContents::FromRenderFrameHost(rfh), service_id, + std::string(challenge.begin(), challenge.end()), + base::Bind( + &PepperPlatformVerificationMessageFilter::ChallengePlatformCallback, + this, context->MakeReplyMessageContext())); return PP_OK_COMPLETIONPENDING; } +#else + NOTREACHED() << "Challenging platform is only supported on ChromeOS."; +#endif - if (!pv_.get()) - pv_ = new PlatformVerificationFlow(); - - pv_->ChallengePlatformKey( - content::WebContents::FromRenderFrameHost(rfh), - service_id, - std::string(challenge.begin(), challenge.end()), - base::Bind( - &PepperPlatformVerificationMessageFilter::ChallengePlatformCallback, - this, - context->MakeReplyMessageContext())); - + ppapi::host::ReplyMessageContext reply_context = + context->MakeReplyMessageContext(); + reply_context.params.set_result(PP_ERROR_FAILED); + SendReply(reply_context, + PpapiHostMsg_PlatformVerification_ChallengePlatformReply( + std::vector<uint8_t>(), std::vector<uint8_t>(), std::string())); return PP_OK_COMPLETIONPENDING; } +#if defined(OS_CHROMEOS) void PepperPlatformVerificationMessageFilter::ChallengePlatformCallback( ppapi::host::ReplyMessageContext reply_context, chromeos::attestation::PlatformVerificationFlow::Result challenge_result, @@ -94,7 +93,8 @@ void PepperPlatformVerificationMessageFilter::ChallengePlatformCallback( const std::string& platform_key_certificate) { DCHECK_CURRENTLY_ON(content::BrowserThread::UI); - if (challenge_result == PlatformVerificationFlow::SUCCESS) { + if (challenge_result == + chromeos::attestation::PlatformVerificationFlow::SUCCESS) { reply_context.params.set_result(PP_OK); } else { reply_context.params.set_result(PP_ERROR_FAILED); @@ -109,5 +109,6 @@ void PepperPlatformVerificationMessageFilter::ChallengePlatformCallback( std::vector<uint8_t>(signature.begin(), signature.end()), platform_key_certificate)); } +#endif } // namespace chrome diff --git a/chromium/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.h b/chromium/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.h index 87644f0eecc..3833f3853d7 100644 --- a/chromium/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.h +++ b/chromium/chrome/browser/renderer_host/pepper/pepper_platform_verification_message_filter.h @@ -8,10 +8,13 @@ #include <stdint.h> #include "base/macros.h" -#include "chrome/browser/chromeos/attestation/platform_verification_flow.h" #include "ppapi/c/pp_instance.h" #include "ppapi/host/resource_message_filter.h" +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/attestation/platform_verification_flow.h" +#endif + namespace content { class BrowserPpapiHost; } // namespace content @@ -44,7 +47,7 @@ class PepperPlatformVerificationMessageFilter int32_t OnChallengePlatform(ppapi::host::HostMessageContext* context, const std::string& service_id, const std::vector<uint8_t>& challenge); - +#if defined(OS_CHROMEOS) // PlatformVerificationFlow callbacks. void ChallengePlatformCallback( ppapi::host::ReplyMessageContext reply_context, @@ -52,13 +55,16 @@ class PepperPlatformVerificationMessageFilter const std::string& signed_data, const std::string& signature, const std::string& platform_key_certificate); +#endif // Used to lookup the WebContents associated with this PP_Instance. int render_process_id_; int render_frame_id_; +#if defined(OS_CHROMEOS) // Must only be accessed on the UI thread. scoped_refptr<chromeos::attestation::PlatformVerificationFlow> pv_; +#endif DISALLOW_COPY_AND_ASSIGN(PepperPlatformVerificationMessageFilter); }; diff --git a/chromium/chrome/browser/resources/BUILD.gn b/chromium/chrome/browser/resources/BUILD.gn index 2d727e7b74e..49a50a3b067 100644 --- a/chromium/chrome/browser/resources/BUILD.gn +++ b/chromium/chrome/browser/resources/BUILD.gn @@ -40,6 +40,7 @@ grit("password_manager_internals_resources") { grit("policy_resources") { source = "md_policy/policy_resources.grd" + defines = chrome_grit_defines # TODO(thestig): use_qualified_include = true outputs = [ @@ -88,6 +89,10 @@ if (!is_ios) { # TODO(thestig): use_qualified_include = true defines = chrome_grit_defines + if (enable_hangout_services_extension) { + defines += [ "enable_hangout_services_extension" ] + } + outputs = [ "grit/component_extension_resources.h", "grit/component_extension_resources_map.cc", diff --git a/chromium/chrome/browser/resources/bluetooth_internals/adapter_broker.js b/chromium/chrome/browser/resources/bluetooth_internals/adapter_broker.js new file mode 100644 index 00000000000..ae9bfaae28d --- /dev/null +++ b/chromium/chrome/browser/resources/bluetooth_internals/adapter_broker.js @@ -0,0 +1,147 @@ +// Copyright 2016 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. + +/** + * Javascript for AdapterBroker, served from + * chrome://bluetooth-internals/. + */ +cr.define('adapter_broker', function() { + /** + * The proxy class of an adapter and router of adapter events. + * Exposes an EventTarget interface that allows other object to subscribe to + * to specific AdapterClient events. + * Provides proxy access to Adapter functions. Converts parameters to Mojo + * handles and back when necessary. + * @constructor + * @extends {cr.EventTarget} + * @param {!interfaces.BluetoothAdapter.Adapter.proxyClass} adapter + */ + var AdapterBroker = function(adapter) { + this.adapter_ = adapter; + this.adapterClient_ = new AdapterClient(this); + this.setClient(this.adapterClient_); + }; + + AdapterBroker.prototype = { + __proto__: cr.EventTarget.prototype, + + /** + * Sets client of Adapter service. + * @param {!interfaces.BluetoothAdapter.AdapterClient} adapterClient + */ + setClient: function(adapterClient) { + this.adapter_.setClient(interfaces.Connection.bindStubDerivedImpl( + adapterClient)); + }, + + /** + * Gets an array of currently detectable devices from the Adapter service. + * @return {!Array<!interfaces.BluetoothDevice.DeviceInfo>} + */ + getDevices: function() { + return this.adapter_.getDevices(); + }, + + /** + * Gets the current state of the Adapter. + * @return {!interfaces.BluetoothAdapter.AdapterInfo} + */ + getInfo: function() { + return this.adapter_.getInfo(); + } + }; + + /** + * The implementation of AdapterClient in + * device/bluetooth/public/interfaces/adapter.mojom. Dispatches events + * through AdapterBroker to notify client objects of changes to the Adapter + * service. + * @constructor + * @param {!AdapterBroker} adapterBroker Broker to dispatch events through. + */ + var AdapterClient = function(adapterBroker) { + this.adapterBroker_ = adapterBroker; + }; + + AdapterClient.prototype = { + /** + * Fires deviceadded event. + * @param {!interfaces.BluetoothDevice.DeviceInfo} deviceInfo + */ + deviceAdded: function(deviceInfo) { + var event = new CustomEvent('deviceadded', { + detail: { + deviceInfo: deviceInfo + } + }); + this.adapterBroker_.dispatchEvent(event); + }, + + /** + * Fires deviceremoved event. + * @param {!interfaces.BluetoothDevice.DeviceInfo} deviceInfo + */ + deviceRemoved: function(deviceInfo) { + var event = new CustomEvent('deviceremoved', { + detail: { + deviceInfo: deviceInfo + } + }); + this.adapterBroker_.dispatchEvent(event); + }, + + /** + * Fires devicechanged event. + * @param {!interfaces.BluetoothDevice.DeviceInfo} deviceInfo + */ + deviceChanged: function(deviceInfo) { + var event = new CustomEvent('devicechanged', { + detail: { + deviceInfo: deviceInfo + } + }); + this.adapterBroker_.dispatchEvent(event); + } + }; + + var adapterBroker = null; + + /** + * Initializes an AdapterBroker if one doesn't exist. + * @return {!Promise<!AdapterBroker>} resolves with AdapterBroker, + * rejects if Bluetooth is not supported. + */ + function getAdapterBroker() { + if (adapterBroker) return Promise.resolve(adapterBroker); + + return interfaces.setupInterfaces().then(function(adapter) { + // Hook up the instance properties. + AdapterClient.prototype.__proto__ = + interfaces.BluetoothAdapter.AdapterClient.stubClass.prototype; + + var adapterFactory = interfaces.Connection.bindHandleToProxy( + interfaces.FrameInterfaces.getInterface( + interfaces.BluetoothAdapter.AdapterFactory.name), + interfaces.BluetoothAdapter.AdapterFactory); + + // Get an Adapter service. + return adapterFactory.getAdapter(); + }).then(function(response) { + if (!response.adapter) { + throw new Error('Bluetooth Not Supported on this platform.'); + } + + var adapter = interfaces.Connection.bindHandleToProxy( + response.adapter, + interfaces.BluetoothAdapter.Adapter); + + adapterBroker = new AdapterBroker(adapter); + return adapterBroker; + }); + } + + return { + getAdapterBroker: getAdapterBroker, + }; +}); diff --git a/chromium/chrome/browser/resources/bluetooth_internals/bluetooth_internals.css b/chromium/chrome/browser/resources/bluetooth_internals/bluetooth_internals.css index 1cd2375dae5..0f4812e4303 100644 --- a/chromium/chrome/browser/resources/bluetooth_internals/bluetooth_internals.css +++ b/chromium/chrome/browser/resources/bluetooth_internals/bluetooth_internals.css @@ -13,11 +13,83 @@ body { padding: 0; } + +/* Header bar */ + header { - background-color: blue; - padding: 2px; + align-items: center; + background-color: rgb(33, 150, 243); + display: flex; + flex-direction: row; + font-size: 20pt; + height: 56px; + justify-content: flex-start; + padding: 0 16px; } -header * { +.title { color: white; + display: inline-block; + margin-left: 8px; +} + + +/* Device table */ + +table { + border: 1px solid #ccc; + border-collapse: collapse; + margin: 0; + padding: 0; + width: 100%; +} + +table tr { + border: 1px solid #ddd; + padding: 5px; +} + +table th, +table td { + padding: 10px; + text-align: center; +} + +table th { + font-size: 14px; + letter-spacing: 1px; + text-transform: uppercase; +} + +@media screen and (max-width: 600px) { + table { + border: 0; + } + table thead { + display: none; + } + table tr { + border-bottom: 2px solid #ddd; + display: block; + } + table td { + border-bottom: 1px dotted #ccc; + display: block; + font-size: 13px; + text-align: right; + } + table td:last-child { + border-bottom: 0; + } + table td::before { + content: attr(data-label); + float: left; + font-weight: bold; + text-transform: uppercase; + } +} + +/* Device Row */ +table .removed { + background-color: #BDBDBD; }
\ No newline at end of file diff --git a/chromium/chrome/browser/resources/bluetooth_internals/bluetooth_internals.html b/chromium/chrome/browser/resources/bluetooth_internals/bluetooth_internals.html index 785afb347cd..8502623ec3e 100644 --- a/chromium/chrome/browser/resources/bluetooth_internals/bluetooth_internals.html +++ b/chromium/chrome/browser/resources/bluetooth_internals/bluetooth_internals.html @@ -1,17 +1,45 @@ <!DOCTYPE HTML> <html> +<!-- TODO(crbug.com/658814): Localize strings. --> <head> <meta charset="utf-8"> + <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Bluetooth Internals</title> + <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css"> <link rel="stylesheet" href="bluetooth_internals.css"> + <link rel="import" href="chrome://resources/html/cr/ui.html"> + <link rel="import" href="chrome://resources/html/cr/event_target.html"> + <link rel="import" href="chrome://resources/html/cr/ui/array_data_model.html"> + <link rel="import" href="chrome://resources/html/util.html"> + + <script src="interfaces.js"></script> + <script src="adapter_broker.js"></script> + <script src="device_collection.js"></script> + <script src="device_table.js"></script> <script src="bluetooth_internals.js"></script> </head> <body> <header> - <h1>Bluetooth Internals</h1> + <div class="title"> + Bluetooth Internals + </div> </header> </body> +<template id="table-template"> + <table> + <thead> + <tr> + <th data-field="name_for_display">Name</th> + <th data-field="address">Address</th> + <th data-field="rssi.value">Latest RSSI</th> + </tr> + </thead> + <tbody class="table-body"> + </tbody> + </table> +</template> + </html>
\ No newline at end of file diff --git a/chromium/chrome/browser/resources/bluetooth_internals/bluetooth_internals.js b/chromium/chrome/browser/resources/bluetooth_internals/bluetooth_internals.js index 0e48aa25c64..4057293273b 100644 --- a/chromium/chrome/browser/resources/bluetooth_internals/bluetooth_internals.js +++ b/chromium/chrome/browser/resources/bluetooth_internals/bluetooth_internals.js @@ -7,90 +7,42 @@ * chrome://bluetooth-internals/. */ -/** - * The implementation of AdapterClient in - * device/bluetooth/public/interfaces/adapter.mojom. - */ -var AdapterClient = function() {}; -AdapterClient.prototype = { - /** - * Prints added device to console. - * @param {!Object} device the device that was added - */ - deviceAdded: function(device) { - console.log('Device added'); - console.log(device); - }, - - /** - * Prints removed device to console. - * @param {!Object} device the device that was removed - */ - deviceRemoved: function(device) { - console.log('Device removed'); - console.log(device); - } -}; - -(function() { - var adapter, adapterClient; - - /** - * TODO: Move to shared location. See crbug.com/652361. - * Helper to convert callback-based define() API to a promise-based API. - * @param {!Array<string>} moduleNames - * @return {!Promise} - */ - function importModules(moduleNames) { - return new Promise(function(resolve, reject) { - define(moduleNames, function(var_args) { - resolve(Array.prototype.slice.call(arguments, 0)); - }); - }); +cr.define('bluetooth_internals', function() { + function initializeViews() { + var adapterBroker = null; + adapter_broker.getAdapterBroker() + .then(function(broker) { adapterBroker = broker; }) + .then(function() { return adapterBroker.getInfo(); }) + .then(function(response) { console.log('adapter', response.info); }) + .then(function() { return adapterBroker.getDevices(); }) + .then(function(response) { + // Hook up device collection events. + var devices = new device_collection.DeviceCollection([]); + adapterBroker.addEventListener('deviceadded', function(event) { + devices.addOrUpdate(event.detail.deviceInfo); + }); + adapterBroker.addEventListener('devicechanged', function(event) { + devices.addOrUpdate(event.detail.deviceInfo); + }); + adapterBroker.addEventListener('deviceremoved', function(event) { + devices.remove(event.detail.deviceInfo); + }); + + response.devices.forEach(devices.addOrUpdate, + devices /* this */); + + var deviceTable = new device_table.DeviceTable(); + deviceTable.setDevices(devices); + document.body.appendChild(deviceTable); + }) + .catch(function(error) { console.error(error); }); } - /** - * Initializes Mojo proxies for page and Bluetooth services. - * @return {!Promise} resolves if adapter is acquired, rejects if Bluetooth - * is not supported. - */ - function initializeProxies() { - return importModules([ - 'content/public/renderer/frame_interfaces', - 'device/bluetooth/public/interfaces/adapter.mojom', - 'mojo/public/js/connection', - ]).then(function([frameInterfaces, bluetoothAdapter, connection]) { - console.log('Loaded modules'); + return { + initializeViews: initializeViews + }; - // Hook up the instance properties. - AdapterClient.prototype.__proto__ = - bluetoothAdapter.AdapterClient.stubClass.prototype; +}); - var adapterFactory = connection.bindHandleToProxy( - frameInterfaces.getInterface(bluetoothAdapter.AdapterFactory.name), - bluetoothAdapter.AdapterFactory); - - // Get an Adapter service. - return adapterFactory.getAdapter().then(function(response) { - if (!response.adapter) { - throw new Error('Bluetooth Not Supported on this platform.'); - } - - adapter = connection.bindHandleToProxy(response.adapter, - bluetoothAdapter.Adapter); - - // Create a message pipe and bind one end to client - // implementation and the other to the Adapter service. - adapterClient = new AdapterClient(); - adapter.setClient(connection.bindStubDerivedImpl(adapterClient)); - }); - }); - } - - document.addEventListener('DOMContentLoaded', function() { - initializeProxies() - .then(function() { return adapter.getDevices(); }) - .then(function(response) { console.log(response.devices); }) - .catch(function(error) { console.error(error); }); - }); -})(); +document.addEventListener( + 'DOMContentLoaded', bluetooth_internals.initializeViews); diff --git a/chromium/chrome/browser/resources/bluetooth_internals/device_collection.js b/chromium/chrome/browser/resources/bluetooth_internals/device_collection.js new file mode 100644 index 00000000000..4d86d99c79d --- /dev/null +++ b/chromium/chrome/browser/resources/bluetooth_internals/device_collection.js @@ -0,0 +1,85 @@ +// Copyright 2016 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. + +/** + * Javascript for DeviceCollection, served from + * chrome://bluetooth-internals/. + */ + +cr.define('device_collection', function() { + /* + * Collection of devices. Extends ArrayDataModel which provides a set of + * functions and events that notifies observers when the collection changes. + * @constructor + * @param {!Array<device_collection.Device>} array The starting collection of + * devices. + * @extends {cr.ui.ArrayDataModel} + */ + var DeviceCollection = function(array) { + cr.ui.ArrayDataModel.call(this, array); + }; + DeviceCollection.prototype = { + __proto__: cr.ui.ArrayDataModel.prototype, + + /** + * Finds the Device in the collection with the matching address. + * @param {string} address + */ + getByAddress: function(address) { + for (var i = 0; i < this.length; i++) { + var device = this.item(i); + if (address == device.info.address) + return device; + } + return null; + }, + + /** + * Adds or updates a Device with new DeviceInfo. + * @param {!interfaces.BluetoothDevice.DeviceInfo} deviceInfo + */ + addOrUpdate: function(deviceInfo) { + var oldDevice = this.getByAddress(deviceInfo.address); + if (oldDevice) { + // Update rssi if it's valid + var rssi = (deviceInfo.rssi && deviceInfo.rssi.value) || + (oldDevice.info.rssi && oldDevice.info.rssi.value); + + oldDevice.info = deviceInfo; + oldDevice.info.rssi = { value: rssi }; + oldDevice.removed = false; + + this.updateIndex(this.indexOf(oldDevice)); + } else { + this.push(new Device(deviceInfo)); + } + }, + + /** + * Marks the Device as removed. + * @param {!interfaces.bluetoothDevice.DeviceInfo} deviceInfo + */ + remove: function(deviceInfo) { + var device = this.getByAddress(deviceInfo.address); + assert(device, 'Device does not exist.'); + device.removed = true; + this.updateIndex(this.indexOf(device)); + } + }; + + /* + * Data model for a cached device. + * @constructor + * @param {!interfaces.BluetoothDevice.DeviceInfo} info + */ + var Device = function(info) { + this.info = info; + this.removed = false; + }; + + return { + Device: Device, + DeviceCollection: DeviceCollection, + }; +}); diff --git a/chromium/chrome/browser/resources/bluetooth_internals/device_table.js b/chromium/chrome/browser/resources/bluetooth_internals/device_table.js new file mode 100644 index 00000000000..443c590ff8f --- /dev/null +++ b/chromium/chrome/browser/resources/bluetooth_internals/device_table.js @@ -0,0 +1,143 @@ +// Copyright 2016 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. + +/** + * Javascript for DeviceTable UI, served from chrome://bluetooth-internals/. + */ + +cr.define('device_table', function() { + /** + * A table that lists the devices and responds to changes in the given + * DeviceCollection. + * @constructor + * @extends {HTMLTableElement} + */ + var DeviceTable = cr.ui.define(function() { + /** @private {?Array<device_collection.Device>} */ + this.devices_ = null; + + return document.importNode($('table-template').content.children[0], + true /* deep */); + }); + + DeviceTable.prototype = { + __proto__: HTMLTableElement.prototype, + + /** + * Decorates an element as a UI element class. Caches references to the + * table body and headers. + */ + decorate: function() { + /** @private */ + this.body_ = this.tBodies[0]; + /** @private */ + this.headers_ = this.tHead.rows[0].cells; + }, + + /** + * Sets the tables device collection. + * @param {!device_collection.DeviceCollection} deviceCollection + */ + setDevices: function(deviceCollection) { + assert(!this.devices_, 'Devices can only be set once.'); + + this.devices_ = deviceCollection; + this.devices_.addEventListener('sorted', this.redraw_.bind(this)); + this.devices_.addEventListener('change', this.handleChange_.bind(this)); + this.devices_.addEventListener('splice', this.handleSplice_.bind(this)); + + this.redraw_(); + }, + + /** + * Updates table row on change event of the device collection. + * @private + * @param {!CustomEvent} event + */ + handleChange_: function(event) { + this.updateRow_(this.devices_.item(event.index), event.index); + }, + + /** + * Updates table row on splice event of the device collection. + * @private + * @param {!CustomEvent} event + */ + handleSplice_: function(event) { + event.removed.forEach(function() { + this.body_.deleteRow(event.index); + }, this); + + event.added.forEach(function(device, index) { + this.insertRow_(device, event.index + index); + }, this); + }, + + /** + * Inserts a new row at |index| and updates it with info from |device|. + * @private + * @param {!device_collection.Device} device + * @param {?number} index + */ + insertRow_: function(device, index) { + var row = this.body_.insertRow(index); + row.id = device.info.address; + + for (var i = 0; i < this.headers_.length; i++) { + row.insertCell(); + } + + this.updateRow_(device, row.sectionRowIndex); + }, + + /** + * Deletes and recreates the table using the cached |devices_|. + * @private + */ + redraw_: function() { + this.removeChild(this.body_); + this.appendChild(document.createElement('tbody')); + this.body_ = this.tBodies[0]; + this.body_.classList.add('table-body'); + + for (var i = 0; i < this.devices_.length; i++) { + this.insertRow_(this.devices_.item(i)); + } + }, + + /** + * Updates the row at |index| with the info from |device|. + * @private + * @param {!device_collection.Device} device + * @param {number} index + */ + updateRow_: function(device, index) { + assert(this.body_.rows[index], 'Row ' + index + ' is not in the table.'); + var row = this.body_.rows[index]; + + row.classList.toggle('removed', device.removed); + + // Update the properties based on the header field path. + for (var i = 0; i < this.headers_.length; i++) { + var header = this.headers_[i]; + var propName = header.dataset.field; + + var parts = propName.split('.'); + var obj = device.info; + while (obj != null && parts.length > 0) { + var part = parts.shift(); + obj = obj[part]; + } + + var cell = row.cells[i]; + cell.textContent = obj || 'Unknown'; + cell.dataset.label = header.textContent; + } + }, + }; + + return { + DeviceTable: DeviceTable, + }; +}); diff --git a/chromium/chrome/browser/resources/bluetooth_internals/interfaces.js b/chromium/chrome/browser/resources/bluetooth_internals/interfaces.js new file mode 100644 index 00000000000..a48eb81f631 --- /dev/null +++ b/chromium/chrome/browser/resources/bluetooth_internals/interfaces.js @@ -0,0 +1,33 @@ +// Copyright 2016 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. + +/** + * Javascript for Mojo interface helpers, served from + * chrome://bluetooth-internals/. + */ + +cr.define('interfaces', function() { + /** + * Sets up Mojo interfaces and adds them to window.interfaces. + * @return {Promise} + */ + function setupInterfaces() { + return importModules([ + 'content/public/renderer/frame_interfaces', + 'device/bluetooth/public/interfaces/adapter.mojom', + 'device/bluetooth/public/interfaces/device.mojom', + 'mojo/public/js/connection', + ]).then(function([frameInterfaces, bluetoothAdapter, bluetoothDevice, + connection]) { + interfaces.BluetoothAdapter = bluetoothAdapter; + interfaces.BluetoothDevice = bluetoothDevice; + interfaces.Connection = connection; + interfaces.FrameInterfaces = frameInterfaces; + }); + } + + return { + setupInterfaces: setupInterfaces, + }; +}); diff --git a/chromium/chrome/browser/resources/bookmark_manager/js/bmm/bookmark_list.js b/chromium/chrome/browser/resources/bookmark_manager/js/bmm/bookmark_list.js index 4914b68e8c2..089b77a7044 100644 --- a/chromium/chrome/browser/resources/bookmark_manager/js/bmm/bookmark_list.js +++ b/chromium/chrome/browser/resources/bookmark_manager/js/bmm/bookmark_list.js @@ -149,6 +149,15 @@ cr.define('bmm', function() { this.fixWidth_(); cr.dispatchSimpleEvent(this, 'load'); + + // Use the same histogram configuration as UMA_HISTOGRAM_COUNTS_1000(). + chrome.metricsPrivate.recordValue({ + 'metricName': 'Bookmarks.BookmarksInFolder', + 'type': chrome.metricsPrivate.MetricTypeType.HISTOGRAM_LOG, + 'min': 1, + 'max': 1000, + 'buckets': 50 + }, this.dataModel.length); }, /** diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/BUILD.gn b/chromium/chrome/browser/resources/chromeos/chromevox/BUILD.gn index fc37ab8dee1..f2efd1da529 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/BUILD.gn +++ b/chromium/chrome/browser/resources/chromeos/chromevox/BUILD.gn @@ -3,6 +3,7 @@ # found in the LICENSE file. import("//build/config/features.gni") +import("//chrome/common/features.gni") import("//testing/test.gni") import("//chrome/test/base/js2gtest.gni") import("run_jsbundler.gni") @@ -124,6 +125,7 @@ chromevox_modules = [ "cvox2/background/automation_util.js", "cvox2/background/background.js", "cvox2/background/base_automation_handler.js", + "cvox2/background/braille_command_handler.js", "cvox2/background/chromevox_state.js", "cvox2/background/command_handler.js", "cvox2/background/constants.js", @@ -542,8 +544,7 @@ test("chromevox_tests") { "//chrome/test:test_support", "//chrome/test:test_support_ui", "//content/test:test_support", - "//services/shell/background:lib", - "//services/shell/background/tests:test_support", + "//services/service_manager/background:lib", "//testing/gmock", "//testing/gtest", "//ui/keyboard:resources", diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json b/chromium/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json index 08dfdb499a2..15a60483b55 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json +++ b/chromium/chrome/browser/resources/chromeos/chromevox/chromevox/background/keymaps/next_keymap.json @@ -174,6 +174,25 @@ } }, { + "command": "previousGraphic", + "sequence": { + "cvoxModifier": true, + "keys": { + "keyCode": [71], + "shiftKey": [true] + } + } + }, + { + "command": "nextGraphic", + "sequence": { + "cvoxModifier": true, + "keys": { + "keyCode": [71] + } + } + }, + { "command": "nextHeading", "sequence": { "cvoxModifier": true, @@ -440,15 +459,6 @@ } }, { - "command": "toggleChromeVox", - "sequence": { - "cvoxModifier": true, - "keys": { - "keyCode": [65, 65] - } - } - }, - { "command": "toggleStickyMode", "sequence": { "doubleTap": true, @@ -586,6 +596,15 @@ } }, { + "command": "help", + "sequence": { + "cvoxModifier": true, + "keys": { + "keyCode": [79, 84] + } + } + }, + { "command": "showNextUpdatePage", "sequence": { "cvoxModifier": true, diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/run_jsbundler.gni b/chromium/chrome/browser/resources/chromeos/chromevox/run_jsbundler.gni index 1dc28258e33..e13d343881f 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/run_jsbundler.gni +++ b/chromium/chrome/browser/resources/chromeos/chromevox/run_jsbundler.gni @@ -15,7 +15,7 @@ jsbundler_modules = rebase_path([ ".", "$closure_library_dir/../bin/build") jsbundler_modules += - [ "//third_party/WebKit/Source/devtools/scripts/rjsmin.py" ] + [ "//third_party/WebKit/Source/devtools/scripts/build/rjsmin.py" ] template("run_jsbundler") { assert(defined(invoker.mode)) diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/strings/BUILD.gn b/chromium/chrome/browser/resources/chromeos/chromevox/strings/BUILD.gn index 1fe755c2c28..5ff0a39e72a 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/strings/BUILD.gn +++ b/chromium/chrome/browser/resources/chromeos/chromevox/strings/BUILD.gn @@ -2,12 +2,14 @@ # Use of this source code is governed by a BSD-style license that can be # found in the LICENSE file. +import("//chrome/common/features.gni") import("//tools/grit/grit_rule.gni") chromevox_out_dir = "$root_out_dir/resources/chromeos/chromevox" grit("chromevox_strings") { source = "chromevox_strings.grd" + defines = chrome_grit_defines use_qualified_include = true outputs = [ "_locales/am/messages.json", diff --git a/chromium/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd b/chromium/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd index 646f7d40f99..42f2f286f23 100644 --- a/chromium/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd +++ b/chromium/chrome/browser/resources/chromeos/chromevox/strings/chromevox_strings.grd @@ -193,13 +193,13 @@ Open ChromeVox tutorial </message> <message desc="The description of the toggleSearchWidget key. Displayed in the Options page." name="IDS_CHROMEVOX_TOGGLE_SEARCH_WIDGET"> - Toggle search widget + ChromeVox find in page </message> <message desc="The description of the showOptionsPage key. Displayed in the Options page." name="IDS_CHROMEVOX_SHOW_OPTIONS_PAGE"> Open options page </message> - <message desc="The description of the showKbExplorerPage key. Displayed in the Options page." name="IDS_CHROMEVOX_SHOW_KB_EXPLORER_PAGE"> - Open keyboard explorer + <message desc="The description of the showKbExplorerPage key; this allows users to learn about their keyboard. Displayed in the Options page." name="IDS_CHROMEVOX_SHOW_KB_EXPLORER_PAGE"> + Open learn mode </message> <message desc="The description of the decreaseTtsRate key. Displayed in the Options page." name="IDS_CHROMEVOX_DECREASE_TTS_RATE"> Decrease rate of speech @@ -438,6 +438,27 @@ <message desc="The title of the extension's options page." name="IDS_CHROMEVOX_OPTIONS_PAGE_TITLE"> ChromeVox Options </message> + <message desc="An options page section header for options about the ChromeVox virtual display. This section lets users change the rows, columns, and display style of the virtual braille display." name="IDS_CHROMEVOX_OPTIONS_VIRTUAL_BRAILLE_DISPLAY"> + Virtual Braille Display + </message> + <message desc="The label for a numberic input field where the user can choose the number of rows in a grid." name="IDS_CHROMEVOX_OPTIONS_VIRTUAL_BRAILLE_DISPLAY_ROWS"> + Rows: + </message> + <message desc="The label for a numberic input field where the user can choose the number of columns in a grid." name="IDS_CHROMEVOX_OPTIONS_VIRTUAL_BRAILLE_DISPLAY_COLUMNS"> + Columns: + </message> + <message desc="A description that tells the user that the current display style of the virtual display interleaves braille and regular text, one on top of the other." name="IDS_CHROMEVOX_OPTIONS_CURRENT_DISPLAY_STYLE_INTERLEAVE"> + Current display style is interleave. + </message> + <message desc="A description that tells the user that the current display style of the virtual display is side by side, where regular text is on the left and braille is on the right." name="IDS_CHROMEVOX_OPTIONS_CURRENT_DISPLAY_STYLE_SIDE_BY_SIDE"> + Current display style is side by side. + </message> + <message desc="Labels the change display style button when the display style is side by side. Pressing the button would make the text interleave with the braille cells, one on top of the other." name="IDS_CHROMEVOX_OPTIONS_CHANGE_CURRENT_DISPLAY_STYLE_INTERLEAVE"> + Change display style to interleave. + </message> + <message desc="Labels the change display style button when the display style is interleave. Pressing the button would put all the text on the left side and all the braille cells on the right." name="IDS_CHROMEVOX_OPTIONS_CHANGE_CURRENT_DISPLAY_STYLE_SIDE_BY_SIDE"> + Change display style to side by side. + </message> <message desc="The summary of the extension's options. Shown at the top of the options page." name="IDS_CHROMEVOX_OPTIONS_PAGE_SUMMARY"> Use the options below to customize ChromeVox. Changes take effect immediately. </message> @@ -507,11 +528,11 @@ <message desc="An option for setting the key combination that will be used as the ChromeVox modifier key (aka, the 'Cvox' key)." name="IDS_CHROMEVOX_OPTIONS_CVOX_MODIFIER_KEY"> ChromeVox modifier key </message> - <message desc="The title of the ChromeOS Keyboard explorer page. The keyboard explorer voices the name of each key when the user presses it." name="IDS_CHROMEVOX_KBEXPLORER_TITLE"> - ChromeOS Keyboard Explorer + <message desc="The title of ChromeVox Learn Mode page. The keyboard explorer voices the name of each key when the user presses it." name="IDS_CHROMEVOX_KBEXPLORER_TITLE"> + ChromeVox Learn Mode </message> - <message desc="The instructions for the keyboard explorer. The keyboard explorer voices the name of each key when the user presses it. * These instructions describe how to use the keyboard explorer." name="IDS_CHROMEVOX_KBEXPLORER_INSTRUCTIONS"> - Press any key to learn its name. Ctrl+W will close the keyboard explorer. + <message desc="The instructions for ChromeVox Learn Mode. The keyboard explorer voices the name of each key when the user presses it. * These instructions describe how to use the keyboard explorer." name="IDS_CHROMEVOX_KBEXPLORER_INSTRUCTIONS"> + Press any key to learn its name. Ctrl+W will close learn mode. </message> <message desc="Spoken when a new Chrome tab named 'title' is opened." name="IDS_CHROMEVOX_CHROME_TAB_CREATED"> tab created @@ -543,6 +564,12 @@ <message desc="The unchecked state for a checkbox." name="IDS_CHROMEVOX_CHECKBOX_UNCHECKED_STATE"> not checked </message> + <message desc="Describes a switch named 'name' in the on/checked state." name="IDS_CHROMEVOX_DESCRIBE_SWITCH_ON"> + <ph name="name">$1</ph>, switch on + </message> + <message desc="Describes a switch named 'name' in the off/unchecked state." name="IDS_CHROMEVOX_DESCRIBE_SWITCH_OFF"> + <ph name="name">$1</ph>, switch off + </message> <message desc="Describes a HTML radio button named 'name' in the selected state." name="IDS_CHROMEVOX_DESCRIBE_RADIO_SELECTED"> <ph name="name">$1</ph>, radio button selected </message> @@ -2272,7 +2299,7 @@ {COUNT, plural, =1 {bullet}other {# bullets}} </message> <message desc="Describes the braille click command. Displayed in the options page." name="IDS_CHROMEVOX_BRAILLE_ROUTING"> - Click the item under a routing key + Click the item under routing key $1 </message> <message desc="Describes the braille pan backward command. Displayed in the options page." name="IDS_CHROMEVOX_BRAILLE_PAN_LEFT"> Pan backward @@ -2292,6 +2319,15 @@ <message desc="The description of the braille bottom command. Displayed in the Options page." name="IDS_CHROMEVOX_BRAILLE_BOTTOM"> Move braille display to bottom of page </message> + <message desc="Describes a single physical braille dot on a refreshable braille display. Will usually be followed with numbers to describe the layout of a braille cell. For example, dot 8" name="IDS_CHROMEVOX_BRAILLE_DOT"> + dot <ph name="dot">$1</ph> + </message> + <message desc="Describes multiple physical braille dots on a refreshable braille display. Will usually be followed with numbers to describe the layout of a braille cell. For example, dots 1 2 3 4 8" name="IDS_CHROMEVOX_BRAILLE_DOTS"> + dots <ph name="dot">$1</ph> + </message> + <message desc="Describes dots on a refreshable braille display pressed with the space key. For example, dots 1 2 3 4 8 chord" name="IDS_CHROMEVOX_BRAILLE_CHORD"> + $1 chord + </message> <message desc="Spoken to describe an access key. An access key consists of a single letter. When pressed along with a modifier (usually alt, but depends on platform), a targetted node will be activated." name="IDS_CHROMEVOX_ACCESS_KEY"> has access key, <ph name="key">$1</ph> </message> @@ -2442,6 +2478,9 @@ <message desc="Title displayed in the panel when there are no menu items." name="IDS_CHROMEVOX_PANEL_MENU_ITEM_NONE"> No items. </message> + <message desc="Title displayed in the panel for the menuitem to report an issue." name="IDS_CHROMEVOX_PANEL_MENU_ITEM_REPORT_ISSUE"> + Report an issue + </message> <message desc="Title of a notification that ChromeVox has been updated." name="IDS_CHROMEVOX_UPDATE_TITLE"> ChromeVox Updated </message> @@ -2515,11 +2554,17 @@ <message desc="Part of the ChromeVox tutorial, explains two keystrokes to jump to the next or previous heading." name="IDS_CHROMEVOX_TUTORIAL_JUMP"> Use jump commands to skip to specific types of elements. To jump forward between headings, press Search + H, or to jump backward, press Search + Shift + H. </message> + <message desc="Part of the ChromeVox tutorial, heading used to illustrate jumping." name="IDS_CHROMEVOX_TUTORIAL_JUMP_SECOND_HEADING"> + This is the second heading. Keep going; either press Search+H or Search+Shift+H + </message> + <message desc="Part of the ChromeVox tutorial, heading used to illustrate jumping from last heading." name="IDS_CHROMEVOX_TUTORIAL_JUMP_WRAP_HEADING"> + This is the last heading. Press Search+H to wrap to the first heading, or Search+Shift+H to go to the second heading on this page. + </message> <message desc="Heading for a section of the ChromeVox tutorial on menus of ChromeVox commands to press" name="IDS_CHROMEVOX_TUTORIAL_MENUS_HEADING"> Command Menus </message> <message desc="Part of the ChromeVox tutorial, explains the keystrokes to press to open and use a menu of commands." name="IDS_CHROMEVOX_TUTORIAL_MENUS"> - To explore all ChromeVox commands and shortcuts, press Search + Period, then use the Arrow keys to navigate the menus, and Enter to activate a command. + To explore all ChromeVox commands and shortcuts, press Search + Period, then use the Arrow keys to navigate the menus, and Enter to activate a command. Return here by pressing Search+o then t. </message> <message desc="Heading for a section of the ChromeVox tutorial on Chrome shortcuts" name="IDS_CHROMEVOX_TUTORIAL_CHROME_SHORTCUTS_HEADING"> Helpful Chrome Shortcuts @@ -2543,6 +2588,24 @@ To open the Chrome browser menu, press Alt+F. Congratulations! You’ve learned the essentials to use ChromeVox Next (beta) successfully. Remember that you can open the ChromeVox command menu at any time by pressing Search+Period. To learn even more about ChromeVox and Chrome OS, visit the following articles. If you're done with the tutorial, use ChromeVox to navigate to the Close button and click it. </message> + <message desc="Part of the ChromeVox update notes for m56, title." name="IDS_CHROMEVOX_UPDATE_56_TITLE"> + You've been updated to a major new release of ChromeVox! + </message> + <message desc="Part of the ChromeVox update notes for m56, introductory text." name="IDS_CHROMEVOX_UPDATE_56_INTRO"> + We've been hard at work on a new and improved ChromeVox experience; here's what's new + </message> + <message desc="Part of the ChromeVox update notes for m56, new items 1." name="IDS_CHROMEVOX_UPDATE_56_ITEM_1"> + New key bindings. We've made Search the ChromeVox modifier and dramatically simplified the key combinations. + </message> + <message desc="Part of the ChromeVox update notes for m56, new items 2." name="IDS_CHROMEVOX_UPDATE_56_ITEM_2"> + New earcons. We've refreshed the set of audio icons you hear to make browsing more responsive. + </message> + <message desc="Part of the ChromeVox update notes for m56, new items 3." name="IDS_CHROMEVOX_UPDATE_56_ITEM_3"> + Under the hood upgrades. We've revamped how ChromeVox works from the bottom up. Expect better performance, stability, and web support/compliance. + </message> + <message desc="Part of the ChromeVox update notes for m56, closing paragraph." name="IDS_CHROMEVOX_UPDATE_56_OUTTRO"> + We're excited to hear from you on this new experience. Send us feedback directly by pressing Search+a, then i. Press the next button to continue onto the tutorial to learn everything you need to get started. + </message> <message desc="Title of an article on the command reference for 'ChromeVox Next'" name="IDS_CHROMEVOX_NEXT_COMMAND_REFERENCE"> ChromeVox Next Command Reference </message> @@ -2552,6 +2615,63 @@ If you're done with the tutorial, use ChromeVox to navigate to the Close button <message desc="Title of an article on how to use accessibility features of the Chromebook touch screen" name="IDS_CHROMEVOX_TOUCHSCREEN_ACCESSIBILITY"> Use Chromebook touch screen accessibility features </message> + <message desc="Describes a UI element that is busy" name="IDS_CHROMEVOX_BUSY_STATE"> + busy + </message> + <message desc="Brailled for a UI element that is busy" name="IDS_CHROMEVOX_BUSY_STATE_BRL"> + busy + </message> + <message desc="Describes a UI element invoked after pressing enter such as an ok button in a dialog" name="IDS_CHROMEVOX_DEFAULT_STATE"> + default + </message> + <message desc="Brailles for a UI element invoked after pressing enter such as an ok button in a dialog" name="IDS_CHROMEVOX_DEFAULT_STATE_BRL"> + default + </message> + <message desc="Title of the earcon page in the ChromeVox tutorial" name="IDS_CHROMEVOX_TUTORIAL_EARCON_PAGE_TITLE"> + Sounds + </message> + <message desc="Body text of the earcon page in the ChromeVox tutorial" name="IDS_CHROMEVOX_TUTORIAL_EARCON_PAGE_BODY"> + ChromeVox uses sounds to give you essential and additional information. You can use these sounds to navigate more quickly by learning what each sound means. Once you get more comfortable, you can turn off verbose descriptions in speech and rely on them for essential information about the page. Here's a complete list of sounds and what they mean. + </message> + <message desc="Describes an audio clip that gets played for a specific event or control type. Use the default string as a guide to what the audio clip represents or conveys." name="IDS_CHROMEVOX_ALERT_MODAL_EARCON_DESCRIPTION"> + A modal alert + </message> + <message desc="Describes an audio clip that gets played for a specific event or control type. Use the default string as a guide to what the audio clip represents or conveys." name="IDS_CHROMEVOX_ALERT_NONMODAL_EARCON_DESCRIPTION"> + A non modal alert + </message> + <message desc="Describes an audio clip that gets played for a specific event or control type. Use the default string as a guide to what the audio clip represents or conveys." name="IDS_CHROMEVOX_BUTTON_EARCON_DESCRIPTION"> + A button + </message> + <message desc="Describes an audio clip that gets played for a specific event or control type. Use the default string as a guide to what the audio clip represents or conveys." name="IDS_CHROMEVOX_CHECK_OFF_EARCON_DESCRIPTION"> + An unchecked checkbox + </message> + <message desc="Describes an audio clip that gets played for a specific event or control type. Use the default string as a guide to what the audio clip represents or conveys." name="IDS_CHROMEVOX_CHECK_ON_EARCON_DESCRIPTION"> + A checked checkbox + </message> + <message desc="Describes an audio clip that gets played for a specific event or control type. Use the default string as a guide to what the audio clip represents or conveys." name="IDS_CHROMEVOX_EDITABLE_TEXT_EARCON_DESCRIPTION"> + An editable text field + </message> + <message desc="Describes an audio clip that gets played for a specific event or control type. Use the default string as a guide to what the audio clip represents or conveys." name="IDS_CHROMEVOX_INVALID_KEYPRESS_EARCON_DESCRIPTION"> + An invalid key press + </message> + <message desc="Describes an audio clip that gets played for a specific event or control type. Use the default string as a guide to what the audio clip represents or conveys." name="IDS_CHROMEVOX_LINK_EARCON_DESCRIPTION"> + A link + </message> + <message desc="Describes an audio clip that gets played for a specific event or control type. Use the default string as a guide to what the audio clip represents or conveys." name="IDS_CHROMEVOX_LISTBOX_EARCON_DESCRIPTION"> + A listbox or combo box + </message> + <message desc="Describes an audio clip that gets played for a specific event or control type. Use the default string as a guide to what the audio clip represents or conveys." name="IDS_CHROMEVOX_PAGE_START_LOADING_EARCON_DESCRIPTION"> + A page load in progress + </message> + <message desc="Describes an audio clip that gets played for a specific event or control type. Use the default string as a guide to what the audio clip represents or conveys." name="IDS_CHROMEVOX_POP_UP_BUTTON_EARCON_DESCRIPTION"> + A pop up button + </message> + <message desc="Describes an audio clip that gets played for a specific event or control type. Use the default string as a guide to what the audio clip represents or conveys." name="IDS_CHROMEVOX_SLIDER_EARCON_DESCRIPTION"> + A slider + </message> + <message desc="Describes an audio clip that gets played for a specific event or control type. Use the default string as a guide to what the audio clip represents or conveys." name="IDS_CHROMEVOX_WRAP_EARCON_DESCRIPTION"> + Wrap from beginning to end or end to beginning inside of a page, dialog, or other container + </message> </messages> </release> </grit> diff --git a/chromium/chrome/browser/resources/chromeos/login/compiled_resources2.gyp b/chromium/chrome/browser/resources/chromeos/login/compiled_resources2.gyp new file mode 100644 index 00000000000..506018a2cb8 --- /dev/null +++ b/chromium/chrome/browser/resources/chromeos/login/compiled_resources2.gyp @@ -0,0 +1,14 @@ +# Copyright 2016 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. +{ + 'targets': [ + { + 'target_name': 'offline_ad_login', + 'dependencies': [ + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', + ], + 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + ], +} diff --git a/chromium/chrome/browser/resources/component_extension_resources.grd b/chromium/chrome/browser/resources/component_extension_resources.grd index 7cc87b7edf7..2cec82f0a5e 100644 --- a/chromium/chrome/browser/resources/component_extension_resources.grd +++ b/chromium/chrome/browser/resources/component_extension_resources.grd @@ -39,6 +39,8 @@ <include name="IDR_BOOKMARK_MANAGER_BOOKMARK_BMM_TREE_JS" file="bookmark_manager/js/bmm/bookmark_tree.js" type="BINDATA" /> <include name="IDR_BOOKMARK_MANAGER_BOOKMARK_DND_JS" file="bookmark_manager/js/dnd.js" type="BINDATA" /> <include name="IDR_BOOKMARK_MANAGER_BOOKMARK_BMM_JS" file="bookmark_manager/js/bmm.js" type="BINDATA" /> + <!-- Material Design Bookmarks --> + <include name="IDR_COMPONENT_MD_BOOKMARKS_BOOKMARKS_HTML" file="md_bookmarks/bookmarks.html" type="BINDATA" /> <!-- Gaia auth extension --> <include name="IDR_GAIA_AUTH_MAIN" file="gaia_auth/main.html" allowexternalscript="true" type="BINDATA" /> <include name="IDR_GAIA_AUTH_MAIN_JS" file="gaia_auth/main.js" type="BINDATA" /> @@ -168,6 +170,7 @@ <include name="IDR_PDF_VIEWPORT_SCROLLER_JS" file="pdf/viewport_scroller.js" type="BINDATA" /> <include name="IDR_PDF_PDF_SCRIPTING_API_JS" file="pdf/pdf_scripting_api.js" type="BINDATA" /> <include name="IDR_PDF_ZOOM_MANAGER_JS" file="pdf/zoom_manager.js" type="BINDATA" /> + <include name="IDR_PDF_GESTURE_DETECTOR_JS" file="pdf/gesture_detector.js" type="BINDATA" /> <include name="IDR_PDF_BROWSER_API_JS" file="pdf/browser_api.js" type="BINDATA" /> <include name="IDR_PDF_CONTENT_SCRIPT_JS" file="pdf/content_script.js" type="BINDATA" /> @@ -183,7 +186,7 @@ <include name="IDR_PDF_VIEWER_ERROR_SCREEN_JS" file="pdf/elements/viewer-error-screen/viewer-error-screen.js" type="BINDATA" /> <include name="IDR_PDF_VIEWER_PAGE_INDICATOR_CSS" file="pdf/elements/viewer-page-indicator/viewer-page-indicator.css" type="BINDATA" /> <include name="IDR_PDF_VIEWER_PAGE_INDICATOR_HTML" file="pdf/elements/viewer-page-indicator/viewer-page-indicator.html" type="BINDATA" /> - <include name="IDR_PDF_VIEWER_PAGE_INDICATOR_JS" file="pdf/elements/viewer-page-indicator/viewer-page-indicator.js" type="BINDATA" /> + <include name="IDR_PDF_VIEWER_PAGE_INDICATOR_JS" file="pdf/elements/viewer-page-indicator/viewer-page-indicator.js" type="BINDATA" flattenhtml="true" /> <include name="IDR_PDF_VIEWER_PAGE_SELECTOR_CSS" file="pdf/elements/viewer-page-selector/viewer-page-selector.css" type="BINDATA" /> <include name="IDR_PDF_VIEWER_PAGE_SELECTOR_HTML" file="pdf/elements/viewer-page-selector/viewer-page-selector.html" type="BINDATA" /> <include name="IDR_PDF_VIEWER_PAGE_SELECTOR_JS" file="pdf/elements/viewer-page-selector/viewer-page-selector.js" type="BINDATA" /> diff --git a/chromium/chrome/browser/resources/cryptotoken/appid.js b/chromium/chrome/browser/resources/cryptotoken/appid.js index dddf08377f0..5e2cb7d0fb3 100644 --- a/chromium/chrome/browser/resources/cryptotoken/appid.js +++ b/chromium/chrome/browser/resources/cryptotoken/appid.js @@ -16,25 +16,20 @@ function getOriginsFromJson(text) { try { var urls, i; var appIdData = JSON.parse(text); - if (Array.isArray(appIdData)) { - // Older format where it is a simple list of facets - urls = appIdData; - } else { - var trustedFacets = appIdData['trustedFacets']; - if (trustedFacets) { - var versionBlock; - for (i = 0; versionBlock = trustedFacets[i]; i++) { - if (versionBlock['version'] && - versionBlock['version']['major'] == 1 && - versionBlock['version']['minor'] == 0) { - urls = versionBlock['ids']; - break; - } + var trustedFacets = appIdData['trustedFacets']; + if (trustedFacets) { + var versionBlock; + for (i = 0; versionBlock = trustedFacets[i]; i++) { + if (versionBlock['version'] && + versionBlock['version']['major'] == 1 && + versionBlock['version']['minor'] == 0) { + urls = versionBlock['ids']; + break; } } - if (typeof urls == 'undefined') { - throw Error('Could not find trustedFacets for version 1.0'); - } + } + if (typeof urls == 'undefined') { + throw Error('Could not find trustedFacets for version 1.0'); } var origins = {}; var url; @@ -207,7 +202,7 @@ XhrAppIdChecker.prototype.fetchAllowedOriginsForAppId_ = function(appId) { return Promise.resolve([]); } - if (appId.startsWith('http://') && !this.allowHttp_) { + if (appId.indexOf('http://') == 0 && !this.allowHttp_) { console.log(UTIL_fmt('http app ids disallowed, ' + appId + ' requested')); return Promise.resolve([]); } diff --git a/chromium/chrome/browser/resources/cryptotoken/devicestatuscodes.js b/chromium/chrome/browser/resources/cryptotoken/devicestatuscodes.js index a7bb72c1756..165102abde9 100644 --- a/chromium/chrome/browser/resources/cryptotoken/devicestatuscodes.js +++ b/chromium/chrome/browser/resources/cryptotoken/devicestatuscodes.js @@ -1,4 +1,4 @@ -// Copyright 2015 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. diff --git a/chromium/chrome/browser/resources/cryptotoken/enroller.js b/chromium/chrome/browser/resources/cryptotoken/enroller.js index 623337373d1..42b7c205deb 100644 --- a/chromium/chrome/browser/resources/cryptotoken/enroller.js +++ b/chromium/chrome/browser/resources/cryptotoken/enroller.js @@ -49,7 +49,7 @@ function handleU2fEnrollRequest(messageSender, request, sendResponse) { sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST}); return null; } - if (sender.origin.startsWith('http://') && !HTTP_ORIGINS_ALLOWED) { + if (sender.origin.indexOf('http://') == 0 && !HTTP_ORIGINS_ALLOWED) { sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST}); return null; } @@ -261,7 +261,7 @@ function Enroller(timer, sender, errorCb, successCb, opt_logMsgUrl) { // what they get.) /** @private {boolean} */ this.allowHttp_ = - this.sender_.origin ? this.sender_.origin.startsWith('http://') : false; + this.sender_.origin ? this.sender_.origin.indexOf('http://') == 0 : false; /** @private {Closeable} */ this.handler_ = null; } @@ -310,6 +310,9 @@ Enroller.prototype.approveOrigin_ = function() { if (!result) { // Origin not approved: rather than give an explicit indication to // the web page, let a timeout occur. + // NOTE: if you are looking at this in a debugger, this line will + // always be false since the origin of the debugger is different + // than origin of requesting page if (self.timer_.expired()) { self.notifyTimeout_(); return; diff --git a/chromium/chrome/browser/resources/cryptotoken/gnubbies.js b/chromium/chrome/browser/resources/cryptotoken/gnubbies.js index 86eb6e6a716..8424b393a8a 100644 --- a/chromium/chrome/browser/resources/cryptotoken/gnubbies.js +++ b/chromium/chrome/browser/resources/cryptotoken/gnubbies.js @@ -9,7 +9,17 @@ /** * @typedef {{ + * vendorId: (number|undefined), + * productId: (number|undefined), + * usagePage: (number|undefined) + * }} + */ +var GnubbyEnumerationFilter; + +/** + * @typedef {{ * namespace: string, + * enumeratedBy: (GnubbyEnumerationFilter|undefined), * device: number * }} */ diff --git a/chromium/chrome/browser/resources/cryptotoken/gnubby.js b/chromium/chrome/browser/resources/cryptotoken/gnubby.js index 197f9fb33d8..b0493cba0c4 100644 --- a/chromium/chrome/browser/resources/cryptotoken/gnubby.js +++ b/chromium/chrome/browser/resources/cryptotoken/gnubby.js @@ -111,6 +111,9 @@ Gnubby.prototype.open = function(which, opt_type, opt_cb, opt_caller) { return; } self.dev = device; + if (self.closeHook_) { + self.dev.setDestroyHook(self.closeHook_); + } cb(rc); }); } @@ -119,7 +122,12 @@ Gnubby.prototype.open = function(which, opt_type, opt_cb, opt_caller) { setCid(which); self.which = which; Gnubby.gnubbies_.addClient(which, self, function(rc, device) { - self.dev = device; + if (!rc) { + self.dev = device; + if (self.closeHook_) { + self.dev.setDestroyHook(self.closeHook_); + } + } cb(rc); }); } else { @@ -186,6 +194,15 @@ Gnubby.prototype.closeWhenIdle = function(cb) { }; /** + * Sets a callback that will get called when this gnubby is closed. + * @param {function() : ?Promise} cb Called back when closed. Callback + * may yield a promise that resolves when the close hook completes. + */ +Gnubby.prototype.setCloseHook = function(cb) { + this.closeHook_ = cb; +}; + +/** * Close and notify every caller that it is now closed. * @private */ @@ -236,6 +253,13 @@ Gnubby.prototype.receivedFrame = function(frame) { }; /** + * @return {number|undefined} The last read error seen by this device. + */ +Gnubby.prototype.getLastReadError = function() { + return this.lastReadError_; +}; + +/** * @return {ArrayBuffer|Uint8Array} oldest received frame. Throw if none. * @private */ @@ -276,6 +300,7 @@ Gnubby.prototype.read_ = function(cmd, timeout, cb) { window.clearTimeout(tid); tid = null; } + self.lastReadError_ = /** @private {number|undefined} */ (a); var c = callback; if (c) { callback = null; diff --git a/chromium/chrome/browser/resources/cryptotoken/gnubbydevice.js b/chromium/chrome/browser/resources/cryptotoken/gnubbydevice.js index 3030a375ab2..fffa19ceb99 100644 --- a/chromium/chrome/browser/resources/cryptotoken/gnubbydevice.js +++ b/chromium/chrome/browser/resources/cryptotoken/gnubbydevice.js @@ -30,6 +30,8 @@ GnubbyDevice.CMD_INIT = 0x86; GnubbyDevice.CMD_PROMPT = 0x87; /** Send device identification wink */ GnubbyDevice.CMD_WINK = 0x88; +/** BLE UID read/set */ +GnubbyDevice.CMD_BLE_UID = 0xb5; /** USB test */ GnubbyDevice.CMD_USB_TEST = 0xb9; /** Device Firmware Upgrade */ @@ -85,6 +87,13 @@ GnubbyDevice.NOPERMISSION = 666; GnubbyDevice.prototype.destroy = function() {}; /** + * Sets a callback that will get called when this device instance is destroyed. + * @param {function() : ?Promise} cb Called back when closed. Callback may + * yield a promise that resolves when the close hook completes. + */ +GnubbyDevice.prototype.setDestroyHook = function(cb) {}; + +/** * Register a client for this gnubby. * @param {*} who The client. */ diff --git a/chromium/chrome/browser/resources/cryptotoken/hidgnubbydevice.js b/chromium/chrome/browser/resources/cryptotoken/hidgnubbydevice.js index 80c40c00b16..ecd83df1637 100644 --- a/chromium/chrome/browser/resources/cryptotoken/hidgnubbydevice.js +++ b/chromium/chrome/browser/resources/cryptotoken/hidgnubbydevice.js @@ -40,6 +40,18 @@ HidGnubbyDevice.NAMESPACE = 'hid'; HidGnubbyDevice.prototype.destroy = function() { if (!this.dev) return; // Already dead. + function closeLowLevelDevice(dev) { + chrome.hid.disconnect(dev.connectionId, function() { + if (chrome.runtime.lastError) { + console.warn(UTIL_fmt('Device ' + dev.connectionId + + ' couldn\'t be disconnected:')); + console.warn(UTIL_fmt(chrome.runtime.lastError.message)); + return; + } + console.log(UTIL_fmt('Device ' + dev.connectionId + ' closed')); + }); + } + this.gnubbies_.removeOpenDevice( {namespace: HidGnubbyDevice.NAMESPACE, device: this.id}); this.closing = true; @@ -69,16 +81,29 @@ HidGnubbyDevice.prototype.destroy = function() { var dev = this.dev; this.dev = null; + var reallyCloseDevice = closeLowLevelDevice.bind(null, dev); - chrome.hid.disconnect(dev.connectionId, function() { - if (chrome.runtime.lastError) { - console.warn(UTIL_fmt('Device ' + dev.connectionId + - ' couldn\'t be disconnected:')); - console.warn(UTIL_fmt(chrome.runtime.lastError.message)); + if (this.destroyHook_) { + var p = this.destroyHook_(); + if (!p) { + reallyCloseDevice(); return; } - console.log(UTIL_fmt('Device ' + dev.connectionId + ' closed')); - }); + // When this method returns, a device reference may still be held, until the + // promise completes. + p.then(reallyCloseDevice); + } else { + reallyCloseDevice(); + } +}; + +/** + * Sets a callback that will get called when this device instance is destroyed. + * @param {function() : ?Promise} cb Called back when closed. Callback may + * yield a promise that resolves when the close hook completes. + */ +HidGnubbyDevice.prototype.setDestroyHook = function(cb) { + this.destroyHook_ = cb; }; /** @@ -411,7 +436,7 @@ HidGnubbyDevice.prototype.writePump_ = function() { * @const */ HidGnubbyDevice.HID_VID_PIDS = [ - {'vendorId': 4176, 'productId': 512} // Google-specific Yubico HID + {'vendorId': 4176, 'productId': 512} // Google-specific Yubico HID ]; /** @@ -427,20 +452,20 @@ HidGnubbyDevice.enumerate = function(cb, opt_type) { var numEnumerated = 0; var allDevs = []; - function enumerated(f1d0Enumerated, devs) { + function enumerated(filter, devs) { // Don't double-add a device; it'll just confuse things. // We assume the various calls to getDevices() return from the same // deviceId pool. for (var i = 0; i < devs.length; i++) { var dev = devs[i]; - dev.f1d0Only = f1d0Enumerated; + dev.enumeratedBy = filter; // Unfortunately indexOf is not usable, since the two calls produce // different objects. Compare their deviceIds instead. var found = false; for (var j = 0; j < allDevs.length; j++) { if (allDevs[j].deviceId == dev.deviceId) { found = true; - allDevs[j].f1d0Only &= f1d0Enumerated; + allDevs[j].enumeratedBy = filter; break; } } @@ -456,11 +481,12 @@ HidGnubbyDevice.enumerate = function(cb, opt_type) { // Pass 1: usagePage-based enumeration, for FIDO U2F devices. If non-FIDO // devices are asked for, "implement" this pass by providing it the empty // list. (enumerated requires that it's called once per pass.) + var f1d0Filter = {usagePage: 0xf1d0}; if (opt_type == GnubbyEnumerationTypes.VID_PID) { - enumerated(true, []); + enumerated(f1d0Filter, []); } else { - chrome.hid.getDevices({filters: [{usagePage: 0xf1d0}]}, - enumerated.bind(null, true)); + chrome.hid.getDevices({filters: [f1d0Filter]}, + enumerated.bind(null, f1d0Filter)); } // Pass 2: vid/pid-based enumeration, for legacy devices. If FIDO devices // are asked for, "implement" this pass by providing it the empty list. @@ -468,8 +494,8 @@ HidGnubbyDevice.enumerate = function(cb, opt_type) { enumerated(false, []); } else { for (var i = 0; i < HidGnubbyDevice.HID_VID_PIDS.length; i++) { - var dev = HidGnubbyDevice.HID_VID_PIDS[i]; - chrome.hid.getDevices({filters: [dev]}, enumerated.bind(null, false)); + var vidPid = HidGnubbyDevice.HID_VID_PIDS[i]; + chrome.hid.getDevices({filters: [vidPid]}, enumerated.bind(null, vidPid)); } } }; @@ -507,6 +533,7 @@ HidGnubbyDevice.deviceToDeviceId = function(dev) { var hidDev = /** @type {!chrome.hid.HidDeviceInfo} */ (dev); var deviceId = { namespace: HidGnubbyDevice.NAMESPACE, + enumeratedBy: hidDev.enumeratedBy, device: hidDev.deviceId }; return deviceId; diff --git a/chromium/chrome/browser/resources/cryptotoken/manifest.json b/chromium/chrome/browser/resources/cryptotoken/manifest.json index 6e4c46df243..b0dbce64b39 100644 --- a/chromium/chrome/browser/resources/cryptotoken/manifest.json +++ b/chromium/chrome/browser/resources/cryptotoken/manifest.json @@ -1,7 +1,7 @@ { "name": "CryptoTokenExtension", "description": "CryptoToken Component Extension", - "version": "0.9.38", + "version": "0.9.46", "key": "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq7zRobvA+AVlvNqkHSSVhh1sEWsHSqz4oR/XptkDe/Cz3+gW9ZGumZ20NCHjaac8j1iiesdigp8B1LJsd/2WWv2Dbnto4f8GrQ5MVphKyQ9WJHwejEHN2K4vzrTcwaXqv5BSTXwxlxS/mXCmXskTfryKTLuYrcHEWK8fCHb+0gvr8b/kvsi75A1aMmb6nUnFJvETmCkOCPNX5CHTdy634Ts/x0fLhRuPlahk63rdf7agxQv5viVjQFk+tbgv6aa9kdSd11Js/RZ9yZjrFgHOBWgP4jTBqud4+HUglrzu8qynFipyNRLCZsaxhm+NItTyNgesxLdxZcwOz56KD1Q4IQIDAQAB", "manifest_version": 2, "permissions": [ diff --git a/chromium/chrome/browser/resources/cryptotoken/signer.js b/chromium/chrome/browser/resources/cryptotoken/signer.js index 3605454208f..6a0fe53c09b 100644 --- a/chromium/chrome/browser/resources/cryptotoken/signer.js +++ b/chromium/chrome/browser/resources/cryptotoken/signer.js @@ -47,7 +47,7 @@ function handleU2fSignRequest(messageSender, request, sendResponse) { sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST}); return null; } - if (sender.origin.startsWith('http://') && !HTTP_ORIGINS_ALLOWED) { + if (sender.origin.indexOf('http://') == 0 && !HTTP_ORIGINS_ALLOWED) { sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST}); return null; } @@ -319,7 +319,7 @@ function Signer(timer, sender, errorCb, successCb, opt_logMsgUrl) { // what they get.) /** @private {boolean} */ this.allowHttp_ = this.sender_.origin ? - this.sender_.origin.startsWith('http://') : false; + this.sender_.origin.indexOf('http://') == 0 : false; /** @private {Closeable} */ this.handler_ = null; } diff --git a/chromium/chrome/browser/resources/cryptotoken/singlesigner.js b/chromium/chrome/browser/resources/cryptotoken/singlesigner.js index b76cc991fc2..9d535058620 100644 --- a/chromium/chrome/browser/resources/cryptotoken/singlesigner.js +++ b/chromium/chrome/browser/resources/cryptotoken/singlesigner.js @@ -463,12 +463,13 @@ SingleGnubbySigner.prototype.goToError_ = function(code, opt_warn) { var logFn = opt_warn ? console.warn.bind(console) : console.log.bind(console); logFn(UTIL_fmt('failed (' + code.toString(16) + ')')); var result = { code: code }; - if (!this.forEnroll_ && code == DeviceStatusCodes.WRONG_DATA_STATUS) { - // When a device yields WRONG_DATA to all sign challenges, and this is a - // sign request, we don't want to yield to the web page that it's not - // enrolled just yet: we want the user to tap the device first. We'll - // report the gnubby to the caller and let it close it instead of closing - // it here. + if (!this.forEnroll_ && + SingleGnubbySigner.signErrorIndicatesInvalidKeyHandle(code)) { + // When a device yields an idempotent bad key handle error to all sign + // challenges, and this is a sign request, we don't want to yield to the + // web page that it's not enrolled just yet: we want the user to tap the + // device first. We'll report the gnubby to the caller and let it close it + // instead of closing it here. result.gnubby = this.gnubby_; } else { // Since this gnubby can no longer produce a useful result, go ahead and diff --git a/chromium/chrome/browser/resources/cryptotoken/usbgnubbydevice.js b/chromium/chrome/browser/resources/cryptotoken/usbgnubbydevice.js index e37f9b31e10..595d3736033 100644 --- a/chromium/chrome/browser/resources/cryptotoken/usbgnubbydevice.js +++ b/chromium/chrome/browser/resources/cryptotoken/usbgnubbydevice.js @@ -44,6 +44,27 @@ UsbGnubbyDevice.NAMESPACE = 'usb'; /** Destroys this low-level device instance. */ UsbGnubbyDevice.prototype.destroy = function() { + function closeLowLevelDevice(dev) { + chrome.usb.releaseInterface(dev, 0, function() { + if (chrome.runtime.lastError) { + console.warn(UTIL_fmt('Device ' + dev.handle + + ' couldn\'t be released:')); + console.warn(UTIL_fmt(chrome.runtime.lastError.message)); + return; + } + console.log(UTIL_fmt('Device ' + dev.handle + ' released')); + chrome.usb.closeDevice(dev, function() { + if (chrome.runtime.lastError) { + console.warn(UTIL_fmt('Device ' + dev.handle + + ' couldn\'t be closed:')); + console.warn(UTIL_fmt(chrome.runtime.lastError.message)); + return; + } + console.log(UTIL_fmt('Device ' + dev.handle + ' closed')); + }); + }); + } + if (!this.dev) return; // Already dead. this.gnubbies_.removeOpenDevice( @@ -75,25 +96,27 @@ UsbGnubbyDevice.prototype.destroy = function() { var dev = this.dev; this.dev = null; + var reallyCloseDevice = closeLowLevelDevice.bind(null, dev); - chrome.usb.releaseInterface(dev, 0, function() { - if (chrome.runtime.lastError) { - console.warn(UTIL_fmt('Device ' + dev.handle + - ' couldn\'t be released:')); - console.warn(UTIL_fmt(chrome.runtime.lastError.message)); + if (this.destroyHook_) { + var p = this.destroyHook_(); + if (!p) { + reallyCloseDevice(); return; } - console.log(UTIL_fmt('Device ' + dev.handle + ' released')); - chrome.usb.closeDevice(dev, function() { - if (chrome.runtime.lastError) { - console.warn(UTIL_fmt('Device ' + dev.handle + - ' couldn\'t be closed:')); - console.warn(UTIL_fmt(chrome.runtime.lastError.message)); - return; - } - console.log(UTIL_fmt('Device ' + dev.handle + ' closed')); - }); - }); + p.then(reallyCloseDevice); + } else { + reallyCloseDevice(); + } +}; + +/** + * Sets a callback that will get called when this device instance is destroyed. + * @param {function() : ?Promise} cb Called back when closed. Callback may + * yield a promise that resolves when the close hook completes. + */ +UsbGnubbyDevice.prototype.setDestroyHook = function(cb) { + this.destroyHook_ = cb; }; /** @@ -391,7 +414,7 @@ UsbGnubbyDevice.prototype.queueCommand = function(cid, cmd, data) { * @const */ UsbGnubbyDevice.WINUSB_VID_PIDS = [ - {'vendorId': 4176, 'productId': 529} // Yubico WinUSB + {'vendorId': 4176, 'productId': 529} // Yubico WinUSB ]; /** @@ -409,15 +432,21 @@ UsbGnubbyDevice.enumerate = function(cb, opt_type) { var numEnumerated = 0; var allDevs = []; - function enumerated(devs) { - allDevs = allDevs.concat(devs); + function enumerated(vidPid, devs) { + if (devs) { + for (var i = 0; i < devs.length; i++) { + devs[i].enumeratedBy = vidPid; + } + allDevs = allDevs.concat(devs); + } if (++numEnumerated == UsbGnubbyDevice.WINUSB_VID_PIDS.length) { cb(allDevs); } } for (var i = 0; i < UsbGnubbyDevice.WINUSB_VID_PIDS.length; i++) { - chrome.usb.getDevices(UsbGnubbyDevice.WINUSB_VID_PIDS[i], enumerated); + var vidPid = UsbGnubbyDevice.WINUSB_VID_PIDS[i]; + chrome.usb.getDevices(vidPid, enumerated.bind(null, vidPid)); } }; @@ -505,6 +534,10 @@ UsbGnubbyDevice.open = function(gnubbies, which, dev, cb) { cb(-GnubbyDevice.BUSY); return; } + // Restore the enumeratedBy value, if we had it. + if (enumeratedBy) { + dev.enumeratedBy = enumeratedBy; + } var gnubby = new UsbGnubbyDevice(gnubbies, nonNullHandle, which, inEndpoint, outEndpoint); cb(-GnubbyDevice.OK, gnubby); @@ -512,10 +545,15 @@ UsbGnubbyDevice.open = function(gnubbies, which, dev, cb) { }); } + var enumeratedBy = dev.enumeratedBy; + if (UsbGnubbyDevice.runningOnCrOS === undefined) { UsbGnubbyDevice.runningOnCrOS = (window.navigator.appVersion.indexOf('; CrOS ') != -1); } + // dev contains an enumeratedBy value, which we need to strip prior to + // calling Chrome APIs with it. + delete dev.enumeratedBy; if (UsbGnubbyDevice.runningOnCrOS) { chrome.usb.requestAccess(dev, 0, function(success) { // Even though the argument to requestAccess is a chrome.usb.Device, the @@ -539,6 +577,7 @@ UsbGnubbyDevice.deviceToDeviceId = function(dev) { var usbDev = /** @type {!chrome.usb.Device} */ (dev); var deviceId = { namespace: UsbGnubbyDevice.NAMESPACE, + enumeratedBy: dev.enumeratedBy, device: usbDev.device }; return deviceId; diff --git a/chromium/chrome/browser/resources/cryptotoken/usbsignhandler.js b/chromium/chrome/browser/resources/cryptotoken/usbsignhandler.js index d06b529708e..57d23583043 100644 --- a/chromium/chrome/browser/resources/cryptotoken/usbsignhandler.js +++ b/chromium/chrome/browser/resources/cryptotoken/usbsignhandler.js @@ -96,7 +96,8 @@ UsbSignHandler.prototype.signerFoundGnubby_ = var challenge = signResult['challenge']; var info = new Uint8Array(signResult['info']); this.notifySuccess_(gnubby, challenge, info); - } else if (signResult.code == DeviceStatusCodes.WRONG_DATA_STATUS) { + } else if (SingleGnubbySigner.signErrorIndicatesInvalidKeyHandle( + signResult.code)) { var gnubby = signResult['gnubby']; this.notEnrolledGnubbies_.push(gnubby); this.sendBogusEnroll_(gnubby); diff --git a/chromium/chrome/browser/resources/cryptotoken/webrequestsender.js b/chromium/chrome/browser/resources/cryptotoken/webrequestsender.js index 0b5817cf2bc..329a6ab4074 100644 --- a/chromium/chrome/browser/resources/cryptotoken/webrequestsender.js +++ b/chromium/chrome/browser/resources/cryptotoken/webrequestsender.js @@ -88,7 +88,7 @@ function getTabIdWhenPossible(sender) { resolve(true); }, function() { // Didn't match? Check if the debugger is open. - if (!tab.url.startsWith('chrome-devtools://')) { + if (tab.url.indexOf('chrome-devtools://') != 0) { reject(false); return; } diff --git a/chromium/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js b/chromium/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js index d6ab087e5e3..1c3aaa504b0 100644 --- a/chromium/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js +++ b/chromium/chrome/browser/resources/gaia_auth_host/gaia_auth_host.js @@ -8,7 +8,7 @@ * authentication flow. There are two events would be raised after this point: * a 'ready' event when the authentication UI is ready to use and a 'completed' * event when the authentication is completed successfully. If caller is - * interested in the user credentials, he may supply a success callback with + * interested in the user credentials, they may supply a success callback with * {@code load} call. The callback will be invoked when the authentication is * completed successfully and with the available credential data. */ @@ -143,9 +143,9 @@ cr.define('cr.login', function() { successCallback_: null, /** - * Invoked when the auth flow needs a user to confirm his/her passwords. - * This could happen when there are more than one passwords scraped during - * SAML flow. The embedder of GaiaAuthHost should show an UI to collect a + * Invoked when the auth flow needs a user to confirm their passwords. This + * could happen when there are more than one passwords scraped during SAML + * flow. The embedder of GaiaAuthHost should show an UI to collect a * password from user then call GaiaAuthHost.verifyConfirmedPassword to * verify. If the password is good, the auth flow continues with success * path. Otherwise, confirmPasswordCallback_ is invoked again. diff --git a/chromium/chrome/browser/resources/hangout_services/manifest.json b/chromium/chrome/browser/resources/hangout_services/manifest.json index 39261430ab8..ee976903196 100644 --- a/chromium/chrome/browser/resources/hangout_services/manifest.json +++ b/chromium/chrome/browser/resources/hangout_services/manifest.json @@ -5,7 +5,7 @@ "name": "Google Hangouts", // Note: Always update the version number when this file is updated. Chrome // triggers extension preferences update on the version increase. - "version": "1.3.1", + "version": "1.3.2", "manifest_version": 2, "externally_connectable": { "matches": [ diff --git a/chromium/chrome/browser/resources/hangout_services/thunk.js b/chromium/chrome/browser/resources/hangout_services/thunk.js index 309e246586b..68c28bf7dc5 100644 --- a/chromium/chrome/browser/resources/hangout_services/thunk.js +++ b/chromium/chrome/browser/resources/hangout_services/thunk.js @@ -33,7 +33,16 @@ chrome.runtime.onMessageExternal.addListener( try { var requestInfo = {}; - if (sender.tab) { + + // Set the tab ID. If it's passed in the message, use that. + // Otherwise use the sender information. + if (message['tabId']) { + requestInfo['tabId'] = +message['tabId']; + if (isNaN(requestInfo['tabId'])) { + throw new Error('Cannot convert tab ID string to integer: ' + + message['tabId']); + } + } else if (sender.tab) { requestInfo['tabId'] = sender.tab.id; } @@ -42,7 +51,16 @@ chrome.runtime.onMessageExternal.addListener( } var method = message['method']; - var origin = getHost(sender.url); + + // Set the origin. If a URL is passed in the message, use that. + // Otherwise use the sender information. + var origin; + if (message['winUrl']) { + origin = getHost(message['winUrl']); + } else { + origin = getHost(sender.url); + } + if (method == 'cpu.getInfo') { chrome.system.cpu.getInfo(doSendResponse); return true; diff --git a/chromium/chrome/browser/resources/history/other_devices.js b/chromium/chrome/browser/resources/history/other_devices.js index 62d817f6a88..2ba6f76f246 100644 --- a/chromium/chrome/browser/resources/history/other_devices.js +++ b/chromium/chrome/browser/resources/history/other_devices.js @@ -585,8 +585,6 @@ function load() { $('search-field').addEventListener('search', doSearch); $('search-button').addEventListener('click', doSearch); - cr.addWebUIListener('sign-in-state-updated', updateSignInState); - chrome.send('otherDevicesInitialized'); } diff --git a/chromium/chrome/browser/resources/inline_login/inline_login.js b/chromium/chrome/browser/resources/inline_login/inline_login.js index 7e67cbc0728..17f1c433863 100644 --- a/chromium/chrome/browser/resources/inline_login/inline_login.js +++ b/chromium/chrome/browser/resources/inline_login/inline_login.js @@ -20,6 +20,11 @@ cr.define('inline.login', function() { */ var authReadyFired; + /** + * Whether the login UI is loaded for signing in primary account. + */ + var isLoginPrimaryAccount; + function onResize(e) { chrome.send('switchToFullTab', [e.detail]); } @@ -27,7 +32,8 @@ cr.define('inline.login', function() { function onAuthReady(e) { $('contents').classList.toggle('loading', false); authReadyFired = true; - chrome.send('metricsHandler:recordAction', ['Signin_SigninPage_Shown']); + if (isLoginPrimaryAccount) + chrome.send('metricsHandler:recordAction', ['Signin_SigninPage_Shown']); } function onDropLink(e) { @@ -74,6 +80,7 @@ cr.define('inline.login', function() { $('contents').classList.toggle('loading', data.authMode != cr.login.GaiaAuthHost.AuthMode.DESKTOP || data.constrained == '1'); + isLoginPrimaryAccount = data.isLoginPrimaryAccount; } /** diff --git a/chromium/chrome/browser/resources/inspect/OWNERS b/chromium/chrome/browser/resources/inspect/OWNERS index 2abc7be24fc..fe38b0fad49 100644 --- a/chromium/chrome/browser/resources/inspect/OWNERS +++ b/chromium/chrome/browser/resources/inspect/OWNERS @@ -1 +1,2 @@ +dgozman@chromium.org pfeldman@chromium.org diff --git a/chromium/chrome/browser/resources/inspect/inspect.css b/chromium/chrome/browser/resources/inspect/inspect.css index 8bef844390f..f8075c27d6f 100644 --- a/chromium/chrome/browser/resources/inspect/inspect.css +++ b/chromium/chrome/browser/resources/inspect/inspect.css @@ -430,11 +430,11 @@ dialog.target-discovery .port-forwarding { } @media (min-width: 47em) { #container { - height: 100vh; + max-height: 100vh; } #navigation, #content { - height: 100vh; + max-height: 100vh; overflow: auto; } } diff --git a/chromium/chrome/browser/resources/local_ntp/most_visited_single.js b/chromium/chrome/browser/resources/local_ntp/most_visited_single.js index 535c3fe624a..f08b0cec42c 100644 --- a/chromium/chrome/browser/resources/local_ntp/most_visited_single.js +++ b/chromium/chrome/browser/resources/local_ntp/most_visited_single.js @@ -16,13 +16,6 @@ * @const */ var LOG_TYPE = { - // The suggestion is coming from the server. - NTP_SERVER_SIDE_SUGGESTION: 0, - // The suggestion is coming from the client. - NTP_CLIENT_SIDE_SUGGESTION: 1, - // Indicates a tile was rendered, no matter if it's a thumbnail, a gray tile - // or an external tile. - NTP_TILE: 2, // All NTP Tiles have finished loading (successfully or failing). NTP_ALL_TILES_LOADED: 11, }; @@ -313,7 +306,6 @@ var addTile = function(args) { data.faviconUrl = 'chrome-search://favicon/size/16@' + window.devicePixelRatio + 'x/' + data.renderViewId + '/' + data.tid; } - logEvent(LOG_TYPE.NTP_CLIENT_SIDE_SUGGESTION); tiles.appendChild(renderTile(data)); } else if (args.url) { // If a URL is passed: a server-side suggestion. @@ -322,7 +314,6 @@ var addTile = function(args) { if (/^javascript:/i.test(args.url) || /^javascript:/i.test(args.thumbnailUrl)) return; - logEvent(LOG_TYPE.NTP_SERVER_SIDE_SUGGESTION); tiles.appendChild(renderTile(args)); } else { // an empty tile tiles.appendChild(renderTile(null)); @@ -371,7 +362,6 @@ var renderTile = function(data) { return tile; } - logEvent(LOG_TYPE.NTP_TILE); // The tile will be appended to tiles. var position = tiles.children.length; logMostVisitedImpression(position, data.tileSource); diff --git a/chromium/chrome/browser/resources/local_ntp/most_visited_thumbnail.js b/chromium/chrome/browser/resources/local_ntp/most_visited_thumbnail.js index 4c83e8a2694..5742d6578dd 100644 --- a/chromium/chrome/browser/resources/local_ntp/most_visited_thumbnail.js +++ b/chromium/chrome/browser/resources/local_ntp/most_visited_thumbnail.js @@ -11,21 +11,13 @@ window.addEventListener('DOMContentLoaded', function() { 'use strict'; fillMostVisited(document.location, function(params, data) { - function logEvent(eventName) { - chrome.embeddedSearch.newTabPage.logEvent(eventName); - } - function logMostVisitedImpression(tileIndex, tileSource) { - chrome.embeddedSearch.newTabPage.logMostVisitedImpression(tileIndex, - tileSource); - } function displayLink(link) { document.body.appendChild(link); window.parent.postMessage('linkDisplayed', '{{ORIGIN}}'); } function showDomainElement() { var link = createMostVisitedLink( - params, data.url, data.title, undefined, data.direction, - data.tileSource); + params, data.url, data.title, undefined, data.direction); var domain = document.createElement('div'); domain.textContent = data.domain; link.appendChild(domain); @@ -35,8 +27,7 @@ window.addEventListener('DOMContentLoaded', function() { // externally by the page itself. function showEmptyTile() { displayLink(createMostVisitedLink( - params, data.url, data.title, undefined, data.direction, - data.tileSource)); + params, data.url, data.title, undefined, data.direction)); } // Creates and adds an image. function createThumbnail(src, imageClass) { @@ -46,15 +37,13 @@ window.addEventListener('DOMContentLoaded', function() { } image.onload = function() { var link = createMostVisitedLink( - params, data.url, data.title, undefined, data.direction, - data.tileSource); + params, data.url, data.title, undefined, data.direction); // Use blocker to prevent context menu from showing image-related items. var blocker = document.createElement('span'); blocker.className = 'blocker'; link.appendChild(blocker); link.appendChild(image); displayLink(link); - logEvent(NTP_LOGGING_EVENT_TYPE.NTP_TILE_LOADED); }; image.onerror = function() { // If no external thumbnail fallback (etfb), and have domain. @@ -63,7 +52,6 @@ window.addEventListener('DOMContentLoaded', function() { } else { showEmptyTile(); } - logEvent(NTP_LOGGING_EVENT_TYPE.NTP_TILE_LOADED); }; image.src = src; } @@ -73,7 +61,6 @@ window.addEventListener('DOMContentLoaded', function() { showEmptyTile(); } else if (useIcons && data.largeIconUrl) { createThumbnail(data.largeIconUrl, 'large-icon'); - // TODO(huangs): Log event for large icons. } else if (!useIcons && data.thumbnailUrls && data.thumbnailUrls.length) { createThumbnail(data.thumbnailUrls[0], 'thumbnail'); } else if (data.domain) { @@ -81,11 +68,5 @@ window.addEventListener('DOMContentLoaded', function() { } else { showEmptyTile(); } - logEvent(NTP_LOGGING_EVENT_TYPE.NTP_TILE); - - // Log an impression if we know the position of the tile. - if (isFinite(params.pos)) { - logMostVisitedImpression(parseInt(params.pos, 10), data.tileSource); - } }); }); diff --git a/chromium/chrome/browser/resources/local_ntp/most_visited_title.js b/chromium/chrome/browser/resources/local_ntp/most_visited_title.js index 87f302c9bf4..7729c1cd04e 100644 --- a/chromium/chrome/browser/resources/local_ntp/most_visited_title.js +++ b/chromium/chrome/browser/resources/local_ntp/most_visited_title.js @@ -13,12 +13,6 @@ window.addEventListener('DOMContentLoaded', function() { fillMostVisited(window.location, function(params, data) { document.body.appendChild( createMostVisitedLink( - params, data.url, data.title, data.title, data.direction, - data.tileSource)); + params, data.url, data.title, data.title, data.direction)); }); }); - -window.addEventListener('load', function() { - chrome.embeddedSearch.newTabPage.logEvent( - NTP_LOGGING_EVENT_TYPE.NTP_TILE_LOADED); -}); diff --git a/chromium/chrome/browser/resources/local_ntp/most_visited_util.js b/chromium/chrome/browser/resources/local_ntp/most_visited_util.js index ded836eb780..ef0099cab5b 100644 --- a/chromium/chrome/browser/resources/local_ntp/most_visited_util.js +++ b/chromium/chrome/browser/resources/local_ntp/most_visited_util.js @@ -10,41 +10,6 @@ <include src="instant_iframe_validation.js"> -// TODO(treib): A number of things from this file (e.g. the "enums" below) are -// duplicated in most_visited_single.js. Pull those out into a shared file. - - -/** - * The different types of events that are logged from the NTP. This enum is - * used to transfer information from the NTP javascript to the renderer and is - * not used as a UMA enum histogram's logged value. - * Note: Keep in sync with common/ntp_logging_events.h - * @enum {number} - * @const - */ -var NTP_LOGGING_EVENT_TYPE = { - // The suggestion is coming from the server. - NTP_SERVER_SIDE_SUGGESTION: 0, - // The suggestion is coming from the client. - NTP_CLIENT_SIDE_SUGGESTION: 1, - // Indicates a tile was rendered, no matter if it's a thumbnail, a gray tile - // or an external tile. - NTP_TILE: 2, - // A NTP Tile has finished loading (successfully or failing). - NTP_TILE_LOADED: 10, -}; - -/** - * The different sources that an NTP tile can have. - * Note: Keep in sync with common/ntp_logging_events.h - * @enum {number} - * @const - */ -var NTPLoggingTileSource = { - CLIENT: 0, - SERVER: 1, -}; - /** * The origin of this request. * @const {string} @@ -83,11 +48,9 @@ function parseQueryParams(location) { * @param {string} title The title for the link. * @param {string|undefined} text The text for the link or none. * @param {string|undefined} direction The text direction. - * @param {number} tileSource The source from NTPLoggingTileSource. * @return {HTMLAnchorElement} A new link element. */ -function createMostVisitedLink( - params, href, title, text, direction, tileSource) { +function createMostVisitedLink(params, href, title, text, direction) { var styles = getMostVisitedStyles(params, !!text); var link = document.createElement('a'); link.style.color = styles.color; @@ -135,12 +98,6 @@ function createMostVisitedLink( generatePing(DOMAIN_ORIGIN + params.ping); } - var ntpApiHandle = chrome.embeddedSearch.newTabPage; - if ('pos' in params && isFinite(params.pos)) { - ntpApiHandle.logMostVisitedNavigation(parseInt(params.pos, 10), - tileSource); - } - // Follow <a> normally, so transition type will be LINK. }; @@ -243,10 +200,6 @@ function fillMostVisited(location, fill) { params.rid = parseInt(params.rid, 10); if (!isFinite(params.rid) && !params.url) return; - // Log whether the suggestion was obtained from the server or the client. - chrome.embeddedSearch.newTabPage.logEvent(params.url ? - NTP_LOGGING_EVENT_TYPE.NTP_SERVER_SIDE_SUGGESTION : - NTP_LOGGING_EVENT_TYPE.NTP_CLIENT_SIDE_SUGGESTION); var data; if (params.url) { // Means that the suggestion data comes from the server. Create data object. @@ -256,15 +209,13 @@ function fillMostVisited(location, fill) { thumbnailUrl: params.tu || '', title: params.ti || '', direction: params.di || '', - domain: params.dom || '', - tileSource: NTPLoggingTileSource.SERVER + domain: params.dom || '' }; } else { var apiHandle = chrome.embeddedSearch.searchBox; data = apiHandle.getMostVisitedItemData(params.rid); if (!data) return; - data.tileSource = NTPLoggingTileSource.CLIENT; } if (isFinite(params.dummy) && parseInt(params.dummy, 10)) { diff --git a/chromium/chrome/browser/resources/md_bookmarks/OWNERS b/chromium/chrome/browser/resources/md_bookmarks/OWNERS new file mode 100644 index 00000000000..793f7b9dc7a --- /dev/null +++ b/chromium/chrome/browser/resources/md_bookmarks/OWNERS @@ -0,0 +1,3 @@ +calamity@chromium.org +dbeam@chromium.org +tsergeant@chromium.org diff --git a/chromium/chrome/browser/resources/md_bookmarks/bookmarks.html b/chromium/chrome/browser/resources/md_bookmarks/bookmarks.html new file mode 100644 index 00000000000..0176d893e17 --- /dev/null +++ b/chromium/chrome/browser/resources/md_bookmarks/bookmarks.html @@ -0,0 +1,13 @@ +<!doctype html> +<html dir="$i18n{textdirection}" lang="$i18n{language}"> +<head> + <meta charset="utf8"> + <title>$i18n{title}</title> + + <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css"> + <link rel="stylesheet" href="chrome://resources/css/md_colors.css"> +</head> +<body> +</body> + +</html> diff --git a/chromium/chrome/browser/resources/md_downloads/compiled_resources2.gyp b/chromium/chrome/browser/resources/md_downloads/compiled_resources2.gyp index 7482bce2c9e..be6ef517193 100644 --- a/chromium/chrome/browser/resources/md_downloads/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/md_downloads/compiled_resources2.gyp @@ -34,6 +34,7 @@ 'dependencies': [ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util', '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-behaviors/compiled_resources2.gyp:paper-inky-focus-behavior-extracted', 'constants', 'action_service', diff --git a/chromium/chrome/browser/resources/md_downloads/crisper.js b/chromium/chrome/browser/resources/md_downloads/crisper.js index 049d55cf13f..b910f1824ad 100644 --- a/chromium/chrome/browser/resources/md_downloads/crisper.js +++ b/chromium/chrome/browser/resources/md_downloads/crisper.js @@ -25,9 +25,9 @@ function $(id){var el=document.getElementById(id);return el?assertInstanceof(el, // <if expr="is_ios"> if(!("key"in KeyboardEvent.prototype)){Object.defineProperty(KeyboardEvent.prototype,"key",{get:function(){if(this.keyCode>=48&&this.keyCode<=57)return String.fromCharCode(this.keyCode);if(this.keyCode>=65&&this.keyCode<=90){var result=String.fromCharCode(this.keyCode).toLowerCase();if(this.shiftKey)result=result.toUpperCase();return result}switch(this.keyCode){case 8:return"Backspace";case 9:return"Tab";case 13:return"Enter";case 16:return"Shift";case 17:return"Control";case 18:return"Alt";case 27:return"Escape";case 32:return" ";case 33:return"PageUp";case 34:return"PageDown";case 35:return"End";case 36:return"Home";case 37:return"ArrowLeft";case 38:return"ArrowUp";case 39:return"ArrowRight";case 40:return"ArrowDown";case 45:return"Insert";case 46:return"Delete";case 91:return"Meta";case 112:return"F1";case 113:return"F2";case 114:return"F3";case 115:return"F4";case 116:return"F5";case 117:return"F6";case 118:return"F7";case 119:return"F8";case 120:return"F9";case 121:return"F10";case 122:return"F11";case 123:return"F12";case 187:return"=";case 189:return"-";case 219:return"[";case 221:return"]"}return"Unidentified"}})}else{window.console.log("KeyboardEvent.Key polyfill not required")} // </if> /* is_ios */ -Polymer.IronResizableBehavior={properties:{_parentResizable:{type:Object,observer:"_parentResizableChanged"},_notifyingDescendant:{type:Boolean,value:false}},listeners:{"iron-request-resize-notifications":"_onIronRequestResizeNotifications"},created:function(){this._interestedResizables=[];this._boundNotifyResize=this.notifyResize.bind(this)},attached:function(){this.fire("iron-request-resize-notifications",null,{node:this,bubbles:true,cancelable:true});if(!this._parentResizable){window.addEventListener("resize",this._boundNotifyResize);this.notifyResize()}},detached:function(){if(this._parentResizable){this._parentResizable.stopResizeNotificationsFor(this)}else{window.removeEventListener("resize",this._boundNotifyResize)}this._parentResizable=null},notifyResize:function(){if(!this.isAttached){return}this._interestedResizables.forEach(function(resizable){if(this.resizerShouldNotify(resizable)){this._notifyDescendant(resizable)}},this);this._fireResize()},assignParentResizable:function(parentResizable){this._parentResizable=parentResizable},stopResizeNotificationsFor:function(target){var index=this._interestedResizables.indexOf(target);if(index>-1){this._interestedResizables.splice(index,1);this.unlisten(target,"iron-resize","_onDescendantIronResize")}},resizerShouldNotify:function(element){return true},_onDescendantIronResize:function(event){if(this._notifyingDescendant){event.stopPropagation();return}if(!Polymer.Settings.useShadow){this._fireResize()}},_fireResize:function(){this.fire("iron-resize",null,{node:this,bubbles:false})},_onIronRequestResizeNotifications:function(event){var target=event.path?event.path[0]:event.target;if(target===this){return}if(this._interestedResizables.indexOf(target)===-1){this._interestedResizables.push(target);this.listen(target,"iron-resize","_onDescendantIronResize")}target.assignParentResizable(this);this._notifyDescendant(target);event.stopPropagation()},_parentResizableChanged:function(parentResizable){if(parentResizable){window.removeEventListener("resize",this._boundNotifyResize)}},_notifyDescendant:function(descendant){if(!this.isAttached){return}this._notifyingDescendant=true;descendant.notifyResize();this._notifyingDescendant=false}};(function(){"use strict";var KEY_IDENTIFIER={"U+0008":"backspace","U+0009":"tab","U+001B":"esc","U+0020":"space","U+007F":"del"};var KEY_CODE={8:"backspace",9:"tab",13:"enter",27:"esc",33:"pageup",34:"pagedown",35:"end",36:"home",32:"space",37:"left",38:"up",39:"right",40:"down",46:"del",106:"*"};var MODIFIER_KEYS={shift:"shiftKey",ctrl:"ctrlKey",alt:"altKey",meta:"metaKey"};var KEY_CHAR=/[a-z0-9*]/;var IDENT_CHAR=/U\+/;var ARROW_KEY=/^arrow/;var SPACE_KEY=/^space(bar)?/;var ESC_KEY=/^escape$/;function transformKey(key,noSpecialChars){var validKey="";if(key){var lKey=key.toLowerCase();if(lKey===" "||SPACE_KEY.test(lKey)){validKey="space"}else if(ESC_KEY.test(lKey)){validKey="esc"}else if(lKey.length==1){if(!noSpecialChars||KEY_CHAR.test(lKey)){validKey=lKey}}else if(ARROW_KEY.test(lKey)){validKey=lKey.replace("arrow","")}else if(lKey=="multiply"){validKey="*"}else{validKey=lKey}}return validKey}function transformKeyIdentifier(keyIdent){var validKey="";if(keyIdent){if(keyIdent in KEY_IDENTIFIER){validKey=KEY_IDENTIFIER[keyIdent]}else if(IDENT_CHAR.test(keyIdent)){keyIdent=parseInt(keyIdent.replace("U+","0x"),16);validKey=String.fromCharCode(keyIdent).toLowerCase()}else{validKey=keyIdent.toLowerCase()}}return validKey}function transformKeyCode(keyCode){var validKey="";if(Number(keyCode)){if(keyCode>=65&&keyCode<=90){validKey=String.fromCharCode(32+keyCode)}else if(keyCode>=112&&keyCode<=123){validKey="f"+(keyCode-112)}else if(keyCode>=48&&keyCode<=57){validKey=String(keyCode-48)}else if(keyCode>=96&&keyCode<=105){validKey=String(keyCode-96)}else{validKey=KEY_CODE[keyCode]}}return validKey}function normalizedKeyForEvent(keyEvent,noSpecialChars){if(keyEvent.key){return transformKey(keyEvent.key,noSpecialChars)}if(keyEvent.detail&&keyEvent.detail.key){return transformKey(keyEvent.detail.key,noSpecialChars)}return transformKeyIdentifier(keyEvent.keyIdentifier)||transformKeyCode(keyEvent.keyCode)||""}function keyComboMatchesEvent(keyCombo,event){var keyEvent=normalizedKeyForEvent(event,keyCombo.hasModifiers);return keyEvent===keyCombo.key&&(!keyCombo.hasModifiers||!!event.shiftKey===!!keyCombo.shiftKey&&!!event.ctrlKey===!!keyCombo.ctrlKey&&!!event.altKey===!!keyCombo.altKey&&!!event.metaKey===!!keyCombo.metaKey)}function parseKeyComboString(keyComboString){if(keyComboString.length===1){return{combo:keyComboString,key:keyComboString,event:"keydown"}}return keyComboString.split("+").reduce(function(parsedKeyCombo,keyComboPart){var eventParts=keyComboPart.split(":");var keyName=eventParts[0];var event=eventParts[1];if(keyName in MODIFIER_KEYS){parsedKeyCombo[MODIFIER_KEYS[keyName]]=true;parsedKeyCombo.hasModifiers=true}else{parsedKeyCombo.key=keyName;parsedKeyCombo.event=event||"keydown"}return parsedKeyCombo},{combo:keyComboString.split(":").shift()})}function parseEventString(eventString){return eventString.trim().split(" ").map(function(keyComboString){return parseKeyComboString(keyComboString)})}Polymer.IronA11yKeysBehavior={properties:{keyEventTarget:{type:Object,value:function(){return this}},stopKeyboardEventPropagation:{type:Boolean,value:false},_boundKeyHandlers:{type:Array,value:function(){return[]}},_imperativeKeyBindings:{type:Object,value:function(){return{}}}},observers:["_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)"],keyBindings:{},registered:function(){this._prepKeyBindings()},attached:function(){this._listenKeyEventListeners()},detached:function(){this._unlistenKeyEventListeners()},addOwnKeyBinding:function(eventString,handlerName){this._imperativeKeyBindings[eventString]=handlerName;this._prepKeyBindings();this._resetKeyEventListeners()},removeOwnKeyBindings:function(){this._imperativeKeyBindings={};this._prepKeyBindings();this._resetKeyEventListeners()},keyboardEventMatchesKeys:function(event,eventString){var keyCombos=parseEventString(eventString);for(var i=0;i<keyCombos.length;++i){if(keyComboMatchesEvent(keyCombos[i],event)){return true}}return false},_collectKeyBindings:function(){var keyBindings=this.behaviors.map(function(behavior){return behavior.keyBindings});if(keyBindings.indexOf(this.keyBindings)===-1){keyBindings.push(this.keyBindings)}return keyBindings},_prepKeyBindings:function(){this._keyBindings={};this._collectKeyBindings().forEach(function(keyBindings){for(var eventString in keyBindings){this._addKeyBinding(eventString,keyBindings[eventString])}},this);for(var eventString in this._imperativeKeyBindings){this._addKeyBinding(eventString,this._imperativeKeyBindings[eventString])}for(var eventName in this._keyBindings){this._keyBindings[eventName].sort(function(kb1,kb2){var b1=kb1[0].hasModifiers;var b2=kb2[0].hasModifiers;return b1===b2?0:b1?-1:1})}},_addKeyBinding:function(eventString,handlerName){parseEventString(eventString).forEach(function(keyCombo){this._keyBindings[keyCombo.event]=this._keyBindings[keyCombo.event]||[];this._keyBindings[keyCombo.event].push([keyCombo,handlerName])},this)},_resetKeyEventListeners:function(){this._unlistenKeyEventListeners();if(this.isAttached){this._listenKeyEventListeners()}},_listenKeyEventListeners:function(){if(!this.keyEventTarget){return}Object.keys(this._keyBindings).forEach(function(eventName){var keyBindings=this._keyBindings[eventName];var boundKeyHandler=this._onKeyBindingEvent.bind(this,keyBindings);this._boundKeyHandlers.push([this.keyEventTarget,eventName,boundKeyHandler]);this.keyEventTarget.addEventListener(eventName,boundKeyHandler)},this)},_unlistenKeyEventListeners:function(){var keyHandlerTuple;var keyEventTarget;var eventName;var boundKeyHandler;while(this._boundKeyHandlers.length){keyHandlerTuple=this._boundKeyHandlers.pop();keyEventTarget=keyHandlerTuple[0];eventName=keyHandlerTuple[1];boundKeyHandler=keyHandlerTuple[2];keyEventTarget.removeEventListener(eventName,boundKeyHandler)}},_onKeyBindingEvent:function(keyBindings,event){if(this.stopKeyboardEventPropagation){event.stopPropagation()}if(event.defaultPrevented){return}for(var i=0;i<keyBindings.length;i++){var keyCombo=keyBindings[i][0];var handlerName=keyBindings[i][1];if(keyComboMatchesEvent(keyCombo,event)){this._triggerKeyHandler(keyCombo,handlerName,event);if(event.defaultPrevented){return}}}},_triggerKeyHandler:function(keyCombo,handlerName,keyboardEvent){var detail=Object.create(keyCombo);detail.keyboardEvent=keyboardEvent;var event=new CustomEvent(keyCombo.event,{detail:detail,cancelable:true});this[handlerName].call(this,event);if(event.defaultPrevented){keyboardEvent.preventDefault()}}}})();Polymer.IronScrollTargetBehavior={properties:{scrollTarget:{type:HTMLElement,value:function(){return this._defaultScrollTarget}}},observers:["_scrollTargetChanged(scrollTarget, isAttached)"],_shouldHaveListener:true,_scrollTargetChanged:function(scrollTarget,isAttached){var eventTarget;if(this._oldScrollTarget){this._toggleScrollListener(false,this._oldScrollTarget);this._oldScrollTarget=null}if(!isAttached){return}if(scrollTarget==="document"){this.scrollTarget=this._doc}else if(typeof scrollTarget==="string"){this.scrollTarget=this.domHost?this.domHost.$[scrollTarget]:Polymer.dom(this.ownerDocument).querySelector("#"+scrollTarget)}else if(this._isValidScrollTarget()){this._boundScrollHandler=this._boundScrollHandler||this._scrollHandler.bind(this);this._oldScrollTarget=scrollTarget;this._toggleScrollListener(this._shouldHaveListener,scrollTarget)}},_scrollHandler:function scrollHandler(){},get _defaultScrollTarget(){return this._doc},get _doc(){return this.ownerDocument.documentElement},get _scrollTop(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.pageYOffset:this.scrollTarget.scrollTop}return 0},get _scrollLeft(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.pageXOffset:this.scrollTarget.scrollLeft}return 0},set _scrollTop(top){if(this.scrollTarget===this._doc){window.scrollTo(window.pageXOffset,top)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollTop=top}},set _scrollLeft(left){if(this.scrollTarget===this._doc){window.scrollTo(left,window.pageYOffset)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollLeft=left}},scroll:function(left,top){if(this.scrollTarget===this._doc){window.scrollTo(left,top)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollLeft=left;this.scrollTarget.scrollTop=top}},get _scrollTargetWidth(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.innerWidth:this.scrollTarget.offsetWidth}return 0},get _scrollTargetHeight(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.innerHeight:this.scrollTarget.offsetHeight}return 0},_isValidScrollTarget:function(){return this.scrollTarget instanceof HTMLElement},_toggleScrollListener:function(yes,scrollTarget){if(!this._boundScrollHandler){return}var eventTarget=scrollTarget===this._doc?window:scrollTarget;if(yes){eventTarget.addEventListener("scroll",this._boundScrollHandler)}else{eventTarget.removeEventListener("scroll",this._boundScrollHandler)}},toggleScrollListener:function(yes){this._shouldHaveListener=yes;this._toggleScrollListener(yes,this.scrollTarget)}};(function(){var IOS=navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);var IOS_TOUCH_SCROLLING=IOS&&IOS[1]>=8;var DEFAULT_PHYSICAL_COUNT=3;var HIDDEN_Y="-10000px";var ITEM_WIDTH=0;var ITEM_HEIGHT=1;var SECRET_TABINDEX=-100;Polymer({is:"iron-list",properties:{items:{type:Array},maxPhysicalCount:{type:Number,value:500},as:{type:String,value:"item"},indexAs:{type:String,value:"index"},selectedAs:{type:String,value:"selected"},grid:{type:Boolean,value:false,reflectToAttribute:true},selectionEnabled:{type:Boolean,value:false},selectedItem:{type:Object,notify:true},selectedItems:{type:Object,notify:true},multiSelection:{type:Boolean,value:false}},observers:["_itemsChanged(items.*)","_selectionEnabledChanged(selectionEnabled)","_multiSelectionChanged(multiSelection)","_setOverflow(scrollTarget)"],behaviors:[Polymer.Templatizer,Polymer.IronResizableBehavior,Polymer.IronA11yKeysBehavior,Polymer.IronScrollTargetBehavior],keyBindings:{up:"_didMoveUp",down:"_didMoveDown",enter:"_didEnter"},_ratio:.5,_scrollerPaddingTop:0,_scrollPosition:0,_physicalSize:0,_physicalAverage:0,_physicalAverageCount:0,_physicalTop:0,_virtualCount:0,_physicalIndexForKey:null,_estScrollHeight:0,_scrollHeight:0,_viewportHeight:0,_viewportWidth:0,_physicalItems:null,_physicalSizes:null,_firstVisibleIndexVal:null,_lastVisibleIndexVal:null,_collection:null,_maxPages:2,_focusedItem:null,_focusedIndex:-1,_offscreenFocusedItem:null,_focusBackfillItem:null,_itemsPerRow:1,_itemWidth:0,_rowHeight:0,_templateCost:0,get _physicalBottom(){return this._physicalTop+this._physicalSize},get _scrollBottom(){return this._scrollPosition+this._viewportHeight},get _virtualEnd(){return this._virtualStart+this._physicalCount-1},get _hiddenContentSize(){var size=this.grid?this._physicalRows*this._rowHeight:this._physicalSize;return size-this._viewportHeight},get _maxScrollTop(){return this._estScrollHeight-this._viewportHeight+this._scrollerPaddingTop},_minVirtualStart:0,get _maxVirtualStart(){return Math.max(0,this._virtualCount-this._physicalCount)},_virtualStartVal:0,set _virtualStart(val){this._virtualStartVal=Math.min(this._maxVirtualStart,Math.max(this._minVirtualStart,val))},get _virtualStart(){return this._virtualStartVal||0},_physicalStartVal:0,set _physicalStart(val){this._physicalStartVal=val%this._physicalCount;if(this._physicalStartVal<0){this._physicalStartVal=this._physicalCount+this._physicalStartVal}this._physicalEnd=(this._physicalStart+this._physicalCount-1)%this._physicalCount},get _physicalStart(){return this._physicalStartVal||0},_physicalCountVal:0,set _physicalCount(val){this._physicalCountVal=val;this._physicalEnd=(this._physicalStart+this._physicalCount-1)%this._physicalCount},get _physicalCount(){return this._physicalCountVal},_physicalEnd:0,get _optPhysicalSize(){if(this.grid){return this._estRowsInView*this._rowHeight*this._maxPages}return this._viewportHeight*this._maxPages},get _isVisible(){return Boolean(this.offsetWidth||this.offsetHeight)},get firstVisibleIndex(){if(this._firstVisibleIndexVal===null){var physicalOffset=Math.floor(this._physicalTop+this._scrollerPaddingTop);this._firstVisibleIndexVal=this._iterateItems(function(pidx,vidx){physicalOffset+=this._getPhysicalSizeIncrement(pidx);if(physicalOffset>this._scrollPosition){return this.grid?vidx-vidx%this._itemsPerRow:vidx}if(this.grid&&this._virtualCount-1===vidx){return vidx-vidx%this._itemsPerRow}})||0}return this._firstVisibleIndexVal},get lastVisibleIndex(){if(this._lastVisibleIndexVal===null){if(this.grid){var lastIndex=this.firstVisibleIndex+this._estRowsInView*this._itemsPerRow-1;this._lastVisibleIndexVal=Math.min(this._virtualCount,lastIndex)}else{var physicalOffset=this._physicalTop;this._iterateItems(function(pidx,vidx){if(physicalOffset<this._scrollBottom){this._lastVisibleIndexVal=vidx}else{return true}physicalOffset+=this._getPhysicalSizeIncrement(pidx)})}}return this._lastVisibleIndexVal},get _defaultScrollTarget(){return this},get _virtualRowCount(){return Math.ceil(this._virtualCount/this._itemsPerRow)},get _estRowsInView(){return Math.ceil(this._viewportHeight/this._rowHeight)},get _physicalRows(){return Math.ceil(this._physicalCount/this._itemsPerRow)},ready:function(){this.addEventListener("focus",this._didFocus.bind(this),true)},attached:function(){if(this._physicalCount===0){this._debounceTemplate(this._render)}this.listen(this,"iron-resize","_resizeHandler")},detached:function(){this.unlisten(this,"iron-resize","_resizeHandler")},_setOverflow:function(scrollTarget){this.style.webkitOverflowScrolling=scrollTarget===this?"touch":"";this.style.overflow=scrollTarget===this?"auto":""},updateViewportBoundaries:function(){this._scrollerPaddingTop=this.scrollTarget===this?0:parseInt(window.getComputedStyle(this)["padding-top"],10);this._viewportWidth=this.$.items.offsetWidth;this._viewportHeight=this._scrollTargetHeight;this.grid&&this._updateGridMetrics()},_scrollHandler:function(){var scrollTop=Math.max(0,Math.min(this._maxScrollTop,this._scrollTop));var delta=scrollTop-this._scrollPosition;var isScrollingDown=delta>=0;this._scrollPosition=scrollTop;this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null;if(Math.abs(delta)>this._physicalSize){var idxAdjustment=Math.round(delta/this._physicalAverage)*this._itemsPerRow;this._physicalTop=this._physicalTop+delta;this._virtualStart=this._virtualStart+idxAdjustment;this._physicalStart=this._physicalStart+idxAdjustment;this._update()}else{var reusables=this._getReusables(isScrollingDown);if(isScrollingDown){this._physicalTop=reusables.physicalTop;this._virtualStart=this._virtualStart+reusables.indexes.length;this._physicalStart=this._physicalStart+reusables.indexes.length}else{this._virtualStart=this._virtualStart-reusables.indexes.length;this._physicalStart=this._physicalStart-reusables.indexes.length}if(reusables.indexes.length===0){this._increasePoolIfNeeded()}else{this._update(reusables.indexes,isScrollingDown?null:reusables.indexes)}}},_getReusables:function(fromTop){var ith,lastIth,offsetContent,physicalItemHeight;var idxs=[];var protectedOffsetContent=this._hiddenContentSize*this._ratio;var virtualStart=this._virtualStart;var virtualEnd=this._virtualEnd;var physicalCount=this._physicalCount;var physicalTop=this._physicalTop;var scrollTop=this._scrollTop;var scrollBottom=this._scrollBottom;if(fromTop){ith=this._physicalStart;lastIth=this._physicalEnd;offsetContent=scrollTop-physicalTop}else{ith=this._physicalEnd;lastIth=this._physicalStart;offsetContent=this._physicalBottom-scrollBottom}while(true){physicalItemHeight=this._getPhysicalSizeIncrement(ith);offsetContent=offsetContent-physicalItemHeight;if(idxs.length>=physicalCount||offsetContent<=protectedOffsetContent){break}if(fromTop){if(virtualEnd+idxs.length+1>=this._virtualCount){break}if(physicalTop+physicalItemHeight>=scrollTop){break}idxs.push(ith);physicalTop=physicalTop+physicalItemHeight;ith=(ith+1)%physicalCount}else{if(virtualStart-idxs.length<=0){break}if(physicalTop+this._physicalSize-physicalItemHeight<=scrollBottom){break}idxs.push(ith);physicalTop=physicalTop-physicalItemHeight;ith=ith===0?physicalCount-1:ith-1}}return{indexes:idxs,physicalTop:physicalTop}},_update:function(itemSet,movingUp){if(itemSet&&itemSet.length===0){return}this._manageFocus();this._assignModels(itemSet);this._updateMetrics(itemSet);if(movingUp){while(movingUp.length){var idx=movingUp.pop();this._physicalTop-=this._getPhysicalSizeIncrement(idx)}}this._positionItems();this._updateScrollerSize();this._increasePoolIfNeeded()},_createPool:function(size){var physicalItems=new Array(size);this._ensureTemplatized();for(var i=0;i<size;i++){var inst=this.stamp(null);physicalItems[i]=inst.root.querySelector("*");Polymer.dom(this).appendChild(inst.root)}return physicalItems},_increasePoolIfNeeded:function(){if(this._viewportHeight===0){return false}var self=this;var isClientFull=this._physicalBottom>=this._scrollBottom&&this._physicalTop<=this._scrollPosition;if(this._physicalSize>=this._optPhysicalSize&&isClientFull){return false}var maxPoolSize=Math.round(this._physicalCount*.5);if(!isClientFull){this._debounceTemplate(this._increasePool.bind(this,maxPoolSize));return true}this._yield(function(){self._increasePool(Math.min(maxPoolSize,Math.max(1,Math.round(50/self._templateCost))))});return true},_yield:function(cb){var g=window;var handle=g.requestIdleCallback?g.requestIdleCallback(cb):g.setTimeout(cb,16);Polymer.dom.addDebouncer({complete:function(){g.cancelIdleCallback?g.cancelIdleCallback(handle):g.clearTimeout(handle);cb()}})},_increasePool:function(missingItems){var nextPhysicalCount=Math.min(this._physicalCount+missingItems,this._virtualCount-this._virtualStart,Math.max(this.maxPhysicalCount,DEFAULT_PHYSICAL_COUNT));var prevPhysicalCount=this._physicalCount;var delta=nextPhysicalCount-prevPhysicalCount;var ts=window.performance.now();if(delta<=0){return}[].push.apply(this._physicalItems,this._createPool(delta));[].push.apply(this._physicalSizes,new Array(delta));this._physicalCount=prevPhysicalCount+delta;if(this._physicalStart>this._physicalEnd&&this._isIndexRendered(this._focusedIndex)&&this._getPhysicalIndex(this._focusedIndex)<this._physicalEnd){this._physicalStart=this._physicalStart+delta}this._update();this._templateCost=(window.performance.now()-ts)/delta},_render:function(){if(this.isAttached&&this._isVisible){if(this._physicalCount===0){this.updateViewportBoundaries();this._increasePool(DEFAULT_PHYSICAL_COUNT)}else{var reusables=this._getReusables(true);this._physicalTop=reusables.physicalTop;this._virtualStart=this._virtualStart+reusables.indexes.length;this._physicalStart=this._physicalStart+reusables.indexes.length;this._update(reusables.indexes);this._update()}}},_ensureTemplatized:function(){if(!this.ctor){var props={};props.__key__=true;props[this.as]=true;props[this.indexAs]=true;props[this.selectedAs]=true;props.tabIndex=true;this._instanceProps=props;this._userTemplate=Polymer.dom(this).querySelector("template");if(this._userTemplate){this.templatize(this._userTemplate)}else{console.warn("iron-list requires a template to be provided in light-dom")}}},_getStampedChildren:function(){return this._physicalItems},_forwardInstancePath:function(inst,path,value){if(path.indexOf(this.as+".")===0){this.notifyPath("items."+inst.__key__+"."+path.slice(this.as.length+1),value)}},_forwardParentProp:function(prop,value){if(this._physicalItems){this._physicalItems.forEach(function(item){item._templateInstance[prop]=value},this)}},_forwardParentPath:function(path,value){if(this._physicalItems){this._physicalItems.forEach(function(item){item._templateInstance.notifyPath(path,value,true)},this)}},_forwardItemPath:function(path,value){if(!this._physicalIndexForKey){return}var dot=path.indexOf(".");var key=path.substring(0,dot<0?path.length:dot);var idx=this._physicalIndexForKey[key];var offscreenItem=this._offscreenFocusedItem;var el=offscreenItem&&offscreenItem._templateInstance.__key__===key?offscreenItem:this._physicalItems[idx];if(!el||el._templateInstance.__key__!==key){return}if(dot>=0){path=this.as+"."+path.substring(dot+1);el._templateInstance.notifyPath(path,value,true)}else{var currentItem=el._templateInstance[this.as];if(Array.isArray(this.selectedItems)){for(var i=0;i<this.selectedItems.length;i++){if(this.selectedItems[i]===currentItem){this.set("selectedItems."+i,value);break}}}else if(this.selectedItem===currentItem){this.set("selectedItem",value)}el._templateInstance[this.as]=value}},_itemsChanged:function(change){if(change.path==="items"){this._virtualStart=0;this._physicalTop=0;this._virtualCount=this.items?this.items.length:0;this._collection=this.items?Polymer.Collection.get(this.items):null;this._physicalIndexForKey={};this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null;this._physicalCount=this._physicalCount||0;this._physicalItems=this._physicalItems||[];this._physicalSizes=this._physicalSizes||[];this._physicalStart=0;this._resetScrollPosition(0);this._removeFocusedItem();this._debounceTemplate(this._render)}else if(change.path==="items.splices"){this._adjustVirtualIndex(change.value.indexSplices);this._virtualCount=this.items?this.items.length:0;this._debounceTemplate(this._render)}else{this._forwardItemPath(change.path.split(".").slice(1).join("."),change.value)}},_adjustVirtualIndex:function(splices){splices.forEach(function(splice){splice.removed.forEach(this._removeItem,this);if(splice.index<this._virtualStart){var delta=Math.max(splice.addedCount-splice.removed.length,splice.index-this._virtualStart);this._virtualStart=this._virtualStart+delta;if(this._focusedIndex>=0){this._focusedIndex=this._focusedIndex+delta}}},this)},_removeItem:function(item){this.$.selector.deselect(item);if(this._focusedItem&&this._focusedItem._templateInstance[this.as]===item){this._removeFocusedItem()}},_iterateItems:function(fn,itemSet){var pidx,vidx,rtn,i;if(arguments.length===2&&itemSet){for(i=0;i<itemSet.length;i++){pidx=itemSet[i];vidx=this._computeVidx(pidx);if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}}else{pidx=this._physicalStart;vidx=this._virtualStart;for(;pidx<this._physicalCount;pidx++,vidx++){if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}for(pidx=0;pidx<this._physicalStart;pidx++,vidx++){if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}}},_computeVidx:function(pidx){if(pidx>=this._physicalStart){return this._virtualStart+(pidx-this._physicalStart)}return this._virtualStart+(this._physicalCount-this._physicalStart)+pidx},_assignModels:function(itemSet){this._iterateItems(function(pidx,vidx){var el=this._physicalItems[pidx];var inst=el._templateInstance;var item=this.items&&this.items[vidx];if(item!=null){inst[this.as]=item;inst.__key__=this._collection.getKey(item);inst[this.selectedAs]=this.$.selector.isSelected(item);inst[this.indexAs]=vidx;inst.tabIndex=this._focusedIndex===vidx?0:-1;this._physicalIndexForKey[inst.__key__]=pidx;el.removeAttribute("hidden")}else{inst.__key__=null;el.setAttribute("hidden","")}},itemSet)},_updateMetrics:function(itemSet){Polymer.dom.flush();var newPhysicalSize=0;var oldPhysicalSize=0;var prevAvgCount=this._physicalAverageCount;var prevPhysicalAvg=this._physicalAverage;this._iterateItems(function(pidx,vidx){oldPhysicalSize+=this._physicalSizes[pidx]||0;this._physicalSizes[pidx]=this._physicalItems[pidx].offsetHeight;newPhysicalSize+=this._physicalSizes[pidx];this._physicalAverageCount+=this._physicalSizes[pidx]?1:0},itemSet);if(this.grid){this._updateGridMetrics();this._physicalSize=Math.ceil(this._physicalCount/this._itemsPerRow)*this._rowHeight}else{this._physicalSize=this._physicalSize+newPhysicalSize-oldPhysicalSize}if(this._physicalAverageCount!==prevAvgCount){this._physicalAverage=Math.round((prevPhysicalAvg*prevAvgCount+newPhysicalSize)/this._physicalAverageCount)}},_updateGridMetrics:function(){this._itemWidth=this._physicalCount>0?this._physicalItems[0].getBoundingClientRect().width:200;this._rowHeight=this._physicalCount>0?this._physicalItems[0].offsetHeight:200;this._itemsPerRow=this._itemWidth?Math.floor(this._viewportWidth/this._itemWidth):this._itemsPerRow},_positionItems:function(){this._adjustScrollPosition();var y=this._physicalTop;if(this.grid){var totalItemWidth=this._itemsPerRow*this._itemWidth;var rowOffset=(this._viewportWidth-totalItemWidth)/2;this._iterateItems(function(pidx,vidx){var modulus=vidx%this._itemsPerRow;var x=Math.floor(modulus*this._itemWidth+rowOffset);this.translate3d(x+"px",y+"px",0,this._physicalItems[pidx]);if(this._shouldRenderNextRow(vidx)){y+=this._rowHeight}})}else{this._iterateItems(function(pidx,vidx){this.translate3d(0,y+"px",0,this._physicalItems[pidx]);y+=this._physicalSizes[pidx]})}},_getPhysicalSizeIncrement:function(pidx){if(!this.grid){return this._physicalSizes[pidx]}if(this._computeVidx(pidx)%this._itemsPerRow!==this._itemsPerRow-1){return 0}return this._rowHeight},_shouldRenderNextRow:function(vidx){return vidx%this._itemsPerRow===this._itemsPerRow-1},_adjustScrollPosition:function(){var deltaHeight=this._virtualStart===0?this._physicalTop:Math.min(this._scrollPosition+this._physicalTop,0);if(deltaHeight){this._physicalTop=this._physicalTop-deltaHeight;if(!IOS_TOUCH_SCROLLING&&this._physicalTop!==0){this._resetScrollPosition(this._scrollTop-deltaHeight)}}},_resetScrollPosition:function(pos){if(this.scrollTarget){this._scrollTop=pos;this._scrollPosition=this._scrollTop}},_updateScrollerSize:function(forceUpdate){if(this.grid){this._estScrollHeight=this._virtualRowCount*this._rowHeight}else{this._estScrollHeight=this._physicalBottom+Math.max(this._virtualCount-this._physicalCount-this._virtualStart,0)*this._physicalAverage}forceUpdate=forceUpdate||this._scrollHeight===0;forceUpdate=forceUpdate||this._scrollPosition>=this._estScrollHeight-this._physicalSize;forceUpdate=forceUpdate||this.grid&&this.$.items.style.height<this._estScrollHeight;if(forceUpdate||Math.abs(this._estScrollHeight-this._scrollHeight)>=this._optPhysicalSize){this.$.items.style.height=this._estScrollHeight+"px";this._scrollHeight=this._estScrollHeight}},scrollToItem:function(item){return this.scrollToIndex(this.items.indexOf(item))},scrollToIndex:function(idx){if(typeof idx!=="number"||idx<0||idx>this.items.length-1){return}Polymer.dom.flush();if(this._physicalCount===0){return}idx=Math.min(Math.max(idx,0),this._virtualCount-1);if(!this._isIndexRendered(idx)||idx>=this._maxVirtualStart){this._virtualStart=this.grid?idx-this._itemsPerRow*2:idx-1}this._manageFocus();this._assignModels();this._updateMetrics();this._physicalTop=Math.floor(this._virtualStart/this._itemsPerRow)*this._physicalAverage;var currentTopItem=this._physicalStart;var currentVirtualItem=this._virtualStart;var targetOffsetTop=0;var hiddenContentSize=this._hiddenContentSize;while(currentVirtualItem<idx&&targetOffsetTop<=hiddenContentSize){targetOffsetTop=targetOffsetTop+this._getPhysicalSizeIncrement(currentTopItem);currentTopItem=(currentTopItem+1)%this._physicalCount;currentVirtualItem++}this._updateScrollerSize(true);this._positionItems();this._resetScrollPosition(this._physicalTop+this._scrollerPaddingTop+targetOffsetTop);this._increasePoolIfNeeded();this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null},_resetAverage:function(){this._physicalAverage=0;this._physicalAverageCount=0},_resizeHandler:function(){if(IOS&&Math.abs(this._viewportHeight-this._scrollTargetHeight)<100){return}Polymer.dom.addDebouncer(this.debounce("_debounceTemplate",function(){this.updateViewportBoundaries();this._render();if(this._isVisible){this.toggleScrollListener(true);if(this._physicalCount>0){this._resetAverage();this.scrollToIndex(this.firstVisibleIndex)}}else{this.toggleScrollListener(false)}}.bind(this),1))},_getModelFromItem:function(item){var key=this._collection.getKey(item);var pidx=this._physicalIndexForKey[key];if(pidx!=null){return this._physicalItems[pidx]._templateInstance}return null},_getNormalizedItem:function(item){if(this._collection.getKey(item)===undefined){if(typeof item==="number"){item=this.items[item];if(!item){throw new RangeError("<item> not found")}return item}throw new TypeError("<item> should be a valid item")}return item},selectItem:function(item){item=this._getNormalizedItem(item);var model=this._getModelFromItem(item);if(!this.multiSelection&&this.selectedItem){this.deselectItem(this.selectedItem)}if(model){model[this.selectedAs]=true}this.$.selector.select(item);this.updateSizeForItem(item)},deselectItem:function(item){item=this._getNormalizedItem(item);var model=this._getModelFromItem(item);if(model){model[this.selectedAs]=false}this.$.selector.deselect(item);this.updateSizeForItem(item)},toggleSelectionForItem:function(item){item=this._getNormalizedItem(item);if(this.$.selector.isSelected(item)){this.deselectItem(item)}else{this.selectItem(item)}},clearSelection:function(){function unselect(item){var model=this._getModelFromItem(item);if(model){model[this.selectedAs]=false}}if(Array.isArray(this.selectedItems)){this.selectedItems.forEach(unselect,this)}else if(this.selectedItem){unselect.call(this,this.selectedItem)}this.$.selector.clearSelection()},_selectionEnabledChanged:function(selectionEnabled){var handler=selectionEnabled?this.listen:this.unlisten;handler.call(this,this,"tap","_selectionHandler")},_selectionHandler:function(e){var model=this.modelForElement(e.target);if(!model){return}var modelTabIndex,activeElTabIndex;var target=Polymer.dom(e).path[0];var activeEl=Polymer.dom(this.domHost?this.domHost.root:document).activeElement;var physicalItem=this._physicalItems[this._getPhysicalIndex(model[this.indexAs])];if(target.localName==="input"||target.localName==="button"||target.localName==="select"){return}modelTabIndex=model.tabIndex;model.tabIndex=SECRET_TABINDEX; +function importModules(moduleNames){return new Promise(function(resolve){define(moduleNames,function(){resolve(Array.from(arguments))})})}Polymer.IronResizableBehavior={properties:{_parentResizable:{type:Object,observer:"_parentResizableChanged"},_notifyingDescendant:{type:Boolean,value:false}},listeners:{"iron-request-resize-notifications":"_onIronRequestResizeNotifications"},created:function(){this._interestedResizables=[];this._boundNotifyResize=this.notifyResize.bind(this)},attached:function(){this.fire("iron-request-resize-notifications",null,{node:this,bubbles:true,cancelable:true});if(!this._parentResizable){window.addEventListener("resize",this._boundNotifyResize);this.notifyResize()}},detached:function(){if(this._parentResizable){this._parentResizable.stopResizeNotificationsFor(this)}else{window.removeEventListener("resize",this._boundNotifyResize)}this._parentResizable=null},notifyResize:function(){if(!this.isAttached){return}this._interestedResizables.forEach(function(resizable){if(this.resizerShouldNotify(resizable)){this._notifyDescendant(resizable)}},this);this._fireResize()},assignParentResizable:function(parentResizable){this._parentResizable=parentResizable},stopResizeNotificationsFor:function(target){var index=this._interestedResizables.indexOf(target);if(index>-1){this._interestedResizables.splice(index,1);this.unlisten(target,"iron-resize","_onDescendantIronResize")}},resizerShouldNotify:function(element){return true},_onDescendantIronResize:function(event){if(this._notifyingDescendant){event.stopPropagation();return}if(!Polymer.Settings.useShadow){this._fireResize()}},_fireResize:function(){this.fire("iron-resize",null,{node:this,bubbles:false})},_onIronRequestResizeNotifications:function(event){var target=event.path?event.path[0]:event.target;if(target===this){return}if(this._interestedResizables.indexOf(target)===-1){this._interestedResizables.push(target);this.listen(target,"iron-resize","_onDescendantIronResize")}target.assignParentResizable(this);this._notifyDescendant(target);event.stopPropagation()},_parentResizableChanged:function(parentResizable){if(parentResizable){window.removeEventListener("resize",this._boundNotifyResize)}},_notifyDescendant:function(descendant){if(!this.isAttached){return}this._notifyingDescendant=true;descendant.notifyResize();this._notifyingDescendant=false}};(function(){"use strict";var KEY_IDENTIFIER={"U+0008":"backspace","U+0009":"tab","U+001B":"esc","U+0020":"space","U+007F":"del"};var KEY_CODE={8:"backspace",9:"tab",13:"enter",27:"esc",33:"pageup",34:"pagedown",35:"end",36:"home",32:"space",37:"left",38:"up",39:"right",40:"down",46:"del",106:"*"};var MODIFIER_KEYS={shift:"shiftKey",ctrl:"ctrlKey",alt:"altKey",meta:"metaKey"};var KEY_CHAR=/[a-z0-9*]/;var IDENT_CHAR=/U\+/;var ARROW_KEY=/^arrow/;var SPACE_KEY=/^space(bar)?/;var ESC_KEY=/^escape$/;function transformKey(key,noSpecialChars){var validKey="";if(key){var lKey=key.toLowerCase();if(lKey===" "||SPACE_KEY.test(lKey)){validKey="space"}else if(ESC_KEY.test(lKey)){validKey="esc"}else if(lKey.length==1){if(!noSpecialChars||KEY_CHAR.test(lKey)){validKey=lKey}}else if(ARROW_KEY.test(lKey)){validKey=lKey.replace("arrow","")}else if(lKey=="multiply"){validKey="*"}else{validKey=lKey}}return validKey}function transformKeyIdentifier(keyIdent){var validKey="";if(keyIdent){if(keyIdent in KEY_IDENTIFIER){validKey=KEY_IDENTIFIER[keyIdent]}else if(IDENT_CHAR.test(keyIdent)){keyIdent=parseInt(keyIdent.replace("U+","0x"),16);validKey=String.fromCharCode(keyIdent).toLowerCase()}else{validKey=keyIdent.toLowerCase()}}return validKey}function transformKeyCode(keyCode){var validKey="";if(Number(keyCode)){if(keyCode>=65&&keyCode<=90){validKey=String.fromCharCode(32+keyCode)}else if(keyCode>=112&&keyCode<=123){validKey="f"+(keyCode-112)}else if(keyCode>=48&&keyCode<=57){validKey=String(keyCode-48)}else if(keyCode>=96&&keyCode<=105){validKey=String(keyCode-96)}else{validKey=KEY_CODE[keyCode]}}return validKey}function normalizedKeyForEvent(keyEvent,noSpecialChars){if(keyEvent.key){return transformKey(keyEvent.key,noSpecialChars)}if(keyEvent.detail&&keyEvent.detail.key){return transformKey(keyEvent.detail.key,noSpecialChars)}return transformKeyIdentifier(keyEvent.keyIdentifier)||transformKeyCode(keyEvent.keyCode)||""}function keyComboMatchesEvent(keyCombo,event){var keyEvent=normalizedKeyForEvent(event,keyCombo.hasModifiers);return keyEvent===keyCombo.key&&(!keyCombo.hasModifiers||!!event.shiftKey===!!keyCombo.shiftKey&&!!event.ctrlKey===!!keyCombo.ctrlKey&&!!event.altKey===!!keyCombo.altKey&&!!event.metaKey===!!keyCombo.metaKey)}function parseKeyComboString(keyComboString){if(keyComboString.length===1){return{combo:keyComboString,key:keyComboString,event:"keydown"}}return keyComboString.split("+").reduce(function(parsedKeyCombo,keyComboPart){var eventParts=keyComboPart.split(":");var keyName=eventParts[0];var event=eventParts[1];if(keyName in MODIFIER_KEYS){parsedKeyCombo[MODIFIER_KEYS[keyName]]=true;parsedKeyCombo.hasModifiers=true}else{parsedKeyCombo.key=keyName;parsedKeyCombo.event=event||"keydown"}return parsedKeyCombo},{combo:keyComboString.split(":").shift()})}function parseEventString(eventString){return eventString.trim().split(" ").map(function(keyComboString){return parseKeyComboString(keyComboString)})}Polymer.IronA11yKeysBehavior={properties:{keyEventTarget:{type:Object,value:function(){return this}},stopKeyboardEventPropagation:{type:Boolean,value:false},_boundKeyHandlers:{type:Array,value:function(){return[]}},_imperativeKeyBindings:{type:Object,value:function(){return{}}}},observers:["_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)"],keyBindings:{},registered:function(){this._prepKeyBindings()},attached:function(){this._listenKeyEventListeners()},detached:function(){this._unlistenKeyEventListeners()},addOwnKeyBinding:function(eventString,handlerName){this._imperativeKeyBindings[eventString]=handlerName;this._prepKeyBindings();this._resetKeyEventListeners()},removeOwnKeyBindings:function(){this._imperativeKeyBindings={};this._prepKeyBindings();this._resetKeyEventListeners()},keyboardEventMatchesKeys:function(event,eventString){var keyCombos=parseEventString(eventString);for(var i=0;i<keyCombos.length;++i){if(keyComboMatchesEvent(keyCombos[i],event)){return true}}return false},_collectKeyBindings:function(){var keyBindings=this.behaviors.map(function(behavior){return behavior.keyBindings});if(keyBindings.indexOf(this.keyBindings)===-1){keyBindings.push(this.keyBindings)}return keyBindings},_prepKeyBindings:function(){this._keyBindings={};this._collectKeyBindings().forEach(function(keyBindings){for(var eventString in keyBindings){this._addKeyBinding(eventString,keyBindings[eventString])}},this);for(var eventString in this._imperativeKeyBindings){this._addKeyBinding(eventString,this._imperativeKeyBindings[eventString])}for(var eventName in this._keyBindings){this._keyBindings[eventName].sort(function(kb1,kb2){var b1=kb1[0].hasModifiers;var b2=kb2[0].hasModifiers;return b1===b2?0:b1?-1:1})}},_addKeyBinding:function(eventString,handlerName){parseEventString(eventString).forEach(function(keyCombo){this._keyBindings[keyCombo.event]=this._keyBindings[keyCombo.event]||[];this._keyBindings[keyCombo.event].push([keyCombo,handlerName])},this)},_resetKeyEventListeners:function(){this._unlistenKeyEventListeners();if(this.isAttached){this._listenKeyEventListeners()}},_listenKeyEventListeners:function(){if(!this.keyEventTarget){return}Object.keys(this._keyBindings).forEach(function(eventName){var keyBindings=this._keyBindings[eventName];var boundKeyHandler=this._onKeyBindingEvent.bind(this,keyBindings);this._boundKeyHandlers.push([this.keyEventTarget,eventName,boundKeyHandler]);this.keyEventTarget.addEventListener(eventName,boundKeyHandler)},this)},_unlistenKeyEventListeners:function(){var keyHandlerTuple;var keyEventTarget;var eventName;var boundKeyHandler;while(this._boundKeyHandlers.length){keyHandlerTuple=this._boundKeyHandlers.pop();keyEventTarget=keyHandlerTuple[0];eventName=keyHandlerTuple[1];boundKeyHandler=keyHandlerTuple[2];keyEventTarget.removeEventListener(eventName,boundKeyHandler)}},_onKeyBindingEvent:function(keyBindings,event){if(this.stopKeyboardEventPropagation){event.stopPropagation()}if(event.defaultPrevented){return}for(var i=0;i<keyBindings.length;i++){var keyCombo=keyBindings[i][0];var handlerName=keyBindings[i][1];if(keyComboMatchesEvent(keyCombo,event)){this._triggerKeyHandler(keyCombo,handlerName,event);if(event.defaultPrevented){return}}}},_triggerKeyHandler:function(keyCombo,handlerName,keyboardEvent){var detail=Object.create(keyCombo);detail.keyboardEvent=keyboardEvent;var event=new CustomEvent(keyCombo.event,{detail:detail,cancelable:true});this[handlerName].call(this,event);if(event.defaultPrevented){keyboardEvent.preventDefault()}}}})();Polymer.IronScrollTargetBehavior={properties:{scrollTarget:{type:HTMLElement,value:function(){return this._defaultScrollTarget}}},observers:["_scrollTargetChanged(scrollTarget, isAttached)"],_shouldHaveListener:true,_scrollTargetChanged:function(scrollTarget,isAttached){var eventTarget;if(this._oldScrollTarget){this._toggleScrollListener(false,this._oldScrollTarget);this._oldScrollTarget=null}if(!isAttached){return}if(scrollTarget==="document"){this.scrollTarget=this._doc}else if(typeof scrollTarget==="string"){this.scrollTarget=this.domHost?this.domHost.$[scrollTarget]:Polymer.dom(this.ownerDocument).querySelector("#"+scrollTarget)}else if(this._isValidScrollTarget()){this._boundScrollHandler=this._boundScrollHandler||this._scrollHandler.bind(this);this._oldScrollTarget=scrollTarget;this._toggleScrollListener(this._shouldHaveListener,scrollTarget)}},_scrollHandler:function scrollHandler(){},get _defaultScrollTarget(){return this._doc},get _doc(){return this.ownerDocument.documentElement},get _scrollTop(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.pageYOffset:this.scrollTarget.scrollTop}return 0},get _scrollLeft(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.pageXOffset:this.scrollTarget.scrollLeft}return 0},set _scrollTop(top){if(this.scrollTarget===this._doc){window.scrollTo(window.pageXOffset,top)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollTop=top}},set _scrollLeft(left){if(this.scrollTarget===this._doc){window.scrollTo(left,window.pageYOffset)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollLeft=left}},scroll:function(left,top){if(this.scrollTarget===this._doc){window.scrollTo(left,top)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollLeft=left;this.scrollTarget.scrollTop=top}},get _scrollTargetWidth(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.innerWidth:this.scrollTarget.offsetWidth}return 0},get _scrollTargetHeight(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.innerHeight:this.scrollTarget.offsetHeight}return 0},_isValidScrollTarget:function(){return this.scrollTarget instanceof HTMLElement},_toggleScrollListener:function(yes,scrollTarget){if(!this._boundScrollHandler){return}var eventTarget=scrollTarget===this._doc?window:scrollTarget;if(yes){eventTarget.addEventListener("scroll",this._boundScrollHandler)}else{eventTarget.removeEventListener("scroll",this._boundScrollHandler)}},toggleScrollListener:function(yes){this._shouldHaveListener=yes;this._toggleScrollListener(yes,this.scrollTarget)}};(function(){var IOS=navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);var IOS_TOUCH_SCROLLING=IOS&&IOS[1]>=8;var DEFAULT_PHYSICAL_COUNT=3;var HIDDEN_Y="-10000px";var ITEM_WIDTH=0;var ITEM_HEIGHT=1;var SECRET_TABINDEX=-100;Polymer({is:"iron-list",properties:{items:{type:Array},maxPhysicalCount:{type:Number,value:500},as:{type:String,value:"item"},indexAs:{type:String,value:"index"},selectedAs:{type:String,value:"selected"},grid:{type:Boolean,value:false,reflectToAttribute:true},selectionEnabled:{type:Boolean,value:false},selectedItem:{type:Object,notify:true},selectedItems:{type:Object,notify:true},multiSelection:{type:Boolean,value:false}},observers:["_itemsChanged(items.*)","_selectionEnabledChanged(selectionEnabled)","_multiSelectionChanged(multiSelection)","_setOverflow(scrollTarget)"],behaviors:[Polymer.Templatizer,Polymer.IronResizableBehavior,Polymer.IronA11yKeysBehavior,Polymer.IronScrollTargetBehavior],keyBindings:{up:"_didMoveUp",down:"_didMoveDown",enter:"_didEnter"},_ratio:.5,_scrollerPaddingTop:0,_scrollPosition:0,_physicalSize:0,_physicalAverage:0,_physicalAverageCount:0,_physicalTop:0,_virtualCount:0,_physicalIndexForKey:null,_estScrollHeight:0,_scrollHeight:0,_viewportHeight:0,_viewportWidth:0,_physicalItems:null,_physicalSizes:null,_firstVisibleIndexVal:null,_lastVisibleIndexVal:null,_collection:null,_maxPages:2,_focusedItem:null,_focusedIndex:-1,_offscreenFocusedItem:null,_focusBackfillItem:null,_itemsPerRow:1,_itemWidth:0,_rowHeight:0,_templateCost:0,get _physicalBottom(){return this._physicalTop+this._physicalSize},get _scrollBottom(){return this._scrollPosition+this._viewportHeight},get _virtualEnd(){return this._virtualStart+this._physicalCount-1},get _hiddenContentSize(){var size=this.grid?this._physicalRows*this._rowHeight:this._physicalSize;return size-this._viewportHeight},get _maxScrollTop(){return this._estScrollHeight-this._viewportHeight+this._scrollerPaddingTop},_minVirtualStart:0,get _maxVirtualStart(){return Math.max(0,this._virtualCount-this._physicalCount)},_virtualStartVal:0,set _virtualStart(val){this._virtualStartVal=Math.min(this._maxVirtualStart,Math.max(this._minVirtualStart,val))},get _virtualStart(){return this._virtualStartVal||0},_physicalStartVal:0,set _physicalStart(val){this._physicalStartVal=val%this._physicalCount;if(this._physicalStartVal<0){this._physicalStartVal=this._physicalCount+this._physicalStartVal}this._physicalEnd=(this._physicalStart+this._physicalCount-1)%this._physicalCount},get _physicalStart(){return this._physicalStartVal||0},_physicalCountVal:0,set _physicalCount(val){this._physicalCountVal=val;this._physicalEnd=(this._physicalStart+this._physicalCount-1)%this._physicalCount},get _physicalCount(){return this._physicalCountVal},_physicalEnd:0,get _optPhysicalSize(){if(this.grid){return this._estRowsInView*this._rowHeight*this._maxPages}return this._viewportHeight*this._maxPages},get _isVisible(){return Boolean(this.offsetWidth||this.offsetHeight)},get firstVisibleIndex(){if(this._firstVisibleIndexVal===null){var physicalOffset=Math.floor(this._physicalTop+this._scrollerPaddingTop);this._firstVisibleIndexVal=this._iterateItems(function(pidx,vidx){physicalOffset+=this._getPhysicalSizeIncrement(pidx);if(physicalOffset>this._scrollPosition){return this.grid?vidx-vidx%this._itemsPerRow:vidx}if(this.grid&&this._virtualCount-1===vidx){return vidx-vidx%this._itemsPerRow}})||0}return this._firstVisibleIndexVal},get lastVisibleIndex(){if(this._lastVisibleIndexVal===null){if(this.grid){var lastIndex=this.firstVisibleIndex+this._estRowsInView*this._itemsPerRow-1;this._lastVisibleIndexVal=Math.min(this._virtualCount,lastIndex)}else{var physicalOffset=this._physicalTop;this._iterateItems(function(pidx,vidx){if(physicalOffset<this._scrollBottom){this._lastVisibleIndexVal=vidx}else{return true}physicalOffset+=this._getPhysicalSizeIncrement(pidx)})}}return this._lastVisibleIndexVal},get _defaultScrollTarget(){return this},get _virtualRowCount(){return Math.ceil(this._virtualCount/this._itemsPerRow)},get _estRowsInView(){return Math.ceil(this._viewportHeight/this._rowHeight)},get _physicalRows(){return Math.ceil(this._physicalCount/this._itemsPerRow)},ready:function(){this.addEventListener("focus",this._didFocus.bind(this),true)},attached:function(){if(this._physicalCount===0){this._debounceTemplate(this._render)}this.listen(this,"iron-resize","_resizeHandler")},detached:function(){this.unlisten(this,"iron-resize","_resizeHandler")},_setOverflow:function(scrollTarget){this.style.webkitOverflowScrolling=scrollTarget===this?"touch":"";this.style.overflow=scrollTarget===this?"auto":""},updateViewportBoundaries:function(){this._scrollerPaddingTop=this.scrollTarget===this?0:parseInt(window.getComputedStyle(this)["padding-top"],10);this._viewportWidth=this.$.items.offsetWidth;this._viewportHeight=this._scrollTargetHeight;this.grid&&this._updateGridMetrics()},_scrollHandler:function(){var scrollTop=Math.max(0,Math.min(this._maxScrollTop,this._scrollTop));var delta=scrollTop-this._scrollPosition;var isScrollingDown=delta>=0;this._scrollPosition=scrollTop;this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null;if(Math.abs(delta)>this._physicalSize){var idxAdjustment=Math.round(delta/this._physicalAverage)*this._itemsPerRow;this._physicalTop=this._physicalTop+delta;this._virtualStart=this._virtualStart+idxAdjustment;this._physicalStart=this._physicalStart+idxAdjustment;this._update()}else{var reusables=this._getReusables(isScrollingDown);if(isScrollingDown){this._physicalTop=reusables.physicalTop;this._virtualStart=this._virtualStart+reusables.indexes.length;this._physicalStart=this._physicalStart+reusables.indexes.length}else{this._virtualStart=this._virtualStart-reusables.indexes.length;this._physicalStart=this._physicalStart-reusables.indexes.length}if(reusables.indexes.length===0){this._increasePoolIfNeeded()}else{this._update(reusables.indexes,isScrollingDown?null:reusables.indexes)}}},_getReusables:function(fromTop){var ith,lastIth,offsetContent,physicalItemHeight;var idxs=[];var protectedOffsetContent=this._hiddenContentSize*this._ratio;var virtualStart=this._virtualStart;var virtualEnd=this._virtualEnd;var physicalCount=this._physicalCount;var physicalTop=this._physicalTop+this._scrollerPaddingTop;var scrollTop=this._scrollTop;var scrollBottom=this._scrollBottom;if(fromTop){ith=this._physicalStart;lastIth=this._physicalEnd;offsetContent=scrollTop-physicalTop}else{ith=this._physicalEnd;lastIth=this._physicalStart;offsetContent=this._physicalBottom-scrollBottom}while(true){physicalItemHeight=this._getPhysicalSizeIncrement(ith);offsetContent=offsetContent-physicalItemHeight;if(idxs.length>=physicalCount||offsetContent<=protectedOffsetContent){break}if(fromTop){if(virtualEnd+idxs.length+1>=this._virtualCount){break}if(physicalTop+physicalItemHeight>=scrollTop){break}idxs.push(ith);physicalTop=physicalTop+physicalItemHeight;ith=(ith+1)%physicalCount}else{if(virtualStart-idxs.length<=0){break}if(physicalTop+this._physicalSize-physicalItemHeight<=scrollBottom){break}idxs.push(ith);physicalTop=physicalTop-physicalItemHeight;ith=ith===0?physicalCount-1:ith-1}}return{indexes:idxs,physicalTop:physicalTop-this._scrollerPaddingTop}},_update:function(itemSet,movingUp){if(itemSet&&itemSet.length===0){return}this._manageFocus();this._assignModels(itemSet);this._updateMetrics(itemSet);if(movingUp){while(movingUp.length){var idx=movingUp.pop();this._physicalTop-=this._getPhysicalSizeIncrement(idx)}}this._positionItems();this._updateScrollerSize();this._increasePoolIfNeeded()},_createPool:function(size){var physicalItems=new Array(size);this._ensureTemplatized();for(var i=0;i<size;i++){var inst=this.stamp(null);physicalItems[i]=inst.root.querySelector("*");Polymer.dom(this).appendChild(inst.root)}return physicalItems},_increasePoolIfNeeded:function(){if(this._viewportHeight===0){return false}var self=this;var isClientFull=this._physicalBottom>=this._scrollBottom&&this._physicalTop<=this._scrollPosition;if(this._physicalSize>=this._optPhysicalSize&&isClientFull){return false}var maxPoolSize=Math.round(this._physicalCount*.5);if(!isClientFull){this._debounceTemplate(this._increasePool.bind(this,maxPoolSize));return true}this._yield(function(){self._increasePool(Math.min(maxPoolSize,Math.max(1,Math.round(50/self._templateCost))))});return true},_yield:function(cb){var g=window;var handle=g.requestIdleCallback?g.requestIdleCallback(cb):g.setTimeout(cb,16);Polymer.dom.addDebouncer({complete:function(){g.cancelIdleCallback?g.cancelIdleCallback(handle):g.clearTimeout(handle);cb()}})},_increasePool:function(missingItems){var nextPhysicalCount=Math.min(this._physicalCount+missingItems,this._virtualCount-this._virtualStart,Math.max(this.maxPhysicalCount,DEFAULT_PHYSICAL_COUNT));var prevPhysicalCount=this._physicalCount;var delta=nextPhysicalCount-prevPhysicalCount;var ts=window.performance.now();if(delta<=0){return}[].push.apply(this._physicalItems,this._createPool(delta));[].push.apply(this._physicalSizes,new Array(delta));this._physicalCount=prevPhysicalCount+delta;if(this._physicalStart>this._physicalEnd&&this._isIndexRendered(this._focusedIndex)&&this._getPhysicalIndex(this._focusedIndex)<this._physicalEnd){this._physicalStart=this._physicalStart+delta}this._update();this._templateCost=(window.performance.now()-ts)/delta},_render:function(){if(this.isAttached&&this._isVisible){if(this._physicalCount===0){this.updateViewportBoundaries();this._increasePool(DEFAULT_PHYSICAL_COUNT)}else{var reusables=this._getReusables(true);this._physicalTop=reusables.physicalTop;this._virtualStart=this._virtualStart+reusables.indexes.length;this._physicalStart=this._physicalStart+reusables.indexes.length;this._update(reusables.indexes);this._update()}}},_ensureTemplatized:function(){if(!this.ctor){var props={};props.__key__=true;props[this.as]=true;props[this.indexAs]=true;props[this.selectedAs]=true;props.tabIndex=true;this._instanceProps=props;this._userTemplate=Polymer.dom(this).querySelector("template");if(this._userTemplate){this.templatize(this._userTemplate)}else{console.warn("iron-list requires a template to be provided in light-dom")}}},_getStampedChildren:function(){return this._physicalItems},_forwardInstancePath:function(inst,path,value){if(path.indexOf(this.as+".")===0){this.notifyPath("items."+inst.__key__+"."+path.slice(this.as.length+1),value)}},_forwardParentProp:function(prop,value){if(this._physicalItems){this._physicalItems.forEach(function(item){item._templateInstance[prop]=value},this)}},_forwardParentPath:function(path,value){if(this._physicalItems){this._physicalItems.forEach(function(item){item._templateInstance.notifyPath(path,value,true)},this)}},_forwardItemPath:function(path,value){if(!this._physicalIndexForKey){return}var dot=path.indexOf(".");var key=path.substring(0,dot<0?path.length:dot);var idx=this._physicalIndexForKey[key];var offscreenItem=this._offscreenFocusedItem;var el=offscreenItem&&offscreenItem._templateInstance.__key__===key?offscreenItem:this._physicalItems[idx];if(!el||el._templateInstance.__key__!==key){return}if(dot>=0){path=this.as+"."+path.substring(dot+1);el._templateInstance.notifyPath(path,value,true)}else{var currentItem=el._templateInstance[this.as];if(Array.isArray(this.selectedItems)){for(var i=0;i<this.selectedItems.length;i++){if(this.selectedItems[i]===currentItem){this.set("selectedItems."+i,value);break}}}else if(this.selectedItem===currentItem){this.set("selectedItem",value)}el._templateInstance[this.as]=value}},_itemsChanged:function(change){if(change.path==="items"){this._virtualStart=0;this._physicalTop=0;this._virtualCount=this.items?this.items.length:0;this._collection=this.items?Polymer.Collection.get(this.items):null;this._physicalIndexForKey={};this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null;this._physicalCount=this._physicalCount||0;this._physicalItems=this._physicalItems||[];this._physicalSizes=this._physicalSizes||[];this._physicalStart=0;this._resetScrollPosition(0);this._removeFocusedItem();this._debounceTemplate(this._render)}else if(change.path==="items.splices"){this._adjustVirtualIndex(change.value.indexSplices);this._virtualCount=this.items?this.items.length:0;this._debounceTemplate(this._render)}else{this._forwardItemPath(change.path.split(".").slice(1).join("."),change.value)}},_adjustVirtualIndex:function(splices){splices.forEach(function(splice){splice.removed.forEach(this._removeItem,this);if(splice.index<this._virtualStart){var delta=Math.max(splice.addedCount-splice.removed.length,splice.index-this._virtualStart);this._virtualStart=this._virtualStart+delta;if(this._focusedIndex>=0){this._focusedIndex=this._focusedIndex+delta}}},this)},_removeItem:function(item){this.$.selector.deselect(item);if(this._focusedItem&&this._focusedItem._templateInstance[this.as]===item){this._removeFocusedItem()}},_iterateItems:function(fn,itemSet){var pidx,vidx,rtn,i;if(arguments.length===2&&itemSet){for(i=0;i<itemSet.length;i++){pidx=itemSet[i];vidx=this._computeVidx(pidx);if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}}else{pidx=this._physicalStart;vidx=this._virtualStart;for(;pidx<this._physicalCount;pidx++,vidx++){if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}for(pidx=0;pidx<this._physicalStart;pidx++,vidx++){if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}}},_computeVidx:function(pidx){if(pidx>=this._physicalStart){return this._virtualStart+(pidx-this._physicalStart)}return this._virtualStart+(this._physicalCount-this._physicalStart)+pidx},_assignModels:function(itemSet){this._iterateItems(function(pidx,vidx){var el=this._physicalItems[pidx];var inst=el._templateInstance;var item=this.items&&this.items[vidx];if(item!=null){inst[this.as]=item;inst.__key__=this._collection.getKey(item);inst[this.selectedAs]=this.$.selector.isSelected(item);inst[this.indexAs]=vidx;inst.tabIndex=this._focusedIndex===vidx?0:-1;this._physicalIndexForKey[inst.__key__]=pidx;el.removeAttribute("hidden")}else{inst.__key__=null;el.setAttribute("hidden","")}},itemSet)},_updateMetrics:function(itemSet){Polymer.dom.flush();var newPhysicalSize=0;var oldPhysicalSize=0;var prevAvgCount=this._physicalAverageCount;var prevPhysicalAvg=this._physicalAverage;this._iterateItems(function(pidx,vidx){oldPhysicalSize+=this._physicalSizes[pidx]||0;this._physicalSizes[pidx]=this._physicalItems[pidx].offsetHeight;newPhysicalSize+=this._physicalSizes[pidx];this._physicalAverageCount+=this._physicalSizes[pidx]?1:0},itemSet);if(this.grid){this._updateGridMetrics();this._physicalSize=Math.ceil(this._physicalCount/this._itemsPerRow)*this._rowHeight}else{this._physicalSize=this._physicalSize+newPhysicalSize-oldPhysicalSize}if(this._physicalAverageCount!==prevAvgCount){this._physicalAverage=Math.round((prevPhysicalAvg*prevAvgCount+newPhysicalSize)/this._physicalAverageCount)}},_updateGridMetrics:function(){this._itemWidth=this._physicalCount>0?this._physicalItems[0].getBoundingClientRect().width:200;this._rowHeight=this._physicalCount>0?this._physicalItems[0].offsetHeight:200;this._itemsPerRow=this._itemWidth?Math.floor(this._viewportWidth/this._itemWidth):this._itemsPerRow},_positionItems:function(){this._adjustScrollPosition();var y=this._physicalTop;if(this.grid){var totalItemWidth=this._itemsPerRow*this._itemWidth;var rowOffset=(this._viewportWidth-totalItemWidth)/2;this._iterateItems(function(pidx,vidx){var modulus=vidx%this._itemsPerRow;var x=Math.floor(modulus*this._itemWidth+rowOffset);this.translate3d(x+"px",y+"px",0,this._physicalItems[pidx]);if(this._shouldRenderNextRow(vidx)){y+=this._rowHeight}})}else{this._iterateItems(function(pidx,vidx){this.translate3d(0,y+"px",0,this._physicalItems[pidx]);y+=this._physicalSizes[pidx]})}},_getPhysicalSizeIncrement:function(pidx){if(!this.grid){return this._physicalSizes[pidx]}if(this._computeVidx(pidx)%this._itemsPerRow!==this._itemsPerRow-1){return 0}return this._rowHeight},_shouldRenderNextRow:function(vidx){return vidx%this._itemsPerRow===this._itemsPerRow-1},_adjustScrollPosition:function(){var deltaHeight=this._virtualStart===0?this._physicalTop:Math.min(this._scrollPosition+this._physicalTop,0);if(deltaHeight){this._physicalTop=this._physicalTop-deltaHeight;if(!IOS_TOUCH_SCROLLING&&this._physicalTop!==0){this._resetScrollPosition(this._scrollTop-deltaHeight)}}},_resetScrollPosition:function(pos){if(this.scrollTarget){this._scrollTop=pos;this._scrollPosition=this._scrollTop}},_updateScrollerSize:function(forceUpdate){if(this.grid){this._estScrollHeight=this._virtualRowCount*this._rowHeight}else{this._estScrollHeight=this._physicalBottom+Math.max(this._virtualCount-this._physicalCount-this._virtualStart,0)*this._physicalAverage}forceUpdate=forceUpdate||this._scrollHeight===0;forceUpdate=forceUpdate||this._scrollPosition>=this._estScrollHeight-this._physicalSize;forceUpdate=forceUpdate||this.grid&&this.$.items.style.height<this._estScrollHeight;if(forceUpdate||Math.abs(this._estScrollHeight-this._scrollHeight)>=this._optPhysicalSize){this.$.items.style.height=this._estScrollHeight+"px";this._scrollHeight=this._estScrollHeight}},scrollToItem:function(item){return this.scrollToIndex(this.items.indexOf(item))},scrollToIndex:function(idx){if(typeof idx!=="number"||idx<0||idx>this.items.length-1){return}Polymer.dom.flush();if(this._physicalCount===0){return}idx=Math.min(Math.max(idx,0),this._virtualCount-1);if(!this._isIndexRendered(idx)||idx>=this._maxVirtualStart){this._virtualStart=this.grid?idx-this._itemsPerRow*2:idx-1}this._manageFocus();this._assignModels();this._updateMetrics();this._physicalTop=Math.floor(this._virtualStart/this._itemsPerRow)*this._physicalAverage;var currentTopItem=this._physicalStart;var currentVirtualItem=this._virtualStart;var targetOffsetTop=0;var hiddenContentSize=this._hiddenContentSize;while(currentVirtualItem<idx&&targetOffsetTop<=hiddenContentSize){targetOffsetTop=targetOffsetTop+this._getPhysicalSizeIncrement(currentTopItem);currentTopItem=(currentTopItem+1)%this._physicalCount;currentVirtualItem++}this._updateScrollerSize(true);this._positionItems();this._resetScrollPosition(this._physicalTop+this._scrollerPaddingTop+targetOffsetTop);this._increasePoolIfNeeded();this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null},_resetAverage:function(){this._physicalAverage=0;this._physicalAverageCount=0},_resizeHandler:function(){var delta=Math.abs(this._viewportHeight-this._scrollTargetHeight);if(IOS&&delta>0&&delta<100){return}Polymer.dom.addDebouncer(this.debounce("_debounceTemplate",function(){this.updateViewportBoundaries();this._render();if(this._isVisible){this.toggleScrollListener(true);if(this._physicalCount>0){this._resetAverage();this.scrollToIndex(this.firstVisibleIndex)}}else{this.toggleScrollListener(false)}}.bind(this),1))},_getModelFromItem:function(item){var key=this._collection.getKey(item);var pidx=this._physicalIndexForKey[key];if(pidx!=null){return this._physicalItems[pidx]._templateInstance}return null},_getNormalizedItem:function(item){if(this._collection.getKey(item)===undefined){if(typeof item==="number"){item=this.items[item];if(!item){throw new RangeError("<item> not found")}return item}throw new TypeError("<item> should be a valid item")}return item},selectItem:function(item){item=this._getNormalizedItem(item);var model=this._getModelFromItem(item);if(!this.multiSelection&&this.selectedItem){this.deselectItem(this.selectedItem)}if(model){model[this.selectedAs]=true}this.$.selector.select(item);this.updateSizeForItem(item)},deselectItem:function(item){item=this._getNormalizedItem(item);var model=this._getModelFromItem(item);if(model){model[this.selectedAs]=false}this.$.selector.deselect(item);this.updateSizeForItem(item)},toggleSelectionForItem:function(item){item=this._getNormalizedItem(item);if(this.$.selector.isSelected(item)){this.deselectItem(item)}else{this.selectItem(item)}},clearSelection:function(){function unselect(item){var model=this._getModelFromItem(item);if(model){model[this.selectedAs]=false}}if(Array.isArray(this.selectedItems)){this.selectedItems.forEach(unselect,this)}else if(this.selectedItem){unselect.call(this,this.selectedItem)}this.$.selector.clearSelection()},_selectionEnabledChanged:function(selectionEnabled){var handler=selectionEnabled?this.listen:this.unlisten;handler.call(this,this,"tap","_selectionHandler")},_selectionHandler:function(e){var model=this.modelForElement(e.target);if(!model){return}var modelTabIndex,activeElTabIndex;var target=Polymer.dom(e).path[0];var activeEl=Polymer.dom(this.domHost?this.domHost.root:document).activeElement;var physicalItem=this._physicalItems[this._getPhysicalIndex(model[this.indexAs])]; -activeElTabIndex=activeEl?activeEl.tabIndex:-1;model.tabIndex=modelTabIndex;if(activeEl&&physicalItem!==activeEl&&physicalItem.contains(activeEl)&&activeElTabIndex!==SECRET_TABINDEX){return}this.toggleSelectionForItem(model[this.as])},_multiSelectionChanged:function(multiSelection){this.clearSelection();this.$.selector.multi=multiSelection},updateSizeForItem:function(item){item=this._getNormalizedItem(item);var key=this._collection.getKey(item);var pidx=this._physicalIndexForKey[key];if(pidx!=null){this._updateMetrics([pidx]);this._positionItems()}},_manageFocus:function(){var fidx=this._focusedIndex;if(fidx>=0&&fidx<this._virtualCount){if(this._isIndexRendered(fidx)){this._restoreFocusedItem()}else{this._createFocusBackfillItem()}}else if(this._virtualCount>0&&this._physicalCount>0){this._focusedIndex=this._virtualStart;this._focusedItem=this._physicalItems[this._physicalStart]}},_isIndexRendered:function(idx){return idx>=this._virtualStart&&idx<=this._virtualEnd},_isIndexVisible:function(idx){return idx>=this.firstVisibleIndex&&idx<=this.lastVisibleIndex},_getPhysicalIndex:function(idx){return this._physicalIndexForKey[this._collection.getKey(this._getNormalizedItem(idx))]},_focusPhysicalItem:function(idx){if(idx<0||idx>=this._virtualCount){return}this._restoreFocusedItem();if(!this._isIndexRendered(idx)){this.scrollToIndex(idx)}var physicalItem=this._physicalItems[this._getPhysicalIndex(idx)];var model=physicalItem._templateInstance;var focusable;model.tabIndex=SECRET_TABINDEX;if(physicalItem.tabIndex===SECRET_TABINDEX){focusable=physicalItem}if(!focusable){focusable=Polymer.dom(physicalItem).querySelector('[tabindex="'+SECRET_TABINDEX+'"]')}model.tabIndex=0;this._focusedIndex=idx;focusable&&focusable.focus()},_removeFocusedItem:function(){if(this._offscreenFocusedItem){Polymer.dom(this).removeChild(this._offscreenFocusedItem)}this._offscreenFocusedItem=null;this._focusBackfillItem=null;this._focusedItem=null;this._focusedIndex=-1},_createFocusBackfillItem:function(){var pidx,fidx=this._focusedIndex;if(this._offscreenFocusedItem||fidx<0){return}if(!this._focusBackfillItem){var stampedTemplate=this.stamp(null);this._focusBackfillItem=stampedTemplate.root.querySelector("*");Polymer.dom(this).appendChild(stampedTemplate.root)}pidx=this._getPhysicalIndex(fidx);if(pidx!=null){this._offscreenFocusedItem=this._physicalItems[pidx];this._physicalItems[pidx]=this._focusBackfillItem;this.translate3d(0,HIDDEN_Y,0,this._offscreenFocusedItem)}},_restoreFocusedItem:function(){var pidx,fidx=this._focusedIndex;if(!this._offscreenFocusedItem||this._focusedIndex<0){return}this._assignModels();pidx=this._getPhysicalIndex(fidx);if(pidx!=null){this._focusBackfillItem=this._physicalItems[pidx];this._physicalItems[pidx]=this._offscreenFocusedItem;this._offscreenFocusedItem=null;this.translate3d(0,HIDDEN_Y,0,this._focusBackfillItem)}},_didFocus:function(e){var targetModel=this.modelForElement(e.target);var focusedModel=this._focusedItem?this._focusedItem._templateInstance:null;var hasOffscreenFocusedItem=this._offscreenFocusedItem!==null;var fidx=this._focusedIndex;if(!targetModel||!focusedModel){return}if(focusedModel===targetModel){if(!this._isIndexVisible(fidx)){this.scrollToIndex(fidx)}}else{this._restoreFocusedItem();focusedModel.tabIndex=-1;targetModel.tabIndex=0;fidx=targetModel[this.indexAs];this._focusedIndex=fidx;this._focusedItem=this._physicalItems[this._getPhysicalIndex(fidx)];if(hasOffscreenFocusedItem&&!this._offscreenFocusedItem){this._update()}}},_didMoveUp:function(){this._focusPhysicalItem(this._focusedIndex-1)},_didMoveDown:function(e){e.detail.keyboardEvent.preventDefault();this._focusPhysicalItem(this._focusedIndex+1)},_didEnter:function(e){this._focusPhysicalItem(this._focusedIndex);this._selectionHandler(e.detail.keyboardEvent)}})})(); +if(target.localName==="input"||target.localName==="button"||target.localName==="select"){return}modelTabIndex=model.tabIndex;model.tabIndex=SECRET_TABINDEX;activeElTabIndex=activeEl?activeEl.tabIndex:-1;model.tabIndex=modelTabIndex;if(activeEl&&physicalItem!==activeEl&&physicalItem.contains(activeEl)&&activeElTabIndex!==SECRET_TABINDEX){return}this.toggleSelectionForItem(model[this.as])},_multiSelectionChanged:function(multiSelection){this.clearSelection();this.$.selector.multi=multiSelection},updateSizeForItem:function(item){item=this._getNormalizedItem(item);var key=this._collection.getKey(item);var pidx=this._physicalIndexForKey[key];if(pidx!=null){this._updateMetrics([pidx]);this._positionItems()}},_manageFocus:function(){var fidx=this._focusedIndex;if(fidx>=0&&fidx<this._virtualCount){if(this._isIndexRendered(fidx)){this._restoreFocusedItem()}else{this._createFocusBackfillItem()}}else if(this._virtualCount>0&&this._physicalCount>0){this._focusedIndex=this._virtualStart;this._focusedItem=this._physicalItems[this._physicalStart]}},_isIndexRendered:function(idx){return idx>=this._virtualStart&&idx<=this._virtualEnd},_isIndexVisible:function(idx){return idx>=this.firstVisibleIndex&&idx<=this.lastVisibleIndex},_getPhysicalIndex:function(idx){return this._physicalIndexForKey[this._collection.getKey(this._getNormalizedItem(idx))]},_focusPhysicalItem:function(idx){if(idx<0||idx>=this._virtualCount){return}this._restoreFocusedItem();if(!this._isIndexRendered(idx)){this.scrollToIndex(idx)}var physicalItem=this._physicalItems[this._getPhysicalIndex(idx)];var model=physicalItem._templateInstance;var focusable;model.tabIndex=SECRET_TABINDEX;if(physicalItem.tabIndex===SECRET_TABINDEX){focusable=physicalItem}if(!focusable){focusable=Polymer.dom(physicalItem).querySelector('[tabindex="'+SECRET_TABINDEX+'"]')}model.tabIndex=0;this._focusedIndex=idx;focusable&&focusable.focus()},_removeFocusedItem:function(){if(this._offscreenFocusedItem){Polymer.dom(this).removeChild(this._offscreenFocusedItem)}this._offscreenFocusedItem=null;this._focusBackfillItem=null;this._focusedItem=null;this._focusedIndex=-1},_createFocusBackfillItem:function(){var fidx=this._focusedIndex;var pidx=this._getPhysicalIndex(fidx);if(this._offscreenFocusedItem||pidx==null||fidx<0){return}if(!this._focusBackfillItem){var stampedTemplate=this.stamp(null);this._focusBackfillItem=stampedTemplate.root.querySelector("*");Polymer.dom(this).appendChild(stampedTemplate.root)}this._offscreenFocusedItem=this._physicalItems[pidx];this._offscreenFocusedItem._templateInstance.tabIndex=0;this._physicalItems[pidx]=this._focusBackfillItem;this.translate3d(0,HIDDEN_Y,0,this._offscreenFocusedItem)},_restoreFocusedItem:function(){var pidx,fidx=this._focusedIndex;if(!this._offscreenFocusedItem||this._focusedIndex<0){return}this._assignModels();pidx=this._getPhysicalIndex(fidx);if(pidx!=null){this._focusBackfillItem=this._physicalItems[pidx];this._focusBackfillItem._templateInstance.tabIndex=-1;this._physicalItems[pidx]=this._offscreenFocusedItem;this._offscreenFocusedItem=null;this.translate3d(0,HIDDEN_Y,0,this._focusBackfillItem)}},_didFocus:function(e){var targetModel=this.modelForElement(e.target);var focusedModel=this._focusedItem?this._focusedItem._templateInstance:null;var hasOffscreenFocusedItem=this._offscreenFocusedItem!==null;var fidx=this._focusedIndex;if(!targetModel||!focusedModel){return}if(focusedModel===targetModel){if(!this._isIndexVisible(fidx)){this.scrollToIndex(fidx)}}else{this._restoreFocusedItem();focusedModel.tabIndex=-1;targetModel.tabIndex=0;fidx=targetModel[this.indexAs];this._focusedIndex=fidx;this._focusedItem=this._physicalItems[this._getPhysicalIndex(fidx)];if(hasOffscreenFocusedItem&&!this._offscreenFocusedItem){this._update()}}},_didMoveUp:function(){this._focusPhysicalItem(this._focusedIndex-1)},_didMoveDown:function(e){e.detail.keyboardEvent.preventDefault();this._focusPhysicalItem(this._focusedIndex+1)},_didEnter:function(e){this._focusPhysicalItem(this._focusedIndex);this._selectionHandler(e.detail.keyboardEvent)}})})(); // 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. @@ -39,25 +39,24 @@ cr.define("downloads",function(){var DangerType={NOT_DANGEROUS:"NOT_DANGEROUS",D // Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -var ActionLink=document.registerElement("action-link",{prototype:{__proto__:HTMLAnchorElement.prototype,createdCallback:function(){this.tabIndex=this.disabled?-1:0;if(!this.hasAttribute("role"))this.setAttribute("role","link");this.addEventListener("keydown",function(e){if(!this.disabled&&e.key=="Enter"&&!this.href){window.setTimeout(this.click.bind(this),0)}});function preventDefault(e){e.preventDefault()}function removePreventDefault(){document.removeEventListener("selectstart",preventDefault);document.removeEventListener("mouseup",removePreventDefault)}this.addEventListener("mousedown",function(){document.addEventListener("selectstart",preventDefault);document.addEventListener("mouseup",removePreventDefault);if(document.activeElement!=this)this.classList.add("no-outline")});this.addEventListener("blur",function(){this.classList.remove("no-outline")})},set disabled(disabled){if(disabled)HTMLAnchorElement.prototype.setAttribute.call(this,"disabled","");else HTMLAnchorElement.prototype.removeAttribute.call(this,"disabled");this.tabIndex=disabled?-1:0},get disabled(){return this.hasAttribute("disabled")},setAttribute:function(attr,val){if(attr.toLowerCase()=="disabled")this.disabled=true;else HTMLAnchorElement.prototype.setAttribute.apply(this,arguments)},removeAttribute:function(attr){if(attr.toLowerCase()=="disabled")this.disabled=false;else HTMLAnchorElement.prototype.removeAttribute.apply(this,arguments)}},"extends":"a"});(function(){var metaDatas={};var metaArrays={};var singleton=null;Polymer.IronMeta=Polymer({is:"iron-meta",properties:{type:{type:String,value:"default",observer:"_typeChanged"},key:{type:String,observer:"_keyChanged"},value:{type:Object,notify:true,observer:"_valueChanged"},self:{type:Boolean,observer:"_selfChanged"},list:{type:Array,notify:true}},hostAttributes:{hidden:true},factoryImpl:function(config){if(config){for(var n in config){switch(n){case"type":case"key":case"value":this[n]=config[n];break}}}},created:function(){this._metaDatas=metaDatas;this._metaArrays=metaArrays},_keyChanged:function(key,old){this._resetRegistration(old)},_valueChanged:function(value){this._resetRegistration(this.key)},_selfChanged:function(self){if(self){this.value=this}},_typeChanged:function(type){this._unregisterKey(this.key);if(!metaDatas[type]){metaDatas[type]={}}this._metaData=metaDatas[type];if(!metaArrays[type]){metaArrays[type]=[]}this.list=metaArrays[type];this._registerKeyValue(this.key,this.value)},byKey:function(key){return this._metaData&&this._metaData[key]},_resetRegistration:function(oldKey){this._unregisterKey(oldKey);this._registerKeyValue(this.key,this.value)},_unregisterKey:function(key){this._unregister(key,this._metaData,this.list)},_registerKeyValue:function(key,value){this._register(key,value,this._metaData,this.list)},_register:function(key,value,data,list){if(key&&data&&value!==undefined){data[key]=value;list.push(value)}},_unregister:function(key,data,list){if(key&&data){if(key in data){var value=data[key];delete data[key];this.arrayDelete(list,value)}}}});Polymer.IronMeta.getIronMeta=function getIronMeta(){if(singleton===null){singleton=new Polymer.IronMeta}return singleton};Polymer.IronMetaQuery=Polymer({is:"iron-meta-query",properties:{type:{type:String,value:"default",observer:"_typeChanged"},key:{type:String,observer:"_keyChanged"},value:{type:Object,notify:true,readOnly:true},list:{type:Array,notify:true}},factoryImpl:function(config){if(config){for(var n in config){switch(n){case"type":case"key":this[n]=config[n];break}}}},created:function(){this._metaDatas=metaDatas;this._metaArrays=metaArrays},_keyChanged:function(key){this._setValue(this._metaData&&this._metaData[key])},_typeChanged:function(type){this._metaData=metaDatas[type];this.list=metaArrays[type];if(this.key){this._keyChanged(this.key)}},byKey:function(key){return this._metaData&&this._metaData[key]}})})();Polymer({is:"iron-icon",properties:{icon:{type:String,observer:"_iconChanged"},theme:{type:String,observer:"_updateIcon"},src:{type:String,observer:"_srcChanged"},_meta:{value:Polymer.Base.create("iron-meta",{type:"iconset"}),observer:"_updateIcon"}},_DEFAULT_ICONSET:"icons",_iconChanged:function(icon){var parts=(icon||"").split(":");this._iconName=parts.pop();this._iconsetName=parts.pop()||this._DEFAULT_ICONSET;this._updateIcon()},_srcChanged:function(src){this._updateIcon()},_usesIconset:function(){return this.icon||!this.src},_updateIcon:function(){if(this._usesIconset()){if(this._img&&this._img.parentNode){Polymer.dom(this.root).removeChild(this._img)}if(this._iconName===""){if(this._iconset){this._iconset.removeIcon(this)}}else if(this._iconsetName&&this._meta){this._iconset=this._meta.byKey(this._iconsetName);if(this._iconset){this._iconset.applyIcon(this,this._iconName,this.theme);this.unlisten(window,"iron-iconset-added","_updateIcon")}else{this.listen(window,"iron-iconset-added","_updateIcon")}}}else{if(this._iconset){this._iconset.removeIcon(this)}if(!this._img){this._img=document.createElement("img");this._img.style.width="100%";this._img.style.height="100%";this._img.draggable=false}this._img.src=this.src;Polymer.dom(this.root).appendChild(this._img)}}});Polymer.IronControlState={properties:{focused:{type:Boolean,value:false,notify:true,readOnly:true,reflectToAttribute:true},disabled:{type:Boolean,value:false,notify:true,observer:"_disabledChanged",reflectToAttribute:true},_oldTabIndex:{type:Number},_boundFocusBlurHandler:{type:Function,value:function(){return this._focusBlurHandler.bind(this)}}},observers:["_changedControlState(focused, disabled)"],ready:function(){this.addEventListener("focus",this._boundFocusBlurHandler,true);this.addEventListener("blur",this._boundFocusBlurHandler,true)},_focusBlurHandler:function(event){if(event.target===this){this._setFocused(event.type==="focus")}else if(!this.shadowRoot){var target=Polymer.dom(event).localTarget;if(!this.isLightDescendant(target)){this.fire(event.type,{sourceEvent:event},{node:this,bubbles:event.bubbles,cancelable:event.cancelable})}}},_disabledChanged:function(disabled,old){this.setAttribute("aria-disabled",disabled?"true":"false");this.style.pointerEvents=disabled?"none":"";if(disabled){this._oldTabIndex=this.tabIndex;this._setFocused(false);this.tabIndex=-1;this.blur()}else if(this._oldTabIndex!==undefined){this.tabIndex=this._oldTabIndex}},_changedControlState:function(){if(this._controlStateChanged){this._controlStateChanged()}}};Polymer.IronButtonStateImpl={properties:{pressed:{type:Boolean,readOnly:true,value:false,reflectToAttribute:true,observer:"_pressedChanged"},toggles:{type:Boolean,value:false,reflectToAttribute:true},active:{type:Boolean,value:false,notify:true,reflectToAttribute:true},pointerDown:{type:Boolean,readOnly:true,value:false},receivedFocusFromKeyboard:{type:Boolean,readOnly:true},ariaActiveAttribute:{type:String,value:"aria-pressed",observer:"_ariaActiveAttributeChanged"}},listeners:{down:"_downHandler",up:"_upHandler",tap:"_tapHandler"},observers:["_detectKeyboardFocus(focused)","_activeChanged(active, ariaActiveAttribute)"],keyBindings:{"enter:keydown":"_asyncClick","space:keydown":"_spaceKeyDownHandler","space:keyup":"_spaceKeyUpHandler"},_mouseEventRe:/^mouse/,_tapHandler:function(){if(this.toggles){this._userActivate(!this.active)}else{this.active=false}},_detectKeyboardFocus:function(focused){this._setReceivedFocusFromKeyboard(!this.pointerDown&&focused)},_userActivate:function(active){if(this.active!==active){this.active=active;this.fire("change")}},_downHandler:function(event){this._setPointerDown(true);this._setPressed(true);this._setReceivedFocusFromKeyboard(false)},_upHandler:function(){this._setPointerDown(false);this._setPressed(false)},_spaceKeyDownHandler:function(event){var keyboardEvent=event.detail.keyboardEvent;var target=Polymer.dom(keyboardEvent).localTarget;if(this.isLightDescendant(target))return;keyboardEvent.preventDefault();keyboardEvent.stopImmediatePropagation();this._setPressed(true)},_spaceKeyUpHandler:function(event){var keyboardEvent=event.detail.keyboardEvent;var target=Polymer.dom(keyboardEvent).localTarget;if(this.isLightDescendant(target))return;if(this.pressed){this._asyncClick()}this._setPressed(false)},_asyncClick:function(){this.async(function(){this.click()},1)},_pressedChanged:function(pressed){this._changedButtonState()},_ariaActiveAttributeChanged:function(value,oldValue){if(oldValue&&oldValue!=value&&this.hasAttribute(oldValue)){this.removeAttribute(oldValue)}},_activeChanged:function(active,ariaActiveAttribute){if(this.toggles){this.setAttribute(this.ariaActiveAttribute,active?"true":"false")}else{this.removeAttribute(this.ariaActiveAttribute)}this._changedButtonState()},_controlStateChanged:function(){if(this.disabled){this._setPressed(false)}else{this._changedButtonState()}},_changedButtonState:function(){if(this._buttonStateChanged){this._buttonStateChanged()}}};Polymer.IronButtonState=[Polymer.IronA11yKeysBehavior,Polymer.IronButtonStateImpl];(function(){var Utility={distance:function(x1,y1,x2,y2){var xDelta=x1-x2;var yDelta=y1-y2;return Math.sqrt(xDelta*xDelta+yDelta*yDelta)},now:window.performance&&window.performance.now?window.performance.now.bind(window.performance):Date.now};function ElementMetrics(element){this.element=element;this.width=this.boundingRect.width;this.height=this.boundingRect.height;this.size=Math.max(this.width,this.height)}ElementMetrics.prototype={get boundingRect(){return this.element.getBoundingClientRect()},furthestCornerDistanceFrom:function(x,y){var topLeft=Utility.distance(x,y,0,0);var topRight=Utility.distance(x,y,this.width,0);var bottomLeft=Utility.distance(x,y,0,this.height);var bottomRight=Utility.distance(x,y,this.width,this.height);return Math.max(topLeft,topRight,bottomLeft,bottomRight)}};function Ripple(element){this.element=element;this.color=window.getComputedStyle(element).color;this.wave=document.createElement("div");this.waveContainer=document.createElement("div");this.wave.style.backgroundColor=this.color;this.wave.classList.add("wave");this.waveContainer.classList.add("wave-container");Polymer.dom(this.waveContainer).appendChild(this.wave);this.resetInteractionState()}Ripple.MAX_RADIUS=300;Ripple.prototype={get recenters(){return this.element.recenters},get center(){return this.element.center},get mouseDownElapsed(){var elapsed;if(!this.mouseDownStart){return 0}elapsed=Utility.now()-this.mouseDownStart;if(this.mouseUpStart){elapsed-=this.mouseUpElapsed}return elapsed},get mouseUpElapsed(){return this.mouseUpStart?Utility.now()-this.mouseUpStart:0},get mouseDownElapsedSeconds(){return this.mouseDownElapsed/1e3},get mouseUpElapsedSeconds(){return this.mouseUpElapsed/1e3},get mouseInteractionSeconds(){return this.mouseDownElapsedSeconds+this.mouseUpElapsedSeconds},get initialOpacity(){return this.element.initialOpacity},get opacityDecayVelocity(){return this.element.opacityDecayVelocity},get radius(){var width2=this.containerMetrics.width*this.containerMetrics.width;var height2=this.containerMetrics.height*this.containerMetrics.height;var waveRadius=Math.min(Math.sqrt(width2+height2),Ripple.MAX_RADIUS)*1.1+5;var duration=1.1-.2*(waveRadius/Ripple.MAX_RADIUS);var timeNow=this.mouseInteractionSeconds/duration;var size=waveRadius*(1-Math.pow(80,-timeNow));return Math.abs(size)},get opacity(){if(!this.mouseUpStart){return this.initialOpacity}return Math.max(0,this.initialOpacity-this.mouseUpElapsedSeconds*this.opacityDecayVelocity)},get outerOpacity(){var outerOpacity=this.mouseUpElapsedSeconds*.3;var waveOpacity=this.opacity;return Math.max(0,Math.min(outerOpacity,waveOpacity))},get isOpacityFullyDecayed(){return this.opacity<.01&&this.radius>=Math.min(this.maxRadius,Ripple.MAX_RADIUS)},get isRestingAtMaxRadius(){return this.opacity>=this.initialOpacity&&this.radius>=Math.min(this.maxRadius,Ripple.MAX_RADIUS)},get isAnimationComplete(){return this.mouseUpStart?this.isOpacityFullyDecayed:this.isRestingAtMaxRadius},get translationFraction(){return Math.min(1,this.radius/this.containerMetrics.size*2/Math.sqrt(2))},get xNow(){if(this.xEnd){return this.xStart+this.translationFraction*(this.xEnd-this.xStart)}return this.xStart},get yNow(){if(this.yEnd){return this.yStart+this.translationFraction*(this.yEnd-this.yStart)}return this.yStart},get isMouseDown(){return this.mouseDownStart&&!this.mouseUpStart},resetInteractionState:function(){this.maxRadius=0;this.mouseDownStart=0;this.mouseUpStart=0;this.xStart=0;this.yStart=0;this.xEnd=0;this.yEnd=0;this.slideDistance=0;this.containerMetrics=new ElementMetrics(this.element)},draw:function(){var scale;var translateString;var dx;var dy;this.wave.style.opacity=this.opacity;scale=this.radius/(this.containerMetrics.size/2);dx=this.xNow-this.containerMetrics.width/2;dy=this.yNow-this.containerMetrics.height/2;this.waveContainer.style.webkitTransform="translate("+dx+"px, "+dy+"px)";this.waveContainer.style.transform="translate3d("+dx+"px, "+dy+"px, 0)";this.wave.style.webkitTransform="scale("+scale+","+scale+")";this.wave.style.transform="scale3d("+scale+","+scale+",1)"},downAction:function(event){var xCenter=this.containerMetrics.width/2;var yCenter=this.containerMetrics.height/2;this.resetInteractionState();this.mouseDownStart=Utility.now();if(this.center){this.xStart=xCenter;this.yStart=yCenter;this.slideDistance=Utility.distance(this.xStart,this.yStart,this.xEnd,this.yEnd)}else{this.xStart=event?event.detail.x-this.containerMetrics.boundingRect.left:this.containerMetrics.width/2;this.yStart=event?event.detail.y-this.containerMetrics.boundingRect.top:this.containerMetrics.height/2}if(this.recenters){this.xEnd=xCenter;this.yEnd=yCenter;this.slideDistance=Utility.distance(this.xStart,this.yStart,this.xEnd,this.yEnd)}this.maxRadius=this.containerMetrics.furthestCornerDistanceFrom(this.xStart,this.yStart);this.waveContainer.style.top=(this.containerMetrics.height-this.containerMetrics.size)/2+"px";this.waveContainer.style.left=(this.containerMetrics.width-this.containerMetrics.size)/2+"px";this.waveContainer.style.width=this.containerMetrics.size+"px";this.waveContainer.style.height=this.containerMetrics.size+"px"},upAction:function(event){if(!this.isMouseDown){return}this.mouseUpStart=Utility.now()},remove:function(){Polymer.dom(this.waveContainer.parentNode).removeChild(this.waveContainer)}};Polymer({is:"paper-ripple",behaviors:[Polymer.IronA11yKeysBehavior],properties:{initialOpacity:{type:Number,value:.25},opacityDecayVelocity:{type:Number,value:.8},recenters:{type:Boolean,value:false},center:{type:Boolean,value:false},ripples:{type:Array,value:function(){return[]}},animating:{type:Boolean,readOnly:true,reflectToAttribute:true,value:false},holdDown:{type:Boolean,value:false,observer:"_holdDownChanged"},noink:{type:Boolean,value:false},_animating:{type:Boolean},_boundAnimate:{type:Function,value:function(){return this.animate.bind(this)}}},get target(){return this.keyEventTarget},keyBindings:{"enter:keydown":"_onEnterKeydown","space:keydown":"_onSpaceKeydown","space:keyup":"_onSpaceKeyup"},attached:function(){if(this.parentNode.nodeType==11){this.keyEventTarget=Polymer.dom(this).getOwnerRoot().host}else{this.keyEventTarget=this.parentNode}var keyEventTarget=this.keyEventTarget;this.listen(keyEventTarget,"up","uiUpAction");this.listen(keyEventTarget,"down","uiDownAction")},detached:function(){this.unlisten(this.keyEventTarget,"up","uiUpAction");this.unlisten(this.keyEventTarget,"down","uiDownAction");this.keyEventTarget=null},get shouldKeepAnimating(){for(var index=0;index<this.ripples.length;++index){if(!this.ripples[index].isAnimationComplete){return true}}return false},simulatedRipple:function(){this.downAction(null);this.async(function(){this.upAction()},1)},uiDownAction:function(event){if(!this.noink){this.downAction(event)}},downAction:function(event){if(this.holdDown&&this.ripples.length>0){return}var ripple=this.addRipple();ripple.downAction(event);if(!this._animating){this._animating=true;this.animate()}},uiUpAction:function(event){if(!this.noink){this.upAction(event)}},upAction:function(event){if(this.holdDown){return}this.ripples.forEach(function(ripple){ripple.upAction(event)});this._animating=true;this.animate()},onAnimationComplete:function(){this._animating=false;this.$.background.style.backgroundColor=null;this.fire("transitionend")},addRipple:function(){var ripple=new Ripple(this);Polymer.dom(this.$.waves).appendChild(ripple.waveContainer);this.$.background.style.backgroundColor=ripple.color;this.ripples.push(ripple);this._setAnimating(true);return ripple},removeRipple:function(ripple){var rippleIndex=this.ripples.indexOf(ripple);if(rippleIndex<0){return}this.ripples.splice(rippleIndex,1);ripple.remove();if(!this.ripples.length){this._setAnimating(false)}},animate:function(){if(!this._animating){return}var index;var ripple;for(index=0;index<this.ripples.length;++index){ripple=this.ripples[index];ripple.draw();this.$.background.style.opacity=ripple.outerOpacity;if(ripple.isOpacityFullyDecayed&&!ripple.isRestingAtMaxRadius){this.removeRipple(ripple)}}if(!this.shouldKeepAnimating&&this.ripples.length===0){this.onAnimationComplete()}else{window.requestAnimationFrame(this._boundAnimate)}},_onEnterKeydown:function(){this.uiDownAction();this.async(this.uiUpAction,1)},_onSpaceKeydown:function(){this.uiDownAction()},_onSpaceKeyup:function(){this.uiUpAction()},_holdDownChanged:function(newVal,oldVal){if(oldVal===undefined){return}if(newVal){this.downAction()}else{this.upAction()}}})})();Polymer.PaperRippleBehavior={properties:{noink:{type:Boolean,observer:"_noinkChanged"},_rippleContainer:{type:Object}},_buttonStateChanged:function(){if(this.focused){this.ensureRipple()}},_downHandler:function(event){Polymer.IronButtonStateImpl._downHandler.call(this,event);if(this.pressed){this.ensureRipple(event)}},ensureRipple:function(optTriggeringEvent){if(!this.hasRipple()){this._ripple=this._createRipple();this._ripple.noink=this.noink;var rippleContainer=this._rippleContainer||this.root;if(rippleContainer){Polymer.dom(rippleContainer).appendChild(this._ripple)}if(optTriggeringEvent){var domContainer=Polymer.dom(this._rippleContainer||this);var target=Polymer.dom(optTriggeringEvent).rootTarget;if(domContainer.deepContains(target)){this._ripple.uiDownAction(optTriggeringEvent)}}}},getRipple:function(){this.ensureRipple();return this._ripple},hasRipple:function(){return Boolean(this._ripple)},_createRipple:function(){return document.createElement("paper-ripple")},_noinkChanged:function(noink){if(this.hasRipple()){this._ripple.noink=noink}}};Polymer.PaperButtonBehaviorImpl={properties:{elevation:{type:Number,reflectToAttribute:true,readOnly:true}},observers:["_calculateElevation(focused, disabled, active, pressed, receivedFocusFromKeyboard)","_computeKeyboardClass(receivedFocusFromKeyboard)"],hostAttributes:{role:"button",tabindex:"0",animated:true},_calculateElevation:function(){var e=1;if(this.disabled){e=0}else if(this.active||this.pressed){e=4}else if(this.receivedFocusFromKeyboard){e=3}this._setElevation(e)},_computeKeyboardClass:function(receivedFocusFromKeyboard){this.toggleClass("keyboard-focus",receivedFocusFromKeyboard)},_spaceKeyDownHandler:function(event){Polymer.IronButtonStateImpl._spaceKeyDownHandler.call(this,event);if(this.hasRipple()&&this.getRipple().ripples.length<1){this._ripple.uiDownAction()}},_spaceKeyUpHandler:function(event){Polymer.IronButtonStateImpl._spaceKeyUpHandler.call(this,event);if(this.hasRipple()){this._ripple.uiUpAction()}}};Polymer.PaperButtonBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperRippleBehavior,Polymer.PaperButtonBehaviorImpl];Polymer({is:"paper-button",behaviors:[Polymer.PaperButtonBehavior],properties:{raised:{type:Boolean,reflectToAttribute:true,value:false,observer:"_calculateElevation"}},_calculateElevation:function(){if(!this.raised){this._setElevation(0)}else{Polymer.PaperButtonBehaviorImpl._calculateElevation.apply(this)}}});Polymer({is:"paper-icon-button-light","extends":"button",behaviors:[Polymer.PaperRippleBehavior],listeners:{down:"_rippleDown",up:"_rippleUp",focus:"_rippleDown",blur:"_rippleUp"},_rippleDown:function(){this.getRipple().downAction()},_rippleUp:function(){this.getRipple().upAction()},ensureRipple:function(var_args){var lastRipple=this._ripple;Polymer.PaperRippleBehavior.ensureRipple.apply(this,arguments);if(this._ripple&&this._ripple!==lastRipple){this._ripple.center=true;this._ripple.classList.add("circle")}}});Polymer.IronRangeBehavior={properties:{value:{type:Number,value:0,notify:true,reflectToAttribute:true},min:{type:Number,value:0,notify:true},max:{type:Number,value:100,notify:true},step:{type:Number,value:1,notify:true},ratio:{type:Number,value:0,readOnly:true,notify:true}},observers:["_update(value, min, max, step)"],_calcRatio:function(value){return(this._clampValue(value)-this.min)/(this.max-this.min)},_clampValue:function(value){return Math.min(this.max,Math.max(this.min,this._calcStep(value)))},_calcStep:function(value){value=parseFloat(value);if(!this.step){return value}var numSteps=Math.round((value-this.min)/this.step);if(this.step<1){return numSteps/(1/this.step)+this.min}else{return numSteps*this.step+this.min}},_validateValue:function(){var v=this._clampValue(this.value);this.value=this.oldValue=isNaN(v)?this.oldValue:v;return this.value!==v},_update:function(){this._validateValue();this._setRatio(this._calcRatio(this.value)*100)}};Polymer({is:"paper-progress",behaviors:[Polymer.IronRangeBehavior],properties:{secondaryProgress:{type:Number,value:0},secondaryRatio:{type:Number,value:0,readOnly:true},indeterminate:{type:Boolean,value:false,observer:"_toggleIndeterminate"},disabled:{type:Boolean,value:false,reflectToAttribute:true,observer:"_disabledChanged"}},observers:["_progressChanged(secondaryProgress, value, min, max)"],hostAttributes:{role:"progressbar"},_toggleIndeterminate:function(indeterminate){this.toggleClass("indeterminate",indeterminate,this.$.primaryProgress)},_transformProgress:function(progress,ratio){var transform="scaleX("+ratio/100+")";progress.style.transform=progress.style.webkitTransform=transform},_mainRatioChanged:function(ratio){this._transformProgress(this.$.primaryProgress,ratio)},_progressChanged:function(secondaryProgress,value,min,max){secondaryProgress=this._clampValue(secondaryProgress);value=this._clampValue(value);var secondaryRatio=this._calcRatio(secondaryProgress)*100;var mainRatio=this._calcRatio(value)*100;this._setSecondaryRatio(secondaryRatio);this._transformProgress(this.$.secondaryProgress,secondaryRatio);this._transformProgress(this.$.primaryProgress,mainRatio);this.secondaryProgress=secondaryProgress;this.setAttribute("aria-valuenow",value);this.setAttribute("aria-valuemin",min);this.setAttribute("aria-valuemax",max)},_disabledChanged:function(disabled){this.setAttribute("aria-disabled",disabled?"true":"false")},_hideSecondaryProgress:function(secondaryRatio){return secondaryRatio===0}});Polymer({is:"iron-iconset-svg",properties:{name:{type:String,observer:"_nameChanged"},size:{type:Number,value:24}},attached:function(){this.style.display="none"},getIconNames:function(){this._icons=this._createIconMap();return Object.keys(this._icons).map(function(n){return this.name+":"+n},this)},applyIcon:function(element,iconName){element=element.root||element;this.removeIcon(element);var svg=this._cloneIcon(iconName);if(svg){var pde=Polymer.dom(element);pde.insertBefore(svg,pde.childNodes[0]);return element._svgIcon=svg}return null},removeIcon:function(element){if(element._svgIcon){Polymer.dom(element).removeChild(element._svgIcon);element._svgIcon=null}},_nameChanged:function(){new Polymer.IronMeta({type:"iconset",key:this.name,value:this});this.async(function(){this.fire("iron-iconset-added",this,{node:window})})},_createIconMap:function(){var icons=Object.create(null);Polymer.dom(this).querySelectorAll("[id]").forEach(function(icon){icons[icon.id]=icon});return icons},_cloneIcon:function(id){this._icons=this._icons||this._createIconMap();return this._prepareSvgClone(this._icons[id],this.size)},_prepareSvgClone:function(sourceSvg,size){if(sourceSvg){var content=sourceSvg.cloneNode(true),svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),viewBox=content.getAttribute("viewBox")||"0 0 "+size+" "+size;svg.setAttribute("viewBox",viewBox);svg.setAttribute("preserveAspectRatio","xMidYMid meet");svg.style.cssText="pointer-events: none; display: block; width: 100%; height: 100%;";svg.appendChild(content).removeAttribute("id");return svg}return null}}); +var ActionLink=document.registerElement("action-link",{prototype:{__proto__:HTMLAnchorElement.prototype,createdCallback:function(){this.tabIndex=this.disabled?-1:0;if(!this.hasAttribute("role"))this.setAttribute("role","link");this.addEventListener("keydown",function(e){if(!this.disabled&&e.key=="Enter"&&!this.href){window.setTimeout(this.click.bind(this),0)}});function preventDefault(e){e.preventDefault()}function removePreventDefault(){document.removeEventListener("selectstart",preventDefault);document.removeEventListener("mouseup",removePreventDefault)}this.addEventListener("mousedown",function(){document.addEventListener("selectstart",preventDefault);document.addEventListener("mouseup",removePreventDefault);if(document.activeElement!=this)this.classList.add("no-outline")});this.addEventListener("blur",function(){this.classList.remove("no-outline")})},set disabled(disabled){if(disabled)HTMLAnchorElement.prototype.setAttribute.call(this,"disabled","");else HTMLAnchorElement.prototype.removeAttribute.call(this,"disabled");this.tabIndex=disabled?-1:0},get disabled(){return this.hasAttribute("disabled")},setAttribute:function(attr,val){if(attr.toLowerCase()=="disabled")this.disabled=true;else HTMLAnchorElement.prototype.setAttribute.apply(this,arguments)},removeAttribute:function(attr){if(attr.toLowerCase()=="disabled")this.disabled=false;else HTMLAnchorElement.prototype.removeAttribute.apply(this,arguments)}},"extends":"a"});(function(){var metaDatas={};var metaArrays={};var singleton=null;Polymer.IronMeta=Polymer({is:"iron-meta",properties:{type:{type:String,value:"default",observer:"_typeChanged"},key:{type:String,observer:"_keyChanged"},value:{type:Object,notify:true,observer:"_valueChanged"},self:{type:Boolean,observer:"_selfChanged"},list:{type:Array,notify:true}},hostAttributes:{hidden:true},factoryImpl:function(config){if(config){for(var n in config){switch(n){case"type":case"key":case"value":this[n]=config[n];break}}}},created:function(){this._metaDatas=metaDatas;this._metaArrays=metaArrays},_keyChanged:function(key,old){this._resetRegistration(old)},_valueChanged:function(value){this._resetRegistration(this.key)},_selfChanged:function(self){if(self){this.value=this}},_typeChanged:function(type){this._unregisterKey(this.key);if(!metaDatas[type]){metaDatas[type]={}}this._metaData=metaDatas[type];if(!metaArrays[type]){metaArrays[type]=[]}this.list=metaArrays[type];this._registerKeyValue(this.key,this.value)},byKey:function(key){return this._metaData&&this._metaData[key]},_resetRegistration:function(oldKey){this._unregisterKey(oldKey);this._registerKeyValue(this.key,this.value)},_unregisterKey:function(key){this._unregister(key,this._metaData,this.list)},_registerKeyValue:function(key,value){this._register(key,value,this._metaData,this.list)},_register:function(key,value,data,list){if(key&&data&&value!==undefined){data[key]=value;list.push(value)}},_unregister:function(key,data,list){if(key&&data){if(key in data){var value=data[key];delete data[key];this.arrayDelete(list,value)}}}});Polymer.IronMeta.getIronMeta=function getIronMeta(){if(singleton===null){singleton=new Polymer.IronMeta}return singleton};Polymer.IronMetaQuery=Polymer({is:"iron-meta-query",properties:{type:{type:String,value:"default",observer:"_typeChanged"},key:{type:String,observer:"_keyChanged"},value:{type:Object,notify:true,readOnly:true},list:{type:Array,notify:true}},factoryImpl:function(config){if(config){for(var n in config){switch(n){case"type":case"key":this[n]=config[n];break}}}},created:function(){this._metaDatas=metaDatas;this._metaArrays=metaArrays},_keyChanged:function(key){this._setValue(this._metaData&&this._metaData[key])},_typeChanged:function(type){this._metaData=metaDatas[type];this.list=metaArrays[type];if(this.key){this._keyChanged(this.key)}},byKey:function(key){return this._metaData&&this._metaData[key]}})})();Polymer({is:"iron-icon",properties:{icon:{type:String,observer:"_iconChanged"},theme:{type:String,observer:"_updateIcon"},src:{type:String,observer:"_srcChanged"},_meta:{value:Polymer.Base.create("iron-meta",{type:"iconset"}),observer:"_updateIcon"}},_DEFAULT_ICONSET:"icons",_iconChanged:function(icon){var parts=(icon||"").split(":");this._iconName=parts.pop();this._iconsetName=parts.pop()||this._DEFAULT_ICONSET;this._updateIcon()},_srcChanged:function(src){this._updateIcon()},_usesIconset:function(){return this.icon||!this.src},_updateIcon:function(){if(this._usesIconset()){if(this._img&&this._img.parentNode){Polymer.dom(this.root).removeChild(this._img)}if(this._iconName===""){if(this._iconset){this._iconset.removeIcon(this)}}else if(this._iconsetName&&this._meta){this._iconset=this._meta.byKey(this._iconsetName);if(this._iconset){this._iconset.applyIcon(this,this._iconName,this.theme);this.unlisten(window,"iron-iconset-added","_updateIcon")}else{this.listen(window,"iron-iconset-added","_updateIcon")}}}else{if(this._iconset){this._iconset.removeIcon(this)}if(!this._img){this._img=document.createElement("img");this._img.style.width="100%";this._img.style.height="100%";this._img.draggable=false}this._img.src=this.src;Polymer.dom(this.root).appendChild(this._img)}}});Polymer.IronControlState={properties:{focused:{type:Boolean,value:false,notify:true,readOnly:true,reflectToAttribute:true},disabled:{type:Boolean,value:false,notify:true,observer:"_disabledChanged",reflectToAttribute:true},_oldTabIndex:{type:Number},_boundFocusBlurHandler:{type:Function,value:function(){return this._focusBlurHandler.bind(this)}}},observers:["_changedControlState(focused, disabled)"],ready:function(){this.addEventListener("focus",this._boundFocusBlurHandler,true);this.addEventListener("blur",this._boundFocusBlurHandler,true)},_focusBlurHandler:function(event){if(event.target===this){this._setFocused(event.type==="focus")}else if(!this.shadowRoot){var target=Polymer.dom(event).localTarget;if(!this.isLightDescendant(target)){this.fire(event.type,{sourceEvent:event},{node:this,bubbles:event.bubbles,cancelable:event.cancelable})}}},_disabledChanged:function(disabled,old){this.setAttribute("aria-disabled",disabled?"true":"false");this.style.pointerEvents=disabled?"none":"";if(disabled){this._oldTabIndex=this.tabIndex;this._setFocused(false);this.tabIndex=-1;this.blur()}else if(this._oldTabIndex!==undefined){this.tabIndex=this._oldTabIndex}},_changedControlState:function(){if(this._controlStateChanged){this._controlStateChanged()}}};Polymer.IronButtonStateImpl={properties:{pressed:{type:Boolean,readOnly:true,value:false,reflectToAttribute:true,observer:"_pressedChanged"},toggles:{type:Boolean,value:false,reflectToAttribute:true},active:{type:Boolean,value:false,notify:true,reflectToAttribute:true},pointerDown:{type:Boolean,readOnly:true,value:false},receivedFocusFromKeyboard:{type:Boolean,readOnly:true},ariaActiveAttribute:{type:String,value:"aria-pressed",observer:"_ariaActiveAttributeChanged"}},listeners:{down:"_downHandler",up:"_upHandler",tap:"_tapHandler"},observers:["_detectKeyboardFocus(focused)","_activeChanged(active, ariaActiveAttribute)"],keyBindings:{"enter:keydown":"_asyncClick","space:keydown":"_spaceKeyDownHandler","space:keyup":"_spaceKeyUpHandler"},_mouseEventRe:/^mouse/,_tapHandler:function(){if(this.toggles){this._userActivate(!this.active)}else{this.active=false}},_detectKeyboardFocus:function(focused){this._setReceivedFocusFromKeyboard(!this.pointerDown&&focused)},_userActivate:function(active){if(this.active!==active){this.active=active;this.fire("change")}},_downHandler:function(event){this._setPointerDown(true);this._setPressed(true);this._setReceivedFocusFromKeyboard(false)},_upHandler:function(){this._setPointerDown(false);this._setPressed(false)},_spaceKeyDownHandler:function(event){var keyboardEvent=event.detail.keyboardEvent;var target=Polymer.dom(keyboardEvent).localTarget;if(this.isLightDescendant(target))return;keyboardEvent.preventDefault();keyboardEvent.stopImmediatePropagation();this._setPressed(true)},_spaceKeyUpHandler:function(event){var keyboardEvent=event.detail.keyboardEvent;var target=Polymer.dom(keyboardEvent).localTarget;if(this.isLightDescendant(target))return;if(this.pressed){this._asyncClick()}this._setPressed(false)},_asyncClick:function(){this.async(function(){this.click()},1)},_pressedChanged:function(pressed){this._changedButtonState()},_ariaActiveAttributeChanged:function(value,oldValue){if(oldValue&&oldValue!=value&&this.hasAttribute(oldValue)){this.removeAttribute(oldValue)}},_activeChanged:function(active,ariaActiveAttribute){if(this.toggles){this.setAttribute(this.ariaActiveAttribute,active?"true":"false")}else{this.removeAttribute(this.ariaActiveAttribute)}this._changedButtonState()},_controlStateChanged:function(){if(this.disabled){this._setPressed(false)}else{this._changedButtonState()}},_changedButtonState:function(){if(this._buttonStateChanged){this._buttonStateChanged()}}};Polymer.IronButtonState=[Polymer.IronA11yKeysBehavior,Polymer.IronButtonStateImpl];(function(){var Utility={distance:function(x1,y1,x2,y2){var xDelta=x1-x2;var yDelta=y1-y2;return Math.sqrt(xDelta*xDelta+yDelta*yDelta)},now:window.performance&&window.performance.now?window.performance.now.bind(window.performance):Date.now};function ElementMetrics(element){this.element=element;this.width=this.boundingRect.width;this.height=this.boundingRect.height;this.size=Math.max(this.width,this.height)}ElementMetrics.prototype={get boundingRect(){return this.element.getBoundingClientRect()},furthestCornerDistanceFrom:function(x,y){var topLeft=Utility.distance(x,y,0,0);var topRight=Utility.distance(x,y,this.width,0);var bottomLeft=Utility.distance(x,y,0,this.height);var bottomRight=Utility.distance(x,y,this.width,this.height);return Math.max(topLeft,topRight,bottomLeft,bottomRight)}};function Ripple(element){this.element=element;this.color=window.getComputedStyle(element).color;this.wave=document.createElement("div");this.waveContainer=document.createElement("div");this.wave.style.backgroundColor=this.color;this.wave.classList.add("wave");this.waveContainer.classList.add("wave-container");Polymer.dom(this.waveContainer).appendChild(this.wave);this.resetInteractionState()}Ripple.MAX_RADIUS=300;Ripple.prototype={get recenters(){return this.element.recenters},get center(){return this.element.center},get mouseDownElapsed(){var elapsed;if(!this.mouseDownStart){return 0}elapsed=Utility.now()-this.mouseDownStart;if(this.mouseUpStart){elapsed-=this.mouseUpElapsed}return elapsed},get mouseUpElapsed(){return this.mouseUpStart?Utility.now()-this.mouseUpStart:0},get mouseDownElapsedSeconds(){return this.mouseDownElapsed/1e3},get mouseUpElapsedSeconds(){return this.mouseUpElapsed/1e3},get mouseInteractionSeconds(){return this.mouseDownElapsedSeconds+this.mouseUpElapsedSeconds},get initialOpacity(){return this.element.initialOpacity},get opacityDecayVelocity(){return this.element.opacityDecayVelocity},get radius(){var width2=this.containerMetrics.width*this.containerMetrics.width;var height2=this.containerMetrics.height*this.containerMetrics.height;var waveRadius=Math.min(Math.sqrt(width2+height2),Ripple.MAX_RADIUS)*1.1+5;var duration=1.1-.2*(waveRadius/Ripple.MAX_RADIUS);var timeNow=this.mouseInteractionSeconds/duration;var size=waveRadius*(1-Math.pow(80,-timeNow));return Math.abs(size)},get opacity(){if(!this.mouseUpStart){return this.initialOpacity}return Math.max(0,this.initialOpacity-this.mouseUpElapsedSeconds*this.opacityDecayVelocity)},get outerOpacity(){var outerOpacity=this.mouseUpElapsedSeconds*.3;var waveOpacity=this.opacity;return Math.max(0,Math.min(outerOpacity,waveOpacity))},get isOpacityFullyDecayed(){return this.opacity<.01&&this.radius>=Math.min(this.maxRadius,Ripple.MAX_RADIUS)},get isRestingAtMaxRadius(){return this.opacity>=this.initialOpacity&&this.radius>=Math.min(this.maxRadius,Ripple.MAX_RADIUS)},get isAnimationComplete(){return this.mouseUpStart?this.isOpacityFullyDecayed:this.isRestingAtMaxRadius},get translationFraction(){return Math.min(1,this.radius/this.containerMetrics.size*2/Math.sqrt(2))},get xNow(){if(this.xEnd){return this.xStart+this.translationFraction*(this.xEnd-this.xStart)}return this.xStart},get yNow(){if(this.yEnd){return this.yStart+this.translationFraction*(this.yEnd-this.yStart)}return this.yStart},get isMouseDown(){return this.mouseDownStart&&!this.mouseUpStart},resetInteractionState:function(){this.maxRadius=0;this.mouseDownStart=0;this.mouseUpStart=0;this.xStart=0;this.yStart=0;this.xEnd=0;this.yEnd=0;this.slideDistance=0;this.containerMetrics=new ElementMetrics(this.element)},draw:function(){var scale;var translateString;var dx;var dy;this.wave.style.opacity=this.opacity;scale=this.radius/(this.containerMetrics.size/2);dx=this.xNow-this.containerMetrics.width/2;dy=this.yNow-this.containerMetrics.height/2;this.waveContainer.style.webkitTransform="translate("+dx+"px, "+dy+"px)";this.waveContainer.style.transform="translate3d("+dx+"px, "+dy+"px, 0)";this.wave.style.webkitTransform="scale("+scale+","+scale+")";this.wave.style.transform="scale3d("+scale+","+scale+",1)"},downAction:function(event){var xCenter=this.containerMetrics.width/2;var yCenter=this.containerMetrics.height/2;this.resetInteractionState();this.mouseDownStart=Utility.now();if(this.center){this.xStart=xCenter;this.yStart=yCenter;this.slideDistance=Utility.distance(this.xStart,this.yStart,this.xEnd,this.yEnd)}else{this.xStart=event?event.detail.x-this.containerMetrics.boundingRect.left:this.containerMetrics.width/2;this.yStart=event?event.detail.y-this.containerMetrics.boundingRect.top:this.containerMetrics.height/2}if(this.recenters){this.xEnd=xCenter;this.yEnd=yCenter;this.slideDistance=Utility.distance(this.xStart,this.yStart,this.xEnd,this.yEnd)}this.maxRadius=this.containerMetrics.furthestCornerDistanceFrom(this.xStart,this.yStart);this.waveContainer.style.top=(this.containerMetrics.height-this.containerMetrics.size)/2+"px";this.waveContainer.style.left=(this.containerMetrics.width-this.containerMetrics.size)/2+"px";this.waveContainer.style.width=this.containerMetrics.size+"px";this.waveContainer.style.height=this.containerMetrics.size+"px"},upAction:function(event){if(!this.isMouseDown){return}this.mouseUpStart=Utility.now()},remove:function(){Polymer.dom(this.waveContainer.parentNode).removeChild(this.waveContainer)}};Polymer({is:"paper-ripple",behaviors:[Polymer.IronA11yKeysBehavior],properties:{initialOpacity:{type:Number,value:.25},opacityDecayVelocity:{type:Number,value:.8},recenters:{type:Boolean,value:false},center:{type:Boolean,value:false},ripples:{type:Array,value:function(){return[]}},animating:{type:Boolean,readOnly:true,reflectToAttribute:true,value:false},holdDown:{type:Boolean,value:false,observer:"_holdDownChanged"},noink:{type:Boolean,value:false},_animating:{type:Boolean},_boundAnimate:{type:Function,value:function(){return this.animate.bind(this)}}},get target(){return this.keyEventTarget},keyBindings:{"enter:keydown":"_onEnterKeydown","space:keydown":"_onSpaceKeydown","space:keyup":"_onSpaceKeyup"},attached:function(){if(this.parentNode.nodeType==11){this.keyEventTarget=Polymer.dom(this).getOwnerRoot().host}else{this.keyEventTarget=this.parentNode}var keyEventTarget=this.keyEventTarget;this.listen(keyEventTarget,"up","uiUpAction");this.listen(keyEventTarget,"down","uiDownAction")},detached:function(){this.unlisten(this.keyEventTarget,"up","uiUpAction");this.unlisten(this.keyEventTarget,"down","uiDownAction");this.keyEventTarget=null},get shouldKeepAnimating(){for(var index=0;index<this.ripples.length;++index){if(!this.ripples[index].isAnimationComplete){return true}}return false},simulatedRipple:function(){this.downAction(null);this.async(function(){this.upAction()},1)},uiDownAction:function(event){if(!this.noink){this.downAction(event)}},downAction:function(event){if(this.holdDown&&this.ripples.length>0){return}var ripple=this.addRipple();ripple.downAction(event);if(!this._animating){this._animating=true;this.animate()}},uiUpAction:function(event){if(!this.noink){this.upAction(event)}},upAction:function(event){if(this.holdDown){return}this.ripples.forEach(function(ripple){ripple.upAction(event)});this._animating=true;this.animate()},onAnimationComplete:function(){this._animating=false;this.$.background.style.backgroundColor=null;this.fire("transitionend")},addRipple:function(){var ripple=new Ripple(this);Polymer.dom(this.$.waves).appendChild(ripple.waveContainer);this.$.background.style.backgroundColor=ripple.color;this.ripples.push(ripple);this._setAnimating(true);return ripple},removeRipple:function(ripple){var rippleIndex=this.ripples.indexOf(ripple);if(rippleIndex<0){return}this.ripples.splice(rippleIndex,1);ripple.remove();if(!this.ripples.length){this._setAnimating(false)}},animate:function(){if(!this._animating){return}var index;var ripple;for(index=0;index<this.ripples.length;++index){ripple=this.ripples[index];ripple.draw();this.$.background.style.opacity=ripple.outerOpacity;if(ripple.isOpacityFullyDecayed&&!ripple.isRestingAtMaxRadius){this.removeRipple(ripple)}}if(!this.shouldKeepAnimating&&this.ripples.length===0){this.onAnimationComplete()}else{window.requestAnimationFrame(this._boundAnimate)}},_onEnterKeydown:function(){this.uiDownAction();this.async(this.uiUpAction,1)},_onSpaceKeydown:function(){this.uiDownAction()},_onSpaceKeyup:function(){this.uiUpAction()},_holdDownChanged:function(newVal,oldVal){if(oldVal===undefined){return}if(newVal){this.downAction()}else{this.upAction()}}})})();Polymer.PaperRippleBehavior={properties:{noink:{type:Boolean,observer:"_noinkChanged"},_rippleContainer:{type:Object}},_buttonStateChanged:function(){if(this.focused){this.ensureRipple()}},_downHandler:function(event){Polymer.IronButtonStateImpl._downHandler.call(this,event);if(this.pressed){this.ensureRipple(event)}},ensureRipple:function(optTriggeringEvent){if(!this.hasRipple()){this._ripple=this._createRipple();this._ripple.noink=this.noink;var rippleContainer=this._rippleContainer||this.root;if(rippleContainer){Polymer.dom(rippleContainer).appendChild(this._ripple)}if(optTriggeringEvent){var domContainer=Polymer.dom(this._rippleContainer||this);var target=Polymer.dom(optTriggeringEvent).rootTarget;if(domContainer.deepContains(target)){this._ripple.uiDownAction(optTriggeringEvent)}}}},getRipple:function(){this.ensureRipple();return this._ripple},hasRipple:function(){return Boolean(this._ripple)},_createRipple:function(){return document.createElement("paper-ripple")},_noinkChanged:function(noink){if(this.hasRipple()){this._ripple.noink=noink}}};Polymer.PaperButtonBehaviorImpl={properties:{elevation:{type:Number,reflectToAttribute:true,readOnly:true}},observers:["_calculateElevation(focused, disabled, active, pressed, receivedFocusFromKeyboard)","_computeKeyboardClass(receivedFocusFromKeyboard)"],hostAttributes:{role:"button",tabindex:"0",animated:true},_calculateElevation:function(){var e=1;if(this.disabled){e=0}else if(this.active||this.pressed){e=4}else if(this.receivedFocusFromKeyboard){e=3}this._setElevation(e)},_computeKeyboardClass:function(receivedFocusFromKeyboard){this.toggleClass("keyboard-focus",receivedFocusFromKeyboard)},_spaceKeyDownHandler:function(event){Polymer.IronButtonStateImpl._spaceKeyDownHandler.call(this,event);if(this.hasRipple()&&this.getRipple().ripples.length<1){this._ripple.uiDownAction()}},_spaceKeyUpHandler:function(event){Polymer.IronButtonStateImpl._spaceKeyUpHandler.call(this,event);if(this.hasRipple()){this._ripple.uiUpAction()}}};Polymer.PaperButtonBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperRippleBehavior,Polymer.PaperButtonBehaviorImpl];Polymer({is:"paper-button",behaviors:[Polymer.PaperButtonBehavior],properties:{raised:{type:Boolean,reflectToAttribute:true,value:false,observer:"_calculateElevation"}},_calculateElevation:function(){if(!this.raised){this._setElevation(0)}else{Polymer.PaperButtonBehaviorImpl._calculateElevation.apply(this)}}});Polymer({is:"paper-icon-button-light","extends":"button",behaviors:[Polymer.PaperRippleBehavior],listeners:{down:"_rippleDown",up:"_rippleUp",focus:"_rippleDown",blur:"_rippleUp"},_rippleDown:function(){this.getRipple().downAction()},_rippleUp:function(){this.getRipple().upAction()},ensureRipple:function(var_args){var lastRipple=this._ripple;Polymer.PaperRippleBehavior.ensureRipple.apply(this,arguments);if(this._ripple&&this._ripple!==lastRipple){this._ripple.center=true;this._ripple.classList.add("circle")}}});Polymer.IronRangeBehavior={properties:{value:{type:Number,value:0,notify:true,reflectToAttribute:true},min:{type:Number,value:0,notify:true},max:{type:Number,value:100,notify:true},step:{type:Number,value:1,notify:true},ratio:{type:Number,value:0,readOnly:true,notify:true}},observers:["_update(value, min, max, step)"],_calcRatio:function(value){return(this._clampValue(value)-this.min)/(this.max-this.min)},_clampValue:function(value){return Math.min(this.max,Math.max(this.min,this._calcStep(value)))},_calcStep:function(value){value=parseFloat(value);if(!this.step){return value}var numSteps=Math.round((value-this.min)/this.step);if(this.step<1){return numSteps/(1/this.step)+this.min}else{return numSteps*this.step+this.min}},_validateValue:function(){var v=this._clampValue(this.value);this.value=this.oldValue=isNaN(v)?this.oldValue:v;return this.value!==v},_update:function(){this._validateValue();this._setRatio(this._calcRatio(this.value)*100)}};Polymer({is:"paper-progress",behaviors:[Polymer.IronRangeBehavior],properties:{secondaryProgress:{type:Number,value:0},secondaryRatio:{type:Number,value:0,readOnly:true},indeterminate:{type:Boolean,value:false,observer:"_toggleIndeterminate"},disabled:{type:Boolean,value:false,reflectToAttribute:true,observer:"_disabledChanged"}},observers:["_progressChanged(secondaryProgress, value, min, max)"],hostAttributes:{role:"progressbar"},_toggleIndeterminate:function(indeterminate){this.toggleClass("indeterminate",indeterminate,this.$.primaryProgress)},_transformProgress:function(progress,ratio){var transform="scaleX("+ratio/100+")";progress.style.transform=progress.style.webkitTransform=transform},_mainRatioChanged:function(ratio){this._transformProgress(this.$.primaryProgress,ratio)},_progressChanged:function(secondaryProgress,value,min,max){secondaryProgress=this._clampValue(secondaryProgress);value=this._clampValue(value);var secondaryRatio=this._calcRatio(secondaryProgress)*100;var mainRatio=this._calcRatio(value)*100;this._setSecondaryRatio(secondaryRatio);this._transformProgress(this.$.secondaryProgress,secondaryRatio);this._transformProgress(this.$.primaryProgress,mainRatio);this.secondaryProgress=secondaryProgress;this.setAttribute("aria-valuenow",value);this.setAttribute("aria-valuemin",min);this.setAttribute("aria-valuemax",max)},_disabledChanged:function(disabled){this.setAttribute("aria-disabled",disabled?"true":"false")},_hideSecondaryProgress:function(secondaryRatio){return secondaryRatio===0}});Polymer({is:"iron-iconset-svg",properties:{name:{type:String,observer:"_nameChanged"},size:{type:Number,value:24},rtlMirroring:{type:Boolean,value:false}},_targetIsRTL:function(target){if(target&&target.nodeType!==Node.ELEMENT_NODE){target=target.host}return target&&window.getComputedStyle(target)["direction"]==="rtl"},attached:function(){this.style.display="none"},getIconNames:function(){this._icons=this._createIconMap();return Object.keys(this._icons).map(function(n){return this.name+":"+n},this)},applyIcon:function(element,iconName){element=element.root||element;this.removeIcon(element);var svg=this._cloneIcon(iconName,this.rtlMirroring&&this._targetIsRTL(element));if(svg){var pde=Polymer.dom(element);pde.insertBefore(svg,pde.childNodes[0]);return element._svgIcon=svg}return null},removeIcon:function(element){element=element.root||element;if(element._svgIcon){Polymer.dom(element).removeChild(element._svgIcon);element._svgIcon=null}},_nameChanged:function(){new Polymer.IronMeta({type:"iconset",key:this.name,value:this});this.async(function(){this.fire("iron-iconset-added",this,{node:window})})},_createIconMap:function(){var icons=Object.create(null);Polymer.dom(this).querySelectorAll("[id]").forEach(function(icon){icons[icon.id]=icon});return icons},_cloneIcon:function(id,mirrorAllowed){this._icons=this._icons||this._createIconMap();return this._prepareSvgClone(this._icons[id],this.size,mirrorAllowed)},_prepareSvgClone:function(sourceSvg,size,mirrorAllowed){if(sourceSvg){var content=sourceSvg.cloneNode(true),svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),viewBox=content.getAttribute("viewBox")||"0 0 "+size+" "+size,cssText="pointer-events: none; display: block; width: 100%; height: 100%;";if(mirrorAllowed&&content.hasAttribute("mirror-in-rtl")){cssText+="-webkit-transform:scale(-1,1);transform:scale(-1,1);"}svg.setAttribute("viewBox",viewBox);svg.setAttribute("preserveAspectRatio","xMidYMid meet");svg.style.cssText=cssText;svg.appendChild(content).removeAttribute("id");return svg}return null}}); // 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("downloads",function(){var Item=Polymer({is:"downloads-item",properties:{data:{type:Object},completelyOnDisk_:{computed:"computeCompletelyOnDisk_("+"data.state, data.file_externally_removed)",type:Boolean,value:true},controlledBy_:{computed:"computeControlledBy_(data.by_ext_id, data.by_ext_name)",type:String,value:""},isActive_:{computed:"computeIsActive_("+"data.state, data.file_externally_removed)",type:Boolean,value:true},isDangerous_:{computed:"computeIsDangerous_(data.state)",type:Boolean,value:false},isMalware_:{computed:"computeIsMalware_(isDangerous_, data.danger_type)",type:Boolean,value:false},isInProgress_:{computed:"computeIsInProgress_(data.state)",type:Boolean,value:false},pauseOrResumeText_:{computed:"computePauseOrResumeText_(isInProgress_, data.resume)",type:String},showCancel_:{computed:"computeShowCancel_(data.state)",type:Boolean,value:false},showProgress_:{computed:"computeShowProgress_(showCancel_, data.percent)",type:Boolean,value:false}},observers:["observeControlledBy_(controlledBy_)","observeIsDangerous_(isDangerous_, data)"],ready:function(){this.content=this.$.content},computeClass_:function(){var classes=[];if(this.isActive_)classes.push("is-active");if(this.isDangerous_)classes.push("dangerous");if(this.showProgress_)classes.push("show-progress");return classes.join(" ")},computeCompletelyOnDisk_:function(){return this.data.state==downloads.States.COMPLETE&&!this.data.file_externally_removed},computeControlledBy_:function(){if(!this.data.by_ext_id||!this.data.by_ext_name)return"";var url="chrome://extensions#"+this.data.by_ext_id;var name=this.data.by_ext_name;return loadTimeData.getStringF("controlledByUrl",url,name)},computeDangerIcon_:function(){if(!this.isDangerous_)return"";switch(this.data.danger_type){case downloads.DangerType.DANGEROUS_CONTENT:case downloads.DangerType.DANGEROUS_HOST:case downloads.DangerType.DANGEROUS_URL:case downloads.DangerType.POTENTIALLY_UNWANTED:case downloads.DangerType.UNCOMMON_CONTENT:return"downloads:remove-circle";default:return"cr:warning"}},computeDate_:function(){assert(typeof this.data.hideDate=="boolean");if(this.data.hideDate)return"";return assert(this.data.since_string||this.data.date_string)},computeDescription_:function(){var data=this.data;switch(data.state){case downloads.States.DANGEROUS:var fileName=data.file_name;switch(data.danger_type){case downloads.DangerType.DANGEROUS_FILE:return loadTimeData.getString("dangerFileDesc");case downloads.DangerType.DANGEROUS_URL:case downloads.DangerType.DANGEROUS_CONTENT:case downloads.DangerType.DANGEROUS_HOST:return loadTimeData.getString("dangerDownloadDesc");case downloads.DangerType.UNCOMMON_CONTENT:return loadTimeData.getString("dangerUncommonDesc");case downloads.DangerType.POTENTIALLY_UNWANTED:return loadTimeData.getString("dangerSettingsDesc")}break;case downloads.States.IN_PROGRESS:case downloads.States.PAUSED:return data.progress_status_text}return""},computeIsActive_:function(){return this.data.state!=downloads.States.CANCELLED&&this.data.state!=downloads.States.INTERRUPTED&&!this.data.file_externally_removed},computeIsDangerous_:function(){return this.data.state==downloads.States.DANGEROUS},computeIsInProgress_:function(){return this.data.state==downloads.States.IN_PROGRESS},computeIsMalware_:function(){return this.isDangerous_&&(this.data.danger_type==downloads.DangerType.DANGEROUS_CONTENT||this.data.danger_type==downloads.DangerType.DANGEROUS_HOST||this.data.danger_type==downloads.DangerType.DANGEROUS_URL||this.data.danger_type==downloads.DangerType.POTENTIALLY_UNWANTED)},computePauseOrResumeText_:function(){if(this.isInProgress_)return loadTimeData.getString("controlPause");if(this.data.resume)return loadTimeData.getString("controlResume");return""},computeRemoveStyle_:function(){var canDelete=loadTimeData.getBoolean("allowDeletingHistory");var hideRemove=this.isDangerous_||this.showCancel_||!canDelete;return hideRemove?"visibility: hidden":""},computeShowCancel_:function(){return this.data.state==downloads.States.IN_PROGRESS||this.data.state==downloads.States.PAUSED},computeShowProgress_:function(){return this.showCancel_&&this.data.percent>=-1},computeTag_:function(){switch(this.data.state){case downloads.States.CANCELLED:return loadTimeData.getString("statusCancelled");case downloads.States.INTERRUPTED:return this.data.last_reason_text;case downloads.States.COMPLETE:return this.data.file_externally_removed?loadTimeData.getString("statusRemoved"):""}return""},isIndeterminate_:function(){return this.data.percent==-1},observeControlledBy_:function(){this.$["controlled-by"].innerHTML=this.controlledBy_},observeIsDangerous_:function(){if(!this.data)return;if(this.isDangerous_){this.$.url.removeAttribute("href")}else{this.$.url.href=assert(this.data.url);var filePath=encodeURIComponent(this.data.file_path);var scaleFactor="?scale="+window.devicePixelRatio+"x";this.$["file-icon"].src="chrome://fileicon/"+filePath+scaleFactor}},onCancelTap_:function(){downloads.ActionService.getInstance().cancel(this.data.id)},onDiscardDangerousTap_:function(){downloads.ActionService.getInstance().discardDangerous(this.data.id)},onDragStart_:function(e){e.preventDefault();downloads.ActionService.getInstance().drag(this.data.id)},onFileLinkTap_:function(e){e.preventDefault();downloads.ActionService.getInstance().openFile(this.data.id)},onPauseOrResumeTap_:function(){if(this.isInProgress_)downloads.ActionService.getInstance().pause(this.data.id);else downloads.ActionService.getInstance().resume(this.data.id)},onRemoveTap_:function(){downloads.ActionService.getInstance().remove(this.data.id)},onRetryTap_:function(){downloads.ActionService.getInstance().download(this.data.url)},onSaveDangerousTap_:function(){downloads.ActionService.getInstance().saveDangerous(this.data.id)},onShowTap_:function(){downloads.ActionService.getInstance().show(this.data.id)}});return{Item:Item}});Polymer.PaperItemBehaviorImpl={hostAttributes:{role:"option",tabindex:"0"}};Polymer.PaperItemBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperItemBehaviorImpl];Polymer({is:"paper-item",behaviors:[Polymer.PaperItemBehavior]});Polymer.IronSelection=function(selectCallback){this.selection=[];this.selectCallback=selectCallback};Polymer.IronSelection.prototype={get:function(){return this.multi?this.selection.slice():this.selection[0]},clear:function(excludes){this.selection.slice().forEach(function(item){if(!excludes||excludes.indexOf(item)<0){this.setItemSelected(item,false)}},this)},isSelected:function(item){return this.selection.indexOf(item)>=0},setItemSelected:function(item,isSelected){if(item!=null){if(isSelected!==this.isSelected(item)){if(isSelected){this.selection.push(item)}else{var i=this.selection.indexOf(item);if(i>=0){this.selection.splice(i,1)}}if(this.selectCallback){this.selectCallback(item,isSelected)}}}},select:function(item){if(this.multi){this.toggle(item)}else if(this.get()!==item){this.setItemSelected(this.get(),false);this.setItemSelected(item,true)}},toggle:function(item){this.setItemSelected(item,!this.isSelected(item))}};Polymer.IronSelectableBehavior={properties:{attrForSelected:{type:String,value:null},selected:{type:String,notify:true},selectedItem:{type:Object,readOnly:true,notify:true},activateEvent:{type:String,value:"tap",observer:"_activateEventChanged"},selectable:String,selectedClass:{type:String,value:"iron-selected"},selectedAttribute:{type:String,value:null},fallbackSelection:{type:String,value:null},items:{type:Array,readOnly:true,notify:true,value:function(){return[]}},_excludedLocalNames:{type:Object,value:function(){return{template:1}}}},observers:["_updateAttrForSelected(attrForSelected)","_updateSelected(selected)","_checkFallback(fallbackSelection)"],created:function(){this._bindFilterItem=this._filterItem.bind(this);this._selection=new Polymer.IronSelection(this._applySelection.bind(this))},attached:function(){this._observer=this._observeItems(this);this._updateItems();if(!this._shouldUpdateSelection){this._updateSelected()}this._addListener(this.activateEvent)},detached:function(){if(this._observer){Polymer.dom(this).unobserveNodes(this._observer)}this._removeListener(this.activateEvent)},indexOf:function(item){return this.items.indexOf(item)},select:function(value){this.selected=value},selectPrevious:function(){var length=this.items.length;var index=(Number(this._valueToIndex(this.selected))-1+length)%length;this.selected=this._indexToValue(index)},selectNext:function(){var index=(Number(this._valueToIndex(this.selected))+1)%this.items.length;this.selected=this._indexToValue(index)},selectIndex:function(index){this.select(this._indexToValue(index))},forceSynchronousItemUpdate:function(){this._updateItems()},get _shouldUpdateSelection(){return this.selected!=null},_checkFallback:function(){if(this._shouldUpdateSelection){this._updateSelected()}},_addListener:function(eventName){this.listen(this,eventName,"_activateHandler")},_removeListener:function(eventName){this.unlisten(this,eventName,"_activateHandler")},_activateEventChanged:function(eventName,old){this._removeListener(old);this._addListener(eventName)},_updateItems:function(){var nodes=Polymer.dom(this).queryDistributedElements(this.selectable||"*");nodes=Array.prototype.filter.call(nodes,this._bindFilterItem);this._setItems(nodes)},_updateAttrForSelected:function(){if(this._shouldUpdateSelection){this.selected=this._indexToValue(this.indexOf(this.selectedItem))}},_updateSelected:function(){this._selectSelected(this.selected)},_selectSelected:function(selected){this._selection.select(this._valueToItem(this.selected));if(this.fallbackSelection&&this.items.length&&this._selection.get()===undefined){this.selected=this.fallbackSelection}},_filterItem:function(node){return!this._excludedLocalNames[node.localName]},_valueToItem:function(value){return value==null?null:this.items[this._valueToIndex(value)]},_valueToIndex:function(value){if(this.attrForSelected){for(var i=0,item;item=this.items[i];i++){if(this._valueForItem(item)==value){return i}}}else{return Number(value)}},_indexToValue:function(index){if(this.attrForSelected){var item=this.items[index];if(item){return this._valueForItem(item)}}else{return index}},_valueForItem:function(item){var propValue=item[Polymer.CaseMap.dashToCamelCase(this.attrForSelected)];return propValue!=undefined?propValue:item.getAttribute(this.attrForSelected)},_applySelection:function(item,isSelected){if(this.selectedClass){this.toggleClass(this.selectedClass,isSelected,item)}if(this.selectedAttribute){this.toggleAttribute(this.selectedAttribute,isSelected,item)}this._selectionChange();this.fire("iron-"+(isSelected?"select":"deselect"),{item:item})},_selectionChange:function(){this._setSelectedItem(this._selection.get())},_observeItems:function(node){return Polymer.dom(node).observeNodes(function(mutation){this._updateItems();if(this._shouldUpdateSelection){this._updateSelected()}this.fire("iron-items-changed",mutation,{bubbles:false,cancelable:false})})},_activateHandler:function(e){var t=e.target;var items=this.items;while(t&&t!=this){var i=items.indexOf(t);if(i>=0){var value=this._indexToValue(i);this._itemActivate(value,t);return}t=t.parentNode}},_itemActivate:function(value,item){if(!this.fire("iron-activate",{selected:value,item:item},{cancelable:true}).defaultPrevented){this.select(value)}}};Polymer.IronMultiSelectableBehaviorImpl={properties:{multi:{type:Boolean,value:false,observer:"multiChanged"},selectedValues:{type:Array,notify:true},selectedItems:{type:Array,readOnly:true,notify:true}},observers:["_updateSelected(selectedValues.splices)"],select:function(value){if(this.multi){if(this.selectedValues){this._toggleSelected(value)}else{this.selectedValues=[value]}}else{this.selected=value}},multiChanged:function(multi){this._selection.multi=multi},get _shouldUpdateSelection(){return this.selected!=null||this.selectedValues!=null&&this.selectedValues.length},_updateAttrForSelected:function(){if(!this.multi){Polymer.IronSelectableBehavior._updateAttrForSelected.apply(this)}else if(this._shouldUpdateSelection){this.selectedValues=this.selectedItems.map(function(selectedItem){return this._indexToValue(this.indexOf(selectedItem))},this).filter(function(unfilteredValue){return unfilteredValue!=null},this)}},_updateSelected:function(){if(this.multi){this._selectMulti(this.selectedValues)}else{this._selectSelected(this.selected)}},_selectMulti:function(values){if(values){var selectedItems=this._valuesToItems(values);this._selection.clear(selectedItems);for(var i=0;i<selectedItems.length;i++){this._selection.setItemSelected(selectedItems[i],true)}if(this.fallbackSelection&&this.items.length&&!this._selection.get().length){var fallback=this._valueToItem(this.fallbackSelection);if(fallback){this.selectedValues=[this.fallbackSelection]}}}else{this._selection.clear()}},_selectionChange:function(){var s=this._selection.get();if(this.multi){this._setSelectedItems(s)}else{this._setSelectedItems([s]);this._setSelectedItem(s)}},_toggleSelected:function(value){var i=this.selectedValues.indexOf(value);var unselected=i<0;if(unselected){this.push("selectedValues",value)}else{this.splice("selectedValues",i,1)}},_valuesToItems:function(values){return values==null?null:values.map(function(value){return this._valueToItem(value)},this)}};Polymer.IronMultiSelectableBehavior=[Polymer.IronSelectableBehavior,Polymer.IronMultiSelectableBehaviorImpl];Polymer.IronMenuBehaviorImpl={properties:{focusedItem:{observer:"_focusedItemChanged",readOnly:true,type:Object},attrForItemTitle:{type:String}},hostAttributes:{role:"menu",tabindex:"0"},observers:["_updateMultiselectable(multi)"],listeners:{focus:"_onFocus",keydown:"_onKeydown","iron-items-changed":"_onIronItemsChanged"},keyBindings:{up:"_onUpKey",down:"_onDownKey",esc:"_onEscKey","shift+tab:keydown":"_onShiftTabDown"},attached:function(){this._resetTabindices()},select:function(value){if(this._defaultFocusAsync){this.cancelAsync(this._defaultFocusAsync);this._defaultFocusAsync=null}var item=this._valueToItem(value);if(item&&item.hasAttribute("disabled"))return;this._setFocusedItem(item);Polymer.IronMultiSelectableBehaviorImpl.select.apply(this,arguments)},_resetTabindices:function(){var selectedItem=this.multi?this.selectedItems&&this.selectedItems[0]:this.selectedItem;this.items.forEach(function(item){item.setAttribute("tabindex",item===selectedItem?"0":"-1")},this)},_updateMultiselectable:function(multi){if(multi){this.setAttribute("aria-multiselectable","true")}else{this.removeAttribute("aria-multiselectable")}},_focusWithKeyboardEvent:function(event){for(var i=0,item;item=this.items[i];i++){var attr=this.attrForItemTitle||"textContent";var title=item[attr]||item.getAttribute(attr);if(!item.hasAttribute("disabled")&&title&&title.trim().charAt(0).toLowerCase()===String.fromCharCode(event.keyCode).toLowerCase()){this._setFocusedItem(item);break}}},_focusPrevious:function(){var length=this.items.length;var curFocusIndex=Number(this.indexOf(this.focusedItem));for(var i=1;i<length+1;i++){var item=this.items[(curFocusIndex-i+length)%length];if(!item.hasAttribute("disabled")){var owner=Polymer.dom(item).getOwnerRoot()||document;this._setFocusedItem(item);if(Polymer.dom(owner).activeElement==item){return}}}},_focusNext:function(){var length=this.items.length;var curFocusIndex=Number(this.indexOf(this.focusedItem));for(var i=1;i<length+1;i++){var item=this.items[(curFocusIndex+i)%length];if(!item.hasAttribute("disabled")){var owner=Polymer.dom(item).getOwnerRoot()||document;this._setFocusedItem(item);if(Polymer.dom(owner).activeElement==item){return}}}},_applySelection:function(item,isSelected){if(isSelected){item.setAttribute("aria-selected","true")}else{item.removeAttribute("aria-selected")}Polymer.IronSelectableBehavior._applySelection.apply(this,arguments)},_focusedItemChanged:function(focusedItem,old){old&&old.setAttribute("tabindex","-1");if(focusedItem){focusedItem.setAttribute("tabindex","0");focusedItem.focus()}},_onIronItemsChanged:function(event){if(event.detail.addedNodes.length){this._resetTabindices()}},_onShiftTabDown:function(event){var oldTabIndex=this.getAttribute("tabindex");Polymer.IronMenuBehaviorImpl._shiftTabPressed=true;this._setFocusedItem(null);this.setAttribute("tabindex","-1");this.async(function(){this.setAttribute("tabindex",oldTabIndex);Polymer.IronMenuBehaviorImpl._shiftTabPressed=false},1)},_onFocus:function(event){if(Polymer.IronMenuBehaviorImpl._shiftTabPressed){return}var rootTarget=Polymer.dom(event).rootTarget;if(rootTarget!==this&&typeof rootTarget.tabIndex!=="undefined"&&!this.isLightDescendant(rootTarget)){return}this._defaultFocusAsync=this.async(function(){var selectedItem=this.multi?this.selectedItems&&this.selectedItems[0]:this.selectedItem;this._setFocusedItem(null);if(selectedItem){this._setFocusedItem(selectedItem)}else if(this.items[0]){this._focusNext()}})},_onUpKey:function(event){this._focusPrevious();event.detail.keyboardEvent.preventDefault()},_onDownKey:function(event){this._focusNext();event.detail.keyboardEvent.preventDefault()},_onEscKey:function(event){this.focusedItem.blur()},_onKeydown:function(event){if(!this.keyboardEventMatchesKeys(event,"up down esc")){this._focusWithKeyboardEvent(event)}event.stopPropagation()},_activateHandler:function(event){Polymer.IronSelectableBehavior._activateHandler.call(this,event);event.stopPropagation()}};Polymer.IronMenuBehaviorImpl._shiftTabPressed=false;Polymer.IronMenuBehavior=[Polymer.IronMultiSelectableBehavior,Polymer.IronA11yKeysBehavior,Polymer.IronMenuBehaviorImpl];(function(){Polymer({is:"paper-menu",behaviors:[Polymer.IronMenuBehavior]})})();Polymer.IronFitBehavior={properties:{sizingTarget:{type:Object,value:function(){return this}},fitInto:{type:Object,value:window},noOverlap:{type:Boolean},positionTarget:{type:Element},horizontalAlign:{type:String},verticalAlign:{type:String},dynamicAlign:{type:Boolean},horizontalOffset:{type:Number,value:0,notify:true},verticalOffset:{type:Number,value:0,notify:true},autoFitOnAttach:{type:Boolean,value:false},_fitInfo:{type:Object}},get _fitWidth(){var fitWidth;if(this.fitInto===window){fitWidth=this.fitInto.innerWidth}else{fitWidth=this.fitInto.getBoundingClientRect().width}return fitWidth},get _fitHeight(){var fitHeight;if(this.fitInto===window){fitHeight=this.fitInto.innerHeight}else{fitHeight=this.fitInto.getBoundingClientRect().height}return fitHeight},get _fitLeft(){var fitLeft;if(this.fitInto===window){fitLeft=0}else{fitLeft=this.fitInto.getBoundingClientRect().left}return fitLeft},get _fitTop(){var fitTop;if(this.fitInto===window){fitTop=0}else{fitTop=this.fitInto.getBoundingClientRect().top}return fitTop},get _defaultPositionTarget(){var parent=Polymer.dom(this).parentNode;if(parent&&parent.nodeType===Node.DOCUMENT_FRAGMENT_NODE){parent=parent.host}return parent},get _localeHorizontalAlign(){if(this._isRTL){if(this.horizontalAlign==="right"){return"left"}if(this.horizontalAlign==="left"){return"right"}}return this.horizontalAlign},attached:function(){this._isRTL=window.getComputedStyle(this).direction=="rtl";this.positionTarget=this.positionTarget||this._defaultPositionTarget;if(this.autoFitOnAttach){if(window.getComputedStyle(this).display==="none"){setTimeout(function(){this.fit()}.bind(this))}else{this.fit()}}},fit:function(){this.position();this.constrain();this.center()},_discoverInfo:function(){if(this._fitInfo){return}var target=window.getComputedStyle(this);var sizer=window.getComputedStyle(this.sizingTarget);this._fitInfo={inlineStyle:{top:this.style.top||"",left:this.style.left||"",position:this.style.position||""},sizerInlineStyle:{maxWidth:this.sizingTarget.style.maxWidth||"",maxHeight:this.sizingTarget.style.maxHeight||"",boxSizing:this.sizingTarget.style.boxSizing||""},positionedBy:{vertically:target.top!=="auto"?"top":target.bottom!=="auto"?"bottom":null,horizontally:target.left!=="auto"?"left":target.right!=="auto"?"right":null},sizedBy:{height:sizer.maxHeight!=="none",width:sizer.maxWidth!=="none",minWidth:parseInt(sizer.minWidth,10)||0,minHeight:parseInt(sizer.minHeight,10)||0},margin:{top:parseInt(target.marginTop,10)||0,right:parseInt(target.marginRight,10)||0,bottom:parseInt(target.marginBottom,10)||0,left:parseInt(target.marginLeft,10)||0}};if(this.verticalOffset){this._fitInfo.margin.top=this._fitInfo.margin.bottom=this.verticalOffset;this._fitInfo.inlineStyle.marginTop=this.style.marginTop||"";this._fitInfo.inlineStyle.marginBottom=this.style.marginBottom||"";this.style.marginTop=this.style.marginBottom=this.verticalOffset+"px"}if(this.horizontalOffset){this._fitInfo.margin.left=this._fitInfo.margin.right=this.horizontalOffset;this._fitInfo.inlineStyle.marginLeft=this.style.marginLeft||"";this._fitInfo.inlineStyle.marginRight=this.style.marginRight||"";this.style.marginLeft=this.style.marginRight=this.horizontalOffset+"px"}},resetFit:function(){var info=this._fitInfo||{};for(var property in info.sizerInlineStyle){this.sizingTarget.style[property]=info.sizerInlineStyle[property]}for(var property in info.inlineStyle){this.style[property]=info.inlineStyle[property]}this._fitInfo=null},refit:function(){var scrollLeft=this.sizingTarget.scrollLeft;var scrollTop=this.sizingTarget.scrollTop;this.resetFit();this.fit();this.sizingTarget.scrollLeft=scrollLeft;this.sizingTarget.scrollTop=scrollTop},position:function(){if(!this.horizontalAlign&&!this.verticalAlign){return}this._discoverInfo();this.style.position="fixed";this.sizingTarget.style.boxSizing="border-box";this.style.left="0px";this.style.top="0px";var rect=this.getBoundingClientRect();var positionRect=this.__getNormalizedRect(this.positionTarget);var fitRect=this.__getNormalizedRect(this.fitInto);var margin=this._fitInfo.margin;var size={width:rect.width+margin.left+margin.right,height:rect.height+margin.top+margin.bottom};var position=this.__getPosition(this._localeHorizontalAlign,this.verticalAlign,size,positionRect,fitRect);var left=position.left+margin.left;var top=position.top+margin.top;var right=Math.min(fitRect.right-margin.right,left+rect.width);var bottom=Math.min(fitRect.bottom-margin.bottom,top+rect.height);var minWidth=this._fitInfo.sizedBy.minWidth;var minHeight=this._fitInfo.sizedBy.minHeight;if(left<margin.left){left=margin.left;if(right-left<minWidth){left=right-minWidth}}if(top<margin.top){top=margin.top;if(bottom-top<minHeight){top=bottom-minHeight}}this.sizingTarget.style.maxWidth=right-left+"px";this.sizingTarget.style.maxHeight=bottom-top+"px";this.style.left=left-rect.left+"px";this.style.top=top-rect.top+"px"},constrain:function(){if(this.horizontalAlign||this.verticalAlign){return}this._discoverInfo();var info=this._fitInfo;if(!info.positionedBy.vertically){this.style.position="fixed";this.style.top="0px"}if(!info.positionedBy.horizontally){this.style.position="fixed";this.style.left="0px"}this.sizingTarget.style.boxSizing="border-box";var rect=this.getBoundingClientRect();if(!info.sizedBy.height){this.__sizeDimension(rect,info.positionedBy.vertically,"top","bottom","Height")}if(!info.sizedBy.width){this.__sizeDimension(rect,info.positionedBy.horizontally,"left","right","Width")}},_sizeDimension:function(rect,positionedBy,start,end,extent){this.__sizeDimension(rect,positionedBy,start,end,extent)},__sizeDimension:function(rect,positionedBy,start,end,extent){var info=this._fitInfo;var fitRect=this.__getNormalizedRect(this.fitInto);var max=extent==="Width"?fitRect.width:fitRect.height;var flip=positionedBy===end;var offset=flip?max-rect[end]:rect[start];var margin=info.margin[flip?start:end];var offsetExtent="offset"+extent;var sizingOffset=this[offsetExtent]-this.sizingTarget[offsetExtent];this.sizingTarget.style["max"+extent]=max-margin-offset-sizingOffset+"px"},center:function(){if(this.horizontalAlign||this.verticalAlign){return}this._discoverInfo();var positionedBy=this._fitInfo.positionedBy;if(positionedBy.vertically&&positionedBy.horizontally){return}this.style.position="fixed";if(!positionedBy.vertically){this.style.top="0px"}if(!positionedBy.horizontally){this.style.left="0px"}var rect=this.getBoundingClientRect();var fitRect=this.__getNormalizedRect(this.fitInto);if(!positionedBy.vertically){var top=fitRect.top-rect.top+(fitRect.height-rect.height)/2;this.style.top=top+"px"}if(!positionedBy.horizontally){var left=fitRect.left-rect.left+(fitRect.width-rect.width)/2;this.style.left=left+"px"}},__getNormalizedRect:function(target){if(target===document.documentElement||target===window){return{top:0,left:0,width:window.innerWidth,height:window.innerHeight,right:window.innerWidth,bottom:window.innerHeight}}return target.getBoundingClientRect()},__getCroppedArea:function(position,size,fitRect){var verticalCrop=Math.min(0,position.top)+Math.min(0,fitRect.bottom-(position.top+size.height));var horizontalCrop=Math.min(0,position.left)+Math.min(0,fitRect.right-(position.left+size.width));return Math.abs(verticalCrop)*size.width+Math.abs(horizontalCrop)*size.height},__getPosition:function(hAlign,vAlign,size,positionRect,fitRect){var positions=[{verticalAlign:"top",horizontalAlign:"left",top:positionRect.top,left:positionRect.left},{verticalAlign:"top",horizontalAlign:"right",top:positionRect.top,left:positionRect.right-size.width},{verticalAlign:"bottom",horizontalAlign:"left",top:positionRect.bottom-size.height,left:positionRect.left},{verticalAlign:"bottom",horizontalAlign:"right",top:positionRect.bottom-size.height,left:positionRect.right-size.width}];if(this.noOverlap){for(var i=0,l=positions.length;i<l;i++){var copy={};for(var key in positions[i]){copy[key]=positions[i][key]}positions.push(copy)}positions[0].top=positions[1].top+=positionRect.height;positions[2].top=positions[3].top-=positionRect.height;positions[4].left=positions[6].left+=positionRect.width;positions[5].left=positions[7].left-=positionRect.width}vAlign=vAlign==="auto"?null:vAlign;hAlign=hAlign==="auto"?null:hAlign;var position;for(var i=0;i<positions.length;i++){var pos=positions[i];if(!this.dynamicAlign&&!this.noOverlap&&pos.verticalAlign===vAlign&&pos.horizontalAlign===hAlign){position=pos;break}var alignOk=(!vAlign||pos.verticalAlign===vAlign)&&(!hAlign||pos.horizontalAlign===hAlign);if(!this.dynamicAlign&&!alignOk){continue}position=position||pos;pos.croppedArea=this.__getCroppedArea(pos,size,fitRect);var diff=pos.croppedArea-position.croppedArea;if(diff<0||diff===0&&alignOk){position=pos}if(position.croppedArea===0&&alignOk){break}}return position}};(function(){"use strict";Polymer({is:"iron-overlay-backdrop",properties:{opened:{reflectToAttribute:true,type:Boolean,value:false,observer:"_openedChanged"}},listeners:{transitionend:"_onTransitionend"},created:function(){this.__openedRaf=null},attached:function(){this.opened&&this._openedChanged(this.opened)},prepare:function(){if(this.opened&&!this.parentNode){Polymer.dom(document.body).appendChild(this)}},open:function(){this.opened=true},close:function(){this.opened=false},complete:function(){if(!this.opened&&this.parentNode===document.body){Polymer.dom(this.parentNode).removeChild(this)}},_onTransitionend:function(event){if(event&&event.target===this){this.complete()}},_openedChanged:function(opened){if(opened){this.prepare()}else{var cs=window.getComputedStyle(this);if(cs.transitionDuration==="0s"||cs.opacity==0){this.complete()}}if(!this.isAttached){return}if(this.__openedRaf){window.cancelAnimationFrame(this.__openedRaf);this.__openedRaf=null}this.scrollTop=this.scrollTop;this.__openedRaf=window.requestAnimationFrame(function(){this.__openedRaf=null;this.toggleClass("opened",this.opened)}.bind(this))}})})();Polymer.IronOverlayManagerClass=function(){this._overlays=[];this._minimumZ=101;this._backdropElement=null;Polymer.Gestures.add(document,"tap",this._onCaptureClick.bind(this));document.addEventListener("focus",this._onCaptureFocus.bind(this),true);document.addEventListener("keydown",this._onCaptureKeyDown.bind(this),true)};Polymer.IronOverlayManagerClass.prototype={constructor:Polymer.IronOverlayManagerClass,get backdropElement(){if(!this._backdropElement){this._backdropElement=document.createElement("iron-overlay-backdrop")}return this._backdropElement},get deepActiveElement(){var active=document.activeElement||document.body;while(active.root&&Polymer.dom(active.root).activeElement){active=Polymer.dom(active.root).activeElement}return active},_bringOverlayAtIndexToFront:function(i){var overlay=this._overlays[i];if(!overlay){return}var lastI=this._overlays.length-1;var currentOverlay=this._overlays[lastI];if(currentOverlay&&this._shouldBeBehindOverlay(overlay,currentOverlay)){lastI--}if(i>=lastI){return}var minimumZ=Math.max(this.currentOverlayZ(),this._minimumZ);if(this._getZ(overlay)<=minimumZ){this._applyOverlayZ(overlay,minimumZ)}while(i<lastI){this._overlays[i]=this._overlays[i+1];i++}this._overlays[lastI]=overlay},addOrRemoveOverlay:function(overlay){if(overlay.opened){this.addOverlay(overlay)}else{this.removeOverlay(overlay)}},addOverlay:function(overlay){var i=this._overlays.indexOf(overlay);if(i>=0){this._bringOverlayAtIndexToFront(i);this.trackBackdrop();return}var insertionIndex=this._overlays.length;var currentOverlay=this._overlays[insertionIndex-1];var minimumZ=Math.max(this._getZ(currentOverlay),this._minimumZ);var newZ=this._getZ(overlay);if(currentOverlay&&this._shouldBeBehindOverlay(overlay,currentOverlay)){this._applyOverlayZ(currentOverlay,minimumZ);insertionIndex--;var previousOverlay=this._overlays[insertionIndex-1];minimumZ=Math.max(this._getZ(previousOverlay),this._minimumZ)}if(newZ<=minimumZ){this._applyOverlayZ(overlay,minimumZ)}this._overlays.splice(insertionIndex,0,overlay);this.trackBackdrop()},removeOverlay:function(overlay){var i=this._overlays.indexOf(overlay);if(i===-1){return}this._overlays.splice(i,1);this.trackBackdrop()},currentOverlay:function(){var i=this._overlays.length-1;return this._overlays[i]},currentOverlayZ:function(){return this._getZ(this.currentOverlay())},ensureMinimumZ:function(minimumZ){this._minimumZ=Math.max(this._minimumZ,minimumZ)},focusOverlay:function(){var current=this.currentOverlay();if(current){current._applyFocus()}},trackBackdrop:function(){var overlay=this._overlayWithBackdrop();if(!overlay&&!this._backdropElement){return}this.backdropElement.style.zIndex=this._getZ(overlay)-1;this.backdropElement.opened=!!overlay},getBackdrops:function(){var backdrops=[];for(var i=0;i<this._overlays.length;i++){if(this._overlays[i].withBackdrop){backdrops.push(this._overlays[i])}}return backdrops},backdropZ:function(){return this._getZ(this._overlayWithBackdrop())-1},_overlayWithBackdrop:function(){for(var i=0;i<this._overlays.length;i++){if(this._overlays[i].withBackdrop){return this._overlays[i]}}},_getZ:function(overlay){var z=this._minimumZ;if(overlay){var z1=Number(overlay.style.zIndex||window.getComputedStyle(overlay).zIndex);if(z1===z1){z=z1}}return z},_setZ:function(element,z){element.style.zIndex=z},_applyOverlayZ:function(overlay,aboveZ){this._setZ(overlay,aboveZ+2)},_overlayInPath:function(path){path=path||[];for(var i=0;i<path.length;i++){if(path[i]._manager===this){return path[i]}}},_onCaptureClick:function(event){var overlay=this.currentOverlay();if(overlay&&this._overlayInPath(Polymer.dom(event).path)!==overlay){overlay._onCaptureClick(event)}},_onCaptureFocus:function(event){var overlay=this.currentOverlay();if(overlay){overlay._onCaptureFocus(event)}},_onCaptureKeyDown:function(event){var overlay=this.currentOverlay();if(overlay){if(Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event,"esc")){overlay._onCaptureEsc(event)}else if(Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event,"tab")){overlay._onCaptureTab(event)}}},_shouldBeBehindOverlay:function(overlay1,overlay2){return!overlay1.alwaysOnTop&&overlay2.alwaysOnTop}};Polymer.IronOverlayManager=new Polymer.IronOverlayManagerClass;(function(){"use strict";Polymer.IronOverlayBehaviorImpl={properties:{opened:{observer:"_openedChanged",type:Boolean,value:false,notify:true},canceled:{observer:"_canceledChanged",readOnly:true, -type:Boolean,value:false},withBackdrop:{observer:"_withBackdropChanged",type:Boolean},noAutoFocus:{type:Boolean,value:false},noCancelOnEscKey:{type:Boolean,value:false},noCancelOnOutsideClick:{type:Boolean,value:false},closingReason:{type:Object},restoreFocusOnClose:{type:Boolean,value:false},alwaysOnTop:{type:Boolean},_manager:{type:Object,value:Polymer.IronOverlayManager},_focusedChild:{type:Object}},listeners:{"iron-resize":"_onIronResize"},get backdropElement(){return this._manager.backdropElement},get _focusNode(){return this._focusedChild||Polymer.dom(this).querySelector("[autofocus]")||this},get _focusableNodes(){var FOCUSABLE_WITH_DISABLED=["a[href]","area[href]","iframe","[tabindex]","[contentEditable=true]"];var FOCUSABLE_WITHOUT_DISABLED=["input","select","textarea","button"];var selector=FOCUSABLE_WITH_DISABLED.join(':not([tabindex="-1"]),')+':not([tabindex="-1"]),'+FOCUSABLE_WITHOUT_DISABLED.join(':not([disabled]):not([tabindex="-1"]),')+':not([disabled]):not([tabindex="-1"])';var focusables=Polymer.dom(this).querySelectorAll(selector);if(this.tabIndex>=0){focusables.splice(0,0,this)}return focusables.sort(function(a,b){if(a.tabIndex===b.tabIndex){return 0}if(a.tabIndex===0||a.tabIndex>b.tabIndex){return 1}return-1})},ready:function(){this.__isAnimating=false;this.__shouldRemoveTabIndex=false;this.__firstFocusableNode=this.__lastFocusableNode=null;this.__raf=null;this.__restoreFocusNode=null;this._ensureSetup()},attached:function(){if(this.opened){this._openedChanged(this.opened)}this._observer=Polymer.dom(this).observeNodes(this._onNodesChange)},detached:function(){Polymer.dom(this).unobserveNodes(this._observer);this._observer=null;if(this.__raf){window.cancelAnimationFrame(this.__raf);this.__raf=null}this._manager.removeOverlay(this)},toggle:function(){this._setCanceled(false);this.opened=!this.opened},open:function(){this._setCanceled(false);this.opened=true},close:function(){this._setCanceled(false);this.opened=false},cancel:function(event){var cancelEvent=this.fire("iron-overlay-canceled",event,{cancelable:true});if(cancelEvent.defaultPrevented){return}this._setCanceled(true);this.opened=false},_ensureSetup:function(){if(this._overlaySetup){return}this._overlaySetup=true;this.style.outline="none";this.style.display="none"},_openedChanged:function(opened){if(opened){this.removeAttribute("aria-hidden")}else{this.setAttribute("aria-hidden","true")}if(!this.isAttached){return}this.__isAnimating=true;this.__onNextAnimationFrame(this.__openedChanged)},_canceledChanged:function(){this.closingReason=this.closingReason||{};this.closingReason.canceled=this.canceled},_withBackdropChanged:function(){if(this.withBackdrop&&!this.hasAttribute("tabindex")){this.setAttribute("tabindex","-1");this.__shouldRemoveTabIndex=true}else if(this.__shouldRemoveTabIndex){this.removeAttribute("tabindex");this.__shouldRemoveTabIndex=false}if(this.opened&&this.isAttached){this._manager.trackBackdrop()}},_prepareRenderOpened:function(){this.__restoreFocusNode=this._manager.deepActiveElement;this._preparePositioning();this.refit();this._finishPositioning();if(this.noAutoFocus&&document.activeElement===this._focusNode){this._focusNode.blur();this.__restoreFocusNode.focus()}},_renderOpened:function(){this._finishRenderOpened()},_renderClosed:function(){this._finishRenderClosed()},_finishRenderOpened:function(){this.notifyResize();this.__isAnimating=false;var focusableNodes=this._focusableNodes;this.__firstFocusableNode=focusableNodes[0];this.__lastFocusableNode=focusableNodes[focusableNodes.length-1];this.fire("iron-overlay-opened")},_finishRenderClosed:function(){this.style.display="none";this.style.zIndex="";this.notifyResize();this.__isAnimating=false;this.fire("iron-overlay-closed",this.closingReason)},_preparePositioning:function(){this.style.transition=this.style.webkitTransition="none";this.style.transform=this.style.webkitTransform="none";this.style.display=""},_finishPositioning:function(){this.style.display="none";this.scrollTop=this.scrollTop;this.style.transition=this.style.webkitTransition="";this.style.transform=this.style.webkitTransform="";this.style.display="";this.scrollTop=this.scrollTop},_applyFocus:function(){if(this.opened){if(!this.noAutoFocus){this._focusNode.focus()}}else{this._focusNode.blur();this._focusedChild=null;if(this.restoreFocusOnClose&&this.__restoreFocusNode){this.__restoreFocusNode.focus()}this.__restoreFocusNode=null;var currentOverlay=this._manager.currentOverlay();if(currentOverlay&&this!==currentOverlay){currentOverlay._applyFocus()}}},_onCaptureClick:function(event){if(!this.noCancelOnOutsideClick){this.cancel(event)}},_onCaptureFocus:function(event){if(!this.withBackdrop){return}var path=Polymer.dom(event).path;if(path.indexOf(this)===-1){event.stopPropagation();this._applyFocus()}else{this._focusedChild=path[0]}},_onCaptureEsc:function(event){if(!this.noCancelOnEscKey){this.cancel(event)}},_onCaptureTab:function(event){if(!this.withBackdrop){return}var shift=event.shiftKey;var nodeToCheck=shift?this.__firstFocusableNode:this.__lastFocusableNode;var nodeToSet=shift?this.__lastFocusableNode:this.__firstFocusableNode;var shouldWrap=false;if(nodeToCheck===nodeToSet){shouldWrap=true}else{var focusedNode=this._manager.deepActiveElement;shouldWrap=focusedNode===nodeToCheck||focusedNode===this}if(shouldWrap){event.preventDefault();this._focusedChild=nodeToSet;this._applyFocus()}},_onIronResize:function(){if(this.opened&&!this.__isAnimating){this.__onNextAnimationFrame(this.refit)}},_onNodesChange:function(){if(this.opened&&!this.__isAnimating){this.notifyResize()}},__openedChanged:function(){if(this.opened){this._prepareRenderOpened();this._manager.addOverlay(this);this._applyFocus();this._renderOpened()}else{this._manager.removeOverlay(this);this._applyFocus();this._renderClosed()}},__onNextAnimationFrame:function(callback){if(this.__raf){window.cancelAnimationFrame(this.__raf)}var self=this;this.__raf=window.requestAnimationFrame(function nextAnimationFrame(){self.__raf=null;callback.call(self)})}};Polymer.IronOverlayBehavior=[Polymer.IronFitBehavior,Polymer.IronResizableBehavior,Polymer.IronOverlayBehaviorImpl]})();Polymer.NeonAnimatableBehavior={properties:{animationConfig:{type:Object},entryAnimation:{observer:"_entryAnimationChanged",type:String},exitAnimation:{observer:"_exitAnimationChanged",type:String}},_entryAnimationChanged:function(){this.animationConfig=this.animationConfig||{};this.animationConfig["entry"]=[{name:this.entryAnimation,node:this}]},_exitAnimationChanged:function(){this.animationConfig=this.animationConfig||{};this.animationConfig["exit"]=[{name:this.exitAnimation,node:this}]},_copyProperties:function(config1,config2){for(var property in config2){config1[property]=config2[property]}},_cloneConfig:function(config){var clone={isClone:true};this._copyProperties(clone,config);return clone},_getAnimationConfigRecursive:function(type,map,allConfigs){if(!this.animationConfig){return}if(this.animationConfig.value&&typeof this.animationConfig.value==="function"){this._warn(this._logf("playAnimation","Please put 'animationConfig' inside of your components 'properties' object instead of outside of it."));return}var thisConfig;if(type){thisConfig=this.animationConfig[type]}else{thisConfig=this.animationConfig}if(!Array.isArray(thisConfig)){thisConfig=[thisConfig]}if(thisConfig){for(var config,index=0;config=thisConfig[index];index++){if(config.animatable){config.animatable._getAnimationConfigRecursive(config.type||type,map,allConfigs)}else{if(config.id){var cachedConfig=map[config.id];if(cachedConfig){if(!cachedConfig.isClone){map[config.id]=this._cloneConfig(cachedConfig);cachedConfig=map[config.id]}this._copyProperties(cachedConfig,config)}else{map[config.id]=config}}else{allConfigs.push(config)}}}}},getAnimationConfig:function(type){var map={};var allConfigs=[];this._getAnimationConfigRecursive(type,map,allConfigs);for(var key in map){allConfigs.push(map[key])}return allConfigs}};Polymer.NeonAnimationRunnerBehaviorImpl={_configureAnimations:function(configs){var results=[];if(configs.length>0){for(var config,index=0;config=configs[index];index++){var neonAnimation=document.createElement(config.name);if(neonAnimation.isNeonAnimation){var result=null;try{result=neonAnimation.configure(config);if(typeof result.cancel!="function"){result=document.timeline.play(result)}}catch(e){result=null;console.warn("Couldnt play","(",config.name,").",e)}if(result){results.push({neonAnimation:neonAnimation,config:config,animation:result})}}else{console.warn(this.is+":",config.name,"not found!")}}}return results},_shouldComplete:function(activeEntries){var finished=true;for(var i=0;i<activeEntries.length;i++){if(activeEntries[i].animation.playState!="finished"){finished=false;break}}return finished},_complete:function(activeEntries){for(var i=0;i<activeEntries.length;i++){activeEntries[i].neonAnimation.complete(activeEntries[i].config)}for(var i=0;i<activeEntries.length;i++){activeEntries[i].animation.cancel()}},playAnimation:function(type,cookie){var configs=this.getAnimationConfig(type);if(!configs){return}this._active=this._active||{};if(this._active[type]){this._complete(this._active[type]);delete this._active[type]}var activeEntries=this._configureAnimations(configs);if(activeEntries.length==0){this.fire("neon-animation-finish",cookie,{bubbles:false});return}this._active[type]=activeEntries;for(var i=0;i<activeEntries.length;i++){activeEntries[i].animation.onfinish=function(){if(this._shouldComplete(activeEntries)){this._complete(activeEntries);delete this._active[type];this.fire("neon-animation-finish",cookie,{bubbles:false})}}.bind(this)}},cancelAnimation:function(){for(var k in this._animations){this._animations[k].cancel()}this._animations={}}};Polymer.NeonAnimationRunnerBehavior=[Polymer.NeonAnimatableBehavior,Polymer.NeonAnimationRunnerBehaviorImpl];Polymer.NeonAnimationBehavior={properties:{animationTiming:{type:Object,value:function(){return{duration:500,easing:"cubic-bezier(0.4, 0, 0.2, 1)",fill:"both"}}}},isNeonAnimation:true,timingFromConfig:function(config){if(config.timing){for(var property in config.timing){this.animationTiming[property]=config.timing[property]}}return this.animationTiming},setPrefixedProperty:function(node,property,value){var map={transform:["webkitTransform"],transformOrigin:["mozTransformOrigin","webkitTransformOrigin"]};var prefixes=map[property];for(var prefix,index=0;prefix=prefixes[index];index++){node.style[prefix]=value}node.style[property]=value},complete:function(){}};Polymer({is:"opaque-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;this._effect=new KeyframeEffect(node,[{opacity:"1"},{opacity:"1"}],this.timingFromConfig(config));node.style.opacity="0";return this._effect},complete:function(config){config.node.style.opacity=""}});(function(){"use strict";var LAST_TOUCH_POSITION={pageX:0,pageY:0};var ROOT_TARGET=null;var SCROLLABLE_NODES=[];Polymer.IronDropdownScrollManager={get currentLockingElement(){return this._lockingElements[this._lockingElements.length-1]},elementIsScrollLocked:function(element){var currentLockingElement=this.currentLockingElement;if(currentLockingElement===undefined)return false;var scrollLocked;if(this._hasCachedLockedElement(element)){return true}if(this._hasCachedUnlockedElement(element)){return false}scrollLocked=!!currentLockingElement&¤tLockingElement!==element&&!this._composedTreeContains(currentLockingElement,element);if(scrollLocked){this._lockedElementCache.push(element)}else{this._unlockedElementCache.push(element)}return scrollLocked},pushScrollLock:function(element){if(this._lockingElements.indexOf(element)>=0){return}if(this._lockingElements.length===0){this._lockScrollInteractions()}this._lockingElements.push(element);this._lockedElementCache=[];this._unlockedElementCache=[]},removeScrollLock:function(element){var index=this._lockingElements.indexOf(element);if(index===-1){return}this._lockingElements.splice(index,1);this._lockedElementCache=[];this._unlockedElementCache=[];if(this._lockingElements.length===0){this._unlockScrollInteractions()}},_lockingElements:[],_lockedElementCache:null,_unlockedElementCache:null,_hasCachedLockedElement:function(element){return this._lockedElementCache.indexOf(element)>-1},_hasCachedUnlockedElement:function(element){return this._unlockedElementCache.indexOf(element)>-1},_composedTreeContains:function(element,child){var contentElements;var distributedNodes;var contentIndex;var nodeIndex;if(element.contains(child)){return true}contentElements=Polymer.dom(element).querySelectorAll("content");for(contentIndex=0;contentIndex<contentElements.length;++contentIndex){distributedNodes=Polymer.dom(contentElements[contentIndex]).getDistributedNodes();for(nodeIndex=0;nodeIndex<distributedNodes.length;++nodeIndex){if(this._composedTreeContains(distributedNodes[nodeIndex],child)){return true}}}return false},_scrollInteractionHandler:function(event){if(event.cancelable&&this._shouldPreventScrolling(event)){event.preventDefault()}if(event.targetTouches){var touch=event.targetTouches[0];LAST_TOUCH_POSITION.pageX=touch.pageX;LAST_TOUCH_POSITION.pageY=touch.pageY}},_lockScrollInteractions:function(){this._boundScrollHandler=this._boundScrollHandler||this._scrollInteractionHandler.bind(this);document.addEventListener("wheel",this._boundScrollHandler,true);document.addEventListener("mousewheel",this._boundScrollHandler,true);document.addEventListener("DOMMouseScroll",this._boundScrollHandler,true);document.addEventListener("touchstart",this._boundScrollHandler,true);document.addEventListener("touchmove",this._boundScrollHandler,true)},_unlockScrollInteractions:function(){document.removeEventListener("wheel",this._boundScrollHandler,true);document.removeEventListener("mousewheel",this._boundScrollHandler,true);document.removeEventListener("DOMMouseScroll",this._boundScrollHandler,true);document.removeEventListener("touchstart",this._boundScrollHandler,true);document.removeEventListener("touchmove",this._boundScrollHandler,true)},_shouldPreventScrolling:function(event){var target=Polymer.dom(event).rootTarget;if(event.type!=="touchmove"&&ROOT_TARGET!==target){ROOT_TARGET=target;SCROLLABLE_NODES=this._getScrollableNodes(Polymer.dom(event).path)}if(!SCROLLABLE_NODES.length){return true}if(event.type==="touchstart"){return false}var info=this._getScrollInfo(event);return!this._getScrollingNode(SCROLLABLE_NODES,info.deltaX,info.deltaY)},_getScrollableNodes:function(nodes){var scrollables=[];var lockingIndex=nodes.indexOf(this.currentLockingElement);for(var i=0;i<=lockingIndex;i++){var node=nodes[i];if(node.nodeType===11){continue}var style=node.style;if(style.overflow!=="scroll"&&style.overflow!=="auto"){style=window.getComputedStyle(node)}if(style.overflow==="scroll"||style.overflow==="auto"){scrollables.push(node)}}return scrollables},_getScrollingNode:function(nodes,deltaX,deltaY){if(!deltaX&&!deltaY){return}var verticalScroll=Math.abs(deltaY)>=Math.abs(deltaX);for(var i=0;i<nodes.length;i++){var node=nodes[i];var canScroll=false;if(verticalScroll){canScroll=deltaY<0?node.scrollTop>0:node.scrollTop<node.scrollHeight-node.clientHeight}else{canScroll=deltaX<0?node.scrollLeft>0:node.scrollLeft<node.scrollWidth-node.clientWidth}if(canScroll){return node}}},_getScrollInfo:function(event){var info={deltaX:event.deltaX,deltaY:event.deltaY};if("deltaX"in event){}else if("wheelDeltaX"in event){info.deltaX=-event.wheelDeltaX;info.deltaY=-event.wheelDeltaY}else if("axis"in event){info.deltaX=event.axis===1?event.detail:0;info.deltaY=event.axis===2?event.detail:0}else if(event.targetTouches){var touch=event.targetTouches[0];info.deltaX=LAST_TOUCH_POSITION.pageX-touch.pageX;info.deltaY=LAST_TOUCH_POSITION.pageY-touch.pageY}return info}}})();(function(){"use strict";Polymer({is:"iron-dropdown",behaviors:[Polymer.IronControlState,Polymer.IronA11yKeysBehavior,Polymer.IronOverlayBehavior,Polymer.NeonAnimationRunnerBehavior],properties:{horizontalAlign:{type:String,value:"left",reflectToAttribute:true},verticalAlign:{type:String,value:"top",reflectToAttribute:true},openAnimationConfig:{type:Object},closeAnimationConfig:{type:Object},focusTarget:{type:Object},noAnimations:{type:Boolean,value:false},allowOutsideScroll:{type:Boolean,value:false},_boundOnCaptureScroll:{type:Function,value:function(){return this._onCaptureScroll.bind(this)}}},listeners:{"neon-animation-finish":"_onNeonAnimationFinish"},observers:["_updateOverlayPosition(positionTarget, verticalAlign, horizontalAlign, verticalOffset, horizontalOffset)"],get containedElement(){return Polymer.dom(this.$.content).getDistributedNodes()[0]},get _focusTarget(){return this.focusTarget||this.containedElement},ready:function(){this._scrollTop=0;this._scrollLeft=0;this._refitOnScrollRAF=null},attached:function(){if(!this.sizingTarget||this.sizingTarget===this){this.sizingTarget=this.containedElement}},detached:function(){this.cancelAnimation();document.removeEventListener("scroll",this._boundOnCaptureScroll);Polymer.IronDropdownScrollManager.removeScrollLock(this)},_openedChanged:function(){if(this.opened&&this.disabled){this.cancel()}else{this.cancelAnimation();this._updateAnimationConfig();this._saveScrollPosition();if(this.opened){document.addEventListener("scroll",this._boundOnCaptureScroll);!this.allowOutsideScroll&&Polymer.IronDropdownScrollManager.pushScrollLock(this)}else{document.removeEventListener("scroll",this._boundOnCaptureScroll);Polymer.IronDropdownScrollManager.removeScrollLock(this)}Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this,arguments)}},_renderOpened:function(){if(!this.noAnimations&&this.animationConfig.open){this.$.contentWrapper.classList.add("animating");this.playAnimation("open")}else{Polymer.IronOverlayBehaviorImpl._renderOpened.apply(this,arguments)}},_renderClosed:function(){if(!this.noAnimations&&this.animationConfig.close){this.$.contentWrapper.classList.add("animating");this.playAnimation("close")}else{Polymer.IronOverlayBehaviorImpl._renderClosed.apply(this,arguments)}},_onNeonAnimationFinish:function(){this.$.contentWrapper.classList.remove("animating");if(this.opened){this._finishRenderOpened()}else{this._finishRenderClosed()}},_onCaptureScroll:function(){if(!this.allowOutsideScroll){this._restoreScrollPosition()}else{this._refitOnScrollRAF&&window.cancelAnimationFrame(this._refitOnScrollRAF);this._refitOnScrollRAF=window.requestAnimationFrame(this.refit.bind(this))}},_saveScrollPosition:function(){if(document.scrollingElement){this._scrollTop=document.scrollingElement.scrollTop;this._scrollLeft=document.scrollingElement.scrollLeft}else{this._scrollTop=Math.max(document.documentElement.scrollTop,document.body.scrollTop);this._scrollLeft=Math.max(document.documentElement.scrollLeft,document.body.scrollLeft)}},_restoreScrollPosition:function(){if(document.scrollingElement){document.scrollingElement.scrollTop=this._scrollTop;document.scrollingElement.scrollLeft=this._scrollLeft}else{document.documentElement.scrollTop=this._scrollTop;document.documentElement.scrollLeft=this._scrollLeft;document.body.scrollTop=this._scrollTop;document.body.scrollLeft=this._scrollLeft}},_updateAnimationConfig:function(){var animations=(this.openAnimationConfig||[]).concat(this.closeAnimationConfig||[]);for(var i=0;i<animations.length;i++){animations[i].node=this.containedElement}this.animationConfig={open:this.openAnimationConfig,close:this.closeAnimationConfig}},_updateOverlayPosition:function(){if(this.isAttached){this.notifyResize()}},_applyFocus:function(){var focusTarget=this.focusTarget||this.containedElement;if(focusTarget&&this.opened&&!this.noAutoFocus){focusTarget.focus()}else{Polymer.IronOverlayBehaviorImpl._applyFocus.apply(this,arguments)}}})})();Polymer({is:"fade-in-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;this._effect=new KeyframeEffect(node,[{opacity:"0"},{opacity:"1"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"fade-out-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;this._effect=new KeyframeEffect(node,[{opacity:"1"},{opacity:"0"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-grow-height-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var height=rect.height;this._effect=new KeyframeEffect(node,[{height:height/2+"px"},{height:height+"px"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-grow-width-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var width=rect.width;this._effect=new KeyframeEffect(node,[{width:width/2+"px"},{width:width+"px"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-shrink-width-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var width=rect.width;this._effect=new KeyframeEffect(node,[{width:width+"px"},{width:width-width/20+"px"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-shrink-height-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var height=rect.height;var top=rect.top;this.setPrefixedProperty(node,"transformOrigin","0 0");this._effect=new KeyframeEffect(node,[{height:height+"px",transform:"translateY(0)"},{height:height/2+"px",transform:"translateY(-20px)"}],this.timingFromConfig(config));return this._effect}});(function(){"use strict";var config={ANIMATION_CUBIC_BEZIER:"cubic-bezier(.3,.95,.5,1)",MAX_ANIMATION_TIME_MS:400};var PaperMenuButton=Polymer({is:"paper-menu-button",behaviors:[Polymer.IronA11yKeysBehavior,Polymer.IronControlState],properties:{opened:{type:Boolean,value:false,notify:true,observer:"_openedChanged"},horizontalAlign:{type:String,value:"left",reflectToAttribute:true},verticalAlign:{type:String,value:"top",reflectToAttribute:true},dynamicAlign:{type:Boolean},horizontalOffset:{type:Number,value:0,notify:true},verticalOffset:{type:Number,value:0,notify:true},noOverlap:{type:Boolean},noAnimations:{type:Boolean,value:false},ignoreSelect:{type:Boolean,value:false},closeOnActivate:{type:Boolean,value:false},openAnimationConfig:{type:Object,value:function(){return[{name:"fade-in-animation",timing:{delay:100,duration:200}},{name:"paper-menu-grow-width-animation",timing:{delay:100,duration:150,easing:config.ANIMATION_CUBIC_BEZIER}},{name:"paper-menu-grow-height-animation",timing:{delay:100,duration:275,easing:config.ANIMATION_CUBIC_BEZIER}}]}},closeAnimationConfig:{type:Object,value:function(){return[{name:"fade-out-animation",timing:{duration:150}},{name:"paper-menu-shrink-width-animation",timing:{delay:100,duration:50,easing:config.ANIMATION_CUBIC_BEZIER}},{name:"paper-menu-shrink-height-animation",timing:{duration:200,easing:"ease-in"}}]}},allowOutsideScroll:{type:Boolean,value:false},restoreFocusOnClose:{type:Boolean,value:true},_dropdownContent:{type:Object}},hostAttributes:{role:"group","aria-haspopup":"true"},listeners:{"iron-activate":"_onIronActivate","iron-select":"_onIronSelect"},get contentElement(){return Polymer.dom(this.$.content).getDistributedNodes()[0]},toggle:function(){if(this.opened){this.close()}else{this.open()}},open:function(){if(this.disabled){return}this.$.dropdown.open()},close:function(){this.$.dropdown.close()},_onIronSelect:function(event){if(!this.ignoreSelect){this.close()}},_onIronActivate:function(event){if(this.closeOnActivate){this.close()}},_openedChanged:function(opened,oldOpened){if(opened){this._dropdownContent=this.contentElement;this.fire("paper-dropdown-open")}else if(oldOpened!=null){this.fire("paper-dropdown-close")}},_disabledChanged:function(disabled){Polymer.IronControlState._disabledChanged.apply(this,arguments);if(disabled&&this.opened){this.close()}},__onIronOverlayCanceled:function(event){var uiEvent=event.detail;var target=Polymer.dom(uiEvent).rootTarget;var trigger=this.$.trigger;var path=Polymer.dom(uiEvent).path;if(path.indexOf(trigger)>-1){event.preventDefault()}}});Object.keys(config).forEach(function(key){PaperMenuButton[key]=config[key]});Polymer.PaperMenuButton=PaperMenuButton})();Polymer.PaperInkyFocusBehaviorImpl={observers:["_focusedChanged(receivedFocusFromKeyboard)"],_focusedChanged:function(receivedFocusFromKeyboard){if(receivedFocusFromKeyboard){this.ensureRipple()}if(this.hasRipple()){this._ripple.holdDown=receivedFocusFromKeyboard}},_createRipple:function(){var ripple=Polymer.PaperRippleBehavior._createRipple();ripple.id="ink";ripple.setAttribute("center","");ripple.classList.add("circle");return ripple}};Polymer.PaperInkyFocusBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperRippleBehavior,Polymer.PaperInkyFocusBehaviorImpl];Polymer({is:"paper-icon-button",hostAttributes:{role:"button",tabindex:"0"},behaviors:[Polymer.PaperInkyFocusBehavior],properties:{src:{type:String},icon:{type:String},alt:{type:String,observer:"_altChanged"}},_altChanged:function(newValue,oldValue){var label=this.getAttribute("aria-label");if(!label||oldValue==label){this.setAttribute("aria-label",newValue)}}});Polymer({is:"iron-media-query",properties:{queryMatches:{type:Boolean,value:false,readOnly:true,notify:true},query:{type:String,observer:"queryChanged"},full:{type:Boolean,value:false},_boundMQHandler:{value:function(){return this.queryHandler.bind(this)}},_mq:{value:null}},attached:function(){this.style.display="none";this.queryChanged()},detached:function(){this._remove()},_add:function(){if(this._mq){this._mq.addListener(this._boundMQHandler)}},_remove:function(){if(this._mq){this._mq.removeListener(this._boundMQHandler)}this._mq=null},queryChanged:function(){this._remove();var query=this.query;if(!query){return}if(!this.full&&query[0]!=="("){query="("+query+")"}this._mq=window.matchMedia(query);this._add();this.queryHandler(this._mq)},queryHandler:function(mq){this._setQueryMatches(mq.matches)}});(function(){"use strict";Polymer.IronA11yAnnouncer=Polymer({is:"iron-a11y-announcer",properties:{mode:{type:String,value:"polite"},_text:{type:String,value:""}},created:function(){if(!Polymer.IronA11yAnnouncer.instance){Polymer.IronA11yAnnouncer.instance=this}document.body.addEventListener("iron-announce",this._onIronAnnounce.bind(this))},announce:function(text){this._text="";this.async(function(){this._text=text},100)},_onIronAnnounce:function(event){if(event.detail&&event.detail.text){this.announce(event.detail.text)}}});Polymer.IronA11yAnnouncer.instance=null;Polymer.IronA11yAnnouncer.requestAvailability=function(){if(!Polymer.IronA11yAnnouncer.instance){Polymer.IronA11yAnnouncer.instance=document.createElement("iron-a11y-announcer")}document.body.appendChild(Polymer.IronA11yAnnouncer.instance)}})();Polymer.IronValidatableBehaviorMeta=null;Polymer.IronValidatableBehavior={properties:{validator:{type:String},invalid:{notify:true,reflectToAttribute:true,type:Boolean,value:false},_validatorMeta:{type:Object},validatorType:{type:String,value:"validator"},_validator:{type:Object,computed:"__computeValidator(validator)"}},observers:["_invalidChanged(invalid)"],registered:function(){Polymer.IronValidatableBehaviorMeta=new Polymer.IronMeta({type:"validator"})},_invalidChanged:function(){if(this.invalid){this.setAttribute("aria-invalid","true")}else{this.removeAttribute("aria-invalid")}},hasValidator:function(){return this._validator!=null},validate:function(value){this.invalid=!this._getValidity(value);return!this.invalid},_getValidity:function(value){if(this.hasValidator()){return this._validator.validate(value)}return true},__computeValidator:function(){return Polymer.IronValidatableBehaviorMeta&&Polymer.IronValidatableBehaviorMeta.byKey(this.validator)}};Polymer({is:"iron-input","extends":"input",behaviors:[Polymer.IronValidatableBehavior],properties:{bindValue:{observer:"_bindValueChanged",type:String},preventInvalidInput:{type:Boolean},allowedPattern:{type:String,observer:"_allowedPatternChanged"},_previousValidInput:{type:String,value:""},_patternAlreadyChecked:{type:Boolean,value:false}},listeners:{input:"_onInput",keypress:"_onKeypress"},registered:function(){if(!this._canDispatchEventOnDisabled()){this._origDispatchEvent=this.dispatchEvent;this.dispatchEvent=this._dispatchEventFirefoxIE}},created:function(){Polymer.IronA11yAnnouncer.requestAvailability()},_canDispatchEventOnDisabled:function(){var input=document.createElement("input");var canDispatch=false;input.disabled=true;input.addEventListener("feature-check-dispatch-event",function(){canDispatch=true});try{input.dispatchEvent(new Event("feature-check-dispatch-event"))}catch(e){}return canDispatch},_dispatchEventFirefoxIE:function(){var disabled=this.disabled;this.disabled=false;this._origDispatchEvent.apply(this,arguments);this.disabled=disabled},get _patternRegExp(){var pattern;if(this.allowedPattern){pattern=new RegExp(this.allowedPattern)}else{switch(this.type){case"number":pattern=/[0-9.,e-]/;break}}return pattern},ready:function(){this.bindValue=this.value},_bindValueChanged:function(){if(this.value!==this.bindValue){this.value=!(this.bindValue||this.bindValue===0||this.bindValue===false)?"":this.bindValue}this.fire("bind-value-changed",{value:this.bindValue})},_allowedPatternChanged:function(){this.preventInvalidInput=this.allowedPattern?true:false},_onInput:function(){if(this.preventInvalidInput&&!this._patternAlreadyChecked){var valid=this._checkPatternValidity();if(!valid){this._announceInvalidCharacter("Invalid string of characters not entered.");this.value=this._previousValidInput}}this.bindValue=this.value;this._previousValidInput=this.value;this._patternAlreadyChecked=false},_isPrintable:function(event){var anyNonPrintable=event.keyCode==8||event.keyCode==9||event.keyCode==13||event.keyCode==27;var mozNonPrintable=event.keyCode==19||event.keyCode==20||event.keyCode==45||event.keyCode==46||event.keyCode==144||event.keyCode==145||event.keyCode>32&&event.keyCode<41||event.keyCode>111&&event.keyCode<124;return!anyNonPrintable&&!(event.charCode==0&&mozNonPrintable)},_onKeypress:function(event){if(!this.preventInvalidInput&&this.type!=="number"){return}var regexp=this._patternRegExp;if(!regexp){return}if(event.metaKey||event.ctrlKey||event.altKey)return;this._patternAlreadyChecked=true;var thisChar=String.fromCharCode(event.charCode);if(this._isPrintable(event)&&!regexp.test(thisChar)){event.preventDefault();this._announceInvalidCharacter("Invalid character "+thisChar+" not entered.")}},_checkPatternValidity:function(){var regexp=this._patternRegExp;if(!regexp){return true}for(var i=0;i<this.value.length;i++){if(!regexp.test(this.value[i])){return false}}return true},validate:function(){var valid=this.checkValidity();if(valid){if(this.required&&this.value===""){valid=false}else if(this.hasValidator()){valid=Polymer.IronValidatableBehavior.validate.call(this,this.value)}}this.invalid=!valid;this.fire("iron-input-validate");return valid},_announceInvalidCharacter:function(message){this.fire("iron-announce",{text:message})}});Polymer({is:"paper-input-container",properties:{noLabelFloat:{type:Boolean,value:false},alwaysFloatLabel:{type:Boolean,value:false},attrForValue:{type:String,value:"bind-value"},autoValidate:{type:Boolean,value:false},invalid:{observer:"_invalidChanged",type:Boolean,value:false},focused:{readOnly:true,type:Boolean,value:false,notify:true},_addons:{type:Array},_inputHasContent:{type:Boolean,value:false},_inputSelector:{type:String,value:"input,textarea,.paper-input-input"},_boundOnFocus:{type:Function,value:function(){return this._onFocus.bind(this)}},_boundOnBlur:{type:Function,value:function(){return this._onBlur.bind(this)}},_boundOnInput:{type:Function,value:function(){return this._onInput.bind(this)}},_boundValueChanged:{ -type:Function,value:function(){return this._onValueChanged.bind(this)}}},listeners:{"addon-attached":"_onAddonAttached","iron-input-validate":"_onIronInputValidate"},get _valueChangedEvent(){return this.attrForValue+"-changed"},get _propertyForValue(){return Polymer.CaseMap.dashToCamelCase(this.attrForValue)},get _inputElement(){return Polymer.dom(this).querySelector(this._inputSelector)},get _inputElementValue(){return this._inputElement[this._propertyForValue]||this._inputElement.value},ready:function(){if(!this._addons){this._addons=[]}this.addEventListener("focus",this._boundOnFocus,true);this.addEventListener("blur",this._boundOnBlur,true)},attached:function(){if(this.attrForValue){this._inputElement.addEventListener(this._valueChangedEvent,this._boundValueChanged)}else{this.addEventListener("input",this._onInput)}if(this._inputElementValue!=""){this._handleValueAndAutoValidate(this._inputElement)}else{this._handleValue(this._inputElement)}},_onAddonAttached:function(event){if(!this._addons){this._addons=[]}var target=event.target;if(this._addons.indexOf(target)===-1){this._addons.push(target);if(this.isAttached){this._handleValue(this._inputElement)}}},_onFocus:function(){this._setFocused(true)},_onBlur:function(){this._setFocused(false);this._handleValueAndAutoValidate(this._inputElement)},_onInput:function(event){this._handleValueAndAutoValidate(event.target)},_onValueChanged:function(event){this._handleValueAndAutoValidate(event.target)},_handleValue:function(inputElement){var value=this._inputElementValue;if(value||value===0||inputElement.type==="number"&&!inputElement.checkValidity()){this._inputHasContent=true}else{this._inputHasContent=false}this.updateAddons({inputElement:inputElement,value:value,invalid:this.invalid})},_handleValueAndAutoValidate:function(inputElement){if(this.autoValidate){var valid;if(inputElement.validate){valid=inputElement.validate(this._inputElementValue)}else{valid=inputElement.checkValidity()}this.invalid=!valid}this._handleValue(inputElement)},_onIronInputValidate:function(event){this.invalid=this._inputElement.invalid},_invalidChanged:function(){if(this._addons){this.updateAddons({invalid:this.invalid})}},updateAddons:function(state){for(var addon,index=0;addon=this._addons[index];index++){addon.update(state)}},_computeInputContentClass:function(noLabelFloat,alwaysFloatLabel,focused,invalid,_inputHasContent){var cls="input-content";if(!noLabelFloat){var label=this.querySelector("label");if(alwaysFloatLabel||_inputHasContent){cls+=" label-is-floating";this.$.labelAndInputContainer.style.position="static";if(invalid){cls+=" is-invalid"}else if(focused){cls+=" label-is-highlighted"}}else{if(label){this.$.labelAndInputContainer.style.position="relative"}}}else{if(_inputHasContent){cls+=" label-is-hidden"}}return cls},_computeUnderlineClass:function(focused,invalid){var cls="underline";if(invalid){cls+=" is-invalid"}else if(focused){cls+=" is-highlighted"}return cls},_computeAddOnContentClass:function(focused,invalid){var cls="add-on-content";if(invalid){cls+=" is-invalid"}else if(focused){cls+=" is-highlighted"}return cls}});Polymer.PaperSpinnerBehavior={listeners:{animationend:"__reset",webkitAnimationEnd:"__reset"},properties:{active:{type:Boolean,value:false,reflectToAttribute:true,observer:"__activeChanged"},alt:{type:String,value:"loading",observer:"__altChanged"},__coolingDown:{type:Boolean,value:false}},__computeContainerClasses:function(active,coolingDown){return[active||coolingDown?"active":"",coolingDown?"cooldown":""].join(" ")},__activeChanged:function(active,old){this.__setAriaHidden(!active);this.__coolingDown=!active&&old},__altChanged:function(alt){if(alt===this.getPropertyInfo("alt").value){this.alt=this.getAttribute("aria-label")||alt}else{this.__setAriaHidden(alt==="");this.setAttribute("aria-label",alt)}},__setAriaHidden:function(hidden){var attr="aria-hidden";if(hidden){this.setAttribute(attr,"true")}else{this.removeAttribute(attr)}},__reset:function(){this.active=false;this.__coolingDown=false}};Polymer({is:"paper-spinner-lite",behaviors:[Polymer.PaperSpinnerBehavior]}); +cr.define("downloads",function(){var Item=Polymer({is:"downloads-item",properties:{data:{type:Object},completelyOnDisk_:{computed:"computeCompletelyOnDisk_("+"data.state, data.file_externally_removed)",type:Boolean,value:true},controlledBy_:{computed:"computeControlledBy_(data.by_ext_id, data.by_ext_name)",type:String,value:""},isActive_:{computed:"computeIsActive_("+"data.state, data.file_externally_removed)",type:Boolean,value:true},isDangerous_:{computed:"computeIsDangerous_(data.state)",type:Boolean,value:false},isMalware_:{computed:"computeIsMalware_(isDangerous_, data.danger_type)",type:Boolean,value:false},isInProgress_:{computed:"computeIsInProgress_(data.state)",type:Boolean,value:false},pauseOrResumeText_:{computed:"computePauseOrResumeText_(isInProgress_, data.resume)",type:String},showCancel_:{computed:"computeShowCancel_(data.state)",type:Boolean,value:false},showProgress_:{computed:"computeShowProgress_(showCancel_, data.percent)",type:Boolean,value:false}},observers:["observeControlledBy_(controlledBy_)","observeIsDangerous_(isDangerous_, data)"],ready:function(){this.content=this.$.content},chopUrl_:function(url){return url.slice(0,300)},computeClass_:function(){var classes=[];if(this.isActive_)classes.push("is-active");if(this.isDangerous_)classes.push("dangerous");if(this.showProgress_)classes.push("show-progress");return classes.join(" ")},computeCompletelyOnDisk_:function(){return this.data.state==downloads.States.COMPLETE&&!this.data.file_externally_removed},computeControlledBy_:function(){if(!this.data.by_ext_id||!this.data.by_ext_name)return"";var url="chrome://extensions#"+this.data.by_ext_id;var name=this.data.by_ext_name;return loadTimeData.getStringF("controlledByUrl",url,HTMLEscape(name))},computeDangerIcon_:function(){return this.isDangerous_?"cr:warning":""},computeDate_:function(){assert(typeof this.data.hideDate=="boolean");if(this.data.hideDate)return"";return assert(this.data.since_string||this.data.date_string)},computeDescription_:function(){var data=this.data;switch(data.state){case downloads.States.DANGEROUS:var fileName=data.file_name;switch(data.danger_type){case downloads.DangerType.DANGEROUS_FILE:return loadTimeData.getString("dangerFileDesc");case downloads.DangerType.DANGEROUS_URL:case downloads.DangerType.DANGEROUS_CONTENT:case downloads.DangerType.DANGEROUS_HOST:return loadTimeData.getString("dangerDownloadDesc");case downloads.DangerType.UNCOMMON_CONTENT:return loadTimeData.getString("dangerUncommonDesc");case downloads.DangerType.POTENTIALLY_UNWANTED:return loadTimeData.getString("dangerSettingsDesc")}break;case downloads.States.IN_PROGRESS:case downloads.States.PAUSED:return data.progress_status_text}return""},computeIsActive_:function(){return this.data.state!=downloads.States.CANCELLED&&this.data.state!=downloads.States.INTERRUPTED&&!this.data.file_externally_removed},computeIsDangerous_:function(){return this.data.state==downloads.States.DANGEROUS},computeIsInProgress_:function(){return this.data.state==downloads.States.IN_PROGRESS},computeIsMalware_:function(){return this.isDangerous_&&(this.data.danger_type==downloads.DangerType.DANGEROUS_CONTENT||this.data.danger_type==downloads.DangerType.DANGEROUS_HOST||this.data.danger_type==downloads.DangerType.DANGEROUS_URL||this.data.danger_type==downloads.DangerType.POTENTIALLY_UNWANTED)},computePauseOrResumeText_:function(){if(this.isInProgress_)return loadTimeData.getString("controlPause");if(this.data.resume)return loadTimeData.getString("controlResume");return""},computeRemoveStyle_:function(){var canDelete=loadTimeData.getBoolean("allowDeletingHistory");var hideRemove=this.isDangerous_||this.showCancel_||!canDelete;return hideRemove?"visibility: hidden":""},computeShowCancel_:function(){return this.data.state==downloads.States.IN_PROGRESS||this.data.state==downloads.States.PAUSED},computeShowProgress_:function(){return this.showCancel_&&this.data.percent>=-1},computeTag_:function(){switch(this.data.state){case downloads.States.CANCELLED:return loadTimeData.getString("statusCancelled");case downloads.States.INTERRUPTED:return this.data.last_reason_text;case downloads.States.COMPLETE:return this.data.file_externally_removed?loadTimeData.getString("statusRemoved"):""}return""},isIndeterminate_:function(){return this.data.percent==-1},observeControlledBy_:function(){this.$["controlled-by"].innerHTML=this.controlledBy_},observeIsDangerous_:function(){if(!this.data)return;if(this.isDangerous_){this.$.url.removeAttribute("href")}else{this.$.url.href=assert(this.data.url);var filePath=encodeURIComponent(this.data.file_path);var scaleFactor="?scale="+window.devicePixelRatio+"x";this.$["file-icon"].src="chrome://fileicon/"+filePath+scaleFactor}},onCancelTap_:function(){downloads.ActionService.getInstance().cancel(this.data.id)},onDiscardDangerousTap_:function(){downloads.ActionService.getInstance().discardDangerous(this.data.id)},onDragStart_:function(e){e.preventDefault();downloads.ActionService.getInstance().drag(this.data.id)},onFileLinkTap_:function(e){e.preventDefault();downloads.ActionService.getInstance().openFile(this.data.id)},onPauseOrResumeTap_:function(){if(this.isInProgress_)downloads.ActionService.getInstance().pause(this.data.id);else downloads.ActionService.getInstance().resume(this.data.id)},onRemoveTap_:function(){downloads.ActionService.getInstance().remove(this.data.id)},onRetryTap_:function(){downloads.ActionService.getInstance().download(this.data.url)},onSaveDangerousTap_:function(){downloads.ActionService.getInstance().saveDangerous(this.data.id)},onShowTap_:function(){downloads.ActionService.getInstance().show(this.data.id)}});return{Item:Item}});Polymer.PaperItemBehaviorImpl={hostAttributes:{role:"option",tabindex:"0"}};Polymer.PaperItemBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperItemBehaviorImpl];Polymer({is:"paper-item",behaviors:[Polymer.PaperItemBehavior]});Polymer.IronSelection=function(selectCallback){this.selection=[];this.selectCallback=selectCallback};Polymer.IronSelection.prototype={get:function(){return this.multi?this.selection.slice():this.selection[0]},clear:function(excludes){this.selection.slice().forEach(function(item){if(!excludes||excludes.indexOf(item)<0){this.setItemSelected(item,false)}},this)},isSelected:function(item){return this.selection.indexOf(item)>=0},setItemSelected:function(item,isSelected){if(item!=null){if(isSelected!==this.isSelected(item)){if(isSelected){this.selection.push(item)}else{var i=this.selection.indexOf(item);if(i>=0){this.selection.splice(i,1)}}if(this.selectCallback){this.selectCallback(item,isSelected)}}}},select:function(item){if(this.multi){this.toggle(item)}else if(this.get()!==item){this.setItemSelected(this.get(),false);this.setItemSelected(item,true)}},toggle:function(item){this.setItemSelected(item,!this.isSelected(item))}};Polymer.IronSelectableBehavior={properties:{attrForSelected:{type:String,value:null},selected:{type:String,notify:true},selectedItem:{type:Object,readOnly:true,notify:true},activateEvent:{type:String,value:"tap",observer:"_activateEventChanged"},selectable:String,selectedClass:{type:String,value:"iron-selected"},selectedAttribute:{type:String,value:null},fallbackSelection:{type:String,value:null},items:{type:Array,readOnly:true,notify:true,value:function(){return[]}},_excludedLocalNames:{type:Object,value:function(){return{template:1}}}},observers:["_updateAttrForSelected(attrForSelected)","_updateSelected(selected)","_checkFallback(fallbackSelection)"],created:function(){this._bindFilterItem=this._filterItem.bind(this);this._selection=new Polymer.IronSelection(this._applySelection.bind(this))},attached:function(){this._observer=this._observeItems(this);this._updateItems();if(!this._shouldUpdateSelection){this._updateSelected()}this._addListener(this.activateEvent)},detached:function(){if(this._observer){Polymer.dom(this).unobserveNodes(this._observer)}this._removeListener(this.activateEvent)},indexOf:function(item){return this.items.indexOf(item)},select:function(value){this.selected=value},selectPrevious:function(){var length=this.items.length;var index=(Number(this._valueToIndex(this.selected))-1+length)%length;this.selected=this._indexToValue(index)},selectNext:function(){var index=(Number(this._valueToIndex(this.selected))+1)%this.items.length;this.selected=this._indexToValue(index)},selectIndex:function(index){this.select(this._indexToValue(index))},forceSynchronousItemUpdate:function(){this._updateItems()},get _shouldUpdateSelection(){return this.selected!=null},_checkFallback:function(){if(this._shouldUpdateSelection){this._updateSelected()}},_addListener:function(eventName){this.listen(this,eventName,"_activateHandler")},_removeListener:function(eventName){this.unlisten(this,eventName,"_activateHandler")},_activateEventChanged:function(eventName,old){this._removeListener(old);this._addListener(eventName)},_updateItems:function(){var nodes=Polymer.dom(this).queryDistributedElements(this.selectable||"*");nodes=Array.prototype.filter.call(nodes,this._bindFilterItem);this._setItems(nodes)},_updateAttrForSelected:function(){if(this._shouldUpdateSelection){this.selected=this._indexToValue(this.indexOf(this.selectedItem))}},_updateSelected:function(){this._selectSelected(this.selected)},_selectSelected:function(selected){this._selection.select(this._valueToItem(this.selected));if(this.fallbackSelection&&this.items.length&&this._selection.get()===undefined){this.selected=this.fallbackSelection}},_filterItem:function(node){return!this._excludedLocalNames[node.localName]},_valueToItem:function(value){return value==null?null:this.items[this._valueToIndex(value)]},_valueToIndex:function(value){if(this.attrForSelected){for(var i=0,item;item=this.items[i];i++){if(this._valueForItem(item)==value){return i}}}else{return Number(value)}},_indexToValue:function(index){if(this.attrForSelected){var item=this.items[index];if(item){return this._valueForItem(item)}}else{return index}},_valueForItem:function(item){var propValue=item[Polymer.CaseMap.dashToCamelCase(this.attrForSelected)];return propValue!=undefined?propValue:item.getAttribute(this.attrForSelected)},_applySelection:function(item,isSelected){if(this.selectedClass){this.toggleClass(this.selectedClass,isSelected,item)}if(this.selectedAttribute){this.toggleAttribute(this.selectedAttribute,isSelected,item)}this._selectionChange();this.fire("iron-"+(isSelected?"select":"deselect"),{item:item})},_selectionChange:function(){this._setSelectedItem(this._selection.get())},_observeItems:function(node){return Polymer.dom(node).observeNodes(function(mutation){this._updateItems();if(this._shouldUpdateSelection){this._updateSelected()}this.fire("iron-items-changed",mutation,{bubbles:false,cancelable:false})})},_activateHandler:function(e){var t=e.target;var items=this.items;while(t&&t!=this){var i=items.indexOf(t);if(i>=0){var value=this._indexToValue(i);this._itemActivate(value,t);return}t=t.parentNode}},_itemActivate:function(value,item){if(!this.fire("iron-activate",{selected:value,item:item},{cancelable:true}).defaultPrevented){this.select(value)}}};Polymer.IronMultiSelectableBehaviorImpl={properties:{multi:{type:Boolean,value:false,observer:"multiChanged"},selectedValues:{type:Array,notify:true},selectedItems:{type:Array,readOnly:true,notify:true}},observers:["_updateSelected(selectedValues.splices)"],select:function(value){if(this.multi){if(this.selectedValues){this._toggleSelected(value)}else{this.selectedValues=[value]}}else{this.selected=value}},multiChanged:function(multi){this._selection.multi=multi},get _shouldUpdateSelection(){return this.selected!=null||this.selectedValues!=null&&this.selectedValues.length},_updateAttrForSelected:function(){if(!this.multi){Polymer.IronSelectableBehavior._updateAttrForSelected.apply(this)}else if(this._shouldUpdateSelection){this.selectedValues=this.selectedItems.map(function(selectedItem){return this._indexToValue(this.indexOf(selectedItem))},this).filter(function(unfilteredValue){return unfilteredValue!=null},this)}},_updateSelected:function(){if(this.multi){this._selectMulti(this.selectedValues)}else{this._selectSelected(this.selected)}},_selectMulti:function(values){if(values){var selectedItems=this._valuesToItems(values);this._selection.clear(selectedItems);for(var i=0;i<selectedItems.length;i++){this._selection.setItemSelected(selectedItems[i],true)}if(this.fallbackSelection&&this.items.length&&!this._selection.get().length){var fallback=this._valueToItem(this.fallbackSelection);if(fallback){this.selectedValues=[this.fallbackSelection]}}}else{this._selection.clear()}},_selectionChange:function(){var s=this._selection.get();if(this.multi){this._setSelectedItems(s)}else{this._setSelectedItems([s]);this._setSelectedItem(s)}},_toggleSelected:function(value){var i=this.selectedValues.indexOf(value);var unselected=i<0;if(unselected){this.push("selectedValues",value)}else{this.splice("selectedValues",i,1)}},_valuesToItems:function(values){return values==null?null:values.map(function(value){return this._valueToItem(value)},this)}};Polymer.IronMultiSelectableBehavior=[Polymer.IronSelectableBehavior,Polymer.IronMultiSelectableBehaviorImpl];Polymer.IronMenuBehaviorImpl={properties:{focusedItem:{observer:"_focusedItemChanged",readOnly:true,type:Object},attrForItemTitle:{type:String}},hostAttributes:{role:"menu",tabindex:"0"},observers:["_updateMultiselectable(multi)"],listeners:{focus:"_onFocus",keydown:"_onKeydown","iron-items-changed":"_onIronItemsChanged"},keyBindings:{up:"_onUpKey",down:"_onDownKey",esc:"_onEscKey","shift+tab:keydown":"_onShiftTabDown"},attached:function(){this._resetTabindices()},select:function(value){if(this._defaultFocusAsync){this.cancelAsync(this._defaultFocusAsync);this._defaultFocusAsync=null}var item=this._valueToItem(value);if(item&&item.hasAttribute("disabled"))return;this._setFocusedItem(item);Polymer.IronMultiSelectableBehaviorImpl.select.apply(this,arguments)},_resetTabindices:function(){var selectedItem=this.multi?this.selectedItems&&this.selectedItems[0]:this.selectedItem;this.items.forEach(function(item){item.setAttribute("tabindex",item===selectedItem?"0":"-1")},this)},_updateMultiselectable:function(multi){if(multi){this.setAttribute("aria-multiselectable","true")}else{this.removeAttribute("aria-multiselectable")}},_focusWithKeyboardEvent:function(event){for(var i=0,item;item=this.items[i];i++){var attr=this.attrForItemTitle||"textContent";var title=item[attr]||item.getAttribute(attr);if(!item.hasAttribute("disabled")&&title&&title.trim().charAt(0).toLowerCase()===String.fromCharCode(event.keyCode).toLowerCase()){this._setFocusedItem(item);break}}},_focusPrevious:function(){var length=this.items.length;var curFocusIndex=Number(this.indexOf(this.focusedItem));for(var i=1;i<length+1;i++){var item=this.items[(curFocusIndex-i+length)%length];if(!item.hasAttribute("disabled")){var owner=Polymer.dom(item).getOwnerRoot()||document;this._setFocusedItem(item);if(Polymer.dom(owner).activeElement==item){return}}}},_focusNext:function(){var length=this.items.length;var curFocusIndex=Number(this.indexOf(this.focusedItem));for(var i=1;i<length+1;i++){var item=this.items[(curFocusIndex+i)%length];if(!item.hasAttribute("disabled")){var owner=Polymer.dom(item).getOwnerRoot()||document;this._setFocusedItem(item);if(Polymer.dom(owner).activeElement==item){return}}}},_applySelection:function(item,isSelected){if(isSelected){item.setAttribute("aria-selected","true")}else{item.removeAttribute("aria-selected")}Polymer.IronSelectableBehavior._applySelection.apply(this,arguments)},_focusedItemChanged:function(focusedItem,old){old&&old.setAttribute("tabindex","-1");if(focusedItem){focusedItem.setAttribute("tabindex","0");focusedItem.focus()}},_onIronItemsChanged:function(event){if(event.detail.addedNodes.length){this._resetTabindices()}},_onShiftTabDown:function(event){var oldTabIndex=this.getAttribute("tabindex");Polymer.IronMenuBehaviorImpl._shiftTabPressed=true;this._setFocusedItem(null);this.setAttribute("tabindex","-1");this.async(function(){this.setAttribute("tabindex",oldTabIndex);Polymer.IronMenuBehaviorImpl._shiftTabPressed=false},1)},_onFocus:function(event){if(Polymer.IronMenuBehaviorImpl._shiftTabPressed){return}var rootTarget=Polymer.dom(event).rootTarget;if(rootTarget!==this&&typeof rootTarget.tabIndex!=="undefined"&&!this.isLightDescendant(rootTarget)){return}this._defaultFocusAsync=this.async(function(){var selectedItem=this.multi?this.selectedItems&&this.selectedItems[0]:this.selectedItem;this._setFocusedItem(null);if(selectedItem){this._setFocusedItem(selectedItem)}else if(this.items[0]){this._focusNext()}})},_onUpKey:function(event){this._focusPrevious();event.detail.keyboardEvent.preventDefault()},_onDownKey:function(event){this._focusNext();event.detail.keyboardEvent.preventDefault()},_onEscKey:function(event){this.focusedItem.blur()},_onKeydown:function(event){if(!this.keyboardEventMatchesKeys(event,"up down esc")){this._focusWithKeyboardEvent(event)}event.stopPropagation()},_activateHandler:function(event){Polymer.IronSelectableBehavior._activateHandler.call(this,event);event.stopPropagation()}};Polymer.IronMenuBehaviorImpl._shiftTabPressed=false;Polymer.IronMenuBehavior=[Polymer.IronMultiSelectableBehavior,Polymer.IronA11yKeysBehavior,Polymer.IronMenuBehaviorImpl];(function(){Polymer({is:"paper-menu",behaviors:[Polymer.IronMenuBehavior]})})();Polymer.IronFitBehavior={properties:{sizingTarget:{type:Object,value:function(){return this}},fitInto:{type:Object,value:window},noOverlap:{type:Boolean},positionTarget:{type:Element},horizontalAlign:{type:String},verticalAlign:{type:String},dynamicAlign:{type:Boolean},horizontalOffset:{type:Number,value:0,notify:true},verticalOffset:{type:Number,value:0,notify:true},autoFitOnAttach:{type:Boolean,value:false},_fitInfo:{type:Object}},get _fitWidth(){var fitWidth;if(this.fitInto===window){fitWidth=this.fitInto.innerWidth}else{fitWidth=this.fitInto.getBoundingClientRect().width}return fitWidth},get _fitHeight(){var fitHeight;if(this.fitInto===window){fitHeight=this.fitInto.innerHeight}else{fitHeight=this.fitInto.getBoundingClientRect().height}return fitHeight},get _fitLeft(){var fitLeft;if(this.fitInto===window){fitLeft=0}else{fitLeft=this.fitInto.getBoundingClientRect().left}return fitLeft},get _fitTop(){var fitTop;if(this.fitInto===window){fitTop=0}else{fitTop=this.fitInto.getBoundingClientRect().top}return fitTop},get _defaultPositionTarget(){var parent=Polymer.dom(this).parentNode;if(parent&&parent.nodeType===Node.DOCUMENT_FRAGMENT_NODE){parent=parent.host}return parent},get _localeHorizontalAlign(){if(this._isRTL){if(this.horizontalAlign==="right"){return"left"}if(this.horizontalAlign==="left"){return"right"}}return this.horizontalAlign},attached:function(){this._isRTL=window.getComputedStyle(this).direction=="rtl";this.positionTarget=this.positionTarget||this._defaultPositionTarget;if(this.autoFitOnAttach){if(window.getComputedStyle(this).display==="none"){setTimeout(function(){this.fit()}.bind(this))}else{this.fit()}}},fit:function(){this.position();this.constrain();this.center()},_discoverInfo:function(){if(this._fitInfo){return}var target=window.getComputedStyle(this);var sizer=window.getComputedStyle(this.sizingTarget);this._fitInfo={inlineStyle:{top:this.style.top||"",left:this.style.left||"",position:this.style.position||""},sizerInlineStyle:{maxWidth:this.sizingTarget.style.maxWidth||"",maxHeight:this.sizingTarget.style.maxHeight||"",boxSizing:this.sizingTarget.style.boxSizing||""},positionedBy:{vertically:target.top!=="auto"?"top":target.bottom!=="auto"?"bottom":null,horizontally:target.left!=="auto"?"left":target.right!=="auto"?"right":null},sizedBy:{height:sizer.maxHeight!=="none",width:sizer.maxWidth!=="none",minWidth:parseInt(sizer.minWidth,10)||0,minHeight:parseInt(sizer.minHeight,10)||0},margin:{top:parseInt(target.marginTop,10)||0,right:parseInt(target.marginRight,10)||0,bottom:parseInt(target.marginBottom,10)||0,left:parseInt(target.marginLeft,10)||0}};if(this.verticalOffset){this._fitInfo.margin.top=this._fitInfo.margin.bottom=this.verticalOffset;this._fitInfo.inlineStyle.marginTop=this.style.marginTop||"";this._fitInfo.inlineStyle.marginBottom=this.style.marginBottom||"";this.style.marginTop=this.style.marginBottom=this.verticalOffset+"px"}if(this.horizontalOffset){this._fitInfo.margin.left=this._fitInfo.margin.right=this.horizontalOffset;this._fitInfo.inlineStyle.marginLeft=this.style.marginLeft||"";this._fitInfo.inlineStyle.marginRight=this.style.marginRight||"";this.style.marginLeft=this.style.marginRight=this.horizontalOffset+"px"}},resetFit:function(){var info=this._fitInfo||{};for(var property in info.sizerInlineStyle){this.sizingTarget.style[property]=info.sizerInlineStyle[property]}for(var property in info.inlineStyle){this.style[property]=info.inlineStyle[property]}this._fitInfo=null},refit:function(){var scrollLeft=this.sizingTarget.scrollLeft;var scrollTop=this.sizingTarget.scrollTop;this.resetFit();this.fit();this.sizingTarget.scrollLeft=scrollLeft;this.sizingTarget.scrollTop=scrollTop},position:function(){if(!this.horizontalAlign&&!this.verticalAlign){return}this._discoverInfo();this.style.position="fixed";this.sizingTarget.style.boxSizing="border-box";this.style.left="0px";this.style.top="0px";var rect=this.getBoundingClientRect();var positionRect=this.__getNormalizedRect(this.positionTarget);var fitRect=this.__getNormalizedRect(this.fitInto);var margin=this._fitInfo.margin;var size={width:rect.width+margin.left+margin.right,height:rect.height+margin.top+margin.bottom};var position=this.__getPosition(this._localeHorizontalAlign,this.verticalAlign,size,positionRect,fitRect);var left=position.left+margin.left;var top=position.top+margin.top;var right=Math.min(fitRect.right-margin.right,left+rect.width);var bottom=Math.min(fitRect.bottom-margin.bottom,top+rect.height);var minWidth=this._fitInfo.sizedBy.minWidth;var minHeight=this._fitInfo.sizedBy.minHeight;if(left<margin.left){left=margin.left;if(right-left<minWidth){left=right-minWidth}}if(top<margin.top){top=margin.top;if(bottom-top<minHeight){top=bottom-minHeight}}this.sizingTarget.style.maxWidth=right-left+"px";this.sizingTarget.style.maxHeight=bottom-top+"px";this.style.left=left-rect.left+"px";this.style.top=top-rect.top+"px"},constrain:function(){if(this.horizontalAlign||this.verticalAlign){return}this._discoverInfo();var info=this._fitInfo;if(!info.positionedBy.vertically){this.style.position="fixed";this.style.top="0px"}if(!info.positionedBy.horizontally){this.style.position="fixed";this.style.left="0px"}this.sizingTarget.style.boxSizing="border-box";var rect=this.getBoundingClientRect();if(!info.sizedBy.height){this.__sizeDimension(rect,info.positionedBy.vertically,"top","bottom","Height")}if(!info.sizedBy.width){this.__sizeDimension(rect,info.positionedBy.horizontally,"left","right","Width")}},_sizeDimension:function(rect,positionedBy,start,end,extent){this.__sizeDimension(rect,positionedBy,start,end,extent)},__sizeDimension:function(rect,positionedBy,start,end,extent){var info=this._fitInfo;var fitRect=this.__getNormalizedRect(this.fitInto);var max=extent==="Width"?fitRect.width:fitRect.height;var flip=positionedBy===end;var offset=flip?max-rect[end]:rect[start];var margin=info.margin[flip?start:end];var offsetExtent="offset"+extent;var sizingOffset=this[offsetExtent]-this.sizingTarget[offsetExtent];this.sizingTarget.style["max"+extent]=max-margin-offset-sizingOffset+"px"},center:function(){if(this.horizontalAlign||this.verticalAlign){return}this._discoverInfo();var positionedBy=this._fitInfo.positionedBy;if(positionedBy.vertically&&positionedBy.horizontally){return}this.style.position="fixed";if(!positionedBy.vertically){this.style.top="0px"}if(!positionedBy.horizontally){this.style.left="0px"}var rect=this.getBoundingClientRect();var fitRect=this.__getNormalizedRect(this.fitInto);if(!positionedBy.vertically){var top=fitRect.top-rect.top+(fitRect.height-rect.height)/2;this.style.top=top+"px"}if(!positionedBy.horizontally){var left=fitRect.left-rect.left+(fitRect.width-rect.width)/2;this.style.left=left+"px"}},__getNormalizedRect:function(target){if(target===document.documentElement||target===window){return{top:0,left:0,width:window.innerWidth,height:window.innerHeight,right:window.innerWidth,bottom:window.innerHeight}}return target.getBoundingClientRect()},__getCroppedArea:function(position,size,fitRect){var verticalCrop=Math.min(0,position.top)+Math.min(0,fitRect.bottom-(position.top+size.height));var horizontalCrop=Math.min(0,position.left)+Math.min(0,fitRect.right-(position.left+size.width));return Math.abs(verticalCrop)*size.width+Math.abs(horizontalCrop)*size.height},__getPosition:function(hAlign,vAlign,size,positionRect,fitRect){var positions=[{verticalAlign:"top",horizontalAlign:"left",top:positionRect.top,left:positionRect.left},{verticalAlign:"top",horizontalAlign:"right",top:positionRect.top,left:positionRect.right-size.width},{verticalAlign:"bottom",horizontalAlign:"left",top:positionRect.bottom-size.height,left:positionRect.left},{verticalAlign:"bottom",horizontalAlign:"right",top:positionRect.bottom-size.height,left:positionRect.right-size.width}];if(this.noOverlap){for(var i=0,l=positions.length;i<l;i++){var copy={};for(var key in positions[i]){copy[key]=positions[i][key]}positions.push(copy)}positions[0].top=positions[1].top+=positionRect.height;positions[2].top=positions[3].top-=positionRect.height;positions[4].left=positions[6].left+=positionRect.width;positions[5].left=positions[7].left-=positionRect.width}vAlign=vAlign==="auto"?null:vAlign;hAlign=hAlign==="auto"?null:hAlign;var position;for(var i=0;i<positions.length;i++){var pos=positions[i];if(!this.dynamicAlign&&!this.noOverlap&&pos.verticalAlign===vAlign&&pos.horizontalAlign===hAlign){position=pos;break}var alignOk=(!vAlign||pos.verticalAlign===vAlign)&&(!hAlign||pos.horizontalAlign===hAlign);if(!this.dynamicAlign&&!alignOk){continue}position=position||pos;pos.croppedArea=this.__getCroppedArea(pos,size,fitRect);var diff=pos.croppedArea-position.croppedArea;if(diff<0||diff===0&&alignOk){position=pos}if(position.croppedArea===0&&alignOk){break}}return position}};(function(){"use strict";Polymer({is:"iron-overlay-backdrop",properties:{opened:{reflectToAttribute:true,type:Boolean,value:false,observer:"_openedChanged"}},listeners:{transitionend:"_onTransitionend"},created:function(){this.__openedRaf=null},attached:function(){this.opened&&this._openedChanged(this.opened)},prepare:function(){if(this.opened&&!this.parentNode){Polymer.dom(document.body).appendChild(this)}},open:function(){this.opened=true},close:function(){this.opened=false},complete:function(){if(!this.opened&&this.parentNode===document.body){Polymer.dom(this.parentNode).removeChild(this)}},_onTransitionend:function(event){if(event&&event.target===this){this.complete()}},_openedChanged:function(opened){if(opened){this.prepare()}else{var cs=window.getComputedStyle(this);if(cs.transitionDuration==="0s"||cs.opacity==0){this.complete()}}if(!this.isAttached){return}if(this.__openedRaf){window.cancelAnimationFrame(this.__openedRaf);this.__openedRaf=null}this.scrollTop=this.scrollTop;this.__openedRaf=window.requestAnimationFrame(function(){this.__openedRaf=null;this.toggleClass("opened",this.opened)}.bind(this))}})})();Polymer.IronOverlayManagerClass=function(){this._overlays=[];this._minimumZ=101;this._backdropElement=null;Polymer.Gestures.add(document,"tap",this._onCaptureClick.bind(this));document.addEventListener("focus",this._onCaptureFocus.bind(this),true);document.addEventListener("keydown",this._onCaptureKeyDown.bind(this),true)};Polymer.IronOverlayManagerClass.prototype={constructor:Polymer.IronOverlayManagerClass,get backdropElement(){if(!this._backdropElement){this._backdropElement=document.createElement("iron-overlay-backdrop")}return this._backdropElement},get deepActiveElement(){var active=document.activeElement||document.body;while(active.root&&Polymer.dom(active.root).activeElement){active=Polymer.dom(active.root).activeElement}return active},_bringOverlayAtIndexToFront:function(i){var overlay=this._overlays[i];if(!overlay){return}var lastI=this._overlays.length-1;var currentOverlay=this._overlays[lastI];if(currentOverlay&&this._shouldBeBehindOverlay(overlay,currentOverlay)){lastI--}if(i>=lastI){return}var minimumZ=Math.max(this.currentOverlayZ(),this._minimumZ);if(this._getZ(overlay)<=minimumZ){this._applyOverlayZ(overlay,minimumZ)}while(i<lastI){this._overlays[i]=this._overlays[i+1];i++}this._overlays[lastI]=overlay},addOrRemoveOverlay:function(overlay){if(overlay.opened){this.addOverlay(overlay)}else{this.removeOverlay(overlay)}},addOverlay:function(overlay){var i=this._overlays.indexOf(overlay);if(i>=0){this._bringOverlayAtIndexToFront(i);this.trackBackdrop();return}var insertionIndex=this._overlays.length;var currentOverlay=this._overlays[insertionIndex-1];var minimumZ=Math.max(this._getZ(currentOverlay),this._minimumZ);var newZ=this._getZ(overlay);if(currentOverlay&&this._shouldBeBehindOverlay(overlay,currentOverlay)){this._applyOverlayZ(currentOverlay,minimumZ);insertionIndex--;var previousOverlay=this._overlays[insertionIndex-1];minimumZ=Math.max(this._getZ(previousOverlay),this._minimumZ)}if(newZ<=minimumZ){this._applyOverlayZ(overlay,minimumZ)}this._overlays.splice(insertionIndex,0,overlay);this.trackBackdrop()},removeOverlay:function(overlay){var i=this._overlays.indexOf(overlay);if(i===-1){return}this._overlays.splice(i,1);this.trackBackdrop()},currentOverlay:function(){var i=this._overlays.length-1;return this._overlays[i]},currentOverlayZ:function(){return this._getZ(this.currentOverlay())},ensureMinimumZ:function(minimumZ){this._minimumZ=Math.max(this._minimumZ,minimumZ)},focusOverlay:function(){var current=this.currentOverlay();if(current){current._applyFocus()}},trackBackdrop:function(){var overlay=this._overlayWithBackdrop();if(!overlay&&!this._backdropElement){return}this.backdropElement.style.zIndex=this._getZ(overlay)-1;this.backdropElement.opened=!!overlay},getBackdrops:function(){var backdrops=[];for(var i=0;i<this._overlays.length;i++){if(this._overlays[i].withBackdrop){backdrops.push(this._overlays[i])}}return backdrops},backdropZ:function(){return this._getZ(this._overlayWithBackdrop())-1},_overlayWithBackdrop:function(){for(var i=0;i<this._overlays.length;i++){if(this._overlays[i].withBackdrop){return this._overlays[i]}}},_getZ:function(overlay){var z=this._minimumZ;if(overlay){var z1=Number(overlay.style.zIndex||window.getComputedStyle(overlay).zIndex);if(z1===z1){z=z1}}return z},_setZ:function(element,z){element.style.zIndex=z},_applyOverlayZ:function(overlay,aboveZ){this._setZ(overlay,aboveZ+2)},_overlayInPath:function(path){path=path||[];for(var i=0;i<path.length;i++){if(path[i]._manager===this){return path[i]}}},_onCaptureClick:function(event){var overlay=this.currentOverlay();if(overlay&&this._overlayInPath(Polymer.dom(event).path)!==overlay){overlay._onCaptureClick(event)}},_onCaptureFocus:function(event){var overlay=this.currentOverlay();if(overlay){overlay._onCaptureFocus(event)}},_onCaptureKeyDown:function(event){var overlay=this.currentOverlay();if(overlay){if(Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event,"esc")){overlay._onCaptureEsc(event)}else if(Polymer.IronA11yKeysBehavior.keyboardEventMatchesKeys(event,"tab")){overlay._onCaptureTab(event)}}},_shouldBeBehindOverlay:function(overlay1,overlay2){return!overlay1.alwaysOnTop&&overlay2.alwaysOnTop}};Polymer.IronOverlayManager=new Polymer.IronOverlayManagerClass;(function(){"use strict";Polymer.IronOverlayBehaviorImpl={properties:{opened:{observer:"_openedChanged",type:Boolean,value:false,notify:true},canceled:{observer:"_canceledChanged",readOnly:true,type:Boolean,value:false},withBackdrop:{observer:"_withBackdropChanged",type:Boolean},noAutoFocus:{type:Boolean,value:false},noCancelOnEscKey:{type:Boolean,value:false},noCancelOnOutsideClick:{type:Boolean,value:false},closingReason:{ +type:Object},restoreFocusOnClose:{type:Boolean,value:false},alwaysOnTop:{type:Boolean},_manager:{type:Object,value:Polymer.IronOverlayManager},_focusedChild:{type:Object}},listeners:{"iron-resize":"_onIronResize"},get backdropElement(){return this._manager.backdropElement},get _focusNode(){return this._focusedChild||Polymer.dom(this).querySelector("[autofocus]")||this},get _focusableNodes(){var FOCUSABLE_WITH_DISABLED=["a[href]","area[href]","iframe","[tabindex]","[contentEditable=true]"];var FOCUSABLE_WITHOUT_DISABLED=["input","select","textarea","button"];var selector=FOCUSABLE_WITH_DISABLED.join(':not([tabindex="-1"]),')+':not([tabindex="-1"]),'+FOCUSABLE_WITHOUT_DISABLED.join(':not([disabled]):not([tabindex="-1"]),')+':not([disabled]):not([tabindex="-1"])';var focusables=Polymer.dom(this).querySelectorAll(selector);if(this.tabIndex>=0){focusables.splice(0,0,this)}return focusables.sort(function(a,b){if(a.tabIndex===b.tabIndex){return 0}if(a.tabIndex===0||a.tabIndex>b.tabIndex){return 1}return-1})},ready:function(){this.__isAnimating=false;this.__shouldRemoveTabIndex=false;this.__firstFocusableNode=this.__lastFocusableNode=null;this.__raf=null;this.__restoreFocusNode=null;this._ensureSetup()},attached:function(){if(this.opened){this._openedChanged(this.opened)}this._observer=Polymer.dom(this).observeNodes(this._onNodesChange)},detached:function(){Polymer.dom(this).unobserveNodes(this._observer);this._observer=null;if(this.__raf){window.cancelAnimationFrame(this.__raf);this.__raf=null}this._manager.removeOverlay(this)},toggle:function(){this._setCanceled(false);this.opened=!this.opened},open:function(){this._setCanceled(false);this.opened=true},close:function(){this._setCanceled(false);this.opened=false},cancel:function(event){var cancelEvent=this.fire("iron-overlay-canceled",event,{cancelable:true});if(cancelEvent.defaultPrevented){return}this._setCanceled(true);this.opened=false},_ensureSetup:function(){if(this._overlaySetup){return}this._overlaySetup=true;this.style.outline="none";this.style.display="none"},_openedChanged:function(opened){if(opened){this.removeAttribute("aria-hidden")}else{this.setAttribute("aria-hidden","true")}if(!this.isAttached){return}this.__isAnimating=true;this.__onNextAnimationFrame(this.__openedChanged)},_canceledChanged:function(){this.closingReason=this.closingReason||{};this.closingReason.canceled=this.canceled},_withBackdropChanged:function(){if(this.withBackdrop&&!this.hasAttribute("tabindex")){this.setAttribute("tabindex","-1");this.__shouldRemoveTabIndex=true}else if(this.__shouldRemoveTabIndex){this.removeAttribute("tabindex");this.__shouldRemoveTabIndex=false}if(this.opened&&this.isAttached){this._manager.trackBackdrop()}},_prepareRenderOpened:function(){this.__restoreFocusNode=this._manager.deepActiveElement;this._preparePositioning();this.refit();this._finishPositioning();if(this.noAutoFocus&&document.activeElement===this._focusNode){this._focusNode.blur();this.__restoreFocusNode.focus()}},_renderOpened:function(){this._finishRenderOpened()},_renderClosed:function(){this._finishRenderClosed()},_finishRenderOpened:function(){this.notifyResize();this.__isAnimating=false;var focusableNodes=this._focusableNodes;this.__firstFocusableNode=focusableNodes[0];this.__lastFocusableNode=focusableNodes[focusableNodes.length-1];this.fire("iron-overlay-opened")},_finishRenderClosed:function(){this.style.display="none";this.style.zIndex="";this.notifyResize();this.__isAnimating=false;this.fire("iron-overlay-closed",this.closingReason)},_preparePositioning:function(){this.style.transition=this.style.webkitTransition="none";this.style.transform=this.style.webkitTransform="none";this.style.display=""},_finishPositioning:function(){this.style.display="none";this.scrollTop=this.scrollTop;this.style.transition=this.style.webkitTransition="";this.style.transform=this.style.webkitTransform="";this.style.display="";this.scrollTop=this.scrollTop},_applyFocus:function(){if(this.opened){if(!this.noAutoFocus){this._focusNode.focus()}}else{this._focusNode.blur();this._focusedChild=null;if(this.restoreFocusOnClose&&this.__restoreFocusNode){this.__restoreFocusNode.focus()}this.__restoreFocusNode=null;var currentOverlay=this._manager.currentOverlay();if(currentOverlay&&this!==currentOverlay){currentOverlay._applyFocus()}}},_onCaptureClick:function(event){if(!this.noCancelOnOutsideClick){this.cancel(event)}},_onCaptureFocus:function(event){if(!this.withBackdrop){return}var path=Polymer.dom(event).path;if(path.indexOf(this)===-1){event.stopPropagation();this._applyFocus()}else{this._focusedChild=path[0]}},_onCaptureEsc:function(event){if(!this.noCancelOnEscKey){this.cancel(event)}},_onCaptureTab:function(event){if(!this.withBackdrop){return}var shift=event.shiftKey;var nodeToCheck=shift?this.__firstFocusableNode:this.__lastFocusableNode;var nodeToSet=shift?this.__lastFocusableNode:this.__firstFocusableNode;var shouldWrap=false;if(nodeToCheck===nodeToSet){shouldWrap=true}else{var focusedNode=this._manager.deepActiveElement;shouldWrap=focusedNode===nodeToCheck||focusedNode===this}if(shouldWrap){event.preventDefault();this._focusedChild=nodeToSet;this._applyFocus()}},_onIronResize:function(){if(this.opened&&!this.__isAnimating){this.__onNextAnimationFrame(this.refit)}},_onNodesChange:function(){if(this.opened&&!this.__isAnimating){this.notifyResize()}},__openedChanged:function(){if(this.opened){this._prepareRenderOpened();this._manager.addOverlay(this);this._applyFocus();this._renderOpened()}else{this._manager.removeOverlay(this);this._applyFocus();this._renderClosed()}},__onNextAnimationFrame:function(callback){if(this.__raf){window.cancelAnimationFrame(this.__raf)}var self=this;this.__raf=window.requestAnimationFrame(function nextAnimationFrame(){self.__raf=null;callback.call(self)})}};Polymer.IronOverlayBehavior=[Polymer.IronFitBehavior,Polymer.IronResizableBehavior,Polymer.IronOverlayBehaviorImpl]})();Polymer.NeonAnimatableBehavior={properties:{animationConfig:{type:Object},entryAnimation:{observer:"_entryAnimationChanged",type:String},exitAnimation:{observer:"_exitAnimationChanged",type:String}},_entryAnimationChanged:function(){this.animationConfig=this.animationConfig||{};this.animationConfig["entry"]=[{name:this.entryAnimation,node:this}]},_exitAnimationChanged:function(){this.animationConfig=this.animationConfig||{};this.animationConfig["exit"]=[{name:this.exitAnimation,node:this}]},_copyProperties:function(config1,config2){for(var property in config2){config1[property]=config2[property]}},_cloneConfig:function(config){var clone={isClone:true};this._copyProperties(clone,config);return clone},_getAnimationConfigRecursive:function(type,map,allConfigs){if(!this.animationConfig){return}if(this.animationConfig.value&&typeof this.animationConfig.value==="function"){this._warn(this._logf("playAnimation","Please put 'animationConfig' inside of your components 'properties' object instead of outside of it."));return}var thisConfig;if(type){thisConfig=this.animationConfig[type]}else{thisConfig=this.animationConfig}if(!Array.isArray(thisConfig)){thisConfig=[thisConfig]}if(thisConfig){for(var config,index=0;config=thisConfig[index];index++){if(config.animatable){config.animatable._getAnimationConfigRecursive(config.type||type,map,allConfigs)}else{if(config.id){var cachedConfig=map[config.id];if(cachedConfig){if(!cachedConfig.isClone){map[config.id]=this._cloneConfig(cachedConfig);cachedConfig=map[config.id]}this._copyProperties(cachedConfig,config)}else{map[config.id]=config}}else{allConfigs.push(config)}}}}},getAnimationConfig:function(type){var map={};var allConfigs=[];this._getAnimationConfigRecursive(type,map,allConfigs);for(var key in map){allConfigs.push(map[key])}return allConfigs}};Polymer.NeonAnimationRunnerBehaviorImpl={_configureAnimations:function(configs){var results=[];if(configs.length>0){for(var config,index=0;config=configs[index];index++){var neonAnimation=document.createElement(config.name);if(neonAnimation.isNeonAnimation){var result=null;try{result=neonAnimation.configure(config);if(typeof result.cancel!="function"){result=document.timeline.play(result)}}catch(e){result=null;console.warn("Couldnt play","(",config.name,").",e)}if(result){results.push({neonAnimation:neonAnimation,config:config,animation:result})}}else{console.warn(this.is+":",config.name,"not found!")}}}return results},_shouldComplete:function(activeEntries){var finished=true;for(var i=0;i<activeEntries.length;i++){if(activeEntries[i].animation.playState!="finished"){finished=false;break}}return finished},_complete:function(activeEntries){for(var i=0;i<activeEntries.length;i++){activeEntries[i].neonAnimation.complete(activeEntries[i].config)}for(var i=0;i<activeEntries.length;i++){activeEntries[i].animation.cancel()}},playAnimation:function(type,cookie){var configs=this.getAnimationConfig(type);if(!configs){return}this._active=this._active||{};if(this._active[type]){this._complete(this._active[type]);delete this._active[type]}var activeEntries=this._configureAnimations(configs);if(activeEntries.length==0){this.fire("neon-animation-finish",cookie,{bubbles:false});return}this._active[type]=activeEntries;for(var i=0;i<activeEntries.length;i++){activeEntries[i].animation.onfinish=function(){if(this._shouldComplete(activeEntries)){this._complete(activeEntries);delete this._active[type];this.fire("neon-animation-finish",cookie,{bubbles:false})}}.bind(this)}},cancelAnimation:function(){for(var k in this._animations){this._animations[k].cancel()}this._animations={}}};Polymer.NeonAnimationRunnerBehavior=[Polymer.NeonAnimatableBehavior,Polymer.NeonAnimationRunnerBehaviorImpl];Polymer.NeonAnimationBehavior={properties:{animationTiming:{type:Object,value:function(){return{duration:500,easing:"cubic-bezier(0.4, 0, 0.2, 1)",fill:"both"}}}},isNeonAnimation:true,timingFromConfig:function(config){if(config.timing){for(var property in config.timing){this.animationTiming[property]=config.timing[property]}}return this.animationTiming},setPrefixedProperty:function(node,property,value){var map={transform:["webkitTransform"],transformOrigin:["mozTransformOrigin","webkitTransformOrigin"]};var prefixes=map[property];for(var prefix,index=0;prefix=prefixes[index];index++){node.style[prefix]=value}node.style[property]=value},complete:function(){}};Polymer({is:"opaque-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;this._effect=new KeyframeEffect(node,[{opacity:"1"},{opacity:"1"}],this.timingFromConfig(config));node.style.opacity="0";return this._effect},complete:function(config){config.node.style.opacity=""}});(function(){"use strict";var LAST_TOUCH_POSITION={pageX:0,pageY:0};var ROOT_TARGET=null;var SCROLLABLE_NODES=[];Polymer.IronDropdownScrollManager={get currentLockingElement(){return this._lockingElements[this._lockingElements.length-1]},elementIsScrollLocked:function(element){var currentLockingElement=this.currentLockingElement;if(currentLockingElement===undefined)return false;var scrollLocked;if(this._hasCachedLockedElement(element)){return true}if(this._hasCachedUnlockedElement(element)){return false}scrollLocked=!!currentLockingElement&¤tLockingElement!==element&&!this._composedTreeContains(currentLockingElement,element);if(scrollLocked){this._lockedElementCache.push(element)}else{this._unlockedElementCache.push(element)}return scrollLocked},pushScrollLock:function(element){if(this._lockingElements.indexOf(element)>=0){return}if(this._lockingElements.length===0){this._lockScrollInteractions()}this._lockingElements.push(element);this._lockedElementCache=[];this._unlockedElementCache=[]},removeScrollLock:function(element){var index=this._lockingElements.indexOf(element);if(index===-1){return}this._lockingElements.splice(index,1);this._lockedElementCache=[];this._unlockedElementCache=[];if(this._lockingElements.length===0){this._unlockScrollInteractions()}},_lockingElements:[],_lockedElementCache:null,_unlockedElementCache:null,_hasCachedLockedElement:function(element){return this._lockedElementCache.indexOf(element)>-1},_hasCachedUnlockedElement:function(element){return this._unlockedElementCache.indexOf(element)>-1},_composedTreeContains:function(element,child){var contentElements;var distributedNodes;var contentIndex;var nodeIndex;if(element.contains(child)){return true}contentElements=Polymer.dom(element).querySelectorAll("content");for(contentIndex=0;contentIndex<contentElements.length;++contentIndex){distributedNodes=Polymer.dom(contentElements[contentIndex]).getDistributedNodes();for(nodeIndex=0;nodeIndex<distributedNodes.length;++nodeIndex){if(this._composedTreeContains(distributedNodes[nodeIndex],child)){return true}}}return false},_scrollInteractionHandler:function(event){if(event.cancelable&&this._shouldPreventScrolling(event)){event.preventDefault()}if(event.targetTouches){var touch=event.targetTouches[0];LAST_TOUCH_POSITION.pageX=touch.pageX;LAST_TOUCH_POSITION.pageY=touch.pageY}},_lockScrollInteractions:function(){this._boundScrollHandler=this._boundScrollHandler||this._scrollInteractionHandler.bind(this);document.addEventListener("wheel",this._boundScrollHandler,true);document.addEventListener("mousewheel",this._boundScrollHandler,true);document.addEventListener("DOMMouseScroll",this._boundScrollHandler,true);document.addEventListener("touchstart",this._boundScrollHandler,true);document.addEventListener("touchmove",this._boundScrollHandler,true)},_unlockScrollInteractions:function(){document.removeEventListener("wheel",this._boundScrollHandler,true);document.removeEventListener("mousewheel",this._boundScrollHandler,true);document.removeEventListener("DOMMouseScroll",this._boundScrollHandler,true);document.removeEventListener("touchstart",this._boundScrollHandler,true);document.removeEventListener("touchmove",this._boundScrollHandler,true)},_shouldPreventScrolling:function(event){var target=Polymer.dom(event).rootTarget;if(event.type!=="touchmove"&&ROOT_TARGET!==target){ROOT_TARGET=target;SCROLLABLE_NODES=this._getScrollableNodes(Polymer.dom(event).path)}if(!SCROLLABLE_NODES.length){return true}if(event.type==="touchstart"){return false}var info=this._getScrollInfo(event);return!this._getScrollingNode(SCROLLABLE_NODES,info.deltaX,info.deltaY)},_getScrollableNodes:function(nodes){var scrollables=[];var lockingIndex=nodes.indexOf(this.currentLockingElement);for(var i=0;i<=lockingIndex;i++){var node=nodes[i];if(node.nodeType===11){continue}var style=node.style;if(style.overflow!=="scroll"&&style.overflow!=="auto"){style=window.getComputedStyle(node)}if(style.overflow==="scroll"||style.overflow==="auto"){scrollables.push(node)}}return scrollables},_getScrollingNode:function(nodes,deltaX,deltaY){if(!deltaX&&!deltaY){return}var verticalScroll=Math.abs(deltaY)>=Math.abs(deltaX);for(var i=0;i<nodes.length;i++){var node=nodes[i];var canScroll=false;if(verticalScroll){canScroll=deltaY<0?node.scrollTop>0:node.scrollTop<node.scrollHeight-node.clientHeight}else{canScroll=deltaX<0?node.scrollLeft>0:node.scrollLeft<node.scrollWidth-node.clientWidth}if(canScroll){return node}}},_getScrollInfo:function(event){var info={deltaX:event.deltaX,deltaY:event.deltaY};if("deltaX"in event){}else if("wheelDeltaX"in event){info.deltaX=-event.wheelDeltaX;info.deltaY=-event.wheelDeltaY}else if("axis"in event){info.deltaX=event.axis===1?event.detail:0;info.deltaY=event.axis===2?event.detail:0}else if(event.targetTouches){var touch=event.targetTouches[0];info.deltaX=LAST_TOUCH_POSITION.pageX-touch.pageX;info.deltaY=LAST_TOUCH_POSITION.pageY-touch.pageY}return info}}})();(function(){"use strict";Polymer({is:"iron-dropdown",behaviors:[Polymer.IronControlState,Polymer.IronA11yKeysBehavior,Polymer.IronOverlayBehavior,Polymer.NeonAnimationRunnerBehavior],properties:{horizontalAlign:{type:String,value:"left",reflectToAttribute:true},verticalAlign:{type:String,value:"top",reflectToAttribute:true},openAnimationConfig:{type:Object},closeAnimationConfig:{type:Object},focusTarget:{type:Object},noAnimations:{type:Boolean,value:false},allowOutsideScroll:{type:Boolean,value:false},_boundOnCaptureScroll:{type:Function,value:function(){return this._onCaptureScroll.bind(this)}}},listeners:{"neon-animation-finish":"_onNeonAnimationFinish"},observers:["_updateOverlayPosition(positionTarget, verticalAlign, horizontalAlign, verticalOffset, horizontalOffset)"],get containedElement(){return Polymer.dom(this.$.content).getDistributedNodes()[0]},get _focusTarget(){return this.focusTarget||this.containedElement},ready:function(){this._scrollTop=0;this._scrollLeft=0;this._refitOnScrollRAF=null},attached:function(){if(!this.sizingTarget||this.sizingTarget===this){this.sizingTarget=this.containedElement}},detached:function(){this.cancelAnimation();document.removeEventListener("scroll",this._boundOnCaptureScroll);Polymer.IronDropdownScrollManager.removeScrollLock(this)},_openedChanged:function(){if(this.opened&&this.disabled){this.cancel()}else{this.cancelAnimation();this._updateAnimationConfig();this._saveScrollPosition();if(this.opened){document.addEventListener("scroll",this._boundOnCaptureScroll);!this.allowOutsideScroll&&Polymer.IronDropdownScrollManager.pushScrollLock(this)}else{document.removeEventListener("scroll",this._boundOnCaptureScroll);Polymer.IronDropdownScrollManager.removeScrollLock(this)}Polymer.IronOverlayBehaviorImpl._openedChanged.apply(this,arguments)}},_renderOpened:function(){if(!this.noAnimations&&this.animationConfig.open){this.$.contentWrapper.classList.add("animating");this.playAnimation("open")}else{Polymer.IronOverlayBehaviorImpl._renderOpened.apply(this,arguments)}},_renderClosed:function(){if(!this.noAnimations&&this.animationConfig.close){this.$.contentWrapper.classList.add("animating");this.playAnimation("close")}else{Polymer.IronOverlayBehaviorImpl._renderClosed.apply(this,arguments)}},_onNeonAnimationFinish:function(){this.$.contentWrapper.classList.remove("animating");if(this.opened){this._finishRenderOpened()}else{this._finishRenderClosed()}},_onCaptureScroll:function(){if(!this.allowOutsideScroll){this._restoreScrollPosition()}else{this._refitOnScrollRAF&&window.cancelAnimationFrame(this._refitOnScrollRAF);this._refitOnScrollRAF=window.requestAnimationFrame(this.refit.bind(this))}},_saveScrollPosition:function(){if(document.scrollingElement){this._scrollTop=document.scrollingElement.scrollTop;this._scrollLeft=document.scrollingElement.scrollLeft}else{this._scrollTop=Math.max(document.documentElement.scrollTop,document.body.scrollTop);this._scrollLeft=Math.max(document.documentElement.scrollLeft,document.body.scrollLeft)}},_restoreScrollPosition:function(){if(document.scrollingElement){document.scrollingElement.scrollTop=this._scrollTop;document.scrollingElement.scrollLeft=this._scrollLeft}else{document.documentElement.scrollTop=this._scrollTop;document.documentElement.scrollLeft=this._scrollLeft;document.body.scrollTop=this._scrollTop;document.body.scrollLeft=this._scrollLeft}},_updateAnimationConfig:function(){var animations=(this.openAnimationConfig||[]).concat(this.closeAnimationConfig||[]);for(var i=0;i<animations.length;i++){animations[i].node=this.containedElement}this.animationConfig={open:this.openAnimationConfig,close:this.closeAnimationConfig}},_updateOverlayPosition:function(){if(this.isAttached){this.notifyResize()}},_applyFocus:function(){var focusTarget=this.focusTarget||this.containedElement;if(focusTarget&&this.opened&&!this.noAutoFocus){focusTarget.focus()}else{Polymer.IronOverlayBehaviorImpl._applyFocus.apply(this,arguments)}}})})();Polymer({is:"fade-in-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;this._effect=new KeyframeEffect(node,[{opacity:"0"},{opacity:"1"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"fade-out-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;this._effect=new KeyframeEffect(node,[{opacity:"1"},{opacity:"0"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-grow-height-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var height=rect.height;this._effect=new KeyframeEffect(node,[{height:height/2+"px"},{height:height+"px"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-grow-width-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var width=rect.width;this._effect=new KeyframeEffect(node,[{width:width/2+"px"},{width:width+"px"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-shrink-width-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var width=rect.width;this._effect=new KeyframeEffect(node,[{width:width+"px"},{width:width-width/20+"px"}],this.timingFromConfig(config));return this._effect}});Polymer({is:"paper-menu-shrink-height-animation",behaviors:[Polymer.NeonAnimationBehavior],configure:function(config){var node=config.node;var rect=node.getBoundingClientRect();var height=rect.height;var top=rect.top;this.setPrefixedProperty(node,"transformOrigin","0 0");this._effect=new KeyframeEffect(node,[{height:height+"px",transform:"translateY(0)"},{height:height/2+"px",transform:"translateY(-20px)"}],this.timingFromConfig(config));return this._effect}});(function(){"use strict";var config={ANIMATION_CUBIC_BEZIER:"cubic-bezier(.3,.95,.5,1)",MAX_ANIMATION_TIME_MS:400};var PaperMenuButton=Polymer({is:"paper-menu-button",behaviors:[Polymer.IronA11yKeysBehavior,Polymer.IronControlState],properties:{opened:{type:Boolean,value:false,notify:true,observer:"_openedChanged"},horizontalAlign:{type:String,value:"left",reflectToAttribute:true},verticalAlign:{type:String,value:"top",reflectToAttribute:true},dynamicAlign:{type:Boolean},horizontalOffset:{type:Number,value:0,notify:true},verticalOffset:{type:Number,value:0,notify:true},noOverlap:{type:Boolean},noAnimations:{type:Boolean,value:false},ignoreSelect:{type:Boolean,value:false},closeOnActivate:{type:Boolean,value:false},openAnimationConfig:{type:Object,value:function(){return[{name:"fade-in-animation",timing:{delay:100,duration:200}},{name:"paper-menu-grow-width-animation",timing:{delay:100,duration:150,easing:config.ANIMATION_CUBIC_BEZIER}},{name:"paper-menu-grow-height-animation",timing:{delay:100,duration:275,easing:config.ANIMATION_CUBIC_BEZIER}}]}},closeAnimationConfig:{type:Object,value:function(){return[{name:"fade-out-animation",timing:{duration:150}},{name:"paper-menu-shrink-width-animation",timing:{delay:100,duration:50,easing:config.ANIMATION_CUBIC_BEZIER}},{name:"paper-menu-shrink-height-animation",timing:{duration:200,easing:"ease-in"}}]}},allowOutsideScroll:{type:Boolean,value:false},restoreFocusOnClose:{type:Boolean,value:true},_dropdownContent:{type:Object}},hostAttributes:{role:"group","aria-haspopup":"true"},listeners:{"iron-activate":"_onIronActivate","iron-select":"_onIronSelect"},get contentElement(){return Polymer.dom(this.$.content).getDistributedNodes()[0]},toggle:function(){if(this.opened){this.close()}else{this.open()}},open:function(){if(this.disabled){return}this.$.dropdown.open()},close:function(){this.$.dropdown.close()},_onIronSelect:function(event){if(!this.ignoreSelect){this.close()}},_onIronActivate:function(event){if(this.closeOnActivate){this.close()}},_openedChanged:function(opened,oldOpened){if(opened){this._dropdownContent=this.contentElement;this.fire("paper-dropdown-open")}else if(oldOpened!=null){this.fire("paper-dropdown-close")}},_disabledChanged:function(disabled){Polymer.IronControlState._disabledChanged.apply(this,arguments);if(disabled&&this.opened){this.close()}},__onIronOverlayCanceled:function(event){var uiEvent=event.detail;var target=Polymer.dom(uiEvent).rootTarget;var trigger=this.$.trigger;var path=Polymer.dom(uiEvent).path;if(path.indexOf(trigger)>-1){event.preventDefault()}}});Object.keys(config).forEach(function(key){PaperMenuButton[key]=config[key]});Polymer.PaperMenuButton=PaperMenuButton})();Polymer.PaperInkyFocusBehaviorImpl={observers:["_focusedChanged(receivedFocusFromKeyboard)"],_focusedChanged:function(receivedFocusFromKeyboard){if(receivedFocusFromKeyboard){this.ensureRipple()}if(this.hasRipple()){this._ripple.holdDown=receivedFocusFromKeyboard}},_createRipple:function(){var ripple=Polymer.PaperRippleBehavior._createRipple();ripple.id="ink";ripple.setAttribute("center","");ripple.classList.add("circle");return ripple}};Polymer.PaperInkyFocusBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperRippleBehavior,Polymer.PaperInkyFocusBehaviorImpl];Polymer({is:"paper-icon-button",hostAttributes:{role:"button",tabindex:"0"},behaviors:[Polymer.PaperInkyFocusBehavior],properties:{src:{type:String},icon:{type:String},alt:{type:String,observer:"_altChanged"}},_altChanged:function(newValue,oldValue){var label=this.getAttribute("aria-label");if(!label||oldValue==label){this.setAttribute("aria-label",newValue)}}});Polymer({is:"iron-media-query",properties:{queryMatches:{type:Boolean,value:false,readOnly:true,notify:true},query:{type:String,observer:"queryChanged"},full:{type:Boolean,value:false},_boundMQHandler:{value:function(){return this.queryHandler.bind(this)}},_mq:{value:null}},attached:function(){this.style.display="none";this.queryChanged()},detached:function(){this._remove()},_add:function(){if(this._mq){this._mq.addListener(this._boundMQHandler)}},_remove:function(){if(this._mq){this._mq.removeListener(this._boundMQHandler)}this._mq=null},queryChanged:function(){this._remove();var query=this.query;if(!query){return}if(!this.full&&query[0]!=="("){query="("+query+")"}this._mq=window.matchMedia(query);this._add();this.queryHandler(this._mq)},queryHandler:function(mq){this._setQueryMatches(mq.matches)}});Polymer.PaperSpinnerBehavior={listeners:{animationend:"__reset",webkitAnimationEnd:"__reset"},properties:{active:{type:Boolean,value:false,reflectToAttribute:true,observer:"__activeChanged"},alt:{type:String,value:"loading",observer:"__altChanged"},__coolingDown:{type:Boolean,value:false}},__computeContainerClasses:function(active,coolingDown){return[active||coolingDown?"active":"",coolingDown?"cooldown":""].join(" ")},__activeChanged:function(active,old){this.__setAriaHidden(!active);this.__coolingDown=!active&&old},__altChanged:function(alt){if(alt===this.getPropertyInfo("alt").value){this.alt=this.getAttribute("aria-label")||alt}else{this.__setAriaHidden(alt==="");this.setAttribute("aria-label",alt)}},__setAriaHidden:function(hidden){var attr="aria-hidden";if(hidden){this.setAttribute(attr,"true")}else{this.removeAttribute(attr)}},__reset:function(){this.active=false;this.__coolingDown=false}};Polymer({is:"paper-spinner-lite",behaviors:[Polymer.PaperSpinnerBehavior]}); // Copyright 2016 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. -var CrSearchFieldBehavior={properties:{label:{type:String,value:""},clearLabel:{type:String,value:""},showingSearch:{type:Boolean,value:false,notify:true,observer:"showingSearchChanged_",reflectToAttribute:true},lastValue_:{type:String,value:""}},getSearchInput:function(){},getValue:function(){return this.getSearchInput().value},setValue:function(value){this.getSearchInput().bindValue=value;this.onValueChanged_(value)},showAndFocus:function(){this.showingSearch=true;this.focus_()},focus_:function(){this.getSearchInput().focus()},onSearchTermSearch:function(){this.onValueChanged_(this.getValue())},onValueChanged_:function(newValue){if(newValue==this.lastValue_)return;this.fire("search-changed",newValue);this.lastValue_=newValue},onSearchTermKeydown:function(e){if(e.key=="Escape")this.showingSearch=false},showingSearchChanged_:function(){if(this.showingSearch){this.focus_();return}this.setValue("");this.getSearchInput().blur()}}; +var CrSearchFieldBehavior={properties:{label:{type:String,value:""},clearLabel:{type:String,value:""},showingSearch:{type:Boolean,value:false,notify:true,observer:"showingSearchChanged_",reflectToAttribute:true},lastValue_:{type:String,value:""}},getSearchInput:function(){},getValue:function(){return this.getSearchInput().value},setValue:function(value,opt_noEvent){var searchInput=this.getSearchInput();searchInput.value=value;if(searchInput.bindValue!=undefined)searchInput.bindValue=value;this.onValueChanged_(value,!!opt_noEvent)},showAndFocus:function(){this.showingSearch=true;this.focus_()},focus_:function(){this.getSearchInput().focus()},onSearchTermSearch:function(){this.onValueChanged_(this.getValue(),false)},onValueChanged_:function(newValue,noEvent){if(newValue==this.lastValue_)return;this.lastValue_=newValue;if(!noEvent)this.fire("search-changed",newValue)},onSearchTermKeydown:function(e){if(e.key=="Escape")this.showingSearch=false},showingSearchChanged_:function(current,previous){if(previous==undefined)return;if(this.showingSearch){this.focus_();return}this.setValue("");this.getSearchInput().blur()}}; // Copyright 2016 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. -Polymer({is:"cr-toolbar-search-field",behaviors:[CrSearchFieldBehavior],properties:{narrow:{type:Boolean,reflectToAttribute:true},label:String,clearLabel:String,spinnerActive:{type:Boolean,reflectToAttribute:true},hasSearchText_:Boolean,isSpinnerShown_:{type:Boolean,computed:"computeIsSpinnerShown_(spinnerActive, showingSearch)"}},listeners:{tap:"showSearch_","searchInput.bind-value-changed":"onBindValueChanged_"},getSearchInput:function(){return this.$.searchInput},isSearchFocused:function(){return this.$.searchTerm.focused},computeIconTabIndex_:function(narrow){return narrow?0:-1},computeIsSpinnerShown_:function(){return this.spinnerActive&&this.showingSearch},onInputBlur_:function(){if(!this.hasSearchText_)this.showingSearch=false},onBindValueChanged_:function(){var newValue=this.$.searchInput.bindValue;this.hasSearchText_=newValue!="";if(newValue!="")this.showingSearch=true},showSearch_:function(e){if(e.target!=this.$.clearSearch)this.showingSearch=true},hideSearch_:function(e){this.showingSearch=false;e.stopPropagation()}}); +Polymer({is:"cr-toolbar-search-field",behaviors:[CrSearchFieldBehavior],properties:{narrow:{type:Boolean,reflectToAttribute:true},label:String,clearLabel:String,spinnerActive:{type:Boolean,reflectToAttribute:true},hasSearchText_:{type:Boolean,reflectToAttribute:true},isSpinnerShown_:{type:Boolean,computed:"computeIsSpinnerShown_(spinnerActive, showingSearch)"},searchFocused_:{type:Boolean,value:false}},listeners:{click:"showSearch_"},getSearchInput:function(){return this.$.searchInput},setValue:function(value,opt_noEvent){CrSearchFieldBehavior.setValue.call(this,value,opt_noEvent);this.onSearchInput_()},isSearchFocused:function(){return this.searchFocused_},computeIconTabIndex_:function(narrow){return narrow?0:-1},computeIsSpinnerShown_:function(){return this.spinnerActive&&this.showingSearch},onInputFocus_:function(){this.searchFocused_=true},onInputBlur_:function(){this.searchFocused_=false;if(!this.hasSearchText_)this.showingSearch=false},onSearchInput_:function(){var newValue=this.$.searchInput.value;this.hasSearchText_=newValue!="";if(newValue!="")this.showingSearch=true},showSearch_:function(e){if(e.target!=this.$.clearSearch)this.showingSearch=true},clearSearch_:function(e){this.setValue("");this.getSearchInput().focus()}}); // Copyright 2016 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. -Polymer({is:"cr-toolbar",properties:{pageName:String,searchPrompt:String,clearLabel:String,menuLabel:String,menuPromo:String,spinnerActive:Boolean,showMenu:{type:Boolean,value:false},showMenuPromo:{type:Boolean,value:false},closeMenuPromo:String,narrow_:{type:Boolean,reflectToAttribute:true},showingSearch_:{type:Boolean,reflectToAttribute:true}},observers:["possiblyShowMenuPromo_(showMenu, showMenuPromo, showingSearch_)"],getSearchField:function(){return this.$.search},onClosePromoTap_:function(){this.showMenuPromo=false},onMenuTap_:function(){this.fire("cr-menu-tap");this.onClosePromoTap_()},possiblyShowMenuPromo_:function(){Polymer.RenderStatus.afterNextRender(this,function(){if(this.showMenu&&this.showMenuPromo&&!this.showingSearch_){this.$$("#menuPromo").animate({opacity:[0,.9]},{duration:500,fill:"forwards"});this.fire("cr-menu-promo-shown")}}.bind(this))},titleIfNotShowMenuPromo_:function(title,showMenuPromo){return showMenuPromo?"":title}}); +Polymer({is:"cr-toolbar",properties:{pageName:String,searchPrompt:String,clearLabel:String,menuLabel:String,menuPromo:String,spinnerActive:Boolean,showMenu:{type:Boolean,value:false},showMenuPromo:{type:Boolean,value:false},closeMenuPromo:String,narrow_:{type:Boolean,reflectToAttribute:true},showingSearch_:{type:Boolean,reflectToAttribute:true}},observers:["possiblyShowMenuPromo_(showMenu, showMenuPromo, showingSearch_)"],getSearchField:function(){return this.$.search},onClosePromoTap_:function(){this.fire("cr-toolbar-menu-promo-close")},onMenuTap_:function(){this.fire("cr-toolbar-menu-tap")},possiblyShowMenuPromo_:function(){Polymer.RenderStatus.afterNextRender(this,function(){if(this.showMenu&&this.showMenuPromo&&!this.showingSearch_){this.$$("#menuPromo").animate({opacity:[0,.9]},{duration:500,fill:"forwards"});this.fire("cr-toolbar-menu-promo-shown")}}.bind(this))},titleIfNotShowMenuPromo_:function(title,showMenuPromo){return showMenuPromo?"":title}}); // 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. @@ -65,7 +64,7 @@ cr.define("downloads",function(){var Toolbar=Polymer({is:"downloads-toolbar",pro // 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("downloads",function(){var Manager=Polymer({is:"downloads-manager",properties:{hasDownloads_:{observer:"hasDownloadsChanged_",type:Boolean},hasShadow_:{type:Boolean,value:false,reflectToAttribute:true},items_:{type:Array,value:function(){return[]}},spinnerActive_:{type:Boolean,notify:true}},hostAttributes:{loading:true},listeners:{"downloads-list.scroll":"onListScroll_"},observers:["itemsChanged_(items_.*)"],clearAll_:function(){this.set("items_",[])},hasDownloadsChanged_:function(){if(loadTimeData.getBoolean("allowDeletingHistory"))this.$.toolbar.downloadsShowing=this.hasDownloads_;if(this.hasDownloads_){this.$["downloads-list"].fire("iron-resize")}else{var isSearching=downloads.ActionService.getInstance().isSearching();var messageToShow=isSearching?"noSearchResults":"noDownloads";this.$["no-downloads"].querySelector("span").textContent=loadTimeData.getString(messageToShow)}},insertItems_:function(index,list){this.splice.apply(this,["items_",index,0].concat(list));this.updateHideDates_(index,index+list.length);this.removeAttribute("loading");this.spinnerActive_=false},itemsChanged_:function(){this.hasDownloads_=this.items_.length>0},onCanExecute_:function(e){e=e;switch(e.command.id){case"undo-command":e.canExecute=this.$.toolbar.canUndo();break;case"clear-all-command":e.canExecute=this.$.toolbar.canClearAll();break;case"find-command":e.canExecute=true;break}},onCommand_:function(e){if(e.command.id=="clear-all-command")downloads.ActionService.getInstance().clearAll();else if(e.command.id=="undo-command")downloads.ActionService.getInstance().undo();else if(e.command.id=="find-command")this.$.toolbar.onFindCommand()},onListScroll_:function(){var list=this.$["downloads-list"];if(list.scrollHeight-list.scrollTop-list.offsetHeight<=100){downloads.ActionService.getInstance().loadMore()}this.hasShadow_=list.scrollTop>0},onLoad_:function(){cr.ui.decorate("command",cr.ui.Command);document.addEventListener("canExecute",this.onCanExecute_.bind(this));document.addEventListener("command",this.onCommand_.bind(this));downloads.ActionService.getInstance().loadMore()},removeItem_:function(index){this.splice("items_",index,1);this.updateHideDates_(index,index);this.onListScroll_()},updateHideDates_:function(start,end){for(var i=start;i<=end;++i){var current=this.items_[i];if(!current)continue;var prev=this.items_[i-1];current.hideDate=!!prev&&prev.date_string==current.date_string}},updateItem_:function(index,data){this.set("items_."+index,data);this.updateHideDates_(index,index);var list=this.$["downloads-list"];list.updateSizeForItem(index)}});Manager.clearAll=function(){Manager.get().clearAll_()};Manager.get=function(){return queryRequiredElement("downloads-manager")};Manager.insertItems=function(index,list){Manager.get().insertItems_(index,list)};Manager.onLoad=function(){Manager.get().onLoad_()};Manager.removeItem=function(index){Manager.get().removeItem_(index)};Manager.updateItem=function(index,data){Manager.get().updateItem_(index,data)};return{Manager:Manager}}); +cr.define("downloads",function(){var Manager=Polymer({is:"downloads-manager",properties:{hasDownloads_:{observer:"hasDownloadsChanged_",type:Boolean},hasShadow_:{type:Boolean,value:false,reflectToAttribute:true},inSearchMode_:{type:Boolean,value:false},items_:{type:Array,value:function(){return[]}},spinnerActive_:{type:Boolean,notify:true}},hostAttributes:{loading:true},listeners:{"downloads-list.scroll":"onListScroll_","toolbar.search-changed":"onSearchChanged_"},observers:["itemsChanged_(items_.*)"],clearAll_:function(){this.set("items_",[])},hasDownloadsChanged_:function(){if(loadTimeData.getBoolean("allowDeletingHistory"))this.$.toolbar.downloadsShowing=this.hasDownloads_;if(this.hasDownloads_)this.$["downloads-list"].fire("iron-resize")},insertItems_:function(index,list){this.splice.apply(this,["items_",index,0].concat(list));this.updateHideDates_(index,index+list.length);this.removeAttribute("loading");this.spinnerActive_=false},itemsChanged_:function(){this.hasDownloads_=this.items_.length>0},noDownloadsText_:function(){return loadTimeData.getString(this.inSearchMode_?"noSearchResults":"noDownloads")},onCanExecute_:function(e){e=e;switch(e.command.id){case"undo-command":e.canExecute=this.$.toolbar.canUndo();break;case"clear-all-command":e.canExecute=this.$.toolbar.canClearAll();break;case"find-command":e.canExecute=true;break}},onCommand_:function(e){if(e.command.id=="clear-all-command")downloads.ActionService.getInstance().clearAll();else if(e.command.id=="undo-command")downloads.ActionService.getInstance().undo();else if(e.command.id=="find-command")this.$.toolbar.onFindCommand()},onListScroll_:function(){var list=this.$["downloads-list"];if(list.scrollHeight-list.scrollTop-list.offsetHeight<=100){downloads.ActionService.getInstance().loadMore()}this.hasShadow_=list.scrollTop>0},onLoad_:function(){cr.ui.decorate("command",cr.ui.Command);document.addEventListener("canExecute",this.onCanExecute_.bind(this));document.addEventListener("command",this.onCommand_.bind(this));downloads.ActionService.getInstance().loadMore()},onSearchChanged_:function(){this.inSearchMode_=downloads.ActionService.getInstance().isSearching()},removeItem_:function(index){this.splice("items_",index,1);this.updateHideDates_(index,index);this.onListScroll_()},updateHideDates_:function(start,end){for(var i=start;i<=end;++i){var current=this.items_[i];if(!current)continue;var prev=this.items_[i-1];var hideDate=!!prev&&prev.date_string==current.date_string;this.set("items_."+i+".hideDate",hideDate)}},updateItem_:function(index,data){this.set("items_."+index,data);this.updateHideDates_(index,index);var list=this.$["downloads-list"];list.updateSizeForItem(index)}});Manager.clearAll=function(){Manager.get().clearAll_()};Manager.get=function(){return queryRequiredElement("downloads-manager")};Manager.insertItems=function(index,list){Manager.get().insertItems_(index,list)};Manager.onLoad=function(){Manager.get().onLoad_()};Manager.removeItem=function(index){Manager.get().removeItem_(index)};Manager.updateItem=function(index,data){Manager.get().updateItem_(index,data)};return{Manager:Manager}}); // 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. diff --git a/chromium/chrome/browser/resources/md_downloads/item.html b/chromium/chrome/browser/resources/md_downloads/item.html index 3f0ff3d0115..ca33797dc18 100644 --- a/chromium/chrome/browser/resources/md_downloads/item.html +++ b/chromium/chrome/browser/resources/md_downloads/item.html @@ -112,12 +112,9 @@ width: 32px; } - #danger-icon[icon='cr:warning'] { - color: rgb(255, 193, 7); - } - - #danger-icon[icon='downloads:remove-circle'] { - color: rgb(244, 67, 54); + #danger-icon[icon='cr:warning'], + .dangerous #description { + color: var(--google-red-700); } #name, @@ -170,10 +167,6 @@ color: #616161; } - .dangerous #description { - color: rgb(239, 108, 0); - } - #progress { --paper-progress-active-color: rgb(54, 126, 237); --paper-progress-container-color: rgb(223, 222, 223); @@ -258,7 +251,7 @@ <span id="tag">[[computeTag_(data.state, data.last_reason_text, data.file_externally_removed)]]</span> </div> - <a id="url" target="_blank">[[data.url]]</a> + <a id="url" target="_blank">[[chopUrl_(data.url)]]</a> <div id="description">[[computeDescription_(data.state, data.danger_type, data.file_name, data.progress_status_text)]]</div> diff --git a/chromium/chrome/browser/resources/md_downloads/item.js b/chromium/chrome/browser/resources/md_downloads/item.js index 3bc1ef68599..00a3716f6a3 100644 --- a/chromium/chrome/browser/resources/md_downloads/item.js +++ b/chromium/chrome/browser/resources/md_downloads/item.js @@ -78,6 +78,15 @@ cr.define('downloads', function() { this.content = this.$.content; }, + /** + * @param {string} url + * @return {string} A reasonably long URL. + * @private + */ + chopUrl_: function(url) { + return url.slice(0, 300); + }, + /** @private */ computeClass_: function() { var classes = []; @@ -107,24 +116,12 @@ cr.define('downloads', function() { var url = 'chrome://extensions#' + this.data.by_ext_id; var name = this.data.by_ext_name; - return loadTimeData.getStringF('controlledByUrl', url, name); + return loadTimeData.getStringF('controlledByUrl', url, HTMLEscape(name)); }, /** @private */ computeDangerIcon_: function() { - if (!this.isDangerous_) - return ''; - - switch (this.data.danger_type) { - case downloads.DangerType.DANGEROUS_CONTENT: - case downloads.DangerType.DANGEROUS_HOST: - case downloads.DangerType.DANGEROUS_URL: - case downloads.DangerType.POTENTIALLY_UNWANTED: - case downloads.DangerType.UNCOMMON_CONTENT: - return 'downloads:remove-circle'; - default: - return 'cr:warning'; - } + return this.isDangerous_ ? 'cr:warning' : ''; }, /** @private */ diff --git a/chromium/chrome/browser/resources/md_downloads/manager.html b/chromium/chrome/browser/resources/md_downloads/manager.html index 65d9ec17331..07e3c5925ce 100644 --- a/chromium/chrome/browser/resources/md_downloads/manager.html +++ b/chromium/chrome/browser/resources/md_downloads/manager.html @@ -98,14 +98,13 @@ <iron-list id="downloads-list" items="{{items_}}" hidden="[[!hasDownloads_]]"> <template> - <downloads-item data="[[item]]" hide-date="[[item.hideDate]]"> - </downloads-item> + <downloads-item data="[[item]]"></downloads-item> </template> </iron-list> <div id="no-downloads" hidden="[[hasDownloads_]]"> <div> <div class="illustration"></div> - <span><!-- Text populated dynamically. --></span> + <span>[[noDownloadsText_(inSearchMode_)]]</span> </div> </div> </template> diff --git a/chromium/chrome/browser/resources/md_downloads/manager.js b/chromium/chrome/browser/resources/md_downloads/manager.js index e66c813a37a..62b6b349236 100644 --- a/chromium/chrome/browser/resources/md_downloads/manager.js +++ b/chromium/chrome/browser/resources/md_downloads/manager.js @@ -7,22 +7,32 @@ cr.define('downloads', function() { is: 'downloads-manager', properties: { + /** @private */ hasDownloads_: { observer: 'hasDownloadsChanged_', type: Boolean, }, + /** @private */ hasShadow_: { type: Boolean, value: false, reflectToAttribute: true, }, + /** @private */ + inSearchMode_: { + type: Boolean, + value: false, + }, + + /** @private {!Array<!downloads.Data>} */ items_: { type: Array, value: function() { return []; }, }, + /** @private */ spinnerActive_: { type: Boolean, notify: true, @@ -35,6 +45,7 @@ cr.define('downloads', function() { listeners: { 'downloads-list.scroll': 'onListScroll_', + 'toolbar.search-changed': 'onSearchChanged_', }, observers: [ @@ -51,14 +62,8 @@ cr.define('downloads', function() { if (loadTimeData.getBoolean('allowDeletingHistory')) this.$.toolbar.downloadsShowing = this.hasDownloads_; - if (this.hasDownloads_) { + if (this.hasDownloads_) this.$['downloads-list'].fire('iron-resize'); - } else { - var isSearching = downloads.ActionService.getInstance().isSearching(); - var messageToShow = isSearching ? 'noSearchResults' : 'noDownloads'; - this.$['no-downloads'].querySelector('span').textContent = - loadTimeData.getString(messageToShow); - } }, /** @@ -79,6 +84,15 @@ cr.define('downloads', function() { }, /** + * @return {string} The text to show when no download items are showing. + * @private + */ + noDownloadsText_: function() { + return loadTimeData.getString( + this.inSearchMode_ ? 'noSearchResults' : 'noDownloads'); + }, + + /** * @param {Event} e * @private */ @@ -129,6 +143,11 @@ cr.define('downloads', function() { downloads.ActionService.getInstance().loadMore(); }, + /** @private */ + onSearchChanged_: function() { + this.inSearchMode_ = downloads.ActionService.getInstance().isSearching(); + }, + /** * @param {number} index * @private @@ -150,7 +169,8 @@ cr.define('downloads', function() { if (!current) continue; var prev = this.items_[i - 1]; - current.hideDate = !!prev && prev.date_string == current.date_string; + var hideDate = !!prev && prev.date_string == current.date_string; + this.set('items_.' + i + '.hideDate', hideDate); } }, diff --git a/chromium/chrome/browser/resources/md_downloads/toolbar.html b/chromium/chrome/browser/resources/md_downloads/toolbar.html index 19fdbdea1a4..d974e9ed292 100644 --- a/chromium/chrome/browser/resources/md_downloads/toolbar.html +++ b/chromium/chrome/browser/resources/md_downloads/toolbar.html @@ -33,7 +33,7 @@ -webkit-margin-end: 16px; /* Only matters around 900px in Russian. */ }; --cr-toolbar-left-content-wide: { - -webkit-margin-start: 0; + -webkit-padding-start: 0; flex: 1 0 1px; max-width: none; position: static; diff --git a/chromium/chrome/browser/resources/md_downloads/vulcanized.html b/chromium/chrome/browser/resources/md_downloads/vulcanized.html index 1013b028b49..386c969be17 100644 --- a/chromium/chrome/browser/resources/md_downloads/vulcanized.html +++ b/chromium/chrome/browser/resources/md_downloads/vulcanized.html @@ -1135,12 +1135,8 @@ paper-button { width: 32px; } -#danger-icon[icon='cr:warning'] { - color: rgb(255, 193, 7); -} - -#danger-icon[icon='downloads:remove-circle'] { - color: rgb(244, 67, 54); +#danger-icon[icon='cr:warning'], .dangerous #description { + color: var(--google-red-700); } #name, #file-link, #url { @@ -1187,10 +1183,6 @@ paper-button { color: #616161; } -.dangerous #description { - color: rgb(239, 108, 0); -} - #progress { --paper-progress-active-color: rgb(54, 126, 237); --paper-progress-container-color: rgb(223, 222, 223); @@ -1262,7 +1254,7 @@ paper-button { <span id="tag">[[computeTag_(data.state, data.last_reason_text, data.file_externally_removed)]]</span> </div> - <a id="url" target="_blank">[[data.url]]</a> + <a id="url" target="_blank">[[chopUrl_(data.url)]]</a> <div id="description">[[computeDescription_(data.state, data.danger_type, data.file_name, data.progress_status_text)]]</div> @@ -1365,7 +1357,7 @@ paper-button { * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -<if expr="not chromeos"> +<if expr="not chromeos and not is_android"> @font-face { font-family: 'Roboto'; font-style: normal; @@ -1819,244 +1811,6 @@ iron-icon { </template> </dom-module> -<dom-module id="iron-a11y-announcer" assetpath="chrome://resources/polymer/v1_0/iron-a11y-announcer/" css-build="shadow"> - <template> - <style scope="iron-a11y-announcer">:host { - display: inline-block; - position: fixed; - clip: rect(0px,0px,0px,0px); -} - -</style> - <div aria-live$="[[mode]]">[[_text]]</div> - </template> - - </dom-module> -<dom-module id="paper-input-container" assetpath="chrome://resources/polymer/v1_0/paper-input/" css-build="shadow"> - <template> - <style scope="paper-input-container">:host { - display: block; - padding: 8px 0; - - ; -} - -:host([inline]) { - display: inline-block; -} - -:host([disabled]) { - pointer-events: none; - opacity: 0.33; - - ; -} - -:host([hidden]) { - display: none !important; -} - -.floated-label-placeholder { - font-family: var(--paper-font-caption_-_font-family); -webkit-font-smoothing: var(--paper-font-caption_-_-webkit-font-smoothing); white-space: var(--paper-font-caption_-_white-space); overflow: var(--paper-font-caption_-_overflow); text-overflow: var(--paper-font-caption_-_text-overflow); font-size: var(--paper-font-caption_-_font-size); font-weight: var(--paper-font-caption_-_font-weight); letter-spacing: var(--paper-font-caption_-_letter-spacing); line-height: var(--paper-font-caption_-_line-height); -} - -.underline { - position: relative; -} - -.focused-line { - position: var(--layout-fit_-_position); top: var(--layout-fit_-_top); right: var(--layout-fit_-_right); bottom: var(--layout-fit_-_bottom); left: var(--layout-fit_-_left); - - background: var(--paper-input-container-focus-color,var(--primary-color));; - height: 2px; - - -webkit-transform-origin: center center; - transform-origin: center center; - -webkit-transform: scale3d(0,1,1); - transform: scale3d(0,1,1); - - display: var(--paper-input-container-underline-focus_-_display); -} - -.underline.is-highlighted .focused-line { - -webkit-transform: none; - transform: none; - -webkit-transition: -webkit-transform 0.25s; - transition: transform 0.25s; - - ; -} - -.underline.is-invalid .focused-line { - background: var(--paper-input-container-invalid-color,var(--error-color));; - -webkit-transform: none; - transform: none; - -webkit-transition: -webkit-transform 0.25s; - transition: transform 0.25s; - - ; -} - -.unfocused-line { - position: var(--layout-fit_-_position); top: var(--layout-fit_-_top); right: var(--layout-fit_-_right); bottom: var(--layout-fit_-_bottom); left: var(--layout-fit_-_left); - - background: var(--paper-input-container-color,var(--secondary-text-color));; - height: 1px; - - display: var(--paper-input-container-underline_-_display); -} - -:host([disabled]) .unfocused-line { - border-bottom: 1px dashed; - border-color: var(--paper-input-container-color,var(--secondary-text-color));; - background: transparent; - - ; -} - -.label-and-input-container { - -ms-flex: var(--layout-flex-auto_-_-ms-flex); -webkit-flex: var(--layout-flex-auto_-_-webkit-flex); flex: var(--layout-flex-auto_-_flex); - position: var(--layout-relative_-_position); - - width: 100%; - max-width: 100%; -} - -.input-content { - display: var(--layout-horizontal_-_display); -ms-flex-direction: var(--layout-horizontal_-_-ms-flex-direction); -webkit-flex-direction: var(--layout-horizontal_-_-webkit-flex-direction); flex-direction: var(--layout-horizontal_-_flex-direction); - -ms-flex-align: var(--layout-center_-_-ms-flex-align); -webkit-align-items: var(--layout-center_-_-webkit-align-items); align-items: var(--layout-center_-_align-items); - - position: relative; -} - -.input-content ::content label, .input-content ::content .paper-input-label { - position: absolute; - top: 0; - right: 0; - left: 0; - width: 100%; - font: inherit; - color: var(--paper-input-container-color,var(--secondary-text-color));; - -webkit-transition: -webkit-transform 0.25s, width 0.25s; - transition: transform 0.25s, width 0.25s; - -webkit-transform-origin: left top; - transform-origin: left top; - - white-space: var(--paper-font-common-nowrap_-_white-space); overflow: var(--paper-font-common-nowrap_-_overflow); text-overflow: var(--paper-font-common-nowrap_-_text-overflow); - font-family: var(--paper-font-subhead_-_font-family); -webkit-font-smoothing: var(--paper-font-subhead_-_-webkit-font-smoothing); font-size: var(--paper-font-subhead_-_font-size); font-weight: var(--paper-font-subhead_-_font-weight); line-height: var(--paper-font-subhead_-_line-height); - color: var(--paper-input-container-label_-_color, var(--paper-input-container-color,var(--secondary-text-color))); font-size: var(--paper-input-container-label_-_font-size, var(--paper-font-subhead_-_font-size)); - ; -} - -.input-content.label-is-floating ::content label, .input-content.label-is-floating ::content .paper-input-label { - -webkit-transform: translateY(-75%) scale(0.75); - transform: translateY(-75%) scale(0.75); - - - width: 133%; - - ; -} - -:host-context([dir="rtl"]) .input-content.label-is-floating ::content label, :host-context([dir="rtl"]) .input-content.label-is-floating ::content .paper-input-label { - width: 100%; - -webkit-transform-origin: right top; - transform-origin: right top; -} - -.input-content.label-is-highlighted ::content label, .input-content.label-is-highlighted ::content .paper-input-label { - color: var(--paper-input-container-focus-color,var(--primary-color));; - - ; -} - -.input-content.is-invalid ::content label, .input-content.is-invalid ::content .paper-input-label { - color: var(--paper-input-container-invalid-color,var(--error-color));; -} - -.input-content.label-is-hidden ::content label, .input-content.label-is-hidden ::content .paper-input-label { - visibility: hidden; -} - -.input-content ::content input, .input-content ::content textarea, .input-content ::content iron-autogrow-textarea, .input-content ::content .paper-input-input { - position: relative; - outline: none; - box-shadow: none; - padding: 0; - width: 100%; - max-width: 100%; - background: transparent; - border: none; - color: var(--paper-input-container-input-color,var(--primary-text-color));; - -webkit-appearance: none; - text-align: inherit; - vertical-align: bottom; - - font-family: var(--paper-font-subhead_-_font-family); -webkit-font-smoothing: var(--paper-font-subhead_-_-webkit-font-smoothing); font-size: var(--paper-font-subhead_-_font-size); font-weight: var(--paper-font-subhead_-_font-weight); line-height: var(--paper-font-subhead_-_line-height); - ; -} - -::content [prefix] { - font-family: var(--paper-font-subhead_-_font-family); -webkit-font-smoothing: var(--paper-font-subhead_-_-webkit-font-smoothing); font-size: var(--paper-font-subhead_-_font-size); font-weight: var(--paper-font-subhead_-_font-weight); line-height: var(--paper-font-subhead_-_line-height); - - ; - -ms-flex: var(--layout-flex-none_-_-ms-flex); -webkit-flex: var(--layout-flex-none_-_-webkit-flex); flex: var(--layout-flex-none_-_flex); -} - -::content [suffix] { - font-family: var(--paper-font-subhead_-_font-family); -webkit-font-smoothing: var(--paper-font-subhead_-_-webkit-font-smoothing); font-size: var(--paper-font-subhead_-_font-size); font-weight: var(--paper-font-subhead_-_font-weight); line-height: var(--paper-font-subhead_-_line-height); - - ; - -ms-flex: var(--layout-flex-none_-_-ms-flex); -webkit-flex: var(--layout-flex-none_-_-webkit-flex); flex: var(--layout-flex-none_-_flex); -} - -.input-content ::content input { - min-width: 0; -} - -.input-content ::content textarea { - resize: none; -} - -.add-on-content { - position: relative; -} - -.add-on-content.is-invalid ::content * { - color: var(--paper-input-container-invalid-color,var(--error-color));; -} - -.add-on-content.is-highlighted ::content * { - color: var(--paper-input-container-focus-color,var(--primary-color));; -} - -</style> - - <template is="dom-if" if="[[!noLabelFloat]]"> - <div class="floated-label-placeholder" aria-hidden="true"> </div> - </template> - - <div class$="[[_computeInputContentClass(noLabelFloat,alwaysFloatLabel,focused,invalid,_inputHasContent)]]"> - <content select="[prefix]" id="prefix"></content> - - <div class="label-and-input-container" id="labelAndInputContainer"> - <content select=":not([add-on]):not([prefix]):not([suffix])"></content> - </div> - - <content select="[suffix]"></content> - </div> - - <div class$="[[_computeUnderlineClass(focused,invalid)]]"> - <div class="unfocused-line"></div> - <div class="focused-line"></div> - </div> - - <div class$="[[_computeAddOnContentClass(focused,invalid)]]"> - <content id="addOnContent" select="[add-on]"></content> - </div> - </template> -</dom-module> - <dom-module id="paper-spinner-styles" assetpath="chrome://resources/polymer/v1_0/paper-spinner/" css-build="shadow"> <template> <style scope="paper-spinner-styles">:host { @@ -3226,13 +2980,39 @@ paper-spinner-lite[active] { transition: opacity 200ms; } -paper-input-container { - --paper-input-container-input-color: white; - --paper-input-container-underline_-_display: none;; - --paper-input-container-underline-focus_-_display: none;; - --paper-input-container-label_-_color: apply-shim-inherit; --paper-input-container-label_-_font-size: apply-shim-inherit;; - -webkit-padding-start: 2px; +#searchTerm { + -webkit-font-smoothing: antialiased; + -webkit-margin-start: 2px; flex: 1; + line-height: 185%; + position: relative; +} + +label { + bottom: 0; + cursor: text; + left: 0; + overflow: hidden; + position: absolute; + right: 0; + top: 0; + white-space: nowrap; +} + +:host([has-search-text_]) label { + visibility: hidden; +} + +input { + -webkit-appearance: none; + background: transparent; + border: none; + color: white; + font: inherit; + outline: none; + padding: 0; + position: relative; + width: 100%; } input[type='search']::-webkit-search-decoration, input[type='search']::-webkit-search-cancel-button, input[type='search']::-webkit-search-results-button { @@ -3251,7 +3031,7 @@ input[type='search']::-webkit-search-decoration, input[type='search']::-webkit-s opacity: 0.6; } -:host([narrow]:not([showing-search])) paper-input-container { +:host([narrow]:not([showing-search])) #searchTerm { display: none; } @@ -3274,12 +3054,13 @@ input[type='search']::-webkit-search-decoration, input[type='search']::-webkit-s </template> <paper-icon-button id="icon" icon="cr:search" title="[[label]]" tabindex$="[[computeIconTabIndex_(narrow)]]"> </paper-icon-button> - <paper-input-container id="searchTerm" on-search="onSearchTermSearch" on-keydown="onSearchTermKeydown" no-label-float=""> + <div id="searchTerm"> <label id="prompt" for="searchInput">[[label]]</label> - <input is="iron-input" id="searchInput" type="search" on-blur="onInputBlur_" incremental="" autofocus=""> - </paper-input-container> + <input id="searchInput" type="search" on-input="onSearchInput_" on-search="onSearchTermSearch" on-keydown="onSearchTermKeydown" on-focus="onInputFocus_" on-blur="onInputBlur_" incremental="" autofocus=""> + + </div> <template is="dom-if" if="[[hasSearchText_]]"> - <paper-icon-button icon="cr:cancel" id="clearSearch" title="[[clearLabel]]" on-tap="hideSearch_"> + <paper-icon-button icon="cr:cancel" id="clearSearch" title="[[clearLabel]]" on-tap="clearSearch_"> </paper-icon-button> </template> </template> @@ -3296,6 +3077,7 @@ input[type='search']::-webkit-search-decoration, input[type='search']::-webkit-s h1 { -webkit-margin-start: 6px; + -webkit-padding-end: 2px; flex: 1; font-size: 123%; font-weight: 400; @@ -3305,8 +3087,9 @@ h1 { } #leftContent { - -webkit-margin-start: 18px; + -webkit-padding-start: 18px; align-items: center; + box-sizing: border-box; display: flex; position: absolute; transition: opacity 100ms; @@ -3337,8 +3120,8 @@ h1 { } :host(:not([narrow_])) #leftContent { - max-width: calc((100% - var(--cr-toolbar-field-width) - 18px) / 2); - -webkit-margin-start: var(--cr-toolbar-left-content-wide_-_-webkit-margin-start); flex: var(--cr-toolbar-left-content-wide_-_flex); max-width: var(--cr-toolbar-left-content-wide_-_max-width, calc((100% - var(--cr-toolbar-field-width) - 18px) / 2)); position: var(--cr-toolbar-left-content-wide_-_position); + max-width: calc((100% - var(--cr-toolbar-field-width)) / 2); + -webkit-padding-start: var(--cr-toolbar-left-content-wide_-_-webkit-padding-start); flex: var(--cr-toolbar-left-content-wide_-_flex); max-width: var(--cr-toolbar-left-content-wide_-_max-width, calc((100% - var(--cr-toolbar-field-width)) / 2)); position: var(--cr-toolbar-left-content-wide_-_position); } :host(:not([narrow_])) #rightContent { @@ -3448,7 +3231,7 @@ h1 { --cr-toolbar-field-end-padding: 0; --cr-toolbar-field-width: var(--downloads-card-width); --cr-toolbar-header-wide_-_-webkit-margin-start: 24px; --cr-toolbar-header-wide_-_-webkit-margin-end: 16px;; - --cr-toolbar-left-content-wide_-_-webkit-margin-start: 0; --cr-toolbar-left-content-wide_-_flex: 1 0 1px; --cr-toolbar-left-content-wide_-_max-width: none; --cr-toolbar-left-content-wide_-_position: static;; + --cr-toolbar-left-content-wide_-_-webkit-padding-start: 0; --cr-toolbar-left-content-wide_-_flex: 1 0 1px; --cr-toolbar-left-content-wide_-_max-width: none; --cr-toolbar-left-content-wide_-_position: static;; --cr-toolbar-right-content-wide_-_flex: 1 0 1px; --cr-toolbar-right-content-wide_-_position: static;; align-items: center; flex: 1; @@ -3598,14 +3381,13 @@ paper-item { </downloads-toolbar> <iron-list id="downloads-list" items="{{items_}}" hidden="[[!hasDownloads_]]"> <template> - <downloads-item data="[[item]]" hide-date="[[item.hideDate]]"> - </downloads-item> + <downloads-item data="[[item]]"></downloads-item> </template> </iron-list> <div id="no-downloads" hidden="[[hasDownloads_]]"> <div> <div class="illustration"></div> - <span></span> + <span>[[noDownloadsText_(inSearchMode_)]]</span> </div> </div> </template> diff --git a/chromium/chrome/browser/resources/md_extensions/code_section.html b/chromium/chrome/browser/resources/md_extensions/code_section.html new file mode 100644 index 00000000000..207eb1540e1 --- /dev/null +++ b/chromium/chrome/browser/resources/md_extensions/code_section.html @@ -0,0 +1,57 @@ +<link rel="import" href="chrome://resources/html/cr.html"> +<link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html"> + +<dom-module id="extensions-code-section"> + <template> + <style> + [hidden] { + display: none !important; + } + + #main { + border: 1px solid var(--paper-grey-500); + color: var(--paper-grey-800); + display: flex; + font-family: monospace; + white-space: pre; + } + + #line-numbers { + background: var(--paper-grey-300); + border-right: 1px solid var(--paper-grey-500); + display: flex; + padding: 0 8px; + text-align: right; + } + + #source { + -webkit-margin-start: 4px; + display: flex; + flex-direction: column; + } + + .highlight { + background: var(--paper-red-100); + } + + #no-code { + color: var(--paper-grey-800); + text-align: center; + } + </style> + <div id="main" hidden$="[[isMainHidden_(code)]]"> + <div id="line-numbers"> + <span>[[computeLineNumbersContent_(code.*)]]</span> + </div> + <div id="source"> + <span>[[code.beforeHighlight]]<!-- No whitespace allowed + --><span class="highlight" title="[[code.message]]"><!-- + -->[[code.highlight]]<!-- + --></span>[[code.afterHighlight]]</span> + </div> + </div> + <div id="no-code" hidden$="[[!isMainHidden_(code)]]">[[noCodeError]]</div> + </template> + <script src="chrome://extensions/code_section.js"></script> +</dom-module> diff --git a/chromium/chrome/browser/resources/md_extensions/code_section.js b/chromium/chrome/browser/resources/md_extensions/code_section.js new file mode 100644 index 00000000000..d0a93e2aac2 --- /dev/null +++ b/chromium/chrome/browser/resources/md_extensions/code_section.js @@ -0,0 +1,60 @@ +// Copyright 2016 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'; + + var CodeSection = Polymer({ + is: 'extensions-code-section', + + properties: { + /** + * The code this object is displaying. + * @type {?chrome.developerPrivate.RequestFileSourceResponse} + */ + code: { + type: Object, + // We initialize to null so that Polymer sees it as defined and calls + // isMainHidden_(). + value: null, + }, + + /** + * The string to display if no code is set. + * @type {string} + */ + noCodeError: String, + }, + + /** + * Computes the content of the line numbers span, which basically just + * contains 1\n2\n3\n... for the number of lines. + * @return {string} + * @private + */ + computeLineNumbersContent_: function() { + if (!this.code) + return ''; + + var lines = [this.code.beforeHighlight, + this.code.highlight, + this.code.afterHighlight].join('').match(/\n/g); + var lineCount = lines ? lines.length : 0; + var textContent = ''; + for (var i = 1; i <= lineCount; ++i) + textContent += i + '\n'; + return textContent; + }, + + /** + * @return {boolean} + * @private + */ + isMainHidden_: function() { + return !this.code; + }, + }); + + return {CodeSection: CodeSection}; +}); diff --git a/chromium/chrome/browser/resources/md_extensions/compiled_resources2.gyp b/chromium/chrome/browser/resources/md_extensions/compiled_resources2.gyp index f51788dc67a..67e67a298cf 100644 --- a/chromium/chrome/browser/resources/md_extensions/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/md_extensions/compiled_resources2.gyp @@ -12,6 +12,14 @@ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], }, { + 'target_name': 'code_section', + 'dependencies': [ + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', + '<(EXTERNS_GYP):developer_private', + ], + 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + { 'target_name': 'detail_view', 'dependencies': [ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', @@ -37,6 +45,17 @@ 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], }, { + 'target_name': 'error_page', + 'dependencies': [ + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', + '<(DEPTH)/third_party/polymer/v1_0/components-chromium/neon-animation/compiled_resources2.gyp:neon-animatable-behavior-extracted', + '<(EXTERNS_GYP):developer_private', + 'animation_helper', + 'code_section', + ], + 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + { 'target_name': 'extensions', 'dependencies': [ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', @@ -132,6 +151,7 @@ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', '<(EXTERNS_GYP):developer_private', '<(EXTERNS_GYP):management', + 'error_page', 'item', 'manager', 'pack_dialog', diff --git a/chromium/chrome/browser/resources/md_extensions/error_page.html b/chromium/chrome/browser/resources/md_extensions/error_page.html new file mode 100644 index 00000000000..801a3df5df4 --- /dev/null +++ b/chromium/chrome/browser/resources/md_extensions/error_page.html @@ -0,0 +1,87 @@ +<link rel="import" href="chrome://resources/html/cr.html"> +<link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-icons/iron-icons.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable-behavior.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html"> +<link rel="import" href="chrome://extensions/animation_helper.html"> +<link rel="import" href="chrome://extensions/code_section.html"> + +<dom-module id="extensions-error-page"> + <template> + <style> + [hidden] { + display: none !important; + } + + #main { + background-color: white; + height: 800px; + width: 90%; + } + + #heading { + color: var(--paper-grey-600); + height: 40px; + margin-bottom: 30px; + padding: 8px 12px 0; + } + + #errors-list { + padding: 0 10px; + } + + .error-item { + align-items: center; + color: var(--paper-grey-800); + display: flex; + margin: 5px 0; + } + + .error-message { + -webkit-margin-start: 10px; + flex-grow: 1; + } + + .icon-severity-info { + /* TODO(devlin): 1x/2x versions? */ + content: url(error_severity_info.png); + } + + .icon-severity-warning { + content: url(error_severity_warning.png); + } + + .icon-severity-fatal { + content: url(error_severity_fatal.png); + } + </style> + <div id="main"> + <div id="heading"> + <paper-icon-button id="close-button" icon="arrow-back" + on-tap="onCloseButtonTap_"></paper-icon-button> + <span>$i18n{errorsPageHeading}</span> + </div> + <div id="errors-list"> + <template is="dom-repeat" items="[[calculateShownItems_(data.*)]]"> + <div class="error-item"> + <img class$="[[computeErrorIconClass_(item)]]"> + <div class="error-message">[[item.message]]</div> + <paper-icon-button class="delete-button" + on-tap="onDeleteErrorTap_" + icon="delete"></paper-icon-button> + </div> + </template> + </div> + <div id="content-view"> + <extensions-code-section id="code-section" + no-code-error="$i18n{noErrorsToShow}"> + </extensions-code-section> + </div> + <div id="devtools-controls"> + <!--TODO--> + </div> + </div> + </template> + <script src="chrome://extensions/error_page.js"></script> +</dom-module> diff --git a/chromium/chrome/browser/resources/md_extensions/error_page.js b/chromium/chrome/browser/resources/md_extensions/error_page.js new file mode 100644 index 00000000000..1203a997cf3 --- /dev/null +++ b/chromium/chrome/browser/resources/md_extensions/error_page.js @@ -0,0 +1,145 @@ +// Copyright 2016 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. + +/** @typedef {chrome.developerPrivate.ManifestError} */ +var ManifestError; +/** @typedef {chrome.developerPrivate.RuntimeError} */ +var RuntimeError; + +cr.define('extensions', function() { + 'use strict'; + + /** @interface */ + var ErrorPageDelegate = function() {}; + + ErrorPageDelegate.prototype = { + /** + * @param {string} extensionId + * @param {!Array<number>=} opt_errorIds + * @param {chrome.developerPrivate.ErrorType=} opt_type + */ + deleteErrors: assertNotReached, + + /** + * @param {chrome.developerPrivate.RequestFileSourceProperties} args + * @return {!Promise<!chrome.developerPrivate.RequestFileSourceResponse>} + */ + requestFileSource: assertNotReached, + }; + + var ErrorPage = Polymer({ + is: 'extensions-error-page', + + behaviors: [Polymer.NeonAnimatableBehavior], + + properties: { + /** @type {!chrome.developerPrivate.ExtensionInfo|undefined} */ + data: Object, + + /** @type {!extensions.ErrorPageDelegate|undefined} */ + delegate: Object, + }, + + observers: [ + 'observeDataChanges_(data)', + ], + + ready: function() { + /** @type {!extensions.AnimationHelper} */ + this.animationHelper = new extensions.AnimationHelper(this, this.$.main); + this.animationHelper.setEntryAnimation(extensions.Animation.FADE_IN); + this.animationHelper.setExitAnimation(extensions.Animation.SCALE_DOWN); + this.sharedElements = {hero: this.$.main}; + }, + + /** + * Watches for changes to |data| in order to fetch the corresponding + * file source. + * @private + */ + observeDataChanges_: function() { + assert(this.data); + var e = this.data.manifestErrors[0] || this.data.runtimeErrors[0]; + if (e) + this.fetchCodeSource_(e); + }, + + /** + * @return {!Array<!(ManifestError|RuntimeError)>} + * @private + */ + calculateShownItems_: function() { + return this.data.manifestErrors.concat(this.data.runtimeErrors); + }, + + /** @private */ + onCloseButtonTap_: function() { + this.fire('close'); + }, + + /** + * @param {!ManifestError|!RuntimeError} error + * @return {string} + * @private + */ + computeErrorIconClass_: function(error) { + if (error.type == chrome.developerPrivate.ErrorType.RUNTIME) { + switch (error.severity) { + case chrome.developerPrivate.ErrorLevel.LOG: + return 'icon-severity-info'; + case chrome.developerPrivate.ErrorLevel.WARN: + return 'icon-severity-warning'; + case chrome.developerPrivate.ErrorLevel.ERROR: + return 'icon-severity-fatal'; + } + assertNotReached(); + } + assert(error.type == chrome.developerPrivate.ErrorType.MANIFEST); + return 'icon-severity-warning'; + }, + + /** + * @param {!Event} event + * @private + */ + onDeleteErrorTap_: function(event) { + // TODO(devlin): It would be cleaner if we could cast this to a + // PolymerDomRepeatEvent-type thing, but that doesn't exist yet. + var e = /** @type {!{model:Object}} */(event); + this.delegate.deleteErrors(this.data.id, [e.model.item.id]); + }, + + /** + * Fetches the source for the given |error| and populates the code section. + * @param {!ManifestError|!RuntimeError} error + */ + fetchCodeSource_: function(error) { + var 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; + break; + } + this.delegate.requestFileSource(args).then(function(code) { + this.$['code-section'].code = code; + }.bind(this)); + }, + }); + + return { + ErrorPage: ErrorPage, + ErrorPageDelegate: ErrorPageDelegate, + }; +}); diff --git a/chromium/chrome/browser/resources/md_extensions/error_severity_fatal.png b/chromium/chrome/browser/resources/md_extensions/error_severity_fatal.png Binary files differnew file mode 100644 index 00000000000..b53dc2cf74b --- /dev/null +++ b/chromium/chrome/browser/resources/md_extensions/error_severity_fatal.png diff --git a/chromium/chrome/browser/resources/md_extensions/error_severity_info.png b/chromium/chrome/browser/resources/md_extensions/error_severity_info.png Binary files differnew file mode 100644 index 00000000000..1c32c6eb83f --- /dev/null +++ b/chromium/chrome/browser/resources/md_extensions/error_severity_info.png diff --git a/chromium/chrome/browser/resources/md_extensions/error_severity_warning.png b/chromium/chrome/browser/resources/md_extensions/error_severity_warning.png Binary files differnew file mode 100644 index 00000000000..d2e3434a595 --- /dev/null +++ b/chromium/chrome/browser/resources/md_extensions/error_severity_warning.png diff --git a/chromium/chrome/browser/resources/md_extensions/item.html b/chromium/chrome/browser/resources/md_extensions/item.html index 9e9a8ef5a28..845f3186c8d 100644 --- a/chromium/chrome/browser/resources/md_extensions/item.html +++ b/chromium/chrome/browser/resources/md_extensions/item.html @@ -216,6 +216,10 @@ <paper-button id="details-button" on-tap="onDetailsTap_"> $i18n{itemDetails} </paper-button> + <paper-button id="errors-button" on-tap="onErrorsTap_" + hidden$="[[computeErrorsHidden_(data.*)]]"> + $i18n{itemErrors} + </paper-button> <paper-button id="remove-button" on-tap="onRemoveTap_"> $i18n{itemRemove} </paper-button> diff --git a/chromium/chrome/browser/resources/md_extensions/item.js b/chromium/chrome/browser/resources/md_extensions/item.js index 70929a12eca..ae9df0a7c51 100644 --- a/chromium/chrome/browser/resources/md_extensions/item.js +++ b/chromium/chrome/browser/resources/md_extensions/item.js @@ -100,6 +100,15 @@ cr.define('extensions', function() { this.fire('extension-item-size-changed', {item: this.data}); }, + /** + * @return {boolean} + * @private + */ + computeErrorsHidden_: function() { + return !this.data.manifestErrors.length && + !this.data.runtimeErrors.length; + }, + /** @private */ onRemoveTap_: function() { this.delegate.deleteItem(this.data.id); @@ -112,8 +121,13 @@ cr.define('extensions', function() { }, /** @private */ + onErrorsTap_: function() { + this.fire('extension-item-show-errors', {data: this.data}); + }, + + /** @private */ onDetailsTap_: function() { - this.fire('extension-item-show-details', {element: this}); + this.fire('extension-item-show-details', {data: this.data}); }, /** diff --git a/chromium/chrome/browser/resources/md_extensions/item_list.js b/chromium/chrome/browser/resources/md_extensions/item_list.js index 909b97b952a..74d9faa0b79 100644 --- a/chromium/chrome/browser/resources/md_extensions/item_list.js +++ b/chromium/chrome/browser/resources/md_extensions/item_list.js @@ -38,10 +38,10 @@ cr.define('extensions', function() { }, /** - * Called when the details for a given item are about to be shown. + * Called when a subpage for a given item is about to be shown. * @param {string} id */ - willShowItemDetails: function(id) { + willShowItemSubpage: function(id) { this.sharedElements = {hero: this.$$('#' + id)}; }, diff --git a/chromium/chrome/browser/resources/md_extensions/manager.html b/chromium/chrome/browser/resources/md_extensions/manager.html index c1f3df435dd..9625639fe40 100644 --- a/chromium/chrome/browser/resources/md_extensions/manager.html +++ b/chromium/chrome/browser/resources/md_extensions/manager.html @@ -8,6 +8,7 @@ <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animated-pages.html"> <link rel="import" href="chrome://extensions/detail_view.html"> <link rel="import" href="chrome://extensions/drop_overlay.html"> +<link rel="import" href="chrome://extensions/error_page.html"> <link rel="import" href="chrome://extensions/item_list.html"> <link rel="import" href="chrome://extensions/keyboard_shortcuts.html"> <link rel="import" href="chrome://extensions/options_dialog.html"> @@ -85,6 +86,8 @@ <extensions-keyboard-shortcuts id="keyboard-shortcuts" items="[[extensions]]"> </extensions-keyboard-shortcuts> + <extensions-error-page id="error-page" on-close="onErrorPageClose_"> + </extensions-error-page> </neon-animated-pages> <extensions-options-dialog id="options-dialog"> </extensions-options-dialog> diff --git a/chromium/chrome/browser/resources/md_extensions/manager.js b/chromium/chrome/browser/resources/md_extensions/manager.js index 15f92ae4137..640c092e35a 100644 --- a/chromium/chrome/browser/resources/md_extensions/manager.js +++ b/chromium/chrome/browser/resources/md_extensions/manager.js @@ -11,6 +11,7 @@ var Page = { ITEM_LIST: '0', DETAIL_VIEW: '1', KEYBOARD_SHORTCUTS: '2', + ERROR_PAGE: '3', }; cr.define('extensions', function() { @@ -77,6 +78,7 @@ cr.define('extensions', function() { listeners: { 'items-list.extension-item-show-details': 'onShouldShowItemDetails_', + 'items-list.extension-item-show-errors': 'onShouldShowItemErrors_', }, created: function() { @@ -104,12 +106,16 @@ cr.define('extensions', function() { return this.$['options-dialog']; }, + get errorPage() { + return this.$['error-page']; + }, + /** * Shows the details view for a given item. * @param {!chrome.developerPrivate.ExtensionInfo} data */ showItemDetails: function(data) { - this.$['items-list'].willShowItemDetails(data.id); + this.$['items-list'].willShowItemSubpage(data.id); this.$['details-view'].data = data; this.changePage(Page.DETAIL_VIEW); }, @@ -226,6 +232,8 @@ cr.define('extensions', function() { return this.$['details-view']; case Page.KEYBOARD_SHORTCUTS: return this.$['keyboard-shortcuts']; + case Page.ERROR_PAGE: + return this.$['error-page']; } assertNotReached(); }, @@ -240,7 +248,8 @@ cr.define('extensions', function() { return; var entry; var exit; - if (fromPage == Page.ITEM_LIST && toPage == Page.DETAIL_VIEW) { + if (fromPage == Page.ITEM_LIST && (toPage == Page.DETAIL_VIEW || + toPage == Page.ERROR_PAGE)) { entry = extensions.Animation.HERO; exit = extensions.Animation.HERO; } else if (toPage == Page.ITEM_LIST) { @@ -263,12 +272,29 @@ cr.define('extensions', function() { * @private */ onShouldShowItemDetails_: function(e) { - this.showItemDetails(e.detail.element.data); + this.showItemDetails(e.detail.data); + }, + + /** + * Handles the event for the user clicking on the errors button. + * @param {!CustomEvent} e + * @private + */ + onShouldShowItemErrors_: function(e) { + var data = e.detail.data; + this.$['items-list'].willShowItemSubpage(data.id); + this.$['error-page'].data = data; + this.changePage(Page.ERROR_PAGE); }, /** @private */ onDetailsViewClose_: function() { this.changePage(Page.ITEM_LIST); + }, + + /** @private */ + onErrorPageClose_: function() { + this.changePage(Page.ITEM_LIST); } }); diff --git a/chromium/chrome/browser/resources/md_extensions/service.js b/chromium/chrome/browser/resources/md_extensions/service.js index 9ef7d8d7209..08abe7d66e8 100644 --- a/chromium/chrome/browser/resources/md_extensions/service.js +++ b/chromium/chrome/browser/resources/md_extensions/service.js @@ -10,6 +10,7 @@ cr.define('extensions', function() { * @implements {extensions.ItemDelegate} * @implements {extensions.SidebarDelegate} * @implements {extensions.PackDialogDelegate} + * @implements {extensions.ErrorPageDelegate} */ function Service() {} @@ -24,6 +25,7 @@ cr.define('extensions', function() { this.manager_.sidebar.setDelegate(this); this.manager_.set('itemDelegate', this); this.manager_.packDialog.set('delegate', this); + this.manager_.errorPage.delegate = this; var keyboardShortcuts = this.manager_.keyboardShortcuts; keyboardShortcuts.addEventListener( 'shortcut-updated', @@ -270,6 +272,24 @@ cr.define('extensions', function() { updateAllExtensions: function() { chrome.developerPrivate.autoUpdate(); }, + + /** @override */ + deleteErrors: function(extensionId, errorIds, type) { + chrome.developerPrivate.deleteExtensionErrors({ + extensionId: extensionId, + errorIds: errorIds, + type: type, + }); + }, + + /** @override */ + requestFileSource: function(args) { + return new Promise(function(resolve, reject) { + chrome.developerPrivate.requestFileSource(args, function(code) { + resolve(code); + }); + }); + }, }; cr.addSingletonGetter(Service); diff --git a/chromium/chrome/browser/resources/md_feedback/compiled_resources2.gyp b/chromium/chrome/browser/resources/md_feedback/compiled_resources2.gyp new file mode 100644 index 00000000000..a3b6ac3db1f --- /dev/null +++ b/chromium/chrome/browser/resources/md_feedback/compiled_resources2.gyp @@ -0,0 +1,22 @@ +# Copyright 2016 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. +{ + 'targets': [ + { + 'target_name': 'feedback', + 'dependencies': [ + '<(EXTERNS_GYP):chrome_send', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util', + ], + 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + { + 'target_name': 'feedback_container', + 'dependencies': [ + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', + ], + 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + ], +} diff --git a/chromium/chrome/browser/resources/md_feedback/feedback.js b/chromium/chrome/browser/resources/md_feedback/feedback.js index d36aab512e7..61695ad98a3 100644 --- a/chromium/chrome/browser/resources/md_feedback/feedback.js +++ b/chromium/chrome/browser/resources/md_feedback/feedback.js @@ -13,8 +13,8 @@ Feedback.UI = class { /** * Populates the feedback form with data. * - * @param {{email: string|undefined, - * url: string|undefined}} data + * @param {{email: (string|undefined), + * url: (string|undefined)}} data * Parameters in data: * email - user's email, if available. * url - url of the tab the user was on before triggering feedback. diff --git a/chromium/chrome/browser/resources/md_feedback/feedback_container.html b/chromium/chrome/browser/resources/md_feedback/feedback_container.html index 3c6b72f9612..6c0047102f3 100644 --- a/chromium/chrome/browser/resources/md_feedback/feedback_container.html +++ b/chromium/chrome/browser/resources/md_feedback/feedback_container.html @@ -55,8 +55,8 @@ <hr> <paper-textarea label="$i18n{openEndedLabel}"></paper-textarea> <span id="additional-info">$i18n{additionalInfoLabel}</span> - <paper-input label="$i18n{urlLabel}" placeholder="[[url]]"></paper-input> - <paper-input label="$i18n{emailLabel}" placeholder="[[email]]"></paper-input> + <paper-input label="$i18n{urlLabel}" value="[[url]]"></paper-input> + <paper-input label="$i18n{emailLabel}" value="[[email]]"></paper-input> <div> <paper-checkbox>$i18n{includeScreenshotLabel}</paper-checkbox> </div> diff --git a/chromium/chrome/browser/resources/md_history/app.crisper.js b/chromium/chrome/browser/resources/md_history/app.crisper.js index 00420efa015..b87c842797a 100644 --- a/chromium/chrome/browser/resources/md_history/app.crisper.js +++ b/chromium/chrome/browser/resources/md_history/app.crisper.js @@ -13,28 +13,25 @@ cr.define("cr.ui",function(){function decorate(source,constr){var elements;if(ty // Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -cr.define("cr.ui",function(){function KeyboardShortcut(shortcut){var mods={};var ident="";shortcut.split("|").forEach(function(part){var partLc=part.toLowerCase();switch(partLc){case"alt":case"ctrl":case"meta":case"shift":mods[partLc+"Key"]=true;break;default:if(ident)throw Error("Invalid shortcut");ident=part}});this.ident_=ident;this.mods_=mods}KeyboardShortcut.prototype={matchesEvent:function(e){if(e.key==this.ident_){var mods=this.mods_;return["altKey","ctrlKey","metaKey","shiftKey"].every(function(k){return e[k]==!!mods[k]})}return false}};var Command=cr.ui.define("command");Command.prototype={__proto__:HTMLElement.prototype,decorate:function(){CommandManager.init(assert(this.ownerDocument));if(this.hasAttribute("shortcut"))this.shortcut=this.getAttribute("shortcut")},execute:function(opt_element){if(this.disabled)return;var doc=this.ownerDocument;if(doc.activeElement){var e=new Event("command",{bubbles:true});e.command=this;(opt_element||doc.activeElement).dispatchEvent(e)}},canExecuteChange:function(opt_node){dispatchCanExecuteEvent(this,opt_node||this.ownerDocument.activeElement)},shortcut_:"",get shortcut(){return this.shortcut_},set shortcut(shortcut){var oldShortcut=this.shortcut_;if(shortcut!==oldShortcut){this.keyboardShortcuts_=shortcut.split(/\s+/).map(function(shortcut){return new KeyboardShortcut(shortcut)});this.shortcut_=shortcut;cr.dispatchPropertyChange(this,"shortcut",this.shortcut_,oldShortcut)}},matchesEvent:function(e){if(!this.keyboardShortcuts_)return false;return this.keyboardShortcuts_.some(function(keyboardShortcut){return keyboardShortcut.matchesEvent(e)})}};cr.defineProperty(Command,"label",cr.PropertyKind.ATTR);cr.defineProperty(Command,"disabled",cr.PropertyKind.BOOL_ATTR);cr.defineProperty(Command,"hidden",cr.PropertyKind.BOOL_ATTR);cr.defineProperty(Command,"checked",cr.PropertyKind.BOOL_ATTR);cr.defineProperty(Command,"hideShortcutText",cr.PropertyKind.BOOL_ATTR);function dispatchCanExecuteEvent(command,target){var e=new CanExecuteEvent(command);target.dispatchEvent(e);command.disabled=!e.canExecute}var commandManagers={};function CommandManager(doc){doc.addEventListener("focus",this.handleFocus_.bind(this),true);doc.addEventListener("keydown",this.handleKeyDown_.bind(this),false)}CommandManager.init=function(doc){var uid=cr.getUid(doc);if(!(uid in commandManagers)){commandManagers[uid]=new CommandManager(doc)}};CommandManager.prototype={handleFocus_:function(e){var target=e.target;if(target.menu||target.command)return;var commands=Array.prototype.slice.call(target.ownerDocument.querySelectorAll("command"));commands.forEach(function(command){dispatchCanExecuteEvent(command,target)})},handleKeyDown_:function(e){var target=e.target;var commands=Array.prototype.slice.call(target.ownerDocument.querySelectorAll("command"));for(var i=0,command;command=commands[i];i++){if(command.matchesEvent(e)){command.canExecuteChange();if(!command.disabled){e.preventDefault();e.stopPropagation();command.execute();return}}}}};function CanExecuteEvent(command){var e=new Event("canExecute",{bubbles:true,cancelable:true});e.__proto__=CanExecuteEvent.prototype;e.command=command;return e}CanExecuteEvent.prototype={__proto__:Event.prototype,command:null,canExecute_:false,get canExecute(){return this.canExecute_},set canExecute(canExecute){this.canExecute_=!!canExecute;this.stopPropagation();this.preventDefault()}};return{Command:Command,CanExecuteEvent:CanExecuteEvent}}); +cr.define("cr.ui",function(){function KeyboardShortcut(shortcut){var mods={};var ident="";shortcut.split("|").forEach(function(part){var partLc=part.toLowerCase();switch(partLc){case"alt":case"ctrl":case"meta":case"shift":mods[partLc+"Key"]=true;break;default:if(ident)throw Error("Invalid shortcut");ident=part}});this.ident_=ident;this.mods_=mods}KeyboardShortcut.prototype={matchesEvent:function(e){if(e.key==this.ident_){var mods=this.mods_;return["altKey","ctrlKey","metaKey","shiftKey"].every(function(k){return e[k]==!!mods[k]})}return false}};var Command=cr.ui.define("command");Command.prototype={__proto__:HTMLElement.prototype,decorate:function(){CommandManager.init(assert(this.ownerDocument));if(this.hasAttribute("shortcut"))this.shortcut=this.getAttribute("shortcut")},execute:function(opt_element){if(this.disabled)return;var doc=this.ownerDocument;if(doc.activeElement){var e=new Event("command",{bubbles:true});e.command=this;(opt_element||doc.activeElement).dispatchEvent(e)}},canExecuteChange:function(opt_node){dispatchCanExecuteEvent(this,opt_node||this.ownerDocument.activeElement)},shortcut_:"",get shortcut(){return this.shortcut_},set shortcut(shortcut){var oldShortcut=this.shortcut_;if(shortcut!==oldShortcut){this.keyboardShortcuts_=shortcut.split(/\s+/).map(function(shortcut){return new KeyboardShortcut(shortcut)});this.shortcut_=shortcut;cr.dispatchPropertyChange(this,"shortcut",this.shortcut_,oldShortcut)}},matchesEvent:function(e){if(!this.keyboardShortcuts_)return false;return this.keyboardShortcuts_.some(function(keyboardShortcut){return keyboardShortcut.matchesEvent(e)})}};cr.defineProperty(Command,"label",cr.PropertyKind.ATTR);cr.defineProperty(Command,"disabled",cr.PropertyKind.BOOL_ATTR);cr.defineProperty(Command,"hidden",cr.PropertyKind.BOOL_ATTR);cr.defineProperty(Command,"checked",cr.PropertyKind.BOOL_ATTR);cr.defineProperty(Command,"hideShortcutText",cr.PropertyKind.BOOL_ATTR);function dispatchCanExecuteEvent(command,target){var e=new CanExecuteEvent(command);target.dispatchEvent(e);command.disabled=!e.canExecute}var commandManagers={};function CommandManager(doc){doc.addEventListener("focus",this.handleFocus_.bind(this),true);doc.addEventListener("keydown",this.handleKeyDown_.bind(this),false)}CommandManager.init=function(doc){var uid=cr.getUid(doc);if(!(uid in commandManagers)){commandManagers[uid]=new CommandManager(doc)}};CommandManager.prototype={handleFocus_:function(e){var target=e.target;if(target.menu||target.command)return;var commands=Array.prototype.slice.call(target.ownerDocument.querySelectorAll("command"));commands.forEach(function(command){dispatchCanExecuteEvent(command,target)})},handleKeyDown_:function(e){var target=e.target;var commands=Array.prototype.slice.call(target.ownerDocument.querySelectorAll("command"));for(var i=0,command;command=commands[i];i++){if(command.matchesEvent(e)){command.canExecuteChange();if(!command.disabled){e.preventDefault();e.stopPropagation();command.execute();return}}}}};function CanExecuteEvent(command){var e=new Event("canExecute",{bubbles:true,cancelable:true});e.__proto__=CanExecuteEvent.prototype;e.command=command;return e}CanExecuteEvent.prototype={__proto__:Event.prototype,command:null,canExecute_:false,get canExecute(){return this.canExecute_},set canExecute(canExecute){this.canExecute_=!!canExecute;this.stopPropagation();this.preventDefault()}};return{Command:Command,CanExecuteEvent:CanExecuteEvent}});Polymer({is:"iron-media-query",properties:{queryMatches:{type:Boolean,value:false,readOnly:true,notify:true},query:{type:String,observer:"queryChanged"},full:{type:Boolean,value:false},_boundMQHandler:{value:function(){return this.queryHandler.bind(this)}},_mq:{value:null}},attached:function(){this.style.display="none";this.queryChanged()},detached:function(){this._remove()},_add:function(){if(this._mq){this._mq.addListener(this._boundMQHandler)}},_remove:function(){if(this._mq){this._mq.removeListener(this._boundMQHandler)}this._mq=null},queryChanged:function(){this._remove();var query=this.query;if(!query){return}if(!this.full&&query[0]!=="("){query="("+query+")"}this._mq=window.matchMedia(query);this._add();this.queryHandler(this._mq)},queryHandler:function(mq){this._setQueryMatches(mq.matches)}});Polymer.IronResizableBehavior={properties:{_parentResizable:{type:Object,observer:"_parentResizableChanged"},_notifyingDescendant:{type:Boolean,value:false}},listeners:{"iron-request-resize-notifications":"_onIronRequestResizeNotifications"},created:function(){this._interestedResizables=[];this._boundNotifyResize=this.notifyResize.bind(this)},attached:function(){this.fire("iron-request-resize-notifications",null,{node:this,bubbles:true,cancelable:true});if(!this._parentResizable){window.addEventListener("resize",this._boundNotifyResize);this.notifyResize()}},detached:function(){if(this._parentResizable){this._parentResizable.stopResizeNotificationsFor(this)}else{window.removeEventListener("resize",this._boundNotifyResize)}this._parentResizable=null},notifyResize:function(){if(!this.isAttached){return}this._interestedResizables.forEach(function(resizable){if(this.resizerShouldNotify(resizable)){this._notifyDescendant(resizable)}},this);this._fireResize()},assignParentResizable:function(parentResizable){this._parentResizable=parentResizable},stopResizeNotificationsFor:function(target){var index=this._interestedResizables.indexOf(target);if(index>-1){this._interestedResizables.splice(index,1);this.unlisten(target,"iron-resize","_onDescendantIronResize")}},resizerShouldNotify:function(element){return true},_onDescendantIronResize:function(event){if(this._notifyingDescendant){event.stopPropagation();return}if(!Polymer.Settings.useShadow){this._fireResize()}},_fireResize:function(){this.fire("iron-resize",null,{node:this,bubbles:false})},_onIronRequestResizeNotifications:function(event){var target=event.path?event.path[0]:event.target;if(target===this){return}if(this._interestedResizables.indexOf(target)===-1){this._interestedResizables.push(target);this.listen(target,"iron-resize","_onDescendantIronResize")}target.assignParentResizable(this);this._notifyDescendant(target);event.stopPropagation()},_parentResizableChanged:function(parentResizable){if(parentResizable){window.removeEventListener("resize",this._boundNotifyResize)}},_notifyDescendant:function(descendant){if(!this.isAttached){return}this._notifyingDescendant=true;descendant.notifyResize();this._notifyingDescendant=false}};Polymer.IronSelection=function(selectCallback){this.selection=[];this.selectCallback=selectCallback};Polymer.IronSelection.prototype={get:function(){return this.multi?this.selection.slice():this.selection[0]},clear:function(excludes){this.selection.slice().forEach(function(item){if(!excludes||excludes.indexOf(item)<0){this.setItemSelected(item,false)}},this)},isSelected:function(item){return this.selection.indexOf(item)>=0},setItemSelected:function(item,isSelected){if(item!=null){if(isSelected!==this.isSelected(item)){if(isSelected){this.selection.push(item)}else{var i=this.selection.indexOf(item);if(i>=0){this.selection.splice(i,1)}}if(this.selectCallback){this.selectCallback(item,isSelected)}}}},select:function(item){if(this.multi){this.toggle(item)}else if(this.get()!==item){this.setItemSelected(this.get(),false);this.setItemSelected(item,true)}},toggle:function(item){this.setItemSelected(item,!this.isSelected(item))}};Polymer.IronSelectableBehavior={properties:{attrForSelected:{type:String,value:null},selected:{type:String,notify:true},selectedItem:{type:Object,readOnly:true,notify:true},activateEvent:{type:String,value:"tap",observer:"_activateEventChanged"},selectable:String,selectedClass:{type:String,value:"iron-selected"},selectedAttribute:{type:String,value:null},fallbackSelection:{type:String,value:null},items:{type:Array,readOnly:true,notify:true,value:function(){return[]}},_excludedLocalNames:{type:Object,value:function(){return{template:1}}}},observers:["_updateAttrForSelected(attrForSelected)","_updateSelected(selected)","_checkFallback(fallbackSelection)"],created:function(){this._bindFilterItem=this._filterItem.bind(this);this._selection=new Polymer.IronSelection(this._applySelection.bind(this))},attached:function(){this._observer=this._observeItems(this);this._updateItems();if(!this._shouldUpdateSelection){this._updateSelected()}this._addListener(this.activateEvent)},detached:function(){if(this._observer){Polymer.dom(this).unobserveNodes(this._observer)}this._removeListener(this.activateEvent)},indexOf:function(item){return this.items.indexOf(item)},select:function(value){this.selected=value},selectPrevious:function(){var length=this.items.length;var index=(Number(this._valueToIndex(this.selected))-1+length)%length;this.selected=this._indexToValue(index)},selectNext:function(){var index=(Number(this._valueToIndex(this.selected))+1)%this.items.length;this.selected=this._indexToValue(index)},selectIndex:function(index){this.select(this._indexToValue(index))},forceSynchronousItemUpdate:function(){this._updateItems()},get _shouldUpdateSelection(){return this.selected!=null},_checkFallback:function(){if(this._shouldUpdateSelection){this._updateSelected()}},_addListener:function(eventName){this.listen(this,eventName,"_activateHandler")},_removeListener:function(eventName){this.unlisten(this,eventName,"_activateHandler")},_activateEventChanged:function(eventName,old){this._removeListener(old);this._addListener(eventName)},_updateItems:function(){var nodes=Polymer.dom(this).queryDistributedElements(this.selectable||"*");nodes=Array.prototype.filter.call(nodes,this._bindFilterItem);this._setItems(nodes)},_updateAttrForSelected:function(){if(this._shouldUpdateSelection){this.selected=this._indexToValue(this.indexOf(this.selectedItem))}},_updateSelected:function(){this._selectSelected(this.selected)},_selectSelected:function(selected){this._selection.select(this._valueToItem(this.selected));if(this.fallbackSelection&&this.items.length&&this._selection.get()===undefined){this.selected=this.fallbackSelection}},_filterItem:function(node){return!this._excludedLocalNames[node.localName]},_valueToItem:function(value){return value==null?null:this.items[this._valueToIndex(value)]},_valueToIndex:function(value){if(this.attrForSelected){for(var i=0,item;item=this.items[i];i++){if(this._valueForItem(item)==value){return i}}}else{return Number(value)}},_indexToValue:function(index){if(this.attrForSelected){var item=this.items[index];if(item){return this._valueForItem(item)}}else{return index}},_valueForItem:function(item){var propValue=item[Polymer.CaseMap.dashToCamelCase(this.attrForSelected)];return propValue!=undefined?propValue:item.getAttribute(this.attrForSelected)},_applySelection:function(item,isSelected){if(this.selectedClass){this.toggleClass(this.selectedClass,isSelected,item)}if(this.selectedAttribute){this.toggleAttribute(this.selectedAttribute,isSelected,item)}this._selectionChange();this.fire("iron-"+(isSelected?"select":"deselect"),{item:item})},_selectionChange:function(){this._setSelectedItem(this._selection.get())},_observeItems:function(node){return Polymer.dom(node).observeNodes(function(mutation){this._updateItems();if(this._shouldUpdateSelection){this._updateSelected()}this.fire("iron-items-changed",mutation,{bubbles:false,cancelable:false})})},_activateHandler:function(e){var t=e.target;var items=this.items;while(t&&t!=this){var i=items.indexOf(t);if(i>=0){var value=this._indexToValue(i);this._itemActivate(value,t);return}t=t.parentNode}},_itemActivate:function(value,item){if(!this.fire("iron-activate",{selected:value,item:item},{cancelable:true}).defaultPrevented){this.select(value)}}};Polymer({is:"iron-pages",behaviors:[Polymer.IronResizableBehavior,Polymer.IronSelectableBehavior],properties:{activateEvent:{type:String,value:null}},observers:["_selectedPageChanged(selected)"],_selectedPageChanged:function(selected,old){this.async(this.notifyResize)}});Polymer.IronScrollTargetBehavior={properties:{scrollTarget:{type:HTMLElement,value:function(){return this._defaultScrollTarget}}},observers:["_scrollTargetChanged(scrollTarget, isAttached)"],_shouldHaveListener:true,_scrollTargetChanged:function(scrollTarget,isAttached){var eventTarget;if(this._oldScrollTarget){this._toggleScrollListener(false,this._oldScrollTarget);this._oldScrollTarget=null}if(!isAttached){return}if(scrollTarget==="document"){this.scrollTarget=this._doc}else if(typeof scrollTarget==="string"){this.scrollTarget=this.domHost?this.domHost.$[scrollTarget]:Polymer.dom(this.ownerDocument).querySelector("#"+scrollTarget)}else if(this._isValidScrollTarget()){this._boundScrollHandler=this._boundScrollHandler||this._scrollHandler.bind(this);this._oldScrollTarget=scrollTarget;this._toggleScrollListener(this._shouldHaveListener,scrollTarget)}},_scrollHandler:function scrollHandler(){},get _defaultScrollTarget(){return this._doc},get _doc(){return this.ownerDocument.documentElement},get _scrollTop(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.pageYOffset:this.scrollTarget.scrollTop}return 0},get _scrollLeft(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.pageXOffset:this.scrollTarget.scrollLeft}return 0},set _scrollTop(top){if(this.scrollTarget===this._doc){window.scrollTo(window.pageXOffset,top)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollTop=top}},set _scrollLeft(left){if(this.scrollTarget===this._doc){window.scrollTo(left,window.pageYOffset)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollLeft=left}},scroll:function(left,top){if(this.scrollTarget===this._doc){window.scrollTo(left,top)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollLeft=left;this.scrollTarget.scrollTop=top}},get _scrollTargetWidth(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.innerWidth:this.scrollTarget.offsetWidth}return 0},get _scrollTargetHeight(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.innerHeight:this.scrollTarget.offsetHeight}return 0},_isValidScrollTarget:function(){return this.scrollTarget instanceof HTMLElement},_toggleScrollListener:function(yes,scrollTarget){if(!this._boundScrollHandler){return}var eventTarget=scrollTarget===this._doc?window:scrollTarget;if(yes){eventTarget.addEventListener("scroll",this._boundScrollHandler)}else{eventTarget.removeEventListener("scroll",this._boundScrollHandler)}},toggleScrollListener:function(yes){this._shouldHaveListener=yes;this._toggleScrollListener(yes,this.scrollTarget)}};(function(){var metaDatas={};var metaArrays={};var singleton=null;Polymer.IronMeta=Polymer({is:"iron-meta",properties:{type:{type:String,value:"default",observer:"_typeChanged"},key:{type:String,observer:"_keyChanged"},value:{type:Object,notify:true,observer:"_valueChanged"},self:{type:Boolean,observer:"_selfChanged"},list:{type:Array,notify:true}},hostAttributes:{hidden:true},factoryImpl:function(config){if(config){for(var n in config){switch(n){case"type":case"key":case"value":this[n]=config[n];break}}}},created:function(){this._metaDatas=metaDatas;this._metaArrays=metaArrays},_keyChanged:function(key,old){this._resetRegistration(old)},_valueChanged:function(value){this._resetRegistration(this.key)},_selfChanged:function(self){if(self){this.value=this}},_typeChanged:function(type){this._unregisterKey(this.key);if(!metaDatas[type]){metaDatas[type]={}}this._metaData=metaDatas[type];if(!metaArrays[type]){metaArrays[type]=[]}this.list=metaArrays[type];this._registerKeyValue(this.key,this.value)},byKey:function(key){return this._metaData&&this._metaData[key]},_resetRegistration:function(oldKey){this._unregisterKey(oldKey);this._registerKeyValue(this.key,this.value)},_unregisterKey:function(key){this._unregister(key,this._metaData,this.list)},_registerKeyValue:function(key,value){this._register(key,value,this._metaData,this.list)},_register:function(key,value,data,list){if(key&&data&&value!==undefined){data[key]=value;list.push(value)}},_unregister:function(key,data,list){if(key&&data){if(key in data){var value=data[key];delete data[key];this.arrayDelete(list,value)}}}});Polymer.IronMeta.getIronMeta=function getIronMeta(){if(singleton===null){singleton=new Polymer.IronMeta}return singleton};Polymer.IronMetaQuery=Polymer({is:"iron-meta-query",properties:{type:{type:String,value:"default",observer:"_typeChanged"},key:{type:String,observer:"_keyChanged"},value:{type:Object,notify:true,readOnly:true},list:{type:Array,notify:true}},factoryImpl:function(config){if(config){for(var n in config){switch(n){case"type":case"key":this[n]=config[n];break}}}},created:function(){this._metaDatas=metaDatas;this._metaArrays=metaArrays},_keyChanged:function(key){this._setValue(this._metaData&&this._metaData[key])},_typeChanged:function(type){this._metaData=metaDatas[type];this.list=metaArrays[type];if(this.key){this._keyChanged(this.key)}},byKey:function(key){return this._metaData&&this._metaData[key]}})})();Polymer({is:"iron-icon",properties:{icon:{type:String,observer:"_iconChanged"},theme:{type:String,observer:"_updateIcon"},src:{type:String,observer:"_srcChanged"},_meta:{value:Polymer.Base.create("iron-meta",{type:"iconset"}),observer:"_updateIcon"}},_DEFAULT_ICONSET:"icons",_iconChanged:function(icon){var parts=(icon||"").split(":");this._iconName=parts.pop();this._iconsetName=parts.pop()||this._DEFAULT_ICONSET;this._updateIcon()},_srcChanged:function(src){this._updateIcon()},_usesIconset:function(){return this.icon||!this.src},_updateIcon:function(){if(this._usesIconset()){if(this._img&&this._img.parentNode){Polymer.dom(this.root).removeChild(this._img)}if(this._iconName===""){if(this._iconset){this._iconset.removeIcon(this)}}else if(this._iconsetName&&this._meta){this._iconset=this._meta.byKey(this._iconsetName);if(this._iconset){this._iconset.applyIcon(this,this._iconName,this.theme);this.unlisten(window,"iron-iconset-added","_updateIcon")}else{this.listen(window,"iron-iconset-added","_updateIcon")}}}else{if(this._iconset){this._iconset.removeIcon(this)}if(!this._img){this._img=document.createElement("img");this._img.style.width="100%";this._img.style.height="100%";this._img.draggable=false}this._img.src=this.src;Polymer.dom(this.root).appendChild(this._img)}}});(function(){"use strict";var KEY_IDENTIFIER={"U+0008":"backspace","U+0009":"tab","U+001B":"esc","U+0020":"space","U+007F":"del"};var KEY_CODE={8:"backspace",9:"tab",13:"enter",27:"esc",33:"pageup",34:"pagedown",35:"end",36:"home",32:"space",37:"left",38:"up",39:"right",40:"down",46:"del",106:"*"};var MODIFIER_KEYS={shift:"shiftKey",ctrl:"ctrlKey",alt:"altKey",meta:"metaKey"};var KEY_CHAR=/[a-z0-9*]/;var IDENT_CHAR=/U\+/;var ARROW_KEY=/^arrow/;var SPACE_KEY=/^space(bar)?/;var ESC_KEY=/^escape$/;function transformKey(key,noSpecialChars){var validKey="";if(key){var lKey=key.toLowerCase();if(lKey===" "||SPACE_KEY.test(lKey)){validKey="space"}else if(ESC_KEY.test(lKey)){validKey="esc"}else if(lKey.length==1){if(!noSpecialChars||KEY_CHAR.test(lKey)){validKey=lKey}}else if(ARROW_KEY.test(lKey)){validKey=lKey.replace("arrow","")}else if(lKey=="multiply"){validKey="*"}else{validKey=lKey}}return validKey}function transformKeyIdentifier(keyIdent){var validKey="";if(keyIdent){if(keyIdent in KEY_IDENTIFIER){validKey=KEY_IDENTIFIER[keyIdent]}else if(IDENT_CHAR.test(keyIdent)){keyIdent=parseInt(keyIdent.replace("U+","0x"),16);validKey=String.fromCharCode(keyIdent).toLowerCase()}else{validKey=keyIdent.toLowerCase()}}return validKey}function transformKeyCode(keyCode){var validKey="";if(Number(keyCode)){if(keyCode>=65&&keyCode<=90){validKey=String.fromCharCode(32+keyCode)}else if(keyCode>=112&&keyCode<=123){validKey="f"+(keyCode-112)}else if(keyCode>=48&&keyCode<=57){validKey=String(keyCode-48)}else if(keyCode>=96&&keyCode<=105){validKey=String(keyCode-96)}else{validKey=KEY_CODE[keyCode]}}return validKey}function normalizedKeyForEvent(keyEvent,noSpecialChars){if(keyEvent.key){return transformKey(keyEvent.key,noSpecialChars)}if(keyEvent.detail&&keyEvent.detail.key){return transformKey(keyEvent.detail.key,noSpecialChars)}return transformKeyIdentifier(keyEvent.keyIdentifier)||transformKeyCode(keyEvent.keyCode)||""}function keyComboMatchesEvent(keyCombo,event){var keyEvent=normalizedKeyForEvent(event,keyCombo.hasModifiers);return keyEvent===keyCombo.key&&(!keyCombo.hasModifiers||!!event.shiftKey===!!keyCombo.shiftKey&&!!event.ctrlKey===!!keyCombo.ctrlKey&&!!event.altKey===!!keyCombo.altKey&&!!event.metaKey===!!keyCombo.metaKey)}function parseKeyComboString(keyComboString){if(keyComboString.length===1){return{combo:keyComboString,key:keyComboString,event:"keydown"}}return keyComboString.split("+").reduce(function(parsedKeyCombo,keyComboPart){var eventParts=keyComboPart.split(":");var keyName=eventParts[0];var event=eventParts[1];if(keyName in MODIFIER_KEYS){parsedKeyCombo[MODIFIER_KEYS[keyName]]=true;parsedKeyCombo.hasModifiers=true}else{parsedKeyCombo.key=keyName;parsedKeyCombo.event=event||"keydown"}return parsedKeyCombo},{combo:keyComboString.split(":").shift()})}function parseEventString(eventString){return eventString.trim().split(" ").map(function(keyComboString){return parseKeyComboString(keyComboString)})}Polymer.IronA11yKeysBehavior={properties:{keyEventTarget:{type:Object,value:function(){return this}},stopKeyboardEventPropagation:{type:Boolean,value:false},_boundKeyHandlers:{type:Array,value:function(){return[]}},_imperativeKeyBindings:{type:Object,value:function(){return{}}}},observers:["_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)"],keyBindings:{},registered:function(){this._prepKeyBindings()},attached:function(){this._listenKeyEventListeners()},detached:function(){this._unlistenKeyEventListeners()},addOwnKeyBinding:function(eventString,handlerName){this._imperativeKeyBindings[eventString]=handlerName;this._prepKeyBindings();this._resetKeyEventListeners()},removeOwnKeyBindings:function(){this._imperativeKeyBindings={};this._prepKeyBindings();this._resetKeyEventListeners()},keyboardEventMatchesKeys:function(event,eventString){var keyCombos=parseEventString(eventString);for(var i=0;i<keyCombos.length;++i){if(keyComboMatchesEvent(keyCombos[i],event)){return true}}return false},_collectKeyBindings:function(){var keyBindings=this.behaviors.map(function(behavior){return behavior.keyBindings});if(keyBindings.indexOf(this.keyBindings)===-1){keyBindings.push(this.keyBindings)}return keyBindings},_prepKeyBindings:function(){this._keyBindings={};this._collectKeyBindings().forEach(function(keyBindings){for(var eventString in keyBindings){this._addKeyBinding(eventString,keyBindings[eventString])}},this);for(var eventString in this._imperativeKeyBindings){this._addKeyBinding(eventString,this._imperativeKeyBindings[eventString])}for(var eventName in this._keyBindings){this._keyBindings[eventName].sort(function(kb1,kb2){var b1=kb1[0].hasModifiers;var b2=kb2[0].hasModifiers;return b1===b2?0:b1?-1:1})}},_addKeyBinding:function(eventString,handlerName){parseEventString(eventString).forEach(function(keyCombo){this._keyBindings[keyCombo.event]=this._keyBindings[keyCombo.event]||[];this._keyBindings[keyCombo.event].push([keyCombo,handlerName])},this)},_resetKeyEventListeners:function(){this._unlistenKeyEventListeners();if(this.isAttached){this._listenKeyEventListeners()}},_listenKeyEventListeners:function(){if(!this.keyEventTarget){return}Object.keys(this._keyBindings).forEach(function(eventName){var keyBindings=this._keyBindings[eventName];var boundKeyHandler=this._onKeyBindingEvent.bind(this,keyBindings);this._boundKeyHandlers.push([this.keyEventTarget,eventName,boundKeyHandler]);this.keyEventTarget.addEventListener(eventName,boundKeyHandler)},this)},_unlistenKeyEventListeners:function(){var keyHandlerTuple;var keyEventTarget;var eventName;var boundKeyHandler;while(this._boundKeyHandlers.length){keyHandlerTuple=this._boundKeyHandlers.pop();keyEventTarget=keyHandlerTuple[0];eventName=keyHandlerTuple[1];boundKeyHandler=keyHandlerTuple[2];keyEventTarget.removeEventListener(eventName,boundKeyHandler)}},_onKeyBindingEvent:function(keyBindings,event){if(this.stopKeyboardEventPropagation){event.stopPropagation()}if(event.defaultPrevented){return}for(var i=0;i<keyBindings.length;i++){var keyCombo=keyBindings[i][0];var handlerName=keyBindings[i][1];if(keyComboMatchesEvent(keyCombo,event)){this._triggerKeyHandler(keyCombo,handlerName,event);if(event.defaultPrevented){return}}}},_triggerKeyHandler:function(keyCombo,handlerName,keyboardEvent){var detail=Object.create(keyCombo);detail.keyboardEvent=keyboardEvent;var event=new CustomEvent(keyCombo.event,{detail:detail,cancelable:true});this[handlerName].call(this,event);if(event.defaultPrevented){keyboardEvent.preventDefault()}}}})();Polymer.IronControlState={properties:{focused:{type:Boolean,value:false,notify:true,readOnly:true,reflectToAttribute:true},disabled:{type:Boolean,value:false,notify:true,observer:"_disabledChanged",reflectToAttribute:true},_oldTabIndex:{type:Number},_boundFocusBlurHandler:{type:Function,value:function(){return this._focusBlurHandler.bind(this)}}},observers:["_changedControlState(focused, disabled)"],ready:function(){this.addEventListener("focus",this._boundFocusBlurHandler,true);this.addEventListener("blur",this._boundFocusBlurHandler,true)},_focusBlurHandler:function(event){if(event.target===this){this._setFocused(event.type==="focus")}else if(!this.shadowRoot){var target=Polymer.dom(event).localTarget;if(!this.isLightDescendant(target)){this.fire(event.type,{sourceEvent:event},{node:this,bubbles:event.bubbles,cancelable:event.cancelable})}}},_disabledChanged:function(disabled,old){this.setAttribute("aria-disabled",disabled?"true":"false");this.style.pointerEvents=disabled?"none":"";if(disabled){this._oldTabIndex=this.tabIndex;this._setFocused(false);this.tabIndex=-1;this.blur()}else if(this._oldTabIndex!==undefined){this.tabIndex=this._oldTabIndex}},_changedControlState:function(){if(this._controlStateChanged){this._controlStateChanged()}}};Polymer.IronButtonStateImpl={properties:{pressed:{type:Boolean,readOnly:true,value:false,reflectToAttribute:true,observer:"_pressedChanged"},toggles:{type:Boolean,value:false,reflectToAttribute:true},active:{type:Boolean,value:false,notify:true,reflectToAttribute:true},pointerDown:{type:Boolean,readOnly:true,value:false},receivedFocusFromKeyboard:{type:Boolean,readOnly:true},ariaActiveAttribute:{type:String,value:"aria-pressed",observer:"_ariaActiveAttributeChanged"}},listeners:{down:"_downHandler",up:"_upHandler",tap:"_tapHandler"},observers:["_detectKeyboardFocus(focused)","_activeChanged(active, ariaActiveAttribute)"],keyBindings:{"enter:keydown":"_asyncClick","space:keydown":"_spaceKeyDownHandler","space:keyup":"_spaceKeyUpHandler"},_mouseEventRe:/^mouse/,_tapHandler:function(){if(this.toggles){this._userActivate(!this.active)}else{this.active=false}},_detectKeyboardFocus:function(focused){this._setReceivedFocusFromKeyboard(!this.pointerDown&&focused)},_userActivate:function(active){if(this.active!==active){this.active=active;this.fire("change")}},_downHandler:function(event){this._setPointerDown(true);this._setPressed(true);this._setReceivedFocusFromKeyboard(false)},_upHandler:function(){this._setPointerDown(false);this._setPressed(false)},_spaceKeyDownHandler:function(event){var keyboardEvent=event.detail.keyboardEvent;var target=Polymer.dom(keyboardEvent).localTarget;if(this.isLightDescendant(target))return;keyboardEvent.preventDefault();keyboardEvent.stopImmediatePropagation();this._setPressed(true)},_spaceKeyUpHandler:function(event){var keyboardEvent=event.detail.keyboardEvent;var target=Polymer.dom(keyboardEvent).localTarget;if(this.isLightDescendant(target))return;if(this.pressed){this._asyncClick()}this._setPressed(false)},_asyncClick:function(){this.async(function(){this.click()},1)},_pressedChanged:function(pressed){this._changedButtonState()},_ariaActiveAttributeChanged:function(value,oldValue){if(oldValue&&oldValue!=value&&this.hasAttribute(oldValue)){this.removeAttribute(oldValue)}},_activeChanged:function(active,ariaActiveAttribute){if(this.toggles){this.setAttribute(this.ariaActiveAttribute,active?"true":"false")}else{this.removeAttribute(this.ariaActiveAttribute)}this._changedButtonState()},_controlStateChanged:function(){if(this.disabled){this._setPressed(false)}else{this._changedButtonState()}},_changedButtonState:function(){if(this._buttonStateChanged){this._buttonStateChanged()}}};Polymer.IronButtonState=[Polymer.IronA11yKeysBehavior,Polymer.IronButtonStateImpl];(function(){var Utility={distance:function(x1,y1,x2,y2){var xDelta=x1-x2;var yDelta=y1-y2;return Math.sqrt(xDelta*xDelta+yDelta*yDelta)},now:window.performance&&window.performance.now?window.performance.now.bind(window.performance):Date.now};function ElementMetrics(element){this.element=element;this.width=this.boundingRect.width;this.height=this.boundingRect.height;this.size=Math.max(this.width,this.height)}ElementMetrics.prototype={get boundingRect(){return this.element.getBoundingClientRect()},furthestCornerDistanceFrom:function(x,y){var topLeft=Utility.distance(x,y,0,0);var topRight=Utility.distance(x,y,this.width,0);var bottomLeft=Utility.distance(x,y,0,this.height);var bottomRight=Utility.distance(x,y,this.width,this.height);return Math.max(topLeft,topRight,bottomLeft,bottomRight)}};function Ripple(element){this.element=element;this.color=window.getComputedStyle(element).color;this.wave=document.createElement("div");this.waveContainer=document.createElement("div");this.wave.style.backgroundColor=this.color;this.wave.classList.add("wave");this.waveContainer.classList.add("wave-container");Polymer.dom(this.waveContainer).appendChild(this.wave);this.resetInteractionState()}Ripple.MAX_RADIUS=300;Ripple.prototype={get recenters(){return this.element.recenters},get center(){return this.element.center},get mouseDownElapsed(){var elapsed;if(!this.mouseDownStart){return 0}elapsed=Utility.now()-this.mouseDownStart;if(this.mouseUpStart){elapsed-=this.mouseUpElapsed}return elapsed},get mouseUpElapsed(){return this.mouseUpStart?Utility.now()-this.mouseUpStart:0},get mouseDownElapsedSeconds(){return this.mouseDownElapsed/1e3},get mouseUpElapsedSeconds(){return this.mouseUpElapsed/1e3},get mouseInteractionSeconds(){return this.mouseDownElapsedSeconds+this.mouseUpElapsedSeconds},get initialOpacity(){return this.element.initialOpacity},get opacityDecayVelocity(){return this.element.opacityDecayVelocity},get radius(){var width2=this.containerMetrics.width*this.containerMetrics.width;var height2=this.containerMetrics.height*this.containerMetrics.height;var waveRadius=Math.min(Math.sqrt(width2+height2),Ripple.MAX_RADIUS)*1.1+5;var duration=1.1-.2*(waveRadius/Ripple.MAX_RADIUS);var timeNow=this.mouseInteractionSeconds/duration;var size=waveRadius*(1-Math.pow(80,-timeNow));return Math.abs(size)},get opacity(){if(!this.mouseUpStart){return this.initialOpacity}return Math.max(0,this.initialOpacity-this.mouseUpElapsedSeconds*this.opacityDecayVelocity)},get outerOpacity(){var outerOpacity=this.mouseUpElapsedSeconds*.3;var waveOpacity=this.opacity;return Math.max(0,Math.min(outerOpacity,waveOpacity))},get isOpacityFullyDecayed(){return this.opacity<.01&&this.radius>=Math.min(this.maxRadius,Ripple.MAX_RADIUS)},get isRestingAtMaxRadius(){return this.opacity>=this.initialOpacity&&this.radius>=Math.min(this.maxRadius,Ripple.MAX_RADIUS)},get isAnimationComplete(){return this.mouseUpStart?this.isOpacityFullyDecayed:this.isRestingAtMaxRadius},get translationFraction(){return Math.min(1,this.radius/this.containerMetrics.size*2/Math.sqrt(2))},get xNow(){if(this.xEnd){return this.xStart+this.translationFraction*(this.xEnd-this.xStart)}return this.xStart},get yNow(){if(this.yEnd){return this.yStart+this.translationFraction*(this.yEnd-this.yStart)}return this.yStart},get isMouseDown(){return this.mouseDownStart&&!this.mouseUpStart},resetInteractionState:function(){this.maxRadius=0;this.mouseDownStart=0;this.mouseUpStart=0;this.xStart=0; + +this.yStart=0;this.xEnd=0;this.yEnd=0;this.slideDistance=0;this.containerMetrics=new ElementMetrics(this.element)},draw:function(){var scale;var translateString;var dx;var dy;this.wave.style.opacity=this.opacity;scale=this.radius/(this.containerMetrics.size/2);dx=this.xNow-this.containerMetrics.width/2;dy=this.yNow-this.containerMetrics.height/2;this.waveContainer.style.webkitTransform="translate("+dx+"px, "+dy+"px)";this.waveContainer.style.transform="translate3d("+dx+"px, "+dy+"px, 0)";this.wave.style.webkitTransform="scale("+scale+","+scale+")";this.wave.style.transform="scale3d("+scale+","+scale+",1)"},downAction:function(event){var xCenter=this.containerMetrics.width/2;var yCenter=this.containerMetrics.height/2;this.resetInteractionState();this.mouseDownStart=Utility.now();if(this.center){this.xStart=xCenter;this.yStart=yCenter;this.slideDistance=Utility.distance(this.xStart,this.yStart,this.xEnd,this.yEnd)}else{this.xStart=event?event.detail.x-this.containerMetrics.boundingRect.left:this.containerMetrics.width/2;this.yStart=event?event.detail.y-this.containerMetrics.boundingRect.top:this.containerMetrics.height/2}if(this.recenters){this.xEnd=xCenter;this.yEnd=yCenter;this.slideDistance=Utility.distance(this.xStart,this.yStart,this.xEnd,this.yEnd)}this.maxRadius=this.containerMetrics.furthestCornerDistanceFrom(this.xStart,this.yStart);this.waveContainer.style.top=(this.containerMetrics.height-this.containerMetrics.size)/2+"px";this.waveContainer.style.left=(this.containerMetrics.width-this.containerMetrics.size)/2+"px";this.waveContainer.style.width=this.containerMetrics.size+"px";this.waveContainer.style.height=this.containerMetrics.size+"px"},upAction:function(event){if(!this.isMouseDown){return}this.mouseUpStart=Utility.now()},remove:function(){Polymer.dom(this.waveContainer.parentNode).removeChild(this.waveContainer)}};Polymer({is:"paper-ripple",behaviors:[Polymer.IronA11yKeysBehavior],properties:{initialOpacity:{type:Number,value:.25},opacityDecayVelocity:{type:Number,value:.8},recenters:{type:Boolean,value:false},center:{type:Boolean,value:false},ripples:{type:Array,value:function(){return[]}},animating:{type:Boolean,readOnly:true,reflectToAttribute:true,value:false},holdDown:{type:Boolean,value:false,observer:"_holdDownChanged"},noink:{type:Boolean,value:false},_animating:{type:Boolean},_boundAnimate:{type:Function,value:function(){return this.animate.bind(this)}}},get target(){return this.keyEventTarget},keyBindings:{"enter:keydown":"_onEnterKeydown","space:keydown":"_onSpaceKeydown","space:keyup":"_onSpaceKeyup"},attached:function(){if(this.parentNode.nodeType==11){this.keyEventTarget=Polymer.dom(this).getOwnerRoot().host}else{this.keyEventTarget=this.parentNode}var keyEventTarget=this.keyEventTarget;this.listen(keyEventTarget,"up","uiUpAction");this.listen(keyEventTarget,"down","uiDownAction")},detached:function(){this.unlisten(this.keyEventTarget,"up","uiUpAction");this.unlisten(this.keyEventTarget,"down","uiDownAction");this.keyEventTarget=null},get shouldKeepAnimating(){for(var index=0;index<this.ripples.length;++index){if(!this.ripples[index].isAnimationComplete){return true}}return false},simulatedRipple:function(){this.downAction(null);this.async(function(){this.upAction()},1)},uiDownAction:function(event){if(!this.noink){this.downAction(event)}},downAction:function(event){if(this.holdDown&&this.ripples.length>0){return}var ripple=this.addRipple();ripple.downAction(event);if(!this._animating){this._animating=true;this.animate()}},uiUpAction:function(event){if(!this.noink){this.upAction(event)}},upAction:function(event){if(this.holdDown){return}this.ripples.forEach(function(ripple){ripple.upAction(event)});this._animating=true;this.animate()},onAnimationComplete:function(){this._animating=false;this.$.background.style.backgroundColor=null;this.fire("transitionend")},addRipple:function(){var ripple=new Ripple(this);Polymer.dom(this.$.waves).appendChild(ripple.waveContainer);this.$.background.style.backgroundColor=ripple.color;this.ripples.push(ripple);this._setAnimating(true);return ripple},removeRipple:function(ripple){var rippleIndex=this.ripples.indexOf(ripple);if(rippleIndex<0){return}this.ripples.splice(rippleIndex,1);ripple.remove();if(!this.ripples.length){this._setAnimating(false)}},animate:function(){if(!this._animating){return}var index;var ripple;for(index=0;index<this.ripples.length;++index){ripple=this.ripples[index];ripple.draw();this.$.background.style.opacity=ripple.outerOpacity;if(ripple.isOpacityFullyDecayed&&!ripple.isRestingAtMaxRadius){this.removeRipple(ripple)}}if(!this.shouldKeepAnimating&&this.ripples.length===0){this.onAnimationComplete()}else{window.requestAnimationFrame(this._boundAnimate)}},_onEnterKeydown:function(){this.uiDownAction();this.async(this.uiUpAction,1)},_onSpaceKeydown:function(){this.uiDownAction()},_onSpaceKeyup:function(){this.uiUpAction()},_holdDownChanged:function(newVal,oldVal){if(oldVal===undefined){return}if(newVal){this.downAction()}else{this.upAction()}}})})();Polymer.PaperRippleBehavior={properties:{noink:{type:Boolean,observer:"_noinkChanged"},_rippleContainer:{type:Object}},_buttonStateChanged:function(){if(this.focused){this.ensureRipple()}},_downHandler:function(event){Polymer.IronButtonStateImpl._downHandler.call(this,event);if(this.pressed){this.ensureRipple(event)}},ensureRipple:function(optTriggeringEvent){if(!this.hasRipple()){this._ripple=this._createRipple();this._ripple.noink=this.noink;var rippleContainer=this._rippleContainer||this.root;if(rippleContainer){Polymer.dom(rippleContainer).appendChild(this._ripple)}if(optTriggeringEvent){var domContainer=Polymer.dom(this._rippleContainer||this);var target=Polymer.dom(optTriggeringEvent).rootTarget;if(domContainer.deepContains(target)){this._ripple.uiDownAction(optTriggeringEvent)}}}},getRipple:function(){this.ensureRipple();return this._ripple},hasRipple:function(){return Boolean(this._ripple)},_createRipple:function(){return document.createElement("paper-ripple")},_noinkChanged:function(noink){if(this.hasRipple()){this._ripple.noink=noink}}};Polymer.PaperInkyFocusBehaviorImpl={observers:["_focusedChanged(receivedFocusFromKeyboard)"],_focusedChanged:function(receivedFocusFromKeyboard){if(receivedFocusFromKeyboard){this.ensureRipple()}if(this.hasRipple()){this._ripple.holdDown=receivedFocusFromKeyboard}},_createRipple:function(){var ripple=Polymer.PaperRippleBehavior._createRipple();ripple.id="ink";ripple.setAttribute("center","");ripple.classList.add("circle");return ripple}};Polymer.PaperInkyFocusBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperRippleBehavior,Polymer.PaperInkyFocusBehaviorImpl];Polymer({is:"paper-icon-button",hostAttributes:{role:"button",tabindex:"0"},behaviors:[Polymer.PaperInkyFocusBehavior],properties:{src:{type:String},icon:{type:String},alt:{type:String,observer:"_altChanged"}},_altChanged:function(newValue,oldValue){var label=this.getAttribute("aria-label");if(!label||oldValue==label){this.setAttribute("aria-label",newValue)}}});Polymer({is:"iron-iconset-svg",properties:{name:{type:String,observer:"_nameChanged"},size:{type:Number,value:24},rtlMirroring:{type:Boolean,value:false}},_targetIsRTL:function(target){if(target&&target.nodeType!==Node.ELEMENT_NODE){target=target.host}return target&&window.getComputedStyle(target)["direction"]==="rtl"},attached:function(){this.style.display="none"},getIconNames:function(){this._icons=this._createIconMap();return Object.keys(this._icons).map(function(n){return this.name+":"+n},this)},applyIcon:function(element,iconName){element=element.root||element;this.removeIcon(element);var svg=this._cloneIcon(iconName,this.rtlMirroring&&this._targetIsRTL(element));if(svg){var pde=Polymer.dom(element);pde.insertBefore(svg,pde.childNodes[0]);return element._svgIcon=svg}return null},removeIcon:function(element){element=element.root||element;if(element._svgIcon){Polymer.dom(element).removeChild(element._svgIcon);element._svgIcon=null}},_nameChanged:function(){new Polymer.IronMeta({type:"iconset",key:this.name,value:this});this.async(function(){this.fire("iron-iconset-added",this,{node:window})})},_createIconMap:function(){var icons=Object.create(null);Polymer.dom(this).querySelectorAll("[id]").forEach(function(icon){icons[icon.id]=icon});return icons},_cloneIcon:function(id,mirrorAllowed){this._icons=this._icons||this._createIconMap();return this._prepareSvgClone(this._icons[id],this.size,mirrorAllowed)},_prepareSvgClone:function(sourceSvg,size,mirrorAllowed){if(sourceSvg){var content=sourceSvg.cloneNode(true),svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),viewBox=content.getAttribute("viewBox")||"0 0 "+size+" "+size,cssText="pointer-events: none; display: block; width: 100%; height: 100%;";if(mirrorAllowed&&content.hasAttribute("mirror-in-rtl")){cssText+="-webkit-transform:scale(-1,1);transform:scale(-1,1);"}svg.setAttribute("viewBox",viewBox);svg.setAttribute("preserveAspectRatio","xMidYMid meet");svg.style.cssText=cssText;svg.appendChild(content).removeAttribute("id");return svg}return null}}); // Copyright 2016 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. -var WebUIListenerBehavior={properties:{webUIListeners_:{type:Array,value:function(){return[]}}},addWebUIListener:function(eventName,callback){this.webUIListeners_.push(cr.addWebUIListener(eventName,callback))},detached:function(){while(this.webUIListeners_.length>0){cr.removeWebUIListener(this.webUIListeners_.pop())}}};Polymer({is:"iron-media-query",properties:{queryMatches:{type:Boolean,value:false,readOnly:true,notify:true},query:{type:String,observer:"queryChanged"},full:{type:Boolean,value:false},_boundMQHandler:{value:function(){return this.queryHandler.bind(this)}},_mq:{value:null}},attached:function(){this.style.display="none";this.queryChanged()},detached:function(){this._remove()},_add:function(){if(this._mq){this._mq.addListener(this._boundMQHandler)}},_remove:function(){if(this._mq){this._mq.removeListener(this._boundMQHandler)}this._mq=null},queryChanged:function(){this._remove();var query=this.query;if(!query){return}if(!this.full&&query[0]!=="("){query="("+query+")"}this._mq=window.matchMedia(query);this._add();this.queryHandler(this._mq)},queryHandler:function(mq){this._setQueryMatches(mq.matches)}});Polymer.IronResizableBehavior={properties:{_parentResizable:{type:Object,observer:"_parentResizableChanged"},_notifyingDescendant:{type:Boolean,value:false}},listeners:{"iron-request-resize-notifications":"_onIronRequestResizeNotifications"},created:function(){this._interestedResizables=[];this._boundNotifyResize=this.notifyResize.bind(this)},attached:function(){this.fire("iron-request-resize-notifications",null,{node:this,bubbles:true,cancelable:true});if(!this._parentResizable){window.addEventListener("resize",this._boundNotifyResize);this.notifyResize()}},detached:function(){if(this._parentResizable){this._parentResizable.stopResizeNotificationsFor(this)}else{window.removeEventListener("resize",this._boundNotifyResize)}this._parentResizable=null},notifyResize:function(){if(!this.isAttached){return}this._interestedResizables.forEach(function(resizable){if(this.resizerShouldNotify(resizable)){this._notifyDescendant(resizable)}},this);this._fireResize()},assignParentResizable:function(parentResizable){this._parentResizable=parentResizable},stopResizeNotificationsFor:function(target){var index=this._interestedResizables.indexOf(target);if(index>-1){this._interestedResizables.splice(index,1);this.unlisten(target,"iron-resize","_onDescendantIronResize")}},resizerShouldNotify:function(element){return true},_onDescendantIronResize:function(event){if(this._notifyingDescendant){event.stopPropagation();return}if(!Polymer.Settings.useShadow){this._fireResize()}},_fireResize:function(){this.fire("iron-resize",null,{node:this,bubbles:false})},_onIronRequestResizeNotifications:function(event){var target=event.path?event.path[0]:event.target;if(target===this){return}if(this._interestedResizables.indexOf(target)===-1){this._interestedResizables.push(target);this.listen(target,"iron-resize","_onDescendantIronResize")}target.assignParentResizable(this);this._notifyDescendant(target);event.stopPropagation()},_parentResizableChanged:function(parentResizable){if(parentResizable){window.removeEventListener("resize",this._boundNotifyResize)}},_notifyDescendant:function(descendant){if(!this.isAttached){return}this._notifyingDescendant=true;descendant.notifyResize();this._notifyingDescendant=false}};Polymer.IronSelection=function(selectCallback){this.selection=[];this.selectCallback=selectCallback};Polymer.IronSelection.prototype={get:function(){return this.multi?this.selection.slice():this.selection[0]},clear:function(excludes){this.selection.slice().forEach(function(item){if(!excludes||excludes.indexOf(item)<0){this.setItemSelected(item,false)}},this)},isSelected:function(item){return this.selection.indexOf(item)>=0},setItemSelected:function(item,isSelected){if(item!=null){if(isSelected!==this.isSelected(item)){if(isSelected){this.selection.push(item)}else{var i=this.selection.indexOf(item);if(i>=0){this.selection.splice(i,1)}}if(this.selectCallback){this.selectCallback(item,isSelected)}}}},select:function(item){if(this.multi){this.toggle(item)}else if(this.get()!==item){this.setItemSelected(this.get(),false);this.setItemSelected(item,true)}},toggle:function(item){this.setItemSelected(item,!this.isSelected(item))}};Polymer.IronSelectableBehavior={properties:{attrForSelected:{type:String,value:null},selected:{type:String,notify:true},selectedItem:{type:Object,readOnly:true,notify:true},activateEvent:{type:String,value:"tap",observer:"_activateEventChanged"},selectable:String,selectedClass:{type:String,value:"iron-selected"},selectedAttribute:{type:String,value:null},fallbackSelection:{type:String,value:null},items:{type:Array,readOnly:true,notify:true,value:function(){return[]}},_excludedLocalNames:{type:Object,value:function(){return{template:1}}}},observers:["_updateAttrForSelected(attrForSelected)","_updateSelected(selected)","_checkFallback(fallbackSelection)"],created:function(){this._bindFilterItem=this._filterItem.bind(this);this._selection=new Polymer.IronSelection(this._applySelection.bind(this))},attached:function(){this._observer=this._observeItems(this);this._updateItems();if(!this._shouldUpdateSelection){this._updateSelected()}this._addListener(this.activateEvent)},detached:function(){if(this._observer){Polymer.dom(this).unobserveNodes(this._observer)}this._removeListener(this.activateEvent)},indexOf:function(item){return this.items.indexOf(item)},select:function(value){this.selected=value},selectPrevious:function(){var length=this.items.length;var index=(Number(this._valueToIndex(this.selected))-1+length)%length;this.selected=this._indexToValue(index)},selectNext:function(){var index=(Number(this._valueToIndex(this.selected))+1)%this.items.length;this.selected=this._indexToValue(index)},selectIndex:function(index){this.select(this._indexToValue(index))},forceSynchronousItemUpdate:function(){this._updateItems()},get _shouldUpdateSelection(){return this.selected!=null},_checkFallback:function(){if(this._shouldUpdateSelection){this._updateSelected()}},_addListener:function(eventName){this.listen(this,eventName,"_activateHandler")},_removeListener:function(eventName){this.unlisten(this,eventName,"_activateHandler")},_activateEventChanged:function(eventName,old){this._removeListener(old);this._addListener(eventName)},_updateItems:function(){var nodes=Polymer.dom(this).queryDistributedElements(this.selectable||"*");nodes=Array.prototype.filter.call(nodes,this._bindFilterItem);this._setItems(nodes)},_updateAttrForSelected:function(){if(this._shouldUpdateSelection){this.selected=this._indexToValue(this.indexOf(this.selectedItem))}},_updateSelected:function(){this._selectSelected(this.selected)},_selectSelected:function(selected){this._selection.select(this._valueToItem(this.selected));if(this.fallbackSelection&&this.items.length&&this._selection.get()===undefined){this.selected=this.fallbackSelection}},_filterItem:function(node){return!this._excludedLocalNames[node.localName]},_valueToItem:function(value){return value==null?null:this.items[this._valueToIndex(value)]},_valueToIndex:function(value){if(this.attrForSelected){for(var i=0,item;item=this.items[i];i++){if(this._valueForItem(item)==value){return i}}}else{return Number(value)}},_indexToValue:function(index){if(this.attrForSelected){var item=this.items[index];if(item){return this._valueForItem(item)}}else{return index}},_valueForItem:function(item){var propValue=item[Polymer.CaseMap.dashToCamelCase(this.attrForSelected)];return propValue!=undefined?propValue:item.getAttribute(this.attrForSelected)},_applySelection:function(item,isSelected){if(this.selectedClass){this.toggleClass(this.selectedClass,isSelected,item)}if(this.selectedAttribute){this.toggleAttribute(this.selectedAttribute,isSelected,item)}this._selectionChange();this.fire("iron-"+(isSelected?"select":"deselect"),{item:item})},_selectionChange:function(){this._setSelectedItem(this._selection.get())},_observeItems:function(node){return Polymer.dom(node).observeNodes(function(mutation){this._updateItems();if(this._shouldUpdateSelection){this._updateSelected()}this.fire("iron-items-changed",mutation,{bubbles:false,cancelable:false})})},_activateHandler:function(e){var t=e.target;var items=this.items;while(t&&t!=this){var i=items.indexOf(t);if(i>=0){var value=this._indexToValue(i);this._itemActivate(value,t);return}t=t.parentNode}},_itemActivate:function(value,item){if(!this.fire("iron-activate",{selected:value,item:item},{cancelable:true}).defaultPrevented){this.select(value)}}};Polymer({is:"iron-pages",behaviors:[Polymer.IronResizableBehavior,Polymer.IronSelectableBehavior],properties:{activateEvent:{type:String,value:null}},observers:["_selectedPageChanged(selected)"],_selectedPageChanged:function(selected,old){this.async(this.notifyResize)}});Polymer.IronScrollTargetBehavior={properties:{scrollTarget:{type:HTMLElement,value:function(){return this._defaultScrollTarget}}},observers:["_scrollTargetChanged(scrollTarget, isAttached)"],_shouldHaveListener:true,_scrollTargetChanged:function(scrollTarget,isAttached){var eventTarget;if(this._oldScrollTarget){this._toggleScrollListener(false,this._oldScrollTarget);this._oldScrollTarget=null}if(!isAttached){return}if(scrollTarget==="document"){this.scrollTarget=this._doc}else if(typeof scrollTarget==="string"){this.scrollTarget=this.domHost?this.domHost.$[scrollTarget]:Polymer.dom(this.ownerDocument).querySelector("#"+scrollTarget)}else if(this._isValidScrollTarget()){this._boundScrollHandler=this._boundScrollHandler||this._scrollHandler.bind(this);this._oldScrollTarget=scrollTarget;this._toggleScrollListener(this._shouldHaveListener,scrollTarget)}},_scrollHandler:function scrollHandler(){},get _defaultScrollTarget(){return this._doc},get _doc(){return this.ownerDocument.documentElement},get _scrollTop(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.pageYOffset:this.scrollTarget.scrollTop}return 0},get _scrollLeft(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.pageXOffset:this.scrollTarget.scrollLeft}return 0},set _scrollTop(top){if(this.scrollTarget===this._doc){window.scrollTo(window.pageXOffset,top)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollTop=top}},set _scrollLeft(left){if(this.scrollTarget===this._doc){window.scrollTo(left,window.pageYOffset)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollLeft=left}},scroll:function(left,top){if(this.scrollTarget===this._doc){window.scrollTo(left,top)}else if(this._isValidScrollTarget()){this.scrollTarget.scrollLeft=left;this.scrollTarget.scrollTop=top}},get _scrollTargetWidth(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.innerWidth:this.scrollTarget.offsetWidth}return 0},get _scrollTargetHeight(){if(this._isValidScrollTarget()){return this.scrollTarget===this._doc?window.innerHeight:this.scrollTarget.offsetHeight}return 0},_isValidScrollTarget:function(){return this.scrollTarget instanceof HTMLElement},_toggleScrollListener:function(yes,scrollTarget){if(!this._boundScrollHandler){return}var eventTarget=scrollTarget===this._doc?window:scrollTarget;if(yes){eventTarget.addEventListener("scroll",this._boundScrollHandler)}else{eventTarget.removeEventListener("scroll",this._boundScrollHandler)}},toggleScrollListener:function(yes){this._shouldHaveListener=yes;this._toggleScrollListener(yes,this.scrollTarget)}};(function(){var metaDatas={};var metaArrays={};var singleton=null;Polymer.IronMeta=Polymer({is:"iron-meta",properties:{type:{type:String,value:"default",observer:"_typeChanged"},key:{type:String,observer:"_keyChanged"},value:{type:Object,notify:true,observer:"_valueChanged"},self:{type:Boolean,observer:"_selfChanged"},list:{type:Array,notify:true}},hostAttributes:{hidden:true},factoryImpl:function(config){if(config){for(var n in config){switch(n){case"type":case"key":case"value":this[n]=config[n];break}}}},created:function(){this._metaDatas=metaDatas;this._metaArrays=metaArrays},_keyChanged:function(key,old){this._resetRegistration(old)},_valueChanged:function(value){this._resetRegistration(this.key)},_selfChanged:function(self){if(self){this.value=this}},_typeChanged:function(type){this._unregisterKey(this.key);if(!metaDatas[type]){metaDatas[type]={}}this._metaData=metaDatas[type];if(!metaArrays[type]){metaArrays[type]=[]}this.list=metaArrays[type];this._registerKeyValue(this.key,this.value)},byKey:function(key){return this._metaData&&this._metaData[key]},_resetRegistration:function(oldKey){this._unregisterKey(oldKey);this._registerKeyValue(this.key,this.value)},_unregisterKey:function(key){this._unregister(key,this._metaData,this.list)},_registerKeyValue:function(key,value){this._register(key,value,this._metaData,this.list)},_register:function(key,value,data,list){if(key&&data&&value!==undefined){data[key]=value;list.push(value)}},_unregister:function(key,data,list){if(key&&data){if(key in data){var value=data[key];delete data[key];this.arrayDelete(list,value)}}}});Polymer.IronMeta.getIronMeta=function getIronMeta(){if(singleton===null){singleton=new Polymer.IronMeta}return singleton};Polymer.IronMetaQuery=Polymer({is:"iron-meta-query",properties:{type:{type:String,value:"default",observer:"_typeChanged"},key:{type:String,observer:"_keyChanged"},value:{type:Object,notify:true,readOnly:true},list:{type:Array,notify:true}},factoryImpl:function(config){if(config){for(var n in config){switch(n){case"type":case"key":this[n]=config[n];break}}}},created:function(){this._metaDatas=metaDatas;this._metaArrays=metaArrays},_keyChanged:function(key){this._setValue(this._metaData&&this._metaData[key])},_typeChanged:function(type){this._metaData=metaDatas[type];this.list=metaArrays[type];if(this.key){this._keyChanged(this.key)}},byKey:function(key){return this._metaData&&this._metaData[key]}})})();Polymer({is:"iron-icon",properties:{icon:{type:String,observer:"_iconChanged"},theme:{type:String,observer:"_updateIcon"},src:{type:String,observer:"_srcChanged"},_meta:{value:Polymer.Base.create("iron-meta",{type:"iconset"}),observer:"_updateIcon"}},_DEFAULT_ICONSET:"icons",_iconChanged:function(icon){var parts=(icon||"").split(":");this._iconName=parts.pop();this._iconsetName=parts.pop()||this._DEFAULT_ICONSET;this._updateIcon()},_srcChanged:function(src){this._updateIcon()},_usesIconset:function(){return this.icon||!this.src},_updateIcon:function(){if(this._usesIconset()){if(this._img&&this._img.parentNode){Polymer.dom(this.root).removeChild(this._img)}if(this._iconName===""){if(this._iconset){this._iconset.removeIcon(this)}}else if(this._iconsetName&&this._meta){this._iconset=this._meta.byKey(this._iconsetName);if(this._iconset){this._iconset.applyIcon(this,this._iconName,this.theme);this.unlisten(window,"iron-iconset-added","_updateIcon")}else{this.listen(window,"iron-iconset-added","_updateIcon")}}}else{if(this._iconset){this._iconset.removeIcon(this)}if(!this._img){this._img=document.createElement("img");this._img.style.width="100%";this._img.style.height="100%";this._img.draggable=false}this._img.src=this.src;Polymer.dom(this.root).appendChild(this._img)}}});(function(){"use strict";var KEY_IDENTIFIER={"U+0008":"backspace","U+0009":"tab","U+001B":"esc","U+0020":"space","U+007F":"del"};var KEY_CODE={8:"backspace",9:"tab",13:"enter",27:"esc",33:"pageup",34:"pagedown",35:"end",36:"home",32:"space",37:"left",38:"up",39:"right",40:"down",46:"del",106:"*"};var MODIFIER_KEYS={shift:"shiftKey",ctrl:"ctrlKey",alt:"altKey",meta:"metaKey"};var KEY_CHAR=/[a-z0-9*]/;var IDENT_CHAR=/U\+/;var ARROW_KEY=/^arrow/;var SPACE_KEY=/^space(bar)?/;var ESC_KEY=/^escape$/;function transformKey(key,noSpecialChars){var validKey="";if(key){var lKey=key.toLowerCase();if(lKey===" "||SPACE_KEY.test(lKey)){validKey="space"}else if(ESC_KEY.test(lKey)){validKey="esc"}else if(lKey.length==1){if(!noSpecialChars||KEY_CHAR.test(lKey)){validKey=lKey}}else if(ARROW_KEY.test(lKey)){validKey=lKey.replace("arrow","")}else if(lKey=="multiply"){validKey="*"}else{validKey=lKey}}return validKey}function transformKeyIdentifier(keyIdent){var validKey="";if(keyIdent){if(keyIdent in KEY_IDENTIFIER){validKey=KEY_IDENTIFIER[keyIdent]}else if(IDENT_CHAR.test(keyIdent)){keyIdent=parseInt(keyIdent.replace("U+","0x"),16);validKey=String.fromCharCode(keyIdent).toLowerCase()}else{validKey=keyIdent.toLowerCase()}}return validKey}function transformKeyCode(keyCode){var validKey="";if(Number(keyCode)){if(keyCode>=65&&keyCode<=90){validKey=String.fromCharCode(32+keyCode)}else if(keyCode>=112&&keyCode<=123){validKey="f"+(keyCode-112)}else if(keyCode>=48&&keyCode<=57){validKey=String(keyCode-48)}else if(keyCode>=96&&keyCode<=105){validKey=String(keyCode-96)}else{validKey=KEY_CODE[keyCode]}}return validKey}function normalizedKeyForEvent(keyEvent,noSpecialChars){if(keyEvent.key){return transformKey(keyEvent.key,noSpecialChars)}if(keyEvent.detail&&keyEvent.detail.key){return transformKey(keyEvent.detail.key,noSpecialChars)}return transformKeyIdentifier(keyEvent.keyIdentifier)||transformKeyCode(keyEvent.keyCode)||""}function keyComboMatchesEvent(keyCombo,event){var keyEvent=normalizedKeyForEvent(event,keyCombo.hasModifiers);return keyEvent===keyCombo.key&&(!keyCombo.hasModifiers||!!event.shiftKey===!!keyCombo.shiftKey&&!!event.ctrlKey===!!keyCombo.ctrlKey&&!!event.altKey===!!keyCombo.altKey&&!!event.metaKey===!!keyCombo.metaKey)}function parseKeyComboString(keyComboString){if(keyComboString.length===1){return{combo:keyComboString,key:keyComboString,event:"keydown"}}return keyComboString.split("+").reduce(function(parsedKeyCombo,keyComboPart){var eventParts=keyComboPart.split(":");var keyName=eventParts[0];var event=eventParts[1];if(keyName in MODIFIER_KEYS){parsedKeyCombo[MODIFIER_KEYS[keyName]]=true;parsedKeyCombo.hasModifiers=true}else{parsedKeyCombo.key=keyName;parsedKeyCombo.event=event||"keydown"}return parsedKeyCombo},{combo:keyComboString.split(":").shift()})}function parseEventString(eventString){return eventString.trim().split(" ").map(function(keyComboString){return parseKeyComboString(keyComboString)})}Polymer.IronA11yKeysBehavior={properties:{keyEventTarget:{type:Object,value:function(){return this}},stopKeyboardEventPropagation:{type:Boolean,value:false},_boundKeyHandlers:{type:Array,value:function(){return[]}},_imperativeKeyBindings:{type:Object,value:function(){return{}}}},observers:["_resetKeyEventListeners(keyEventTarget, _boundKeyHandlers)"],keyBindings:{},registered:function(){this._prepKeyBindings()},attached:function(){this._listenKeyEventListeners()},detached:function(){this._unlistenKeyEventListeners()},addOwnKeyBinding:function(eventString,handlerName){this._imperativeKeyBindings[eventString]=handlerName;this._prepKeyBindings();this._resetKeyEventListeners()},removeOwnKeyBindings:function(){this._imperativeKeyBindings={};this._prepKeyBindings();this._resetKeyEventListeners()},keyboardEventMatchesKeys:function(event,eventString){var keyCombos=parseEventString(eventString);for(var i=0;i<keyCombos.length;++i){if(keyComboMatchesEvent(keyCombos[i],event)){return true}}return false},_collectKeyBindings:function(){var keyBindings=this.behaviors.map(function(behavior){return behavior.keyBindings});if(keyBindings.indexOf(this.keyBindings)===-1){keyBindings.push(this.keyBindings)}return keyBindings},_prepKeyBindings:function(){this._keyBindings={};this._collectKeyBindings().forEach(function(keyBindings){for(var eventString in keyBindings){this._addKeyBinding(eventString,keyBindings[eventString])}},this);for(var eventString in this._imperativeKeyBindings){this._addKeyBinding(eventString,this._imperativeKeyBindings[eventString])}for(var eventName in this._keyBindings){this._keyBindings[eventName].sort(function(kb1,kb2){var b1=kb1[0].hasModifiers;var b2=kb2[0].hasModifiers;return b1===b2?0:b1?-1:1})}},_addKeyBinding:function(eventString,handlerName){parseEventString(eventString).forEach(function(keyCombo){this._keyBindings[keyCombo.event]=this._keyBindings[keyCombo.event]||[];this._keyBindings[keyCombo.event].push([keyCombo,handlerName])},this)},_resetKeyEventListeners:function(){this._unlistenKeyEventListeners();if(this.isAttached){this._listenKeyEventListeners()}},_listenKeyEventListeners:function(){if(!this.keyEventTarget){return}Object.keys(this._keyBindings).forEach(function(eventName){var keyBindings=this._keyBindings[eventName];var boundKeyHandler=this._onKeyBindingEvent.bind(this,keyBindings);this._boundKeyHandlers.push([this.keyEventTarget,eventName,boundKeyHandler]);this.keyEventTarget.addEventListener(eventName,boundKeyHandler)},this)},_unlistenKeyEventListeners:function(){var keyHandlerTuple;var keyEventTarget;var eventName;var boundKeyHandler;while(this._boundKeyHandlers.length){keyHandlerTuple=this._boundKeyHandlers.pop();keyEventTarget=keyHandlerTuple[0];eventName=keyHandlerTuple[1];boundKeyHandler=keyHandlerTuple[2];keyEventTarget.removeEventListener(eventName,boundKeyHandler)}},_onKeyBindingEvent:function(keyBindings,event){if(this.stopKeyboardEventPropagation){event.stopPropagation()}if(event.defaultPrevented){return}for(var i=0;i<keyBindings.length;i++){var keyCombo=keyBindings[i][0];var handlerName=keyBindings[i][1];if(keyComboMatchesEvent(keyCombo,event)){this._triggerKeyHandler(keyCombo,handlerName,event);if(event.defaultPrevented){return}}}},_triggerKeyHandler:function(keyCombo,handlerName,keyboardEvent){var detail=Object.create(keyCombo);detail.keyboardEvent=keyboardEvent;var event=new CustomEvent(keyCombo.event,{detail:detail,cancelable:true});this[handlerName].call(this,event);if(event.defaultPrevented){keyboardEvent.preventDefault()}}}})();Polymer.IronControlState={properties:{focused:{type:Boolean,value:false,notify:true,readOnly:true,reflectToAttribute:true},disabled:{type:Boolean,value:false,notify:true,observer:"_disabledChanged",reflectToAttribute:true},_oldTabIndex:{type:Number},_boundFocusBlurHandler:{type:Function,value:function(){return this._focusBlurHandler.bind(this)}}},observers:["_changedControlState(focused, disabled)"],ready:function(){this.addEventListener("focus",this._boundFocusBlurHandler,true);this.addEventListener("blur",this._boundFocusBlurHandler,true)},_focusBlurHandler:function(event){if(event.target===this){this._setFocused(event.type==="focus")}else if(!this.shadowRoot){var target=Polymer.dom(event).localTarget;if(!this.isLightDescendant(target)){this.fire(event.type,{sourceEvent:event},{node:this,bubbles:event.bubbles,cancelable:event.cancelable})}}},_disabledChanged:function(disabled,old){this.setAttribute("aria-disabled",disabled?"true":"false");this.style.pointerEvents=disabled?"none":"";if(disabled){this._oldTabIndex=this.tabIndex;this._setFocused(false);this.tabIndex=-1;this.blur()}else if(this._oldTabIndex!==undefined){this.tabIndex=this._oldTabIndex}},_changedControlState:function(){if(this._controlStateChanged){this._controlStateChanged()}}};Polymer.IronButtonStateImpl={properties:{pressed:{type:Boolean,readOnly:true,value:false,reflectToAttribute:true,observer:"_pressedChanged"},toggles:{type:Boolean,value:false,reflectToAttribute:true},active:{type:Boolean,value:false,notify:true,reflectToAttribute:true},pointerDown:{type:Boolean,readOnly:true,value:false},receivedFocusFromKeyboard:{type:Boolean,readOnly:true},ariaActiveAttribute:{type:String,value:"aria-pressed",observer:"_ariaActiveAttributeChanged"}},listeners:{down:"_downHandler",up:"_upHandler",tap:"_tapHandler"},observers:["_detectKeyboardFocus(focused)","_activeChanged(active, ariaActiveAttribute)"],keyBindings:{"enter:keydown":"_asyncClick","space:keydown":"_spaceKeyDownHandler","space:keyup":"_spaceKeyUpHandler"},_mouseEventRe:/^mouse/,_tapHandler:function(){if(this.toggles){this._userActivate(!this.active)}else{this.active=false}},_detectKeyboardFocus:function(focused){this._setReceivedFocusFromKeyboard(!this.pointerDown&&focused)},_userActivate:function(active){if(this.active!==active){this.active=active;this.fire("change")}},_downHandler:function(event){this._setPointerDown(true);this._setPressed(true);this._setReceivedFocusFromKeyboard(false)},_upHandler:function(){this._setPointerDown(false);this._setPressed(false)},_spaceKeyDownHandler:function(event){var keyboardEvent=event.detail.keyboardEvent;var target=Polymer.dom(keyboardEvent).localTarget;if(this.isLightDescendant(target))return;keyboardEvent.preventDefault();keyboardEvent.stopImmediatePropagation();this._setPressed(true)},_spaceKeyUpHandler:function(event){var keyboardEvent=event.detail.keyboardEvent;var target=Polymer.dom(keyboardEvent).localTarget;if(this.isLightDescendant(target))return;if(this.pressed){this._asyncClick()}this._setPressed(false)},_asyncClick:function(){this.async(function(){this.click()},1)},_pressedChanged:function(pressed){this._changedButtonState()},_ariaActiveAttributeChanged:function(value,oldValue){if(oldValue&&oldValue!=value&&this.hasAttribute(oldValue)){this.removeAttribute(oldValue)}},_activeChanged:function(active,ariaActiveAttribute){if(this.toggles){this.setAttribute(this.ariaActiveAttribute,active?"true":"false")}else{this.removeAttribute(this.ariaActiveAttribute)}this._changedButtonState()},_controlStateChanged:function(){if(this.disabled){this._setPressed(false)}else{this._changedButtonState()}},_changedButtonState:function(){if(this._buttonStateChanged){this._buttonStateChanged()}}};Polymer.IronButtonState=[Polymer.IronA11yKeysBehavior,Polymer.IronButtonStateImpl];(function(){var Utility={distance:function(x1,y1,x2,y2){var xDelta=x1-x2;var yDelta=y1-y2;return Math.sqrt(xDelta*xDelta+yDelta*yDelta)},now:window.performance&&window.performance.now?window.performance.now.bind(window.performance):Date.now};function ElementMetrics(element){this.element=element;this.width=this.boundingRect.width;this.height=this.boundingRect.height;this.size=Math.max(this.width,this.height)}ElementMetrics.prototype={get boundingRect(){return this.element.getBoundingClientRect()},furthestCornerDistanceFrom:function(x,y){var topLeft=Utility.distance(x,y,0,0);var topRight=Utility.distance(x,y,this.width,0);var bottomLeft=Utility.distance(x,y,0,this.height);var bottomRight=Utility.distance(x,y,this.width,this.height);return Math.max(topLeft,topRight,bottomLeft,bottomRight)}};function Ripple(element){this.element=element;this.color=window.getComputedStyle(element).color;this.wave=document.createElement("div");this.waveContainer=document.createElement("div");this.wave.style.backgroundColor=this.color;this.wave.classList.add("wave");this.waveContainer.classList.add("wave-container");Polymer.dom(this.waveContainer).appendChild(this.wave);this.resetInteractionState()}Ripple.MAX_RADIUS=300;Ripple.prototype={get recenters(){return this.element.recenters},get center(){return this.element.center},get mouseDownElapsed(){var elapsed;if(!this.mouseDownStart){return 0}elapsed=Utility.now()-this.mouseDownStart;if(this.mouseUpStart){elapsed-=this.mouseUpElapsed}return elapsed},get mouseUpElapsed(){return this.mouseUpStart?Utility.now()-this.mouseUpStart:0},get mouseDownElapsedSeconds(){return this.mouseDownElapsed/1e3},get mouseUpElapsedSeconds(){return this.mouseUpElapsed/1e3},get mouseInteractionSeconds(){return this.mouseDownElapsedSeconds+this.mouseUpElapsedSeconds},get initialOpacity(){return this.element.initialOpacity},get opacityDecayVelocity(){return this.element.opacityDecayVelocity},get radius(){var width2=this.containerMetrics.width*this.containerMetrics.width;var height2=this.containerMetrics.height*this.containerMetrics.height;var waveRadius=Math.min(Math.sqrt(width2+height2),Ripple.MAX_RADIUS)*1.1+5;var duration=1.1-.2*(waveRadius/Ripple.MAX_RADIUS);var timeNow=this.mouseInteractionSeconds/duration;var size=waveRadius*(1-Math.pow(80,-timeNow));return Math.abs(size)},get opacity(){if(!this.mouseUpStart){return this.initialOpacity}return Math.max(0,this.initialOpacity-this.mouseUpElapsedSeconds*this.opacityDecayVelocity)},get outerOpacity(){var outerOpacity=this.mouseUpElapsedSeconds*.3;var waveOpacity=this.opacity;return Math.max(0,Math.min(outerOpacity,waveOpacity))},get isOpacityFullyDecayed(){return this.opacity<.01&&this.radius>=Math.min(this.maxRadius,Ripple.MAX_RADIUS)},get isRestingAtMaxRadius(){return this.opacity>=this.initialOpacity&&this.radius>=Math.min(this.maxRadius,Ripple.MAX_RADIUS)},get isAnimationComplete(){return this.mouseUpStart?this.isOpacityFullyDecayed:this.isRestingAtMaxRadius},get translationFraction(){return Math.min(1,this.radius/this.containerMetrics.size*2/Math.sqrt(2))},get xNow(){if(this.xEnd){return this.xStart+this.translationFraction*(this.xEnd-this.xStart)}return this.xStart},get yNow(){if(this.yEnd){return this.yStart+this.translationFraction*(this.yEnd-this.yStart)}return this.yStart},get isMouseDown(){return this.mouseDownStart&&!this.mouseUpStart},resetInteractionState:function(){this.maxRadius=0;this.mouseDownStart=0;this.mouseUpStart=0;this.xStart=0;this.yStart=0;this.xEnd=0;this.yEnd=0;this.slideDistance=0;this.containerMetrics=new ElementMetrics(this.element)},draw:function(){var scale;var translateString;var dx;var dy;this.wave.style.opacity=this.opacity;scale=this.radius/(this.containerMetrics.size/2);dx=this.xNow-this.containerMetrics.width/2;dy=this.yNow-this.containerMetrics.height/2;this.waveContainer.style.webkitTransform="translate("+dx+"px, "+dy+"px)";this.waveContainer.style.transform="translate3d("+dx+"px, "+dy+"px, 0)";this.wave.style.webkitTransform="scale("+scale+","+scale+")";this.wave.style.transform="scale3d("+scale+","+scale+",1)"},downAction:function(event){var xCenter=this.containerMetrics.width/2;var yCenter=this.containerMetrics.height/2;this.resetInteractionState();this.mouseDownStart=Utility.now();if(this.center){this.xStart=xCenter;this.yStart=yCenter;this.slideDistance=Utility.distance(this.xStart,this.yStart,this.xEnd,this.yEnd)}else{this.xStart=event?event.detail.x-this.containerMetrics.boundingRect.left:this.containerMetrics.width/2;this.yStart=event?event.detail.y-this.containerMetrics.boundingRect.top:this.containerMetrics.height/2}if(this.recenters){this.xEnd=xCenter;this.yEnd=yCenter;this.slideDistance=Utility.distance(this.xStart,this.yStart,this.xEnd,this.yEnd)}this.maxRadius=this.containerMetrics.furthestCornerDistanceFrom(this.xStart,this.yStart);this.waveContainer.style.top=(this.containerMetrics.height-this.containerMetrics.size)/2+"px";this.waveContainer.style.left=(this.containerMetrics.width-this.containerMetrics.size)/2+"px";this.waveContainer.style.width=this.containerMetrics.size+"px";this.waveContainer.style.height=this.containerMetrics.size+"px"},upAction:function(event){if(!this.isMouseDown){return}this.mouseUpStart=Utility.now()},remove:function(){Polymer.dom(this.waveContainer.parentNode).removeChild(this.waveContainer)}};Polymer({is:"paper-ripple",behaviors:[Polymer.IronA11yKeysBehavior],properties:{initialOpacity:{type:Number,value:.25},opacityDecayVelocity:{type:Number,value:.8},recenters:{type:Boolean,value:false},center:{type:Boolean,value:false},ripples:{type:Array,value:function(){return[]}},animating:{type:Boolean,readOnly:true,reflectToAttribute:true,value:false},holdDown:{type:Boolean,value:false,observer:"_holdDownChanged"},noink:{type:Boolean,value:false},_animating:{type:Boolean},_boundAnimate:{type:Function,value:function(){return this.animate.bind(this)}}},get target(){return this.keyEventTarget},keyBindings:{"enter:keydown":"_onEnterKeydown","space:keydown":"_onSpaceKeydown","space:keyup":"_onSpaceKeyup"},attached:function(){if(this.parentNode.nodeType==11){this.keyEventTarget=Polymer.dom(this).getOwnerRoot().host}else{this.keyEventTarget=this.parentNode}var keyEventTarget=this.keyEventTarget;this.listen(keyEventTarget,"up","uiUpAction");this.listen(keyEventTarget,"down","uiDownAction")},detached:function(){this.unlisten(this.keyEventTarget,"up","uiUpAction");this.unlisten(this.keyEventTarget,"down","uiDownAction");this.keyEventTarget=null},get shouldKeepAnimating(){for(var index=0;index<this.ripples.length;++index){if(!this.ripples[index].isAnimationComplete){ -return true}}return false},simulatedRipple:function(){this.downAction(null);this.async(function(){this.upAction()},1)},uiDownAction:function(event){if(!this.noink){this.downAction(event)}},downAction:function(event){if(this.holdDown&&this.ripples.length>0){return}var ripple=this.addRipple();ripple.downAction(event);if(!this._animating){this._animating=true;this.animate()}},uiUpAction:function(event){if(!this.noink){this.upAction(event)}},upAction:function(event){if(this.holdDown){return}this.ripples.forEach(function(ripple){ripple.upAction(event)});this._animating=true;this.animate()},onAnimationComplete:function(){this._animating=false;this.$.background.style.backgroundColor=null;this.fire("transitionend")},addRipple:function(){var ripple=new Ripple(this);Polymer.dom(this.$.waves).appendChild(ripple.waveContainer);this.$.background.style.backgroundColor=ripple.color;this.ripples.push(ripple);this._setAnimating(true);return ripple},removeRipple:function(ripple){var rippleIndex=this.ripples.indexOf(ripple);if(rippleIndex<0){return}this.ripples.splice(rippleIndex,1);ripple.remove();if(!this.ripples.length){this._setAnimating(false)}},animate:function(){if(!this._animating){return}var index;var ripple;for(index=0;index<this.ripples.length;++index){ripple=this.ripples[index];ripple.draw();this.$.background.style.opacity=ripple.outerOpacity;if(ripple.isOpacityFullyDecayed&&!ripple.isRestingAtMaxRadius){this.removeRipple(ripple)}}if(!this.shouldKeepAnimating&&this.ripples.length===0){this.onAnimationComplete()}else{window.requestAnimationFrame(this._boundAnimate)}},_onEnterKeydown:function(){this.uiDownAction();this.async(this.uiUpAction,1)},_onSpaceKeydown:function(){this.uiDownAction()},_onSpaceKeyup:function(){this.uiUpAction()},_holdDownChanged:function(newVal,oldVal){if(oldVal===undefined){return}if(newVal){this.downAction()}else{this.upAction()}}})})();Polymer.PaperRippleBehavior={properties:{noink:{type:Boolean,observer:"_noinkChanged"},_rippleContainer:{type:Object}},_buttonStateChanged:function(){if(this.focused){this.ensureRipple()}},_downHandler:function(event){Polymer.IronButtonStateImpl._downHandler.call(this,event);if(this.pressed){this.ensureRipple(event)}},ensureRipple:function(optTriggeringEvent){if(!this.hasRipple()){this._ripple=this._createRipple();this._ripple.noink=this.noink;var rippleContainer=this._rippleContainer||this.root;if(rippleContainer){Polymer.dom(rippleContainer).appendChild(this._ripple)}if(optTriggeringEvent){var domContainer=Polymer.dom(this._rippleContainer||this);var target=Polymer.dom(optTriggeringEvent).rootTarget;if(domContainer.deepContains(target)){this._ripple.uiDownAction(optTriggeringEvent)}}}},getRipple:function(){this.ensureRipple();return this._ripple},hasRipple:function(){return Boolean(this._ripple)},_createRipple:function(){return document.createElement("paper-ripple")},_noinkChanged:function(noink){if(this.hasRipple()){this._ripple.noink=noink}}};Polymer.PaperInkyFocusBehaviorImpl={observers:["_focusedChanged(receivedFocusFromKeyboard)"],_focusedChanged:function(receivedFocusFromKeyboard){if(receivedFocusFromKeyboard){this.ensureRipple()}if(this.hasRipple()){this._ripple.holdDown=receivedFocusFromKeyboard}},_createRipple:function(){var ripple=Polymer.PaperRippleBehavior._createRipple();ripple.id="ink";ripple.setAttribute("center","");ripple.classList.add("circle");return ripple}};Polymer.PaperInkyFocusBehavior=[Polymer.IronButtonState,Polymer.IronControlState,Polymer.PaperRippleBehavior,Polymer.PaperInkyFocusBehaviorImpl];Polymer({is:"paper-icon-button",hostAttributes:{role:"button",tabindex:"0"},behaviors:[Polymer.PaperInkyFocusBehavior],properties:{src:{type:String},icon:{type:String},alt:{type:String,observer:"_altChanged"}},_altChanged:function(newValue,oldValue){var label=this.getAttribute("aria-label");if(!label||oldValue==label){this.setAttribute("aria-label",newValue)}}});Polymer({is:"iron-iconset-svg",properties:{name:{type:String,observer:"_nameChanged"},size:{type:Number,value:24}},attached:function(){this.style.display="none"},getIconNames:function(){this._icons=this._createIconMap();return Object.keys(this._icons).map(function(n){return this.name+":"+n},this)},applyIcon:function(element,iconName){element=element.root||element;this.removeIcon(element);var svg=this._cloneIcon(iconName);if(svg){var pde=Polymer.dom(element);pde.insertBefore(svg,pde.childNodes[0]);return element._svgIcon=svg}return null},removeIcon:function(element){if(element._svgIcon){Polymer.dom(element).removeChild(element._svgIcon);element._svgIcon=null}},_nameChanged:function(){new Polymer.IronMeta({type:"iconset",key:this.name,value:this});this.async(function(){this.fire("iron-iconset-added",this,{node:window})})},_createIconMap:function(){var icons=Object.create(null);Polymer.dom(this).querySelectorAll("[id]").forEach(function(icon){icons[icon.id]=icon});return icons},_cloneIcon:function(id){this._icons=this._icons||this._createIconMap();return this._prepareSvgClone(this._icons[id],this.size)},_prepareSvgClone:function(sourceSvg,size){if(sourceSvg){var content=sourceSvg.cloneNode(true),svg=document.createElementNS("http://www.w3.org/2000/svg","svg"),viewBox=content.getAttribute("viewBox")||"0 0 "+size+" "+size;svg.setAttribute("viewBox",viewBox);svg.setAttribute("preserveAspectRatio","xMidYMid meet");svg.style.cssText="pointer-events: none; display: block; width: 100%; height: 100%;";svg.appendChild(content).removeAttribute("id");return svg}return null}}); +Polymer({is:"cr-lazy-render","extends":"template",behaviors:[Polymer.Templatizer],child_:null,get:function(){if(!this.child_)this.render_();return this.child_},getIfExists:function(){return this.child_},render_:function(){if(!this.ctor)this.templatize(this);var parentNode=this.parentNode;if(parentNode&&!this.child_){var instance=this.stamp({});this.child_=instance.root.firstElementChild;parentNode.insertBefore(instance.root,this)}},_forwardParentProp:function(prop,value){if(this.child_)this.child_._templateInstance[prop]=value},_forwardParentPath:function(path,value){if(this.child_)this.child_._templateInstance.notifyPath(path,value,true)}});Polymer.PaperSpinnerBehavior={listeners:{animationend:"__reset",webkitAnimationEnd:"__reset"},properties:{active:{type:Boolean,value:false,reflectToAttribute:true,observer:"__activeChanged"},alt:{type:String,value:"loading",observer:"__altChanged"},__coolingDown:{type:Boolean,value:false}},__computeContainerClasses:function(active,coolingDown){return[active||coolingDown?"active":"",coolingDown?"cooldown":""].join(" ")},__activeChanged:function(active,old){this.__setAriaHidden(!active);this.__coolingDown=!active&&old},__altChanged:function(alt){if(alt===this.getPropertyInfo("alt").value){this.alt=this.getAttribute("aria-label")||alt}else{this.__setAriaHidden(alt==="");this.setAttribute("aria-label",alt)}},__setAriaHidden:function(hidden){var attr="aria-hidden";if(hidden){this.setAttribute(attr,"true")}else{this.removeAttribute(attr)}},__reset:function(){this.active=false;this.__coolingDown=false}};Polymer({is:"paper-spinner-lite",behaviors:[Polymer.PaperSpinnerBehavior]}); // Copyright 2016 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. -Polymer({is:"cr-lazy-render","extends":"template",behaviors:[Polymer.Templatizer],child_:null,get:function(){if(!this.child_)this.render_();return this.child_},getIfExists:function(){return this.child_},render_:function(){if(!this.ctor)this.templatize(this);var parentNode=this.parentNode;if(parentNode&&!this.child_){var instance=this.stamp({});this.child_=instance.root.firstElementChild;parentNode.insertBefore(instance.root,this)}},_forwardParentProp:function(prop,value){if(this.child_)this.child_._templateInstance[prop]=value},_forwardParentPath:function(path,value){if(this.child_)this.child_._templateInstance.notifyPath(path,value,true)}});(function(){"use strict";Polymer.IronA11yAnnouncer=Polymer({is:"iron-a11y-announcer",properties:{mode:{type:String,value:"polite"},_text:{type:String,value:""}},created:function(){if(!Polymer.IronA11yAnnouncer.instance){Polymer.IronA11yAnnouncer.instance=this}document.body.addEventListener("iron-announce",this._onIronAnnounce.bind(this))},announce:function(text){this._text="";this.async(function(){this._text=text},100)},_onIronAnnounce:function(event){if(event.detail&&event.detail.text){this.announce(event.detail.text)}}});Polymer.IronA11yAnnouncer.instance=null;Polymer.IronA11yAnnouncer.requestAvailability=function(){if(!Polymer.IronA11yAnnouncer.instance){Polymer.IronA11yAnnouncer.instance=document.createElement("iron-a11y-announcer")}document.body.appendChild(Polymer.IronA11yAnnouncer.instance)}})();Polymer.IronValidatableBehaviorMeta=null;Polymer.IronValidatableBehavior={properties:{validator:{type:String},invalid:{notify:true,reflectToAttribute:true,type:Boolean,value:false},_validatorMeta:{type:Object},validatorType:{type:String,value:"validator"},_validator:{type:Object,computed:"__computeValidator(validator)"}},observers:["_invalidChanged(invalid)"],registered:function(){Polymer.IronValidatableBehaviorMeta=new Polymer.IronMeta({type:"validator"})},_invalidChanged:function(){if(this.invalid){this.setAttribute("aria-invalid","true")}else{this.removeAttribute("aria-invalid")}},hasValidator:function(){return this._validator!=null},validate:function(value){this.invalid=!this._getValidity(value);return!this.invalid},_getValidity:function(value){if(this.hasValidator()){return this._validator.validate(value)}return true},__computeValidator:function(){return Polymer.IronValidatableBehaviorMeta&&Polymer.IronValidatableBehaviorMeta.byKey(this.validator)}};Polymer({is:"iron-input","extends":"input",behaviors:[Polymer.IronValidatableBehavior],properties:{bindValue:{observer:"_bindValueChanged",type:String},preventInvalidInput:{type:Boolean},allowedPattern:{type:String,observer:"_allowedPatternChanged"},_previousValidInput:{type:String,value:""},_patternAlreadyChecked:{type:Boolean,value:false}},listeners:{input:"_onInput",keypress:"_onKeypress"},registered:function(){if(!this._canDispatchEventOnDisabled()){this._origDispatchEvent=this.dispatchEvent;this.dispatchEvent=this._dispatchEventFirefoxIE}},created:function(){Polymer.IronA11yAnnouncer.requestAvailability()},_canDispatchEventOnDisabled:function(){var input=document.createElement("input");var canDispatch=false;input.disabled=true;input.addEventListener("feature-check-dispatch-event",function(){canDispatch=true});try{input.dispatchEvent(new Event("feature-check-dispatch-event"))}catch(e){}return canDispatch},_dispatchEventFirefoxIE:function(){var disabled=this.disabled;this.disabled=false;this._origDispatchEvent.apply(this,arguments);this.disabled=disabled},get _patternRegExp(){var pattern;if(this.allowedPattern){pattern=new RegExp(this.allowedPattern)}else{switch(this.type){case"number":pattern=/[0-9.,e-]/;break}}return pattern},ready:function(){this.bindValue=this.value},_bindValueChanged:function(){if(this.value!==this.bindValue){this.value=!(this.bindValue||this.bindValue===0||this.bindValue===false)?"":this.bindValue}this.fire("bind-value-changed",{value:this.bindValue})},_allowedPatternChanged:function(){this.preventInvalidInput=this.allowedPattern?true:false},_onInput:function(){if(this.preventInvalidInput&&!this._patternAlreadyChecked){var valid=this._checkPatternValidity();if(!valid){this._announceInvalidCharacter("Invalid string of characters not entered.");this.value=this._previousValidInput}}this.bindValue=this.value;this._previousValidInput=this.value;this._patternAlreadyChecked=false},_isPrintable:function(event){var anyNonPrintable=event.keyCode==8||event.keyCode==9||event.keyCode==13||event.keyCode==27;var mozNonPrintable=event.keyCode==19||event.keyCode==20||event.keyCode==45||event.keyCode==46||event.keyCode==144||event.keyCode==145||event.keyCode>32&&event.keyCode<41||event.keyCode>111&&event.keyCode<124;return!anyNonPrintable&&!(event.charCode==0&&mozNonPrintable)},_onKeypress:function(event){if(!this.preventInvalidInput&&this.type!=="number"){return}var regexp=this._patternRegExp;if(!regexp){return}if(event.metaKey||event.ctrlKey||event.altKey)return;this._patternAlreadyChecked=true;var thisChar=String.fromCharCode(event.charCode);if(this._isPrintable(event)&&!regexp.test(thisChar)){event.preventDefault();this._announceInvalidCharacter("Invalid character "+thisChar+" not entered.")}},_checkPatternValidity:function(){var regexp=this._patternRegExp;if(!regexp){return true}for(var i=0;i<this.value.length;i++){if(!regexp.test(this.value[i])){return false}}return true},validate:function(){var valid=this.checkValidity();if(valid){if(this.required&&this.value===""){valid=false}else if(this.hasValidator()){valid=Polymer.IronValidatableBehavior.validate.call(this,this.value)}}this.invalid=!valid;this.fire("iron-input-validate");return valid},_announceInvalidCharacter:function(message){this.fire("iron-announce",{text:message})}});Polymer({is:"paper-input-container",properties:{noLabelFloat:{type:Boolean,value:false},alwaysFloatLabel:{type:Boolean,value:false},attrForValue:{type:String,value:"bind-value"},autoValidate:{type:Boolean,value:false},invalid:{observer:"_invalidChanged",type:Boolean,value:false},focused:{readOnly:true,type:Boolean,value:false,notify:true},_addons:{type:Array},_inputHasContent:{type:Boolean,value:false},_inputSelector:{type:String,value:"input,textarea,.paper-input-input"},_boundOnFocus:{type:Function,value:function(){return this._onFocus.bind(this)}},_boundOnBlur:{type:Function,value:function(){return this._onBlur.bind(this)}},_boundOnInput:{type:Function,value:function(){return this._onInput.bind(this)}},_boundValueChanged:{type:Function,value:function(){return this._onValueChanged.bind(this)}}},listeners:{"addon-attached":"_onAddonAttached","iron-input-validate":"_onIronInputValidate"},get _valueChangedEvent(){return this.attrForValue+"-changed"},get _propertyForValue(){return Polymer.CaseMap.dashToCamelCase(this.attrForValue)},get _inputElement(){return Polymer.dom(this).querySelector(this._inputSelector)},get _inputElementValue(){return this._inputElement[this._propertyForValue]||this._inputElement.value},ready:function(){if(!this._addons){this._addons=[]}this.addEventListener("focus",this._boundOnFocus,true);this.addEventListener("blur",this._boundOnBlur,true)},attached:function(){if(this.attrForValue){this._inputElement.addEventListener(this._valueChangedEvent,this._boundValueChanged)}else{this.addEventListener("input",this._onInput)}if(this._inputElementValue!=""){this._handleValueAndAutoValidate(this._inputElement)}else{this._handleValue(this._inputElement)}},_onAddonAttached:function(event){if(!this._addons){this._addons=[]}var target=event.target;if(this._addons.indexOf(target)===-1){this._addons.push(target);if(this.isAttached){this._handleValue(this._inputElement)}}},_onFocus:function(){this._setFocused(true)},_onBlur:function(){this._setFocused(false);this._handleValueAndAutoValidate(this._inputElement)},_onInput:function(event){this._handleValueAndAutoValidate(event.target)},_onValueChanged:function(event){this._handleValueAndAutoValidate(event.target)},_handleValue:function(inputElement){var value=this._inputElementValue;if(value||value===0||inputElement.type==="number"&&!inputElement.checkValidity()){this._inputHasContent=true}else{this._inputHasContent=false}this.updateAddons({inputElement:inputElement,value:value,invalid:this.invalid})},_handleValueAndAutoValidate:function(inputElement){if(this.autoValidate){var valid;if(inputElement.validate){valid=inputElement.validate(this._inputElementValue)}else{valid=inputElement.checkValidity()}this.invalid=!valid}this._handleValue(inputElement)},_onIronInputValidate:function(event){this.invalid=this._inputElement.invalid},_invalidChanged:function(){if(this._addons){this.updateAddons({invalid:this.invalid})}},updateAddons:function(state){for(var addon,index=0;addon=this._addons[index];index++){addon.update(state)}},_computeInputContentClass:function(noLabelFloat,alwaysFloatLabel,focused,invalid,_inputHasContent){var cls="input-content";if(!noLabelFloat){var label=this.querySelector("label");if(alwaysFloatLabel||_inputHasContent){cls+=" label-is-floating";this.$.labelAndInputContainer.style.position="static";if(invalid){cls+=" is-invalid"}else if(focused){cls+=" label-is-highlighted"}}else{if(label){this.$.labelAndInputContainer.style.position="relative"}}}else{if(_inputHasContent){cls+=" label-is-hidden"}}return cls},_computeUnderlineClass:function(focused,invalid){var cls="underline";if(invalid){cls+=" is-invalid"}else if(focused){cls+=" is-highlighted"}return cls},_computeAddOnContentClass:function(focused,invalid){var cls="add-on-content";if(invalid){cls+=" is-invalid"}else if(focused){cls+=" is-highlighted"}return cls}});Polymer.PaperSpinnerBehavior={listeners:{animationend:"__reset",webkitAnimationEnd:"__reset"},properties:{active:{type:Boolean,value:false,reflectToAttribute:true,observer:"__activeChanged"},alt:{type:String,value:"loading",observer:"__altChanged"},__coolingDown:{type:Boolean,value:false}},__computeContainerClasses:function(active,coolingDown){return[active||coolingDown?"active":"",coolingDown?"cooldown":""].join(" ")},__activeChanged:function(active,old){this.__setAriaHidden(!active);this.__coolingDown=!active&&old},__altChanged:function(alt){if(alt===this.getPropertyInfo("alt").value){this.alt=this.getAttribute("aria-label")||alt}else{this.__setAriaHidden(alt==="");this.setAttribute("aria-label",alt)}},__setAriaHidden:function(hidden){var attr="aria-hidden";if(hidden){this.setAttribute(attr,"true")}else{this.removeAttribute(attr)}},__reset:function(){this.active=false;this.__coolingDown=false}};Polymer({is:"paper-spinner-lite",behaviors:[Polymer.PaperSpinnerBehavior]}); +var CrSearchFieldBehavior={properties:{label:{type:String,value:""},clearLabel:{type:String,value:""},showingSearch:{type:Boolean,value:false,notify:true,observer:"showingSearchChanged_",reflectToAttribute:true},lastValue_:{type:String,value:""}},getSearchInput:function(){},getValue:function(){return this.getSearchInput().value},setValue:function(value,opt_noEvent){var searchInput=this.getSearchInput();searchInput.value=value;if(searchInput.bindValue!=undefined)searchInput.bindValue=value;this.onValueChanged_(value,!!opt_noEvent)},showAndFocus:function(){this.showingSearch=true;this.focus_()},focus_:function(){this.getSearchInput().focus()},onSearchTermSearch:function(){this.onValueChanged_(this.getValue(),false)},onValueChanged_:function(newValue,noEvent){if(newValue==this.lastValue_)return;this.lastValue_=newValue;if(!noEvent)this.fire("search-changed",newValue)},onSearchTermKeydown:function(e){if(e.key=="Escape")this.showingSearch=false},showingSearchChanged_:function(current,previous){if(previous==undefined)return;if(this.showingSearch){this.focus_();return}this.setValue("");this.getSearchInput().blur()}}; // Copyright 2016 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. -var CrSearchFieldBehavior={properties:{label:{type:String,value:""},clearLabel:{type:String,value:""},showingSearch:{type:Boolean,value:false,notify:true,observer:"showingSearchChanged_",reflectToAttribute:true},lastValue_:{type:String,value:""}},getSearchInput:function(){},getValue:function(){return this.getSearchInput().value},setValue:function(value){this.getSearchInput().bindValue=value;this.onValueChanged_(value)},showAndFocus:function(){this.showingSearch=true;this.focus_()},focus_:function(){this.getSearchInput().focus()},onSearchTermSearch:function(){this.onValueChanged_(this.getValue())},onValueChanged_:function(newValue){if(newValue==this.lastValue_)return;this.fire("search-changed",newValue);this.lastValue_=newValue},onSearchTermKeydown:function(e){if(e.key=="Escape")this.showingSearch=false},showingSearchChanged_:function(){if(this.showingSearch){this.focus_();return}this.setValue("");this.getSearchInput().blur()}}; +Polymer({is:"cr-toolbar-search-field",behaviors:[CrSearchFieldBehavior],properties:{narrow:{type:Boolean,reflectToAttribute:true},label:String,clearLabel:String,spinnerActive:{type:Boolean,reflectToAttribute:true},hasSearchText_:{type:Boolean,reflectToAttribute:true},isSpinnerShown_:{type:Boolean,computed:"computeIsSpinnerShown_(spinnerActive, showingSearch)"},searchFocused_:{type:Boolean,value:false}},listeners:{click:"showSearch_"},getSearchInput:function(){return this.$.searchInput},setValue:function(value,opt_noEvent){CrSearchFieldBehavior.setValue.call(this,value,opt_noEvent);this.onSearchInput_()},isSearchFocused:function(){return this.searchFocused_},computeIconTabIndex_:function(narrow){return narrow?0:-1},computeIsSpinnerShown_:function(){return this.spinnerActive&&this.showingSearch},onInputFocus_:function(){this.searchFocused_=true},onInputBlur_:function(){this.searchFocused_=false;if(!this.hasSearchText_)this.showingSearch=false},onSearchInput_:function(){var newValue=this.$.searchInput.value;this.hasSearchText_=newValue!="";if(newValue!="")this.showingSearch=true},showSearch_:function(e){if(e.target!=this.$.clearSearch)this.showingSearch=true},clearSearch_:function(e){this.setValue("");this.getSearchInput().focus()}}); // Copyright 2016 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. -Polymer({is:"cr-toolbar-search-field",behaviors:[CrSearchFieldBehavior],properties:{narrow:{type:Boolean,reflectToAttribute:true},label:String,clearLabel:String,spinnerActive:{type:Boolean,reflectToAttribute:true},hasSearchText_:Boolean,isSpinnerShown_:{type:Boolean,computed:"computeIsSpinnerShown_(spinnerActive, showingSearch)"}},listeners:{tap:"showSearch_","searchInput.bind-value-changed":"onBindValueChanged_"},getSearchInput:function(){return this.$.searchInput},isSearchFocused:function(){return this.$.searchTerm.focused},computeIconTabIndex_:function(narrow){return narrow?0:-1},computeIsSpinnerShown_:function(){return this.spinnerActive&&this.showingSearch},onInputBlur_:function(){if(!this.hasSearchText_)this.showingSearch=false},onBindValueChanged_:function(){var newValue=this.$.searchInput.bindValue;this.hasSearchText_=newValue!="";if(newValue!="")this.showingSearch=true},showSearch_:function(e){if(e.target!=this.$.clearSearch)this.showingSearch=true},hideSearch_:function(e){this.showingSearch=false;e.stopPropagation()}}); -// Copyright 2016 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. -Polymer({is:"cr-toolbar",properties:{pageName:String,searchPrompt:String,clearLabel:String,menuLabel:String,menuPromo:String,spinnerActive:Boolean,showMenu:{type:Boolean,value:false},showMenuPromo:{type:Boolean,value:false},closeMenuPromo:String,narrow_:{type:Boolean,reflectToAttribute:true},showingSearch_:{type:Boolean,reflectToAttribute:true}},observers:["possiblyShowMenuPromo_(showMenu, showMenuPromo, showingSearch_)"],getSearchField:function(){return this.$.search},onClosePromoTap_:function(){this.showMenuPromo=false},onMenuTap_:function(){this.fire("cr-menu-tap");this.onClosePromoTap_()},possiblyShowMenuPromo_:function(){Polymer.RenderStatus.afterNextRender(this,function(){if(this.showMenu&&this.showMenuPromo&&!this.showingSearch_){this.$$("#menuPromo").animate({opacity:[0,.9]},{duration:500,fill:"forwards"});this.fire("cr-menu-promo-shown")}}.bind(this))},titleIfNotShowMenuPromo_:function(title,showMenuPromo){return showMenuPromo?"":title}}); +Polymer({is:"cr-toolbar",properties:{pageName:String,searchPrompt:String,clearLabel:String,menuLabel:String,menuPromo:String,spinnerActive:Boolean,showMenu:{type:Boolean,value:false},showMenuPromo:{type:Boolean,value:false},closeMenuPromo:String,narrow_:{type:Boolean,reflectToAttribute:true},showingSearch_:{type:Boolean,reflectToAttribute:true}},observers:["possiblyShowMenuPromo_(showMenu, showMenuPromo, showingSearch_)"],getSearchField:function(){return this.$.search},onClosePromoTap_:function(){this.fire("cr-toolbar-menu-promo-close")},onMenuTap_:function(){this.fire("cr-toolbar-menu-tap")},possiblyShowMenuPromo_:function(){Polymer.RenderStatus.afterNextRender(this,function(){if(this.showMenu&&this.showMenuPromo&&!this.showingSearch_){this.$$("#menuPromo").animate({opacity:[0,.9]},{duration:500,fill:"forwards"});this.fire("cr-toolbar-menu-promo-shown")}}.bind(this))},titleIfNotShowMenuPromo_:function(title,showMenuPromo){return showMenuPromo?"":title}}); // Copyright 2016 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. @@ -42,7 +39,7 @@ cr.define("md_history",function(){function BrowserService(){this.pendingDeleteIt // 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. -Polymer({is:"history-toolbar",properties:{count:{type:Number,value:0,observer:"changeToolbarView_"},itemsSelected_:{type:Boolean,value:false,reflectToAttribute:true},searchTerm:{type:String,observer:"searchTermChanged_",notify:true},spinnerActive:{type:Boolean,value:false},hasDrawer:{type:Boolean,observer:"hasDrawerChanged_",reflectToAttribute:true},showSyncNotice:Boolean,isGroupedMode:{type:Boolean,reflectToAttribute:true},groupedRange:{type:Number,value:0,reflectToAttribute:true,notify:true},queryStartTime:String,queryEndTime:String,showMenuPromo_:{type:Boolean,value:function(){return loadTimeData.getBoolean("showMenuPromo")}}},get searchField(){return this.$["main-toolbar"].getSearchField()},showSearchField:function(){this.searchField.showAndFocus()},changeToolbarView_:function(){this.itemsSelected_=this.count>0},searchTermChanged_:function(){if(this.searchField.getValue()!=this.searchTerm){this.searchField.showAndFocus();this.searchField.setValue(this.searchTerm)}},onMenuPromoShown_:function(){md_history.BrowserService.getInstance().menuPromoShown()},onSearchChanged_:function(event){this.searchTerm=event.detail},onInfoButtonTap_:function(){var dropdown=this.$.syncNotice.get();dropdown.positionTarget=this.$$("#info-button-icon");if(dropdown.style.display=="none")dropdown.open()},onClearSelectionTap_:function(){this.fire("unselect-all")},onDeleteTap_:function(){this.fire("delete-selected")},deletingAllowed_:function(){return loadTimeData.getBoolean("allowDeletingHistory")},numberOfItemsSelected_:function(count){return count>0?loadTimeData.getStringF("itemsSelected",count):""},getHistoryInterval_:function(queryStartTime,queryEndTime){return loadTimeData.getStringF("historyInterval",queryStartTime,queryEndTime)},hasDrawerChanged_:function(){this.updateStyles()}});(function(){var IOS=navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);var IOS_TOUCH_SCROLLING=IOS&&IOS[1]>=8;var DEFAULT_PHYSICAL_COUNT=3;var HIDDEN_Y="-10000px";var ITEM_WIDTH=0;var ITEM_HEIGHT=1;var SECRET_TABINDEX=-100;Polymer({is:"iron-list",properties:{items:{type:Array},maxPhysicalCount:{type:Number,value:500},as:{type:String,value:"item"},indexAs:{type:String,value:"index"},selectedAs:{type:String,value:"selected"},grid:{type:Boolean,value:false,reflectToAttribute:true},selectionEnabled:{type:Boolean,value:false},selectedItem:{type:Object,notify:true},selectedItems:{type:Object,notify:true},multiSelection:{type:Boolean,value:false}},observers:["_itemsChanged(items.*)","_selectionEnabledChanged(selectionEnabled)","_multiSelectionChanged(multiSelection)","_setOverflow(scrollTarget)"],behaviors:[Polymer.Templatizer,Polymer.IronResizableBehavior,Polymer.IronA11yKeysBehavior,Polymer.IronScrollTargetBehavior],keyBindings:{up:"_didMoveUp",down:"_didMoveDown",enter:"_didEnter"},_ratio:.5,_scrollerPaddingTop:0,_scrollPosition:0,_physicalSize:0,_physicalAverage:0,_physicalAverageCount:0,_physicalTop:0,_virtualCount:0,_physicalIndexForKey:null,_estScrollHeight:0,_scrollHeight:0,_viewportHeight:0,_viewportWidth:0,_physicalItems:null,_physicalSizes:null,_firstVisibleIndexVal:null,_lastVisibleIndexVal:null,_collection:null,_maxPages:2,_focusedItem:null,_focusedIndex:-1,_offscreenFocusedItem:null,_focusBackfillItem:null,_itemsPerRow:1,_itemWidth:0,_rowHeight:0,_templateCost:0,get _physicalBottom(){return this._physicalTop+this._physicalSize},get _scrollBottom(){return this._scrollPosition+this._viewportHeight},get _virtualEnd(){return this._virtualStart+this._physicalCount-1},get _hiddenContentSize(){var size=this.grid?this._physicalRows*this._rowHeight:this._physicalSize;return size-this._viewportHeight},get _maxScrollTop(){return this._estScrollHeight-this._viewportHeight+this._scrollerPaddingTop},_minVirtualStart:0,get _maxVirtualStart(){return Math.max(0,this._virtualCount-this._physicalCount)},_virtualStartVal:0,set _virtualStart(val){this._virtualStartVal=Math.min(this._maxVirtualStart,Math.max(this._minVirtualStart,val))},get _virtualStart(){return this._virtualStartVal||0},_physicalStartVal:0,set _physicalStart(val){this._physicalStartVal=val%this._physicalCount;if(this._physicalStartVal<0){this._physicalStartVal=this._physicalCount+this._physicalStartVal}this._physicalEnd=(this._physicalStart+this._physicalCount-1)%this._physicalCount},get _physicalStart(){return this._physicalStartVal||0},_physicalCountVal:0,set _physicalCount(val){this._physicalCountVal=val;this._physicalEnd=(this._physicalStart+this._physicalCount-1)%this._physicalCount},get _physicalCount(){return this._physicalCountVal},_physicalEnd:0,get _optPhysicalSize(){if(this.grid){return this._estRowsInView*this._rowHeight*this._maxPages}return this._viewportHeight*this._maxPages},get _isVisible(){return Boolean(this.offsetWidth||this.offsetHeight)},get firstVisibleIndex(){if(this._firstVisibleIndexVal===null){var physicalOffset=Math.floor(this._physicalTop+this._scrollerPaddingTop);this._firstVisibleIndexVal=this._iterateItems(function(pidx,vidx){physicalOffset+=this._getPhysicalSizeIncrement(pidx);if(physicalOffset>this._scrollPosition){return this.grid?vidx-vidx%this._itemsPerRow:vidx}if(this.grid&&this._virtualCount-1===vidx){return vidx-vidx%this._itemsPerRow}})||0}return this._firstVisibleIndexVal},get lastVisibleIndex(){if(this._lastVisibleIndexVal===null){if(this.grid){var lastIndex=this.firstVisibleIndex+this._estRowsInView*this._itemsPerRow-1;this._lastVisibleIndexVal=Math.min(this._virtualCount,lastIndex)}else{var physicalOffset=this._physicalTop;this._iterateItems(function(pidx,vidx){if(physicalOffset<this._scrollBottom){this._lastVisibleIndexVal=vidx}else{return true}physicalOffset+=this._getPhysicalSizeIncrement(pidx)})}}return this._lastVisibleIndexVal},get _defaultScrollTarget(){return this},get _virtualRowCount(){return Math.ceil(this._virtualCount/this._itemsPerRow)},get _estRowsInView(){return Math.ceil(this._viewportHeight/this._rowHeight)},get _physicalRows(){return Math.ceil(this._physicalCount/this._itemsPerRow)},ready:function(){this.addEventListener("focus",this._didFocus.bind(this),true)},attached:function(){if(this._physicalCount===0){this._debounceTemplate(this._render)}this.listen(this,"iron-resize","_resizeHandler")},detached:function(){this.unlisten(this,"iron-resize","_resizeHandler")},_setOverflow:function(scrollTarget){this.style.webkitOverflowScrolling=scrollTarget===this?"touch":"";this.style.overflow=scrollTarget===this?"auto":""},updateViewportBoundaries:function(){this._scrollerPaddingTop=this.scrollTarget===this?0:parseInt(window.getComputedStyle(this)["padding-top"],10);this._viewportWidth=this.$.items.offsetWidth;this._viewportHeight=this._scrollTargetHeight;this.grid&&this._updateGridMetrics()},_scrollHandler:function(){var scrollTop=Math.max(0,Math.min(this._maxScrollTop,this._scrollTop));var delta=scrollTop-this._scrollPosition;var isScrollingDown=delta>=0;this._scrollPosition=scrollTop;this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null;if(Math.abs(delta)>this._physicalSize){var idxAdjustment=Math.round(delta/this._physicalAverage)*this._itemsPerRow;this._physicalTop=this._physicalTop+delta;this._virtualStart=this._virtualStart+idxAdjustment;this._physicalStart=this._physicalStart+idxAdjustment;this._update()}else{var reusables=this._getReusables(isScrollingDown);if(isScrollingDown){this._physicalTop=reusables.physicalTop;this._virtualStart=this._virtualStart+reusables.indexes.length;this._physicalStart=this._physicalStart+reusables.indexes.length}else{this._virtualStart=this._virtualStart-reusables.indexes.length;this._physicalStart=this._physicalStart-reusables.indexes.length}if(reusables.indexes.length===0){this._increasePoolIfNeeded()}else{this._update(reusables.indexes,isScrollingDown?null:reusables.indexes)}}},_getReusables:function(fromTop){var ith,lastIth,offsetContent,physicalItemHeight;var idxs=[];var protectedOffsetContent=this._hiddenContentSize*this._ratio;var virtualStart=this._virtualStart;var virtualEnd=this._virtualEnd;var physicalCount=this._physicalCount;var physicalTop=this._physicalTop;var scrollTop=this._scrollTop;var scrollBottom=this._scrollBottom;if(fromTop){ith=this._physicalStart;lastIth=this._physicalEnd;offsetContent=scrollTop-physicalTop}else{ith=this._physicalEnd;lastIth=this._physicalStart;offsetContent=this._physicalBottom-scrollBottom}while(true){physicalItemHeight=this._getPhysicalSizeIncrement(ith);offsetContent=offsetContent-physicalItemHeight;if(idxs.length>=physicalCount||offsetContent<=protectedOffsetContent){break}if(fromTop){if(virtualEnd+idxs.length+1>=this._virtualCount){break}if(physicalTop+physicalItemHeight>=scrollTop){break}idxs.push(ith);physicalTop=physicalTop+physicalItemHeight;ith=(ith+1)%physicalCount}else{if(virtualStart-idxs.length<=0){break}if(physicalTop+this._physicalSize-physicalItemHeight<=scrollBottom){break}idxs.push(ith);physicalTop=physicalTop-physicalItemHeight;ith=ith===0?physicalCount-1:ith-1}}return{indexes:idxs,physicalTop:physicalTop}},_update:function(itemSet,movingUp){if(itemSet&&itemSet.length===0){return}this._manageFocus();this._assignModels(itemSet);this._updateMetrics(itemSet);if(movingUp){while(movingUp.length){var idx=movingUp.pop();this._physicalTop-=this._getPhysicalSizeIncrement(idx)}}this._positionItems();this._updateScrollerSize();this._increasePoolIfNeeded()},_createPool:function(size){var physicalItems=new Array(size);this._ensureTemplatized();for(var i=0;i<size;i++){var inst=this.stamp(null);physicalItems[i]=inst.root.querySelector("*");Polymer.dom(this).appendChild(inst.root)}return physicalItems},_increasePoolIfNeeded:function(){if(this._viewportHeight===0){return false}var self=this;var isClientFull=this._physicalBottom>=this._scrollBottom&&this._physicalTop<=this._scrollPosition;if(this._physicalSize>=this._optPhysicalSize&&isClientFull){return false}var maxPoolSize=Math.round(this._physicalCount*.5);if(!isClientFull){this._debounceTemplate(this._increasePool.bind(this,maxPoolSize));return true}this._yield(function(){self._increasePool(Math.min(maxPoolSize,Math.max(1,Math.round(50/self._templateCost))))});return true},_yield:function(cb){var g=window;var handle=g.requestIdleCallback?g.requestIdleCallback(cb):g.setTimeout(cb,16);Polymer.dom.addDebouncer({complete:function(){g.cancelIdleCallback?g.cancelIdleCallback(handle):g.clearTimeout(handle);cb()}})},_increasePool:function(missingItems){var nextPhysicalCount=Math.min(this._physicalCount+missingItems,this._virtualCount-this._virtualStart,Math.max(this.maxPhysicalCount,DEFAULT_PHYSICAL_COUNT));var prevPhysicalCount=this._physicalCount;var delta=nextPhysicalCount-prevPhysicalCount;var ts=window.performance.now();if(delta<=0){return}[].push.apply(this._physicalItems,this._createPool(delta));[].push.apply(this._physicalSizes,new Array(delta));this._physicalCount=prevPhysicalCount+delta;if(this._physicalStart>this._physicalEnd&&this._isIndexRendered(this._focusedIndex)&&this._getPhysicalIndex(this._focusedIndex)<this._physicalEnd){this._physicalStart=this._physicalStart+delta}this._update();this._templateCost=(window.performance.now()-ts)/delta},_render:function(){if(this.isAttached&&this._isVisible){if(this._physicalCount===0){this.updateViewportBoundaries();this._increasePool(DEFAULT_PHYSICAL_COUNT)}else{var reusables=this._getReusables(true);this._physicalTop=reusables.physicalTop;this._virtualStart=this._virtualStart+reusables.indexes.length;this._physicalStart=this._physicalStart+reusables.indexes.length;this._update(reusables.indexes);this._update()}}},_ensureTemplatized:function(){if(!this.ctor){var props={};props.__key__=true;props[this.as]=true;props[this.indexAs]=true;props[this.selectedAs]=true;props.tabIndex=true;this._instanceProps=props;this._userTemplate=Polymer.dom(this).querySelector("template");if(this._userTemplate){this.templatize(this._userTemplate)}else{console.warn("iron-list requires a template to be provided in light-dom")}}},_getStampedChildren:function(){return this._physicalItems},_forwardInstancePath:function(inst,path,value){if(path.indexOf(this.as+".")===0){this.notifyPath("items."+inst.__key__+"."+path.slice(this.as.length+1),value)}},_forwardParentProp:function(prop,value){if(this._physicalItems){this._physicalItems.forEach(function(item){item._templateInstance[prop]=value},this)}},_forwardParentPath:function(path,value){if(this._physicalItems){this._physicalItems.forEach(function(item){item._templateInstance.notifyPath(path,value,true)},this)}},_forwardItemPath:function(path,value){if(!this._physicalIndexForKey){return}var dot=path.indexOf(".");var key=path.substring(0,dot<0?path.length:dot);var idx=this._physicalIndexForKey[key];var offscreenItem=this._offscreenFocusedItem;var el=offscreenItem&&offscreenItem._templateInstance.__key__===key?offscreenItem:this._physicalItems[idx];if(!el||el._templateInstance.__key__!==key){return}if(dot>=0){path=this.as+"."+path.substring(dot+1);el._templateInstance.notifyPath(path,value,true)}else{var currentItem=el._templateInstance[this.as];if(Array.isArray(this.selectedItems)){for(var i=0;i<this.selectedItems.length;i++){if(this.selectedItems[i]===currentItem){this.set("selectedItems."+i,value);break}}}else if(this.selectedItem===currentItem){this.set("selectedItem",value)}el._templateInstance[this.as]=value}},_itemsChanged:function(change){if(change.path==="items"){this._virtualStart=0;this._physicalTop=0;this._virtualCount=this.items?this.items.length:0;this._collection=this.items?Polymer.Collection.get(this.items):null;this._physicalIndexForKey={};this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null;this._physicalCount=this._physicalCount||0;this._physicalItems=this._physicalItems||[];this._physicalSizes=this._physicalSizes||[];this._physicalStart=0;this._resetScrollPosition(0);this._removeFocusedItem();this._debounceTemplate(this._render)}else if(change.path==="items.splices"){this._adjustVirtualIndex(change.value.indexSplices);this._virtualCount=this.items?this.items.length:0;this._debounceTemplate(this._render)}else{this._forwardItemPath(change.path.split(".").slice(1).join("."),change.value)}},_adjustVirtualIndex:function(splices){splices.forEach(function(splice){splice.removed.forEach(this._removeItem,this);if(splice.index<this._virtualStart){var delta=Math.max(splice.addedCount-splice.removed.length,splice.index-this._virtualStart);this._virtualStart=this._virtualStart+delta;if(this._focusedIndex>=0){this._focusedIndex=this._focusedIndex+delta}}},this)},_removeItem:function(item){this.$.selector.deselect(item);if(this._focusedItem&&this._focusedItem._templateInstance[this.as]===item){this._removeFocusedItem()}},_iterateItems:function(fn,itemSet){var pidx,vidx,rtn,i;if(arguments.length===2&&itemSet){for(i=0;i<itemSet.length;i++){pidx=itemSet[i];vidx=this._computeVidx(pidx);if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}}else{pidx=this._physicalStart;vidx=this._virtualStart;for(;pidx<this._physicalCount;pidx++,vidx++){if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}for(pidx=0;pidx<this._physicalStart;pidx++,vidx++){if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}}},_computeVidx:function(pidx){if(pidx>=this._physicalStart){return this._virtualStart+(pidx-this._physicalStart)}return this._virtualStart+(this._physicalCount-this._physicalStart)+pidx},_assignModels:function(itemSet){this._iterateItems(function(pidx,vidx){var el=this._physicalItems[pidx];var inst=el._templateInstance;var item=this.items&&this.items[vidx];if(item!=null){inst[this.as]=item;inst.__key__=this._collection.getKey(item);inst[this.selectedAs]=this.$.selector.isSelected(item);inst[this.indexAs]=vidx;inst.tabIndex=this._focusedIndex===vidx?0:-1;this._physicalIndexForKey[inst.__key__]=pidx;el.removeAttribute("hidden")}else{inst.__key__=null;el.setAttribute("hidden","")}},itemSet)},_updateMetrics:function(itemSet){Polymer.dom.flush();var newPhysicalSize=0;var oldPhysicalSize=0;var prevAvgCount=this._physicalAverageCount;var prevPhysicalAvg=this._physicalAverage;this._iterateItems(function(pidx,vidx){oldPhysicalSize+=this._physicalSizes[pidx]||0;this._physicalSizes[pidx]=this._physicalItems[pidx].offsetHeight;newPhysicalSize+=this._physicalSizes[pidx];this._physicalAverageCount+=this._physicalSizes[pidx]?1:0},itemSet);if(this.grid){this._updateGridMetrics();this._physicalSize=Math.ceil(this._physicalCount/this._itemsPerRow)*this._rowHeight}else{this._physicalSize=this._physicalSize+newPhysicalSize-oldPhysicalSize}if(this._physicalAverageCount!==prevAvgCount){this._physicalAverage=Math.round((prevPhysicalAvg*prevAvgCount+newPhysicalSize)/this._physicalAverageCount)}},_updateGridMetrics:function(){this._itemWidth=this._physicalCount>0?this._physicalItems[0].getBoundingClientRect().width:200;this._rowHeight=this._physicalCount>0?this._physicalItems[0].offsetHeight:200;this._itemsPerRow=this._itemWidth?Math.floor(this._viewportWidth/this._itemWidth):this._itemsPerRow},_positionItems:function(){this._adjustScrollPosition();var y=this._physicalTop;if(this.grid){var totalItemWidth=this._itemsPerRow*this._itemWidth;var rowOffset=(this._viewportWidth-totalItemWidth)/2;this._iterateItems(function(pidx,vidx){var modulus=vidx%this._itemsPerRow;var x=Math.floor(modulus*this._itemWidth+rowOffset);this.translate3d(x+"px",y+"px",0,this._physicalItems[pidx]);if(this._shouldRenderNextRow(vidx)){y+=this._rowHeight}})}else{this._iterateItems(function(pidx,vidx){this.translate3d(0,y+"px",0,this._physicalItems[pidx]);y+=this._physicalSizes[pidx]})}},_getPhysicalSizeIncrement:function(pidx){if(!this.grid){return this._physicalSizes[pidx]}if(this._computeVidx(pidx)%this._itemsPerRow!==this._itemsPerRow-1){return 0}return this._rowHeight},_shouldRenderNextRow:function(vidx){return vidx%this._itemsPerRow===this._itemsPerRow-1},_adjustScrollPosition:function(){var deltaHeight=this._virtualStart===0?this._physicalTop:Math.min(this._scrollPosition+this._physicalTop,0);if(deltaHeight){this._physicalTop=this._physicalTop-deltaHeight;if(!IOS_TOUCH_SCROLLING&&this._physicalTop!==0){this._resetScrollPosition(this._scrollTop-deltaHeight)}}},_resetScrollPosition:function(pos){if(this.scrollTarget){this._scrollTop=pos;this._scrollPosition=this._scrollTop}},_updateScrollerSize:function(forceUpdate){if(this.grid){this._estScrollHeight=this._virtualRowCount*this._rowHeight}else{this._estScrollHeight=this._physicalBottom+Math.max(this._virtualCount-this._physicalCount-this._virtualStart,0)*this._physicalAverage}forceUpdate=forceUpdate||this._scrollHeight===0;forceUpdate=forceUpdate||this._scrollPosition>=this._estScrollHeight-this._physicalSize;forceUpdate=forceUpdate||this.grid&&this.$.items.style.height<this._estScrollHeight;if(forceUpdate||Math.abs(this._estScrollHeight-this._scrollHeight)>=this._optPhysicalSize){this.$.items.style.height=this._estScrollHeight+"px";this._scrollHeight=this._estScrollHeight}},scrollToItem:function(item){return this.scrollToIndex(this.items.indexOf(item))},scrollToIndex:function(idx){if(typeof idx!=="number"||idx<0||idx>this.items.length-1){return}Polymer.dom.flush();if(this._physicalCount===0){return}idx=Math.min(Math.max(idx,0),this._virtualCount-1);if(!this._isIndexRendered(idx)||idx>=this._maxVirtualStart){this._virtualStart=this.grid?idx-this._itemsPerRow*2:idx-1}this._manageFocus();this._assignModels();this._updateMetrics();this._physicalTop=Math.floor(this._virtualStart/this._itemsPerRow)*this._physicalAverage;var currentTopItem=this._physicalStart;var currentVirtualItem=this._virtualStart;var targetOffsetTop=0;var hiddenContentSize=this._hiddenContentSize;while(currentVirtualItem<idx&&targetOffsetTop<=hiddenContentSize){targetOffsetTop=targetOffsetTop+this._getPhysicalSizeIncrement(currentTopItem);currentTopItem=(currentTopItem+1)%this._physicalCount;currentVirtualItem++}this._updateScrollerSize(true);this._positionItems();this._resetScrollPosition(this._physicalTop+this._scrollerPaddingTop+targetOffsetTop);this._increasePoolIfNeeded();this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null},_resetAverage:function(){this._physicalAverage=0;this._physicalAverageCount=0},_resizeHandler:function(){if(IOS&&Math.abs(this._viewportHeight-this._scrollTargetHeight)<100){return}Polymer.dom.addDebouncer(this.debounce("_debounceTemplate",function(){this.updateViewportBoundaries();this._render();if(this._isVisible){this.toggleScrollListener(true);if(this._physicalCount>0){this._resetAverage();this.scrollToIndex(this.firstVisibleIndex)}}else{this.toggleScrollListener(false)}}.bind(this),1))},_getModelFromItem:function(item){var key=this._collection.getKey(item);var pidx=this._physicalIndexForKey[key];if(pidx!=null){return this._physicalItems[pidx]._templateInstance}return null},_getNormalizedItem:function(item){if(this._collection.getKey(item)===undefined){if(typeof item==="number"){item=this.items[item];if(!item){throw new RangeError("<item> not found")}return item}throw new TypeError("<item> should be a valid item")}return item},selectItem:function(item){item=this._getNormalizedItem(item);var model=this._getModelFromItem(item);if(!this.multiSelection&&this.selectedItem){this.deselectItem(this.selectedItem)}if(model){model[this.selectedAs]=true}this.$.selector.select(item);this.updateSizeForItem(item)},deselectItem:function(item){item=this._getNormalizedItem(item);var model=this._getModelFromItem(item);if(model){model[this.selectedAs]=false}this.$.selector.deselect(item);this.updateSizeForItem(item)},toggleSelectionForItem:function(item){item=this._getNormalizedItem(item);if(this.$.selector.isSelected(item)){this.deselectItem(item)}else{this.selectItem(item)}},clearSelection:function(){function unselect(item){var model=this._getModelFromItem(item);if(model){model[this.selectedAs]=false}}if(Array.isArray(this.selectedItems)){this.selectedItems.forEach(unselect,this)}else if(this.selectedItem){unselect.call(this,this.selectedItem)}this.$.selector.clearSelection()},_selectionEnabledChanged:function(selectionEnabled){var handler=selectionEnabled?this.listen:this.unlisten;handler.call(this,this,"tap","_selectionHandler")},_selectionHandler:function(e){var model=this.modelForElement(e.target);if(!model){return}var modelTabIndex,activeElTabIndex;var target=Polymer.dom(e).path[0];var activeEl=Polymer.dom(this.domHost?this.domHost.root:document).activeElement;var physicalItem=this._physicalItems[this._getPhysicalIndex(model[this.indexAs])];if(target.localName==="input"||target.localName==="button"||target.localName==="select"){return}modelTabIndex=model.tabIndex;model.tabIndex=SECRET_TABINDEX;activeElTabIndex=activeEl?activeEl.tabIndex:-1;model.tabIndex=modelTabIndex;if(activeEl&&physicalItem!==activeEl&&physicalItem.contains(activeEl)&&activeElTabIndex!==SECRET_TABINDEX){return}this.toggleSelectionForItem(model[this.as])},_multiSelectionChanged:function(multiSelection){this.clearSelection();this.$.selector.multi=multiSelection},updateSizeForItem:function(item){item=this._getNormalizedItem(item);var key=this._collection.getKey(item);var pidx=this._physicalIndexForKey[key];if(pidx!=null){this._updateMetrics([pidx]);this._positionItems()}},_manageFocus:function(){var fidx=this._focusedIndex;if(fidx>=0&&fidx<this._virtualCount){if(this._isIndexRendered(fidx)){this._restoreFocusedItem()}else{this._createFocusBackfillItem()}}else if(this._virtualCount>0&&this._physicalCount>0){this._focusedIndex=this._virtualStart;this._focusedItem=this._physicalItems[this._physicalStart]}},_isIndexRendered:function(idx){return idx>=this._virtualStart&&idx<=this._virtualEnd},_isIndexVisible:function(idx){return idx>=this.firstVisibleIndex&&idx<=this.lastVisibleIndex},_getPhysicalIndex:function(idx){return this._physicalIndexForKey[this._collection.getKey(this._getNormalizedItem(idx))]},_focusPhysicalItem:function(idx){if(idx<0||idx>=this._virtualCount){return}this._restoreFocusedItem();if(!this._isIndexRendered(idx)){this.scrollToIndex(idx)}var physicalItem=this._physicalItems[this._getPhysicalIndex(idx)];var model=physicalItem._templateInstance;var focusable;model.tabIndex=SECRET_TABINDEX;if(physicalItem.tabIndex===SECRET_TABINDEX){focusable=physicalItem}if(!focusable){focusable=Polymer.dom(physicalItem).querySelector('[tabindex="'+SECRET_TABINDEX+'"]')}model.tabIndex=0;this._focusedIndex=idx;focusable&&focusable.focus()},_removeFocusedItem:function(){if(this._offscreenFocusedItem){Polymer.dom(this).removeChild(this._offscreenFocusedItem)}this._offscreenFocusedItem=null;this._focusBackfillItem=null;this._focusedItem=null;this._focusedIndex=-1},_createFocusBackfillItem:function(){var pidx,fidx=this._focusedIndex;if(this._offscreenFocusedItem||fidx<0){return}if(!this._focusBackfillItem){var stampedTemplate=this.stamp(null);this._focusBackfillItem=stampedTemplate.root.querySelector("*");Polymer.dom(this).appendChild(stampedTemplate.root)}pidx=this._getPhysicalIndex(fidx);if(pidx!=null){this._offscreenFocusedItem=this._physicalItems[pidx];this._physicalItems[pidx]=this._focusBackfillItem;this.translate3d(0,HIDDEN_Y,0,this._offscreenFocusedItem)}},_restoreFocusedItem:function(){var pidx,fidx=this._focusedIndex;if(!this._offscreenFocusedItem||this._focusedIndex<0){return}this._assignModels();pidx=this._getPhysicalIndex(fidx);if(pidx!=null){this._focusBackfillItem=this._physicalItems[pidx];this._physicalItems[pidx]=this._offscreenFocusedItem;this._offscreenFocusedItem=null;this.translate3d(0,HIDDEN_Y,0,this._focusBackfillItem)}},_didFocus:function(e){var targetModel=this.modelForElement(e.target);var focusedModel=this._focusedItem?this._focusedItem._templateInstance:null;var hasOffscreenFocusedItem=this._offscreenFocusedItem!==null;var fidx=this._focusedIndex;if(!targetModel||!focusedModel){return}if(focusedModel===targetModel){if(!this._isIndexVisible(fidx)){this.scrollToIndex(fidx)}}else{this._restoreFocusedItem();focusedModel.tabIndex=-1;targetModel.tabIndex=0;fidx=targetModel[this.indexAs];this._focusedIndex=fidx;this._focusedItem=this._physicalItems[this._getPhysicalIndex(fidx)];if(hasOffscreenFocusedItem&&!this._offscreenFocusedItem){this._update()}}},_didMoveUp:function(){this._focusPhysicalItem(this._focusedIndex-1)},_didMoveDown:function(e){e.detail.keyboardEvent.preventDefault();this._focusPhysicalItem(this._focusedIndex+1)},_didEnter:function(e){this._focusPhysicalItem(this._focusedIndex);this._selectionHandler(e.detail.keyboardEvent)}})})();Polymer({is:"iron-scroll-threshold",properties:{upperThreshold:{type:Number,value:100},lowerThreshold:{type:Number,value:100},upperTriggered:{type:Boolean,value:false,notify:true,readOnly:true},lowerTriggered:{type:Boolean,value:false,notify:true,readOnly:true},horizontal:{type:Boolean,value:false}},behaviors:[Polymer.IronScrollTargetBehavior],observers:["_setOverflow(scrollTarget)","_initCheck(horizontal, isAttached)"],get _defaultScrollTarget(){return this},_setOverflow:function(scrollTarget){this.style.overflow=scrollTarget===this?"auto":""},_scrollHandler:function(){var THROTTLE_THRESHOLD=200;if(!this.isDebouncerActive("_checkTheshold")){this.debounce("_checkTheshold",function(){this.checkScrollThesholds()},THROTTLE_THRESHOLD)}},_initCheck:function(horizontal,isAttached){if(isAttached){this.debounce("_init",function(){this.clearTriggers();this.checkScrollThesholds()})}},checkScrollThesholds:function(){if(!this.scrollTarget||this.lowerTriggered&&this.upperTriggered){return}var upperScrollValue=this.horizontal?this._scrollLeft:this._scrollTop;var lowerScrollValue=this.horizontal?this.scrollTarget.scrollWidth-this._scrollTargetWidth-this._scrollLeft:this.scrollTarget.scrollHeight-this._scrollTargetHeight-this._scrollTop;if(upperScrollValue<=this.upperThreshold&&!this.upperTriggered){this._setUpperTriggered(true);this.fire("upper-threshold")}if(lowerScrollValue<=this.lowerThreshold&&!this.lowerTriggered){this._setLowerTriggered(true);this.fire("lower-threshold")}},clearTriggers:function(){this._setUpperTriggered(false);this._setLowerTriggered(false)}}); +Polymer({is:"history-toolbar",properties:{count:{type:Number,value:0,observer:"changeToolbarView_"},itemsSelected_:{type:Boolean,value:false,reflectToAttribute:true},searchTerm:{type:String,observer:"searchTermChanged_",notify:true},spinnerActive:{type:Boolean,value:false},hasDrawer:{type:Boolean,observer:"hasDrawerChanged_",reflectToAttribute:true},showSyncNotice:Boolean,isGroupedMode:{type:Boolean,reflectToAttribute:true},groupedRange:{type:Number,value:0,reflectToAttribute:true,notify:true},queryStartTime:String,queryEndTime:String,showMenuPromo:Boolean},get searchField(){return this.$["main-toolbar"].getSearchField()},showSearchField:function(){this.searchField.showAndFocus()},changeToolbarView_:function(){this.itemsSelected_=this.count>0},searchTermChanged_:function(){if(this.searchField.getValue()!=this.searchTerm){this.searchField.showAndFocus();this.searchField.setValue(this.searchTerm)}},onSearchChanged_:function(event){this.searchTerm=event.detail},onInfoButtonTap_:function(){var dropdown=this.$.syncNotice.get();dropdown.positionTarget=this.$$("#info-button-icon");if(dropdown.style.display=="none")dropdown.open()},onClearSelectionTap_:function(){this.fire("unselect-all")},onDeleteTap_:function(){this.fire("delete-selected")},deletingAllowed_:function(){return loadTimeData.getBoolean("allowDeletingHistory")},numberOfItemsSelected_:function(count){return count>0?loadTimeData.getStringF("itemsSelected",count):""},getHistoryInterval_:function(queryStartTime,queryEndTime){return loadTimeData.getStringF("historyInterval",queryStartTime,queryEndTime)},hasDrawerChanged_:function(){this.updateStyles()}});(function(){"use strict";Polymer.IronA11yAnnouncer=Polymer({is:"iron-a11y-announcer",properties:{mode:{type:String,value:"polite"},_text:{type:String,value:""}},created:function(){if(!Polymer.IronA11yAnnouncer.instance){Polymer.IronA11yAnnouncer.instance=this}document.body.addEventListener("iron-announce",this._onIronAnnounce.bind(this))},announce:function(text){this._text="";this.async(function(){this._text=text},100)},_onIronAnnounce:function(event){if(event.detail&&event.detail.text){this.announce(event.detail.text)}}});Polymer.IronA11yAnnouncer.instance=null;Polymer.IronA11yAnnouncer.requestAvailability=function(){if(!Polymer.IronA11yAnnouncer.instance){Polymer.IronA11yAnnouncer.instance=document.createElement("iron-a11y-announcer")}document.body.appendChild(Polymer.IronA11yAnnouncer.instance)}})();(function(){var IOS=navigator.userAgent.match(/iP(?:hone|ad;(?: U;)? CPU) OS (\d+)/);var IOS_TOUCH_SCROLLING=IOS&&IOS[1]>=8;var DEFAULT_PHYSICAL_COUNT=3;var HIDDEN_Y="-10000px";var ITEM_WIDTH=0;var ITEM_HEIGHT=1;var SECRET_TABINDEX=-100;Polymer({is:"iron-list",properties:{items:{type:Array},maxPhysicalCount:{type:Number,value:500},as:{type:String,value:"item"},indexAs:{type:String,value:"index"},selectedAs:{type:String,value:"selected"},grid:{type:Boolean,value:false,reflectToAttribute:true},selectionEnabled:{type:Boolean,value:false},selectedItem:{type:Object,notify:true},selectedItems:{type:Object,notify:true},multiSelection:{type:Boolean,value:false}},observers:["_itemsChanged(items.*)","_selectionEnabledChanged(selectionEnabled)","_multiSelectionChanged(multiSelection)","_setOverflow(scrollTarget)"],behaviors:[Polymer.Templatizer,Polymer.IronResizableBehavior,Polymer.IronA11yKeysBehavior,Polymer.IronScrollTargetBehavior],keyBindings:{up:"_didMoveUp",down:"_didMoveDown",enter:"_didEnter"},_ratio:.5,_scrollerPaddingTop:0,_scrollPosition:0,_physicalSize:0,_physicalAverage:0,_physicalAverageCount:0,_physicalTop:0,_virtualCount:0,_physicalIndexForKey:null,_estScrollHeight:0,_scrollHeight:0,_viewportHeight:0,_viewportWidth:0,_physicalItems:null,_physicalSizes:null,_firstVisibleIndexVal:null,_lastVisibleIndexVal:null,_collection:null,_maxPages:2,_focusedItem:null,_focusedIndex:-1,_offscreenFocusedItem:null,_focusBackfillItem:null,_itemsPerRow:1,_itemWidth:0,_rowHeight:0,_templateCost:0,get _physicalBottom(){return this._physicalTop+this._physicalSize},get _scrollBottom(){return this._scrollPosition+this._viewportHeight},get _virtualEnd(){return this._virtualStart+this._physicalCount-1},get _hiddenContentSize(){var size=this.grid?this._physicalRows*this._rowHeight:this._physicalSize;return size-this._viewportHeight},get _maxScrollTop(){return this._estScrollHeight-this._viewportHeight+this._scrollerPaddingTop},_minVirtualStart:0,get _maxVirtualStart(){return Math.max(0,this._virtualCount-this._physicalCount)},_virtualStartVal:0,set _virtualStart(val){this._virtualStartVal=Math.min(this._maxVirtualStart,Math.max(this._minVirtualStart,val))},get _virtualStart(){return this._virtualStartVal||0},_physicalStartVal:0,set _physicalStart(val){this._physicalStartVal=val%this._physicalCount;if(this._physicalStartVal<0){this._physicalStartVal=this._physicalCount+this._physicalStartVal}this._physicalEnd=(this._physicalStart+this._physicalCount-1)%this._physicalCount},get _physicalStart(){return this._physicalStartVal||0},_physicalCountVal:0,set _physicalCount(val){this._physicalCountVal=val;this._physicalEnd=(this._physicalStart+this._physicalCount-1)%this._physicalCount},get _physicalCount(){return this._physicalCountVal},_physicalEnd:0,get _optPhysicalSize(){if(this.grid){return this._estRowsInView*this._rowHeight*this._maxPages}return this._viewportHeight*this._maxPages},get _isVisible(){return Boolean(this.offsetWidth||this.offsetHeight)},get firstVisibleIndex(){if(this._firstVisibleIndexVal===null){var physicalOffset=Math.floor(this._physicalTop+this._scrollerPaddingTop);this._firstVisibleIndexVal=this._iterateItems(function(pidx,vidx){physicalOffset+=this._getPhysicalSizeIncrement(pidx);if(physicalOffset>this._scrollPosition){return this.grid?vidx-vidx%this._itemsPerRow:vidx}if(this.grid&&this._virtualCount-1===vidx){return vidx-vidx%this._itemsPerRow}})||0}return this._firstVisibleIndexVal},get lastVisibleIndex(){if(this._lastVisibleIndexVal===null){if(this.grid){var lastIndex=this.firstVisibleIndex+this._estRowsInView*this._itemsPerRow-1;this._lastVisibleIndexVal=Math.min(this._virtualCount,lastIndex)}else{var physicalOffset=this._physicalTop;this._iterateItems(function(pidx,vidx){if(physicalOffset<this._scrollBottom){this._lastVisibleIndexVal=vidx}else{return true}physicalOffset+=this._getPhysicalSizeIncrement(pidx)})}}return this._lastVisibleIndexVal},get _defaultScrollTarget(){return this},get _virtualRowCount(){return Math.ceil(this._virtualCount/this._itemsPerRow)},get _estRowsInView(){return Math.ceil(this._viewportHeight/this._rowHeight)},get _physicalRows(){return Math.ceil(this._physicalCount/this._itemsPerRow)},ready:function(){this.addEventListener("focus",this._didFocus.bind(this),true)},attached:function(){if(this._physicalCount===0){this._debounceTemplate(this._render)}this.listen(this,"iron-resize","_resizeHandler")},detached:function(){this.unlisten(this,"iron-resize","_resizeHandler")},_setOverflow:function(scrollTarget){this.style.webkitOverflowScrolling=scrollTarget===this?"touch":"";this.style.overflow=scrollTarget===this?"auto":""},updateViewportBoundaries:function(){this._scrollerPaddingTop=this.scrollTarget===this?0:parseInt(window.getComputedStyle(this)["padding-top"],10);this._viewportWidth=this.$.items.offsetWidth;this._viewportHeight=this._scrollTargetHeight;this.grid&&this._updateGridMetrics()},_scrollHandler:function(){var scrollTop=Math.max(0,Math.min(this._maxScrollTop,this._scrollTop));var delta=scrollTop-this._scrollPosition;var isScrollingDown=delta>=0;this._scrollPosition=scrollTop;this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null;if(Math.abs(delta)>this._physicalSize){var idxAdjustment=Math.round(delta/this._physicalAverage)*this._itemsPerRow;this._physicalTop=this._physicalTop+delta;this._virtualStart=this._virtualStart+idxAdjustment;this._physicalStart=this._physicalStart+idxAdjustment;this._update()}else{var reusables=this._getReusables(isScrollingDown);if(isScrollingDown){this._physicalTop=reusables.physicalTop;this._virtualStart=this._virtualStart+reusables.indexes.length;this._physicalStart=this._physicalStart+reusables.indexes.length}else{this._virtualStart=this._virtualStart-reusables.indexes.length;this._physicalStart=this._physicalStart-reusables.indexes.length}if(reusables.indexes.length===0){this._increasePoolIfNeeded()}else{this._update(reusables.indexes,isScrollingDown?null:reusables.indexes)}}},_getReusables:function(fromTop){var ith,lastIth,offsetContent,physicalItemHeight;var idxs=[];var protectedOffsetContent=this._hiddenContentSize*this._ratio;var virtualStart=this._virtualStart;var virtualEnd=this._virtualEnd;var physicalCount=this._physicalCount;var physicalTop=this._physicalTop+this._scrollerPaddingTop;var scrollTop=this._scrollTop;var scrollBottom=this._scrollBottom;if(fromTop){ith=this._physicalStart;lastIth=this._physicalEnd;offsetContent=scrollTop-physicalTop}else{ith=this._physicalEnd;lastIth=this._physicalStart;offsetContent=this._physicalBottom-scrollBottom}while(true){physicalItemHeight=this._getPhysicalSizeIncrement(ith);offsetContent=offsetContent-physicalItemHeight;if(idxs.length>=physicalCount||offsetContent<=protectedOffsetContent){break}if(fromTop){if(virtualEnd+idxs.length+1>=this._virtualCount){break}if(physicalTop+physicalItemHeight>=scrollTop){break}idxs.push(ith);physicalTop=physicalTop+physicalItemHeight;ith=(ith+1)%physicalCount}else{if(virtualStart-idxs.length<=0){break}if(physicalTop+this._physicalSize-physicalItemHeight<=scrollBottom){break}idxs.push(ith);physicalTop=physicalTop-physicalItemHeight;ith=ith===0?physicalCount-1:ith-1}}return{indexes:idxs,physicalTop:physicalTop-this._scrollerPaddingTop}},_update:function(itemSet,movingUp){if(itemSet&&itemSet.length===0){return}this._manageFocus();this._assignModels(itemSet);this._updateMetrics(itemSet);if(movingUp){while(movingUp.length){var idx=movingUp.pop();this._physicalTop-=this._getPhysicalSizeIncrement(idx)}}this._positionItems();this._updateScrollerSize();this._increasePoolIfNeeded()},_createPool:function(size){var physicalItems=new Array(size);this._ensureTemplatized();for(var i=0;i<size;i++){var inst=this.stamp(null);physicalItems[i]=inst.root.querySelector("*");Polymer.dom(this).appendChild(inst.root)}return physicalItems},_increasePoolIfNeeded:function(){if(this._viewportHeight===0){return false}var self=this;var isClientFull=this._physicalBottom>=this._scrollBottom&&this._physicalTop<=this._scrollPosition;if(this._physicalSize>=this._optPhysicalSize&&isClientFull){return false}var maxPoolSize=Math.round(this._physicalCount*.5);if(!isClientFull){this._debounceTemplate(this._increasePool.bind(this,maxPoolSize));return true}this._yield(function(){self._increasePool(Math.min(maxPoolSize,Math.max(1,Math.round(50/self._templateCost))))});return true},_yield:function(cb){var g=window;var handle=g.requestIdleCallback?g.requestIdleCallback(cb):g.setTimeout(cb,16);Polymer.dom.addDebouncer({complete:function(){g.cancelIdleCallback?g.cancelIdleCallback(handle):g.clearTimeout(handle);cb()}})},_increasePool:function(missingItems){var nextPhysicalCount=Math.min(this._physicalCount+missingItems,this._virtualCount-this._virtualStart,Math.max(this.maxPhysicalCount,DEFAULT_PHYSICAL_COUNT));var prevPhysicalCount=this._physicalCount;var delta=nextPhysicalCount-prevPhysicalCount;var ts=window.performance.now();if(delta<=0){return}[].push.apply(this._physicalItems,this._createPool(delta));[].push.apply(this._physicalSizes,new Array(delta));this._physicalCount=prevPhysicalCount+delta;if(this._physicalStart>this._physicalEnd&&this._isIndexRendered(this._focusedIndex)&&this._getPhysicalIndex(this._focusedIndex)<this._physicalEnd){this._physicalStart=this._physicalStart+delta}this._update();this._templateCost=(window.performance.now()-ts)/delta},_render:function(){if(this.isAttached&&this._isVisible){if(this._physicalCount===0){this.updateViewportBoundaries();this._increasePool(DEFAULT_PHYSICAL_COUNT)}else{var reusables=this._getReusables(true);this._physicalTop=reusables.physicalTop;this._virtualStart=this._virtualStart+reusables.indexes.length;this._physicalStart=this._physicalStart+reusables.indexes.length;this._update(reusables.indexes);this._update()}}},_ensureTemplatized:function(){if(!this.ctor){var props={};props.__key__=true;props[this.as]=true;props[this.indexAs]=true;props[this.selectedAs]=true;props.tabIndex=true;this._instanceProps=props;this._userTemplate=Polymer.dom(this).querySelector("template");if(this._userTemplate){this.templatize(this._userTemplate)}else{console.warn("iron-list requires a template to be provided in light-dom")}}},_getStampedChildren:function(){return this._physicalItems},_forwardInstancePath:function(inst,path,value){if(path.indexOf(this.as+".")===0){this.notifyPath("items."+inst.__key__+"."+path.slice(this.as.length+1),value)}},_forwardParentProp:function(prop,value){if(this._physicalItems){this._physicalItems.forEach(function(item){item._templateInstance[prop]=value},this)}},_forwardParentPath:function(path,value){if(this._physicalItems){this._physicalItems.forEach(function(item){item._templateInstance.notifyPath(path,value,true)},this)}},_forwardItemPath:function(path,value){if(!this._physicalIndexForKey){return}var dot=path.indexOf(".");var key=path.substring(0,dot<0?path.length:dot);var idx=this._physicalIndexForKey[key];var offscreenItem=this._offscreenFocusedItem;var el=offscreenItem&&offscreenItem._templateInstance.__key__===key?offscreenItem:this._physicalItems[idx];if(!el||el._templateInstance.__key__!==key){return}if(dot>=0){path=this.as+"."+path.substring(dot+1);el._templateInstance.notifyPath(path,value,true)}else{var currentItem=el._templateInstance[this.as];if(Array.isArray(this.selectedItems)){for(var i=0;i<this.selectedItems.length;i++){if(this.selectedItems[i]===currentItem){this.set("selectedItems."+i,value);break}}}else if(this.selectedItem===currentItem){this.set("selectedItem",value)}el._templateInstance[this.as]=value}},_itemsChanged:function(change){if(change.path==="items"){this._virtualStart=0;this._physicalTop=0;this._virtualCount=this.items?this.items.length:0;this._collection=this.items?Polymer.Collection.get(this.items):null;this._physicalIndexForKey={};this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null;this._physicalCount=this._physicalCount||0;this._physicalItems=this._physicalItems||[];this._physicalSizes=this._physicalSizes||[];this._physicalStart=0;this._resetScrollPosition(0);this._removeFocusedItem();this._debounceTemplate(this._render)}else if(change.path==="items.splices"){this._adjustVirtualIndex(change.value.indexSplices);this._virtualCount=this.items?this.items.length:0;this._debounceTemplate(this._render)}else{this._forwardItemPath(change.path.split(".").slice(1).join("."),change.value)}},_adjustVirtualIndex:function(splices){splices.forEach(function(splice){splice.removed.forEach(this._removeItem,this);if(splice.index<this._virtualStart){var delta=Math.max(splice.addedCount-splice.removed.length,splice.index-this._virtualStart);this._virtualStart=this._virtualStart+delta;if(this._focusedIndex>=0){this._focusedIndex=this._focusedIndex+delta}}},this)},_removeItem:function(item){this.$.selector.deselect(item);if(this._focusedItem&&this._focusedItem._templateInstance[this.as]===item){this._removeFocusedItem()}},_iterateItems:function(fn,itemSet){var pidx,vidx,rtn,i;if(arguments.length===2&&itemSet){for(i=0;i<itemSet.length;i++){pidx=itemSet[i];vidx=this._computeVidx(pidx);if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}}else{pidx=this._physicalStart;vidx=this._virtualStart;for(;pidx<this._physicalCount;pidx++,vidx++){if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}for(pidx=0;pidx<this._physicalStart;pidx++,vidx++){if((rtn=fn.call(this,pidx,vidx))!=null){return rtn}}}},_computeVidx:function(pidx){if(pidx>=this._physicalStart){return this._virtualStart+(pidx-this._physicalStart)}return this._virtualStart+(this._physicalCount-this._physicalStart)+pidx},_assignModels:function(itemSet){this._iterateItems(function(pidx,vidx){var el=this._physicalItems[pidx];var inst=el._templateInstance;var item=this.items&&this.items[vidx];if(item!=null){inst[this.as]=item;inst.__key__=this._collection.getKey(item);inst[this.selectedAs]=this.$.selector.isSelected(item);inst[this.indexAs]=vidx;inst.tabIndex=this._focusedIndex===vidx?0:-1;this._physicalIndexForKey[inst.__key__]=pidx;el.removeAttribute("hidden")}else{inst.__key__=null;el.setAttribute("hidden","")}},itemSet)},_updateMetrics:function(itemSet){Polymer.dom.flush();var newPhysicalSize=0;var oldPhysicalSize=0;var prevAvgCount=this._physicalAverageCount;var prevPhysicalAvg=this._physicalAverage;this._iterateItems(function(pidx,vidx){oldPhysicalSize+=this._physicalSizes[pidx]||0;this._physicalSizes[pidx]=this._physicalItems[pidx].offsetHeight;newPhysicalSize+=this._physicalSizes[pidx];this._physicalAverageCount+=this._physicalSizes[pidx]?1:0},itemSet);if(this.grid){this._updateGridMetrics();this._physicalSize=Math.ceil(this._physicalCount/this._itemsPerRow)*this._rowHeight}else{this._physicalSize=this._physicalSize+newPhysicalSize-oldPhysicalSize}if(this._physicalAverageCount!==prevAvgCount){this._physicalAverage=Math.round((prevPhysicalAvg*prevAvgCount+newPhysicalSize)/this._physicalAverageCount)}},_updateGridMetrics:function(){this._itemWidth=this._physicalCount>0?this._physicalItems[0].getBoundingClientRect().width:200;this._rowHeight=this._physicalCount>0?this._physicalItems[0].offsetHeight:200;this._itemsPerRow=this._itemWidth?Math.floor(this._viewportWidth/this._itemWidth):this._itemsPerRow},_positionItems:function(){this._adjustScrollPosition();var y=this._physicalTop;if(this.grid){var totalItemWidth=this._itemsPerRow*this._itemWidth;var rowOffset=(this._viewportWidth-totalItemWidth)/2;this._iterateItems(function(pidx,vidx){var modulus=vidx%this._itemsPerRow;var x=Math.floor(modulus*this._itemWidth+rowOffset);this.translate3d(x+"px",y+"px",0,this._physicalItems[pidx]);if(this._shouldRenderNextRow(vidx)){y+=this._rowHeight}})}else{this._iterateItems(function(pidx,vidx){this.translate3d(0,y+"px",0,this._physicalItems[pidx]);y+=this._physicalSizes[pidx]})}},_getPhysicalSizeIncrement:function(pidx){if(!this.grid){return this._physicalSizes[pidx]}if(this._computeVidx(pidx)%this._itemsPerRow!==this._itemsPerRow-1){return 0}return this._rowHeight},_shouldRenderNextRow:function(vidx){return vidx%this._itemsPerRow===this._itemsPerRow-1},_adjustScrollPosition:function(){var deltaHeight=this._virtualStart===0?this._physicalTop:Math.min(this._scrollPosition+this._physicalTop,0);if(deltaHeight){this._physicalTop=this._physicalTop-deltaHeight;if(!IOS_TOUCH_SCROLLING&&this._physicalTop!==0){this._resetScrollPosition(this._scrollTop-deltaHeight)}}},_resetScrollPosition:function(pos){if(this.scrollTarget){this._scrollTop=pos;this._scrollPosition=this._scrollTop}},_updateScrollerSize:function(forceUpdate){if(this.grid){this._estScrollHeight=this._virtualRowCount*this._rowHeight}else{this._estScrollHeight=this._physicalBottom+Math.max(this._virtualCount-this._physicalCount-this._virtualStart,0)*this._physicalAverage}forceUpdate=forceUpdate||this._scrollHeight===0;forceUpdate=forceUpdate||this._scrollPosition>=this._estScrollHeight-this._physicalSize;forceUpdate=forceUpdate||this.grid&&this.$.items.style.height<this._estScrollHeight;if(forceUpdate||Math.abs(this._estScrollHeight-this._scrollHeight)>=this._optPhysicalSize){this.$.items.style.height=this._estScrollHeight+"px";this._scrollHeight=this._estScrollHeight}},scrollToItem:function(item){return this.scrollToIndex(this.items.indexOf(item))},scrollToIndex:function(idx){if(typeof idx!=="number"||idx<0||idx>this.items.length-1){return}Polymer.dom.flush();if(this._physicalCount===0){return}idx=Math.min(Math.max(idx,0),this._virtualCount-1);if(!this._isIndexRendered(idx)||idx>=this._maxVirtualStart){this._virtualStart=this.grid?idx-this._itemsPerRow*2:idx-1}this._manageFocus();this._assignModels();this._updateMetrics();this._physicalTop=Math.floor(this._virtualStart/this._itemsPerRow)*this._physicalAverage;var currentTopItem=this._physicalStart;var currentVirtualItem=this._virtualStart;var targetOffsetTop=0;var hiddenContentSize=this._hiddenContentSize;while(currentVirtualItem<idx&&targetOffsetTop<=hiddenContentSize){targetOffsetTop=targetOffsetTop+this._getPhysicalSizeIncrement(currentTopItem);currentTopItem=(currentTopItem+1)%this._physicalCount;currentVirtualItem++}this._updateScrollerSize(true);this._positionItems();this._resetScrollPosition(this._physicalTop+this._scrollerPaddingTop+targetOffsetTop);this._increasePoolIfNeeded();this._firstVisibleIndexVal=null;this._lastVisibleIndexVal=null},_resetAverage:function(){this._physicalAverage=0;this._physicalAverageCount=0},_resizeHandler:function(){var delta=Math.abs(this._viewportHeight-this._scrollTargetHeight);if(IOS&&delta>0&&delta<100){return}Polymer.dom.addDebouncer(this.debounce("_debounceTemplate",function(){this.updateViewportBoundaries();this._render();if(this._isVisible){this.toggleScrollListener(true);if(this._physicalCount>0){this._resetAverage();this.scrollToIndex(this.firstVisibleIndex)}}else{this.toggleScrollListener(false)}}.bind(this),1))},_getModelFromItem:function(item){var key=this._collection.getKey(item);var pidx=this._physicalIndexForKey[key];if(pidx!=null){return this._physicalItems[pidx]._templateInstance}return null},_getNormalizedItem:function(item){if(this._collection.getKey(item)===undefined){if(typeof item==="number"){item=this.items[item];if(!item){throw new RangeError("<item> not found")}return item}throw new TypeError("<item> should be a valid item")}return item},selectItem:function(item){item=this._getNormalizedItem(item);var model=this._getModelFromItem(item);if(!this.multiSelection&&this.selectedItem){this.deselectItem(this.selectedItem)}if(model){model[this.selectedAs]=true}this.$.selector.select(item);this.updateSizeForItem(item)},deselectItem:function(item){item=this._getNormalizedItem(item);var model=this._getModelFromItem(item);if(model){model[this.selectedAs]=false}this.$.selector.deselect(item);this.updateSizeForItem(item)},toggleSelectionForItem:function(item){item=this._getNormalizedItem(item);if(this.$.selector.isSelected(item)){this.deselectItem(item)}else{this.selectItem(item)}},clearSelection:function(){function unselect(item){var model=this._getModelFromItem(item);if(model){model[this.selectedAs]=false}}if(Array.isArray(this.selectedItems)){this.selectedItems.forEach(unselect,this)}else if(this.selectedItem){unselect.call(this,this.selectedItem)}this.$.selector.clearSelection()},_selectionEnabledChanged:function(selectionEnabled){var handler=selectionEnabled?this.listen:this.unlisten;handler.call(this,this,"tap","_selectionHandler")},_selectionHandler:function(e){var model=this.modelForElement(e.target);if(!model){return}var modelTabIndex,activeElTabIndex;var target=Polymer.dom(e).path[0];var activeEl=Polymer.dom(this.domHost?this.domHost.root:document).activeElement;var physicalItem=this._physicalItems[this._getPhysicalIndex(model[this.indexAs])];if(target.localName==="input"||target.localName==="button"||target.localName==="select"){return}modelTabIndex=model.tabIndex;model.tabIndex=SECRET_TABINDEX;activeElTabIndex=activeEl?activeEl.tabIndex:-1;model.tabIndex=modelTabIndex;if(activeEl&&physicalItem!==activeEl&&physicalItem.contains(activeEl)&&activeElTabIndex!==SECRET_TABINDEX){return}this.toggleSelectionForItem(model[this.as])},_multiSelectionChanged:function(multiSelection){this.clearSelection();this.$.selector.multi=multiSelection},updateSizeForItem:function(item){item=this._getNormalizedItem(item);var key=this._collection.getKey(item);var pidx=this._physicalIndexForKey[key];if(pidx!=null){this._updateMetrics([pidx]);this._positionItems()}},_manageFocus:function(){var fidx=this._focusedIndex;if(fidx>=0&&fidx<this._virtualCount){if(this._isIndexRendered(fidx)){this._restoreFocusedItem()}else{this._createFocusBackfillItem()}}else if(this._virtualCount>0&&this._physicalCount>0){this._focusedIndex=this._virtualStart;this._focusedItem=this._physicalItems[this._physicalStart]}},_isIndexRendered:function(idx){return idx>=this._virtualStart&&idx<=this._virtualEnd},_isIndexVisible:function(idx){return idx>=this.firstVisibleIndex&&idx<=this.lastVisibleIndex},_getPhysicalIndex:function(idx){return this._physicalIndexForKey[this._collection.getKey(this._getNormalizedItem(idx))]},_focusPhysicalItem:function(idx){if(idx<0||idx>=this._virtualCount){return}this._restoreFocusedItem();if(!this._isIndexRendered(idx)){this.scrollToIndex(idx)}var physicalItem=this._physicalItems[this._getPhysicalIndex(idx)];var model=physicalItem._templateInstance;var focusable;model.tabIndex=SECRET_TABINDEX;if(physicalItem.tabIndex===SECRET_TABINDEX){focusable=physicalItem}if(!focusable){focusable=Polymer.dom(physicalItem).querySelector('[tabindex="'+SECRET_TABINDEX+'"]')}model.tabIndex=0;this._focusedIndex=idx;focusable&&focusable.focus()},_removeFocusedItem:function(){if(this._offscreenFocusedItem){Polymer.dom(this).removeChild(this._offscreenFocusedItem)}this._offscreenFocusedItem=null;this._focusBackfillItem=null;this._focusedItem=null;this._focusedIndex=-1},_createFocusBackfillItem:function(){var fidx=this._focusedIndex;var pidx=this._getPhysicalIndex(fidx);if(this._offscreenFocusedItem||pidx==null||fidx<0){return}if(!this._focusBackfillItem){var stampedTemplate=this.stamp(null);this._focusBackfillItem=stampedTemplate.root.querySelector("*");Polymer.dom(this).appendChild(stampedTemplate.root)}this._offscreenFocusedItem=this._physicalItems[pidx];this._offscreenFocusedItem._templateInstance.tabIndex=0;this._physicalItems[pidx]=this._focusBackfillItem;this.translate3d(0,HIDDEN_Y,0,this._offscreenFocusedItem)},_restoreFocusedItem:function(){var pidx,fidx=this._focusedIndex;if(!this._offscreenFocusedItem||this._focusedIndex<0){return}this._assignModels();pidx=this._getPhysicalIndex(fidx);if(pidx!=null){this._focusBackfillItem=this._physicalItems[pidx];this._focusBackfillItem._templateInstance.tabIndex=-1;this._physicalItems[pidx]=this._offscreenFocusedItem;this._offscreenFocusedItem=null;this.translate3d(0,HIDDEN_Y,0,this._focusBackfillItem)}},_didFocus:function(e){var targetModel=this.modelForElement(e.target);var focusedModel=this._focusedItem?this._focusedItem._templateInstance:null;var hasOffscreenFocusedItem=this._offscreenFocusedItem!==null;var fidx=this._focusedIndex;if(!targetModel||!focusedModel){return}if(focusedModel===targetModel){if(!this._isIndexVisible(fidx)){this.scrollToIndex(fidx)}}else{this._restoreFocusedItem();focusedModel.tabIndex=-1;targetModel.tabIndex=0;fidx=targetModel[this.indexAs];this._focusedIndex=fidx;this._focusedItem=this._physicalItems[this._getPhysicalIndex(fidx)];if(hasOffscreenFocusedItem&&!this._offscreenFocusedItem){this._update()}}},_didMoveUp:function(){this._focusPhysicalItem(this._focusedIndex-1)},_didMoveDown:function(e){e.detail.keyboardEvent.preventDefault();this._focusPhysicalItem(this._focusedIndex+1)},_didEnter:function(e){this._focusPhysicalItem(this._focusedIndex);this._selectionHandler(e.detail.keyboardEvent)}})})();Polymer({is:"iron-scroll-threshold",properties:{upperThreshold:{type:Number,value:100},lowerThreshold:{type:Number,value:100},upperTriggered:{type:Boolean,value:false,notify:true,readOnly:true},lowerTriggered:{type:Boolean,value:false,notify:true,readOnly:true},horizontal:{type:Boolean,value:false}},behaviors:[Polymer.IronScrollTargetBehavior],observers:["_setOverflow(scrollTarget)","_initCheck(horizontal, isAttached)"],get _defaultScrollTarget(){return this},_setOverflow:function(scrollTarget){this.style.overflow=scrollTarget===this?"auto":""},_scrollHandler:function(){var THROTTLE_THRESHOLD=200;if(!this.isDebouncerActive("_checkTheshold")){this.debounce("_checkTheshold",function(){this.checkScrollThesholds()},THROTTLE_THRESHOLD)}},_initCheck:function(horizontal,isAttached){if(isAttached){this.debounce("_init",function(){this.clearTriggers();this.checkScrollThesholds()})}},checkScrollThesholds:function(){if(!this.scrollTarget||this.lowerTriggered&&this.upperTriggered){return}var upperScrollValue=this.horizontal?this._scrollLeft:this._scrollTop;var lowerScrollValue=this.horizontal?this.scrollTarget.scrollWidth-this._scrollTargetWidth-this._scrollLeft:this.scrollTarget.scrollHeight-this._scrollTargetHeight-this._scrollTop;if(upperScrollValue<=this.upperThreshold&&!this.upperTriggered){this._setUpperTriggered(true);this.fire("upper-threshold")}if(lowerScrollValue<=this.lowerThreshold&&!this.lowerTriggered){this._setLowerTriggered(true);this.fire("lower-threshold")}},clearTriggers:function(){this._setUpperTriggered(false);this._setLowerTriggered(false)}}); // Copyright (c) 2011 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. @@ -62,7 +59,7 @@ Polymer({is:"history-searched-label",properties:{title:String,searchTerm:String} // 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. -function HistoryFocusRow(root,boundary,delegate){cr.ui.FocusRow.call(this,root,boundary,delegate);this.addItems()}HistoryFocusRow.prototype={__proto__:cr.ui.FocusRow.prototype,getCustomEquivalent:function(sampleElement){var equivalent;if(this.getTypeForElement(sampleElement)=="star")equivalent=this.getFirstFocusable("title");return equivalent||cr.ui.FocusRow.prototype.getCustomEquivalent.call(this,sampleElement)},addItems:function(){this.destroy();assert(this.addItem("checkbox","#checkbox"));assert(this.addItem("title","#title"));assert(this.addItem("menu-button","#menu-button"));this.addItem("star","#bookmark-star")}};cr.define("md_history",function(){function FocusRowDelegate(historyItemElement){this.historyItemElement=historyItemElement}FocusRowDelegate.prototype={onFocus:function(row,e){this.historyItemElement.lastFocused=e.path[0]},onKeydown:function(row,e){if(e.key=="Enter")e.stopPropagation();return false}};var HistoryItem=Polymer({is:"history-item",properties:{item:{type:Object,observer:"showIcon_"},searchTerm:{type:String},selected:{type:Boolean,reflectToAttribute:true},isCardStart:{type:Boolean,reflectToAttribute:true},isCardEnd:{type:Boolean,reflectToAttribute:true},embedded:{type:Boolean,reflectToAttribute:true},hasTimeGap:{type:Boolean},numberOfItems:{type:Number},path:String,index:Number,lastFocused:{type:Object,notify:true},ironListTabIndex:{type:Number,observer:"ironListTabIndexChanged_"}},row_:null,attached:function(){Polymer.RenderStatus.afterNextRender(this,function(){this.row_=new HistoryFocusRow(this.$["main-container"],null,new FocusRowDelegate(this));this.row_.makeActive(this.ironListTabIndex==0);this.listen(this,"focus","onFocus_");this.listen(this,"dom-change","onDomChange_")})},detached:function(){this.unlisten(this,"focus","onFocus_");this.unlisten(this,"dom-change","onDomChange_");if(this.row_)this.row_.destroy()},onFocus_:function(){if(this.lastFocused)this.row_.getEquivalentElement(this.lastFocused).focus();else this.row_.getFirstFocusable().focus();this.tabIndex=-1},ironListTabIndexChanged_:function(){if(this.row_)this.row_.makeActive(this.ironListTabIndex==0)},onDomChange_:function(){if(this.row_)this.row_.addItems()},onCheckboxSelected_:function(e){this.fire("history-checkbox-select",{element:this,shiftKey:e.shiftKey});e.preventDefault()},onCheckboxMousedown_:function(e){if(e.shiftKey)e.preventDefault()},getEntrySummary_:function(){var item=this.item;return loadTimeData.getStringF("entrySummary",item.dateTimeOfDay,item.starred?loadTimeData.getString("bookmarked"):"",item.title,item.domain)},getAriaChecked_:function(selected){return selected?"true":"false"},onRemoveBookmarkTap_:function(){if(!this.item.starred)return;if(this.$$("#bookmark-star")==this.root.activeElement)this.$["menu-button"].focus();var browserService=md_history.BrowserService.getInstance();browserService.removeBookmark(this.item.url);browserService.recordAction("BookmarkStarClicked");this.fire("remove-bookmark-stars",this.item.url)},onMenuButtonTap_:function(e){this.fire("toggle-menu",{target:Polymer.dom(e).localTarget,index:this.index,item:this.item,path:this.path});e.stopPropagation()},onLinkClick_:function(){var browserService=md_history.BrowserService.getInstance();browserService.recordAction("EntryLinkClick");if(this.searchTerm)browserService.recordAction("SearchResultClick");if(this.index==undefined)return;browserService.recordHistogram("HistoryPage.ClickPosition",this.index,UMA_MAX_BUCKET_VALUE);if(this.index<=UMA_MAX_SUBSET_BUCKET_VALUE){browserService.recordHistogram("HistoryPage.ClickPositionSubset",this.index,UMA_MAX_SUBSET_BUCKET_VALUE)}},onLinkRightClick_:function(){md_history.BrowserService.getInstance().recordAction("EntryLinkRightClick")},showIcon_:function(){this.$.icon.style.backgroundImage=cr.icon.getFavicon(this.item.url)},selectionNotAllowed_:function(){return!loadTimeData.getBoolean("allowDeletingHistory")},cardTitle_:function(numberOfItems,historyDate,search){if(!search)return this.item.dateRelativeDay;return HistoryItem.searchResultsTitle(numberOfItems,search)}});HistoryItem.needsTimeGap=function(visits,currentIndex,searchedTerm){if(currentIndex>=visits.length-1||visits.length==0)return false;var currentItem=visits[currentIndex];var nextItem=visits[currentIndex+1];if(searchedTerm)return currentItem.dateShort!=nextItem.dateShort;return currentItem.time-nextItem.time>BROWSING_GAP_TIME&¤tItem.dateRelativeDay==nextItem.dateRelativeDay};HistoryItem.searchResultsTitle=function(numberOfResults,searchTerm){var resultId=numberOfResults==1?"searchResult":"searchResults";return loadTimeData.getStringF("foundSearchResults",numberOfResults,loadTimeData.getString(resultId),searchTerm)};return{HistoryItem:HistoryItem}}); +function HistoryFocusRow(root,boundary,delegate){cr.ui.FocusRow.call(this,root,boundary,delegate);this.addItems()}HistoryFocusRow.prototype={__proto__:cr.ui.FocusRow.prototype,getCustomEquivalent:function(sampleElement){var equivalent;if(this.getTypeForElement(sampleElement)=="star")equivalent=this.getFirstFocusable("title");return equivalent||cr.ui.FocusRow.prototype.getCustomEquivalent.call(this,sampleElement)},addItems:function(){this.destroy();assert(this.addItem("checkbox","#checkbox"));assert(this.addItem("title","#title"));assert(this.addItem("menu-button","#menu-button"));this.addItem("star","#bookmark-star")}};cr.define("md_history",function(){function FocusRowDelegate(historyItemElement){this.historyItemElement=historyItemElement}FocusRowDelegate.prototype={onFocus:function(row,e){this.historyItemElement.lastFocused=e.path[0]},onKeydown:function(row,e){if(e.key=="Enter")e.stopPropagation();return false}};var HistoryItem=Polymer({is:"history-item",properties:{item:{type:Object,observer:"showIcon_"},searchTerm:{type:String},selected:{type:Boolean,reflectToAttribute:true},isCardStart:{type:Boolean,reflectToAttribute:true},isCardEnd:{type:Boolean,reflectToAttribute:true},embedded:{type:Boolean,reflectToAttribute:true},hasTimeGap:{type:Boolean},numberOfItems:{type:Number},path:String,index:Number,lastFocused:{type:Object,notify:true},ironListTabIndex:{type:Number,observer:"ironListTabIndexChanged_"}},row_:null,attached:function(){Polymer.RenderStatus.afterNextRender(this,function(){this.row_=new HistoryFocusRow(this.$["main-container"],null,new FocusRowDelegate(this));this.row_.makeActive(this.ironListTabIndex==0);this.listen(this,"focus","onFocus_");this.listen(this,"dom-change","onDomChange_")})},detached:function(){this.unlisten(this,"focus","onFocus_");this.unlisten(this,"dom-change","onDomChange_");if(this.row_)this.row_.destroy()},onFocus_:function(){if(this.lastFocused)this.row_.getEquivalentElement(this.lastFocused).focus();else this.row_.getFirstFocusable().focus();this.tabIndex=-1},ironListTabIndexChanged_:function(){if(this.row_)this.row_.makeActive(this.ironListTabIndex==0)},onDomChange_:function(){if(this.row_)this.row_.addItems()},onItemClick_:function(e){for(var i=0;i<e.path.length;i++){var elem=e.path[i];if(elem.id!="checkbox"&&(elem.nodeName=="A"||elem.nodeName=="BUTTON")){return}}if(this.selectionNotAllowed_())return;this.$.checkbox.focus();this.fire("history-checkbox-select",{element:this,shiftKey:e.shiftKey})},onItemMousedown_:function(e){if(e.shiftKey)e.preventDefault()},getEntrySummary_:function(){var item=this.item;return loadTimeData.getStringF("entrySummary",item.dateTimeOfDay,item.starred?loadTimeData.getString("bookmarked"):"",item.title,item.domain)},getAriaChecked_:function(selected){return selected?"true":"false"},onRemoveBookmarkTap_:function(){if(!this.item.starred)return;if(this.$$("#bookmark-star")==this.root.activeElement)this.$["menu-button"].focus();var browserService=md_history.BrowserService.getInstance();browserService.removeBookmark(this.item.url);browserService.recordAction("BookmarkStarClicked");this.fire("remove-bookmark-stars",this.item.url)},onMenuButtonTap_:function(e){this.fire("toggle-menu",{target:Polymer.dom(e).localTarget,index:this.index,item:this.item,path:this.path});e.stopPropagation()},onLinkClick_:function(){var browserService=md_history.BrowserService.getInstance();browserService.recordAction("EntryLinkClick");if(this.searchTerm)browserService.recordAction("SearchResultClick");if(this.index==undefined)return;browserService.recordHistogram("HistoryPage.ClickPosition",Math.min(this.index,UMA_MAX_BUCKET_VALUE),UMA_MAX_BUCKET_VALUE);if(this.index<=UMA_MAX_SUBSET_BUCKET_VALUE){browserService.recordHistogram("HistoryPage.ClickPositionSubset",this.index,UMA_MAX_SUBSET_BUCKET_VALUE)}},onLinkRightClick_:function(){md_history.BrowserService.getInstance().recordAction("EntryLinkRightClick")},showIcon_:function(){this.$.icon.style.backgroundImage=cr.icon.getFavicon(this.item.url)},selectionNotAllowed_:function(){return!loadTimeData.getBoolean("allowDeletingHistory")},cardTitle_:function(numberOfItems,historyDate,search){if(!search)return this.item.dateRelativeDay;return HistoryItem.searchResultsTitle(numberOfItems,search)},addTimeTitle_:function(){var el=this.$["time-accessed"];el.setAttribute("title",new Date(this.item.time).toString());this.unlisten(el,"mouseover","addTimeTitle_")}});HistoryItem.needsTimeGap=function(visits,currentIndex,searchedTerm){if(currentIndex>=visits.length-1||visits.length==0)return false;var currentItem=visits[currentIndex];var nextItem=visits[currentIndex+1];if(searchedTerm)return currentItem.dateShort!=nextItem.dateShort;return currentItem.time-nextItem.time>BROWSING_GAP_TIME&¤tItem.dateRelativeDay==nextItem.dateRelativeDay};HistoryItem.searchResultsTitle=function(numberOfResults,searchTerm){var resultId=numberOfResults==1?"searchResult":"searchResults";return loadTimeData.getStringF("foundSearchResults",numberOfResults,loadTimeData.getString(resultId),searchTerm)};return{HistoryItem:HistoryItem}}); // Copyright 2016 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. @@ -74,7 +71,7 @@ Polymer({is:"history-list",behaviors:[HistoryListBehavior],properties:{searchedT // Copyright 2016 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. -Polymer({is:"history-list-container",properties:{selectedPage_:String,grouped:Boolean,groupedRange:{type:Number,observer:"groupedRangeChanged_"},queryState:Object,queryResult:Object},observers:["searchTermChanged_(queryState.searchTerm)"],listeners:{"history-list-scrolled":"closeMenu_","load-more-history":"loadMoreHistory_","toggle-menu":"toggleMenu_"},historyResult:function(info,results){this.initializeResults_(info,results);this.closeMenu_();if(info.term&&!this.queryState.incremental){Polymer.IronA11yAnnouncer.requestAvailability();this.fire("iron-announce",{text:md_history.HistoryItem.searchResultsTitle(results.length,info.term)})}if(this.selectedPage_=="grouped-list"){this.$$("#grouped-list").historyData=results;return}var list=this.$["infinite-list"];list.addNewResults(results,this.queryState.incremental);if(info.finished)list.disableResultLoading()},queryHistory:function(incremental){var queryState=this.queryState;var noResults=!this.queryResult||this.queryResult.results==null;if(queryState.queryingDisabled||!this.queryState.searchTerm&&noResults){return}var dialog=this.$.dialog.getIfExists();if(!incremental&&dialog&&dialog.open)dialog.close();this.set("queryState.querying",true);this.set("queryState.incremental",incremental);var lastVisitTime=0;if(incremental){var lastVisit=this.queryResult.results.slice(-1)[0];lastVisitTime=lastVisit?Math.floor(lastVisit.time):0}var maxResults=this.groupedRange==HistoryRange.ALL_TIME?RESULTS_PER_PAGE:0;chrome.send("queryHistory",[queryState.searchTerm,queryState.groupedOffset,queryState.range,lastVisitTime,maxResults])},historyDeleted:function(){if(this.getSelectedItemCount()>0)return;this.queryHistory(false)},getContentScrollTarget:function(){return this.getSelectedList_()},getSelectedItemCount:function(){return this.getSelectedList_().selectedPaths.size},unselectAllItems:function(count){var selectedList=this.getSelectedList_();if(selectedList)selectedList.unselectAllItems(count)},deleteSelectedWithPrompt:function(){if(!loadTimeData.getBoolean("allowDeletingHistory"))return;var browserService=md_history.BrowserService.getInstance();browserService.recordAction("RemoveSelected");if(this.queryState.searchTerm!="")browserService.recordAction("SearchResultRemove");this.$.dialog.get().showModal();this.$$(".action-button").focus()},groupedRangeChanged_:function(range,oldRange){this.selectedPage_=range==HistoryRange.ALL_TIME?"infinite-list":"grouped-list";if(oldRange==undefined)return;this.queryHistory(false);this.fire("history-view-changed")},searchTermChanged_:function(){this.queryHistory(false);if(this.queryState.searchTerm)md_history.BrowserService.getInstance().recordAction("Search")},loadMoreHistory_:function(){this.queryHistory(true)},initializeResults_:function(info,results){if(results.length==0)return;var currentDate=results[0].dateRelativeDay;for(var i=0;i<results.length;i++){results[i].selected=false;results[i].readableTimestamp=info.term==""?results[i].dateTimeOfDay:results[i].dateShort;if(results[i].dateRelativeDay!=currentDate){currentDate=results[i].dateRelativeDay}}},onDialogConfirmTap_:function(){md_history.BrowserService.getInstance().recordAction("ConfirmRemoveSelected");this.getSelectedList_().deleteSelected();var dialog=assert(this.$.dialog.getIfExists());dialog.close()},onDialogCancelTap_:function(){md_history.BrowserService.getInstance().recordAction("CancelRemoveSelected");var dialog=assert(this.$.dialog.getIfExists());dialog.close()},closeMenu_:function(){var menu=this.$.sharedMenu.getIfExists();if(menu)menu.closeMenu()},toggleMenu_:function(e){var target=e.detail.target;var menu=this.$.sharedMenu.get();menu.toggleMenu(target,e.detail)},onMoreFromSiteTap_:function(){md_history.BrowserService.getInstance().recordAction("EntryMenuShowMoreFromSite");var menu=assert(this.$.sharedMenu.getIfExists());this.set("queryState.searchTerm",menu.itemData.item.domain);menu.closeMenu()},onRemoveFromHistoryTap_:function(){var browserService=md_history.BrowserService.getInstance();browserService.recordAction("EntryMenuRemoveFromHistory");var menu=assert(this.$.sharedMenu.getIfExists());var itemData=menu.itemData;browserService.deleteItems([itemData.item]).then(function(items){this.fire("unselect-all");this.getSelectedList_().removeItemsByPath([itemData.path]);var index=itemData.index;if(index==undefined)return;var browserService=md_history.BrowserService.getInstance();browserService.recordHistogram("HistoryPage.RemoveEntryPosition",index,UMA_MAX_BUCKET_VALUE);if(index<=UMA_MAX_SUBSET_BUCKET_VALUE){browserService.recordHistogram("HistoryPage.RemoveEntryPositionSubset",index,UMA_MAX_SUBSET_BUCKET_VALUE)}}.bind(this));menu.closeMenu()},getSelectedList_:function(){return this.$.content.selectedItem}});(function(){"use strict";Polymer({is:"iron-location",properties:{path:{type:String,notify:true,value:function(){return window.decodeURIComponent(window.location.pathname)}},query:{type:String,notify:true,value:function(){return window.decodeURIComponent(window.location.search.slice(1))}},hash:{type:String,notify:true,value:function(){return window.decodeURIComponent(window.location.hash.slice(1))}},dwellTime:{type:Number,value:2e3},urlSpaceRegex:{type:String,value:""},_urlSpaceRegExp:{computed:"_makeRegExp(urlSpaceRegex)"},_lastChangedAt:{type:Number},_initialized:{type:Boolean,value:false}},hostAttributes:{hidden:true},observers:["_updateUrl(path, query, hash)"],attached:function(){this.listen(window,"hashchange","_hashChanged");this.listen(window,"location-changed","_urlChanged");this.listen(window,"popstate","_urlChanged");this.listen(document.body,"click","_globalOnClick");this._lastChangedAt=window.performance.now()-(this.dwellTime-200);this._initialized=true;this._urlChanged()},detached:function(){this.unlisten(window,"hashchange","_hashChanged");this.unlisten(window,"location-changed","_urlChanged");this.unlisten(window,"popstate","_urlChanged");this.unlisten(document.body,"click","_globalOnClick");this._initialized=false},_hashChanged:function(){this.hash=window.decodeURIComponent(window.location.hash.substring(1))},_urlChanged:function(){this._dontUpdateUrl=true;this._hashChanged();this.path=window.decodeURIComponent(window.location.pathname);this.query=window.decodeURIComponent(window.location.search.substring(1));this._dontUpdateUrl=false;this._updateUrl()},_getUrl:function(){var partiallyEncodedPath=window.encodeURI(this.path).replace(/\#/g,"%23").replace(/\?/g,"%3F");var partiallyEncodedQuery="";if(this.query){partiallyEncodedQuery="?"+window.encodeURI(this.query).replace(/\#/g,"%23")}var partiallyEncodedHash="";if(this.hash){partiallyEncodedHash="#"+window.encodeURI(this.hash)}return partiallyEncodedPath+partiallyEncodedQuery+partiallyEncodedHash},_updateUrl:function(){if(this._dontUpdateUrl||!this._initialized){return}if(this.path===window.decodeURIComponent(window.location.pathname)&&this.query===window.decodeURIComponent(window.location.search.substring(1))&&this.hash===window.decodeURIComponent(window.location.hash.substring(1))){return}var newUrl=this._getUrl();var fullNewUrl=new URL(newUrl,window.location.protocol+"//"+window.location.host).href;var now=window.performance.now();var shouldReplace=this._lastChangedAt+this.dwellTime>now;this._lastChangedAt=now;if(shouldReplace){window.history.replaceState({},"",fullNewUrl)}else{window.history.pushState({},"",fullNewUrl)}this.fire("location-changed",{},{node:window})},_globalOnClick:function(event){if(event.defaultPrevented){return}var href=this._getSameOriginLinkHref(event);if(!href){return}event.preventDefault();if(href===window.location.href){return}window.history.pushState({},"",href);this.fire("location-changed",{},{node:window})},_getSameOriginLinkHref:function(event){if(event.button!==0){return null}if(event.metaKey||event.ctrlKey){return null}var eventPath=Polymer.dom(event).path;var anchor=null;for(var i=0;i<eventPath.length;i++){var element=eventPath[i];if(element.tagName==="A"&&element.href){anchor=element;break}}if(!anchor){return null}if(anchor.target==="_blank"){return null}if((anchor.target==="_top"||anchor.target==="_parent")&&window.top!==window){return null}var href=anchor.href;var url;if(document.baseURI!=null){url=new URL(href,document.baseURI)}else{url=new URL(href)}var origin;if(window.location.origin){origin=window.location.origin}else{origin=window.location.protocol+"//"+window.location.hostname;if(window.location.port){origin+=":"+window.location.port}}if(url.origin!==origin){return null}var normalizedHref=url.pathname+url.search+url.hash;if(this._urlSpaceRegExp&&!this._urlSpaceRegExp.test(normalizedHref)){return null}var fullNormalizedHref=new URL(normalizedHref,window.location.href).href;return fullNormalizedHref},_makeRegExp:function(urlSpaceRegex){return RegExp(urlSpaceRegex)}})})();"use strict";Polymer({is:"iron-query-params",properties:{paramsString:{type:String,notify:true,observer:"paramsStringChanged"},paramsObject:{type:Object,notify:true,value:function(){return{}}},_dontReact:{type:Boolean,value:false}},hostAttributes:{hidden:true},observers:["paramsObjectChanged(paramsObject.*)"],paramsStringChanged:function(){this._dontReact=true;this.paramsObject=this._decodeParams(this.paramsString);this._dontReact=false},paramsObjectChanged:function(){if(this._dontReact){return}this.paramsString=this._encodeParams(this.paramsObject)},_encodeParams:function(params){var encodedParams=[];for(var key in params){var value=params[key];if(value===""){encodedParams.push(encodeURIComponent(key))}else if(value){encodedParams.push(encodeURIComponent(key)+"="+encodeURIComponent(value.toString()))}}return encodedParams.join("&")},_decodeParams:function(paramString){var params={};paramString=(paramString||"").replace(/\+/g,"%20");var paramList=paramString.split("&");for(var i=0;i<paramList.length;i++){var param=paramList[i].split("=");if(param[0]){params[decodeURIComponent(param[0])]=decodeURIComponent(param[1]||"")}}return params}}); +Polymer({is:"history-list-container",properties:{selectedPage_:String,grouped:Boolean,groupedRange:{type:Number,observer:"groupedRangeChanged_"},queryState:Object,queryResult:Object},observers:["searchTermChanged_(queryState.searchTerm)"],listeners:{"history-list-scrolled":"closeMenu_","load-more-history":"loadMoreHistory_","toggle-menu":"toggleMenu_"},historyResult:function(info,results){this.initializeResults_(info,results);this.closeMenu_();if(info.term&&!this.queryState.incremental){Polymer.IronA11yAnnouncer.requestAvailability();this.fire("iron-announce",{text:md_history.HistoryItem.searchResultsTitle(results.length,info.term)})}if(this.selectedPage_=="grouped-list"){this.$$("#grouped-list").historyData=results;return}var list=this.$["infinite-list"];list.addNewResults(results,this.queryState.incremental);if(info.finished)list.disableResultLoading()},queryHistory:function(incremental){var queryState=this.queryState;var noResults=!this.queryResult||this.queryResult.results==null;if(queryState.queryingDisabled||!this.queryState.searchTerm&&noResults){return}var dialog=this.$.dialog.getIfExists();if(!incremental&&dialog&&dialog.open)dialog.close();this.set("queryState.querying",true);this.set("queryState.incremental",incremental);var lastVisitTime=0;if(incremental){var lastVisit=this.queryResult.results.slice(-1)[0];lastVisitTime=lastVisit?Math.floor(lastVisit.time):0}var maxResults=this.groupedRange==HistoryRange.ALL_TIME?RESULTS_PER_PAGE:0;chrome.send("queryHistory",[queryState.searchTerm,queryState.groupedOffset,queryState.range,lastVisitTime,maxResults])},historyDeleted:function(){if(this.getSelectedItemCount()>0)return;this.queryHistory(false)},getContentScrollTarget:function(){return this.getSelectedList_()},getSelectedItemCount:function(){return this.getSelectedList_().selectedPaths.size},unselectAllItems:function(count){var selectedList=this.getSelectedList_();if(selectedList)selectedList.unselectAllItems(count)},deleteSelectedWithPrompt:function(){if(!loadTimeData.getBoolean("allowDeletingHistory"))return;var browserService=md_history.BrowserService.getInstance();browserService.recordAction("RemoveSelected");if(this.queryState.searchTerm!="")browserService.recordAction("SearchResultRemove");this.$.dialog.get().showModal();this.$$(".action-button").focus()},groupedRangeChanged_:function(range,oldRange){this.selectedPage_=range==HistoryRange.ALL_TIME?"infinite-list":"grouped-list";if(oldRange==undefined)return;this.queryHistory(false);this.fire("history-view-changed")},searchTermChanged_:function(){this.queryHistory(false);if(this.queryState.searchTerm)md_history.BrowserService.getInstance().recordAction("Search")},loadMoreHistory_:function(){this.queryHistory(true)},initializeResults_:function(info,results){if(results.length==0)return;var currentDate=results[0].dateRelativeDay;for(var i=0;i<results.length;i++){results[i].selected=false;results[i].readableTimestamp=info.term==""?results[i].dateTimeOfDay:results[i].dateShort;if(results[i].dateRelativeDay!=currentDate){currentDate=results[i].dateRelativeDay}}},onDialogConfirmTap_:function(){md_history.BrowserService.getInstance().recordAction("ConfirmRemoveSelected");this.getSelectedList_().deleteSelected();var dialog=assert(this.$.dialog.getIfExists());dialog.close()},onDialogCancelTap_:function(){md_history.BrowserService.getInstance().recordAction("CancelRemoveSelected");var dialog=assert(this.$.dialog.getIfExists());dialog.close()},closeMenu_:function(){var menu=this.$.sharedMenu.getIfExists();if(menu)menu.closeMenu()},toggleMenu_:function(e){var target=e.detail.target;var menu=this.$.sharedMenu.get();menu.toggleMenu(target,e.detail)},onMoreFromSiteTap_:function(){md_history.BrowserService.getInstance().recordAction("EntryMenuShowMoreFromSite");var menu=assert(this.$.sharedMenu.getIfExists());this.set("queryState.searchTerm",menu.itemData.item.domain);menu.closeMenu()},onRemoveFromHistoryTap_:function(){var browserService=md_history.BrowserService.getInstance();browserService.recordAction("EntryMenuRemoveFromHistory");var menu=assert(this.$.sharedMenu.getIfExists());var itemData=menu.itemData;browserService.deleteItems([itemData.item]).then(function(items){this.fire("unselect-all");this.getSelectedList_().removeItemsByPath([itemData.path]);var index=itemData.index;if(index==undefined)return;var browserService=md_history.BrowserService.getInstance();browserService.recordHistogram("HistoryPage.RemoveEntryPosition",Math.min(index,UMA_MAX_BUCKET_VALUE),UMA_MAX_BUCKET_VALUE);if(index<=UMA_MAX_SUBSET_BUCKET_VALUE){browserService.recordHistogram("HistoryPage.RemoveEntryPositionSubset",index,UMA_MAX_SUBSET_BUCKET_VALUE)}}.bind(this));menu.closeMenu()},getSelectedList_:function(){return this.$.content.selectedItem},canDeleteHistory_:function(){return loadTimeData.getBoolean("allowDeletingHistory")}});(function(){"use strict";Polymer({is:"iron-location",properties:{path:{type:String,notify:true,value:function(){return window.decodeURIComponent(window.location.pathname)}},query:{type:String,notify:true,value:function(){return window.decodeURIComponent(window.location.search.slice(1))}},hash:{type:String,notify:true,value:function(){return window.decodeURIComponent(window.location.hash.slice(1))}},dwellTime:{type:Number,value:2e3},urlSpaceRegex:{type:String,value:""},_urlSpaceRegExp:{computed:"_makeRegExp(urlSpaceRegex)"},_lastChangedAt:{type:Number},_initialized:{type:Boolean,value:false}},hostAttributes:{hidden:true},observers:["_updateUrl(path, query, hash)"],attached:function(){this.listen(window,"hashchange","_hashChanged");this.listen(window,"location-changed","_urlChanged");this.listen(window,"popstate","_urlChanged");this.listen(document.body,"click","_globalOnClick");this._lastChangedAt=window.performance.now()-(this.dwellTime-200);this._initialized=true;this._urlChanged()},detached:function(){this.unlisten(window,"hashchange","_hashChanged");this.unlisten(window,"location-changed","_urlChanged");this.unlisten(window,"popstate","_urlChanged");this.unlisten(document.body,"click","_globalOnClick");this._initialized=false},_hashChanged:function(){this.hash=window.decodeURIComponent(window.location.hash.substring(1))},_urlChanged:function(){this._dontUpdateUrl=true;this._hashChanged();this.path=window.decodeURIComponent(window.location.pathname);this.query=window.decodeURIComponent(window.location.search.substring(1));this._dontUpdateUrl=false;this._updateUrl()},_getUrl:function(){var partiallyEncodedPath=window.encodeURI(this.path).replace(/\#/g,"%23").replace(/\?/g,"%3F");var partiallyEncodedQuery="";if(this.query){partiallyEncodedQuery="?"+window.encodeURI(this.query).replace(/\#/g,"%23")}var partiallyEncodedHash="";if(this.hash){partiallyEncodedHash="#"+window.encodeURI(this.hash)}return partiallyEncodedPath+partiallyEncodedQuery+partiallyEncodedHash},_updateUrl:function(){if(this._dontUpdateUrl||!this._initialized){return}if(this.path===window.decodeURIComponent(window.location.pathname)&&this.query===window.decodeURIComponent(window.location.search.substring(1))&&this.hash===window.decodeURIComponent(window.location.hash.substring(1))){return}var newUrl=this._getUrl();var fullNewUrl=new URL(newUrl,window.location.protocol+"//"+window.location.host).href;var now=window.performance.now();var shouldReplace=this._lastChangedAt+this.dwellTime>now;this._lastChangedAt=now;if(shouldReplace){window.history.replaceState({},"",fullNewUrl)}else{window.history.pushState({},"",fullNewUrl)}this.fire("location-changed",{},{node:window})},_globalOnClick:function(event){if(event.defaultPrevented){return}var href=this._getSameOriginLinkHref(event);if(!href){return}event.preventDefault();if(href===window.location.href){return}window.history.pushState({},"",href);this.fire("location-changed",{},{node:window})},_getSameOriginLinkHref:function(event){if(event.button!==0){return null}if(event.metaKey||event.ctrlKey){return null}var eventPath=Polymer.dom(event).path;var anchor=null;for(var i=0;i<eventPath.length;i++){var element=eventPath[i];if(element.tagName==="A"&&element.href){anchor=element;break}}if(!anchor){return null}if(anchor.target==="_blank"){return null}if((anchor.target==="_top"||anchor.target==="_parent")&&window.top!==window){return null}var href=anchor.href;var url;if(document.baseURI!=null){url=new URL(href,document.baseURI)}else{url=new URL(href)}var origin;if(window.location.origin){origin=window.location.origin}else{origin=window.location.protocol+"//"+window.location.hostname;if(window.location.port){origin+=":"+window.location.port}}if(url.origin!==origin){return null}var normalizedHref=url.pathname+url.search+url.hash;if(this._urlSpaceRegExp&&!this._urlSpaceRegExp.test(normalizedHref)){return null}var fullNormalizedHref=new URL(normalizedHref,window.location.href).href;return fullNormalizedHref},_makeRegExp:function(urlSpaceRegex){return RegExp(urlSpaceRegex)}})})();"use strict";Polymer({is:"iron-query-params",properties:{paramsString:{type:String,notify:true,observer:"paramsStringChanged"},paramsObject:{type:Object,notify:true,value:function(){return{}}},_dontReact:{type:Boolean,value:false}},hostAttributes:{hidden:true},observers:["paramsObjectChanged(paramsObject.*)"],paramsStringChanged:function(){this._dontReact=true;this.paramsObject=this._decodeParams(this.paramsString);this._dontReact=false},paramsObjectChanged:function(){if(this._dontReact){return}this.paramsString=this._encodeParams(this.paramsObject)},_encodeParams:function(params){var encodedParams=[];for(var key in params){var value=params[key];if(value===""){encodedParams.push(encodeURIComponent(key))}else if(value){encodedParams.push(encodeURIComponent(key)+"="+encodeURIComponent(value.toString()))}}return encodedParams.join("&")},_decodeParams:function(paramString){var params={};paramString=(paramString||"").replace(/\+/g,"%20");var paramList=paramString.split("&");for(var i=0;i<paramList.length;i++){var param=paramList[i].split("=");if(param[0]){params[decodeURIComponent(param[0])]=decodeURIComponent(param[1]||"")}}return params}}); // Copyright 2016 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. @@ -86,4 +83,4 @@ Polymer({is:"history-side-bar",behaviors:[Polymer.IronA11yKeysBehavior],properti // Copyright 2016 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("md_history",function(){var lazyLoadPromise=null;function ensureLazyLoaded(){if(!lazyLoadPromise){lazyLoadPromise=new Promise(function(resolve,reject){Polymer.Base.importHref("chrome://history/lazy_load.html",resolve,reject,true)})}return lazyLoadPromise}return{ensureLazyLoaded:ensureLazyLoaded}});Polymer({is:"history-app",behaviors:[Polymer.IronScrollTargetBehavior,WebUIListenerBehavior],properties:{showSidebarFooter:Boolean,hasSyncedResults:Boolean,selectedPage_:{type:String,observer:"selectedPageChanged_"},grouped_:{type:Boolean,reflectToAttribute:true},queryState_:{type:Object,value:function(){return{incremental:false,querying:true,queryingDisabled:false,_range:HistoryRange.ALL_TIME,searchTerm:"",groupedOffset:0,set range(val){this._range=Number(val)},get range(){return this._range}}}},queryResult_:{type:Object,value:function(){return{info:null,results:null,sessionList:null}}},hasDrawer_:Boolean,isUserSignedIn_:{type:Boolean,value:loadTimeData.getBoolean("isUserSignedIn")},toolbarShadow_:{type:Boolean,reflectToAttribute:true,notify:true}},listeners:{"cr-menu-tap":"onMenuTap_","history-checkbox-select":"checkboxSelected","unselect-all":"unselectAll","delete-selected":"deleteSelected","history-close-drawer":"closeDrawer_","history-view-changed":"historyViewChanged_"},ready:function(){this.grouped_=loadTimeData.getBoolean("groupByDomain");cr.ui.decorate("command",cr.ui.Command);document.addEventListener("canExecute",this.onCanExecute_.bind(this));document.addEventListener("command",this.onCommand_.bind(this))},attached:function(){this.addWebUIListener("sign-in-state-updated",this.updateSignInState.bind(this))},onFirstRender:function(){setTimeout(function(){chrome.send("metricsHandler:recordTime",["History.ResultsRenderedTime",window.performance.now()])});var searchField=this.$.toolbar.searchField;if(!searchField.narrow){searchField.getSearchInput().focus()}md_history.ensureLazyLoaded()},_scrollHandler:function(){if(this.scrollTarget)this.toolbarShadow_=this.scrollTarget.scrollTop!=0},onMenuTap_:function(){var drawer=this.$$("#drawer");if(drawer)drawer.toggle()},checkboxSelected:function(e){var toolbar=this.$.toolbar;toolbar.count=this.$.history.getSelectedItemCount()},unselectAll:function(){var listContainer=this.$.history;var toolbar=this.$.toolbar;listContainer.unselectAllItems(toolbar.count);toolbar.count=0},deleteSelected:function(){this.$.history.deleteSelectedWithPrompt()},historyResult:function(info,results){this.set("queryState_.querying",false);this.set("queryResult_.info",info);this.set("queryResult_.results",results);var listContainer=this.$["history"];listContainer.historyResult(info,results)},focusToolbarSearchField:function(){this.$.toolbar.showSearchField()},onCanExecute_:function(e){e=e;switch(e.command.id){case"find-command":e.canExecute=true;break;case"slash-command":e.canExecute=!this.$.toolbar.searchField.isSearchFocused();break;case"delete-command":e.canExecute=this.$.toolbar.count>0;break}},onCommand_:function(e){if(e.command.id=="find-command"||e.command.id=="slash-command")this.focusToolbarSearchField();if(e.command.id=="delete-command")this.deleteSelected()},setForeignSessions:function(sessionList,isTabSyncEnabled){if(!isTabSyncEnabled){var syncedDeviceManagerElem=this.$$("history-synced-device-manager");if(syncedDeviceManagerElem)syncedDeviceManagerElem.tabSyncDisabled();return}this.set("queryResult_.sessionList",sessionList)},historyDeleted:function(){this.$.history.historyDeleted()},updateSignInState:function(isUserSignedIn){this.isUserSignedIn_=isUserSignedIn},syncedTabsSelected_:function(selectedPage){return selectedPage=="syncedTabs"},shouldShowSpinner_:function(querying,incremental,searchTerm){return querying&&!incremental&&searchTerm!=""},showSyncNotice_:function(hasSyncedResults,selectedPage){return hasSyncedResults&&selectedPage!="syncedTabs"},selectedPageChanged_:function(){this.unselectAll();this.historyViewChanged_()},historyViewChanged_:function(){requestAnimationFrame(function(){if(!this.$.content.selectedItem)return;this.scrollTarget=this.$.content.selectedItem.getContentScrollTarget();this._scrollHandler()}.bind(this));this.recordHistoryPageView_()},getSelectedPage_:function(selectedPage,items){return selectedPage},closeDrawer_:function(){var drawer=this.$$("#drawer");if(drawer)drawer.close()},recordHistoryPageView_:function(){var histogramValue=HistoryPageViewHistogram.END;switch(this.selectedPage_){case"syncedTabs":histogramValue=this.isUserSignedIn_?HistoryPageViewHistogram.SYNCED_TABS:HistoryPageViewHistogram.SIGNIN_PROMO;break;default:switch(this.queryState_.range){case HistoryRange.ALL_TIME:histogramValue=HistoryPageViewHistogram.HISTORY;break;case HistoryRange.WEEK:histogramValue=HistoryPageViewHistogram.GROUPED_WEEK;break;case HistoryRange.MONTH:histogramValue=HistoryPageViewHistogram.GROUPED_MONTH;break}break}md_history.BrowserService.getInstance().recordHistogram("History.HistoryPageView",histogramValue,HistoryPageViewHistogram.END)}});
\ No newline at end of file +cr.define("md_history",function(){var lazyLoadPromise=null;function ensureLazyLoaded(){if(!lazyLoadPromise){lazyLoadPromise=new Promise(function(resolve,reject){Polymer.Base.importHref("chrome://history/lazy_load.html",resolve,reject,true)})}return lazyLoadPromise}return{ensureLazyLoaded:ensureLazyLoaded}});Polymer({is:"history-app",behaviors:[Polymer.IronScrollTargetBehavior],properties:{showSidebarFooter:Boolean,hasSyncedResults:Boolean,selectedPage_:{type:String,observer:"selectedPageChanged_"},grouped_:{type:Boolean,reflectToAttribute:true},queryState_:{type:Object,value:function(){return{incremental:false,querying:true,queryingDisabled:false,_range:HistoryRange.ALL_TIME,searchTerm:"",groupedOffset:0,set range(val){this._range=Number(val)},get range(){return this._range}}}},queryResult_:{type:Object,value:function(){return{info:null,results:null,sessionList:null}}},hasDrawer_:Boolean,isUserSignedIn_:{type:Boolean,value:loadTimeData.getBoolean("isUserSignedIn")},toolbarShadow_:{type:Boolean,reflectToAttribute:true,notify:true},showMenuPromo_:{type:Boolean,value:function(){return loadTimeData.getBoolean("showMenuPromo")}}},listeners:{"cr-toolbar-menu-promo-close":"onCrToolbarMenuPromoClose_","cr-toolbar-menu-promo-shown":"onCrToolbarMenuPromoShown_","cr-toolbar-menu-tap":"onCrToolbarMenuTap_","delete-selected":"deleteSelected","history-checkbox-select":"checkboxSelected","history-close-drawer":"closeDrawer_","history-view-changed":"historyViewChanged_","opened-changed":"onOpenedChanged_","unselect-all":"unselectAll"},boundOnCanExecute_:null,boundOnCommand_:null,attached:function(){this.grouped_=loadTimeData.getBoolean("groupByDomain");cr.ui.decorate("command",cr.ui.Command);this.boundOnCanExecute_=this.onCanExecute_.bind(this);this.boundOnCommand_=this.onCommand_.bind(this);document.addEventListener("canExecute",this.boundOnCanExecute_);document.addEventListener("command",this.boundOnCommand_)},detached:function(){document.removeEventListener("canExecute",this.boundOnCanExecute_);document.removeEventListener("command",this.boundOnCommand_)},onFirstRender:function(){setTimeout(function(){chrome.send("metricsHandler:recordTime",["History.ResultsRenderedTime",window.performance.now()])});var searchField=this.$.toolbar.searchField;if(!searchField.narrow){searchField.getSearchInput().focus()}md_history.ensureLazyLoaded().then(function(){window.requestIdleCallback(function(){document.fonts.load("bold 12px Roboto")})})},_scrollHandler:function(){if(this.scrollTarget)this.toolbarShadow_=this.scrollTarget.scrollTop!=0},onCrToolbarMenuPromoClose_:function(){this.showMenuPromo_=false},onCrToolbarMenuPromoShown_:function(){md_history.BrowserService.getInstance().menuPromoShown()},onCrToolbarMenuTap_:function(){var drawer=this.$$("#drawer");if(drawer)drawer.toggle()},onOpenedChanged_:function(e){if(e.detail.value)this.showMenuPromo_=false},checkboxSelected:function(e){var toolbar=this.$.toolbar;toolbar.count=this.$.history.getSelectedItemCount()},unselectAll:function(){var listContainer=this.$.history;var toolbar=this.$.toolbar;listContainer.unselectAllItems(toolbar.count);toolbar.count=0},deleteSelected:function(){this.$.history.deleteSelectedWithPrompt()},historyResult:function(info,results){this.set("queryState_.querying",false);this.set("queryResult_.info",info);this.set("queryResult_.results",results);var listContainer=this.$["history"];listContainer.historyResult(info,results)},focusToolbarSearchField:function(){this.$.toolbar.showSearchField()},onCanExecute_:function(e){e=e;switch(e.command.id){case"find-command":e.canExecute=true;break;case"slash-command":e.canExecute=!this.$.toolbar.searchField.isSearchFocused();break;case"delete-command":e.canExecute=this.$.toolbar.count>0;break}},onCommand_:function(e){if(e.command.id=="find-command"||e.command.id=="slash-command")this.focusToolbarSearchField();if(e.command.id=="delete-command")this.deleteSelected()},setForeignSessions:function(sessionList,isTabSyncEnabled){if(!isTabSyncEnabled){var syncedDeviceManagerElem=this.$$("history-synced-device-manager");if(syncedDeviceManagerElem){md_history.ensureLazyLoaded().then(function(){syncedDeviceManagerElem.tabSyncDisabled()})}return}this.set("queryResult_.sessionList",sessionList)},historyDeleted:function(){this.$.history.historyDeleted()},updateSignInState:function(isUserSignedIn){this.isUserSignedIn_=isUserSignedIn},syncedTabsSelected_:function(selectedPage){return selectedPage=="syncedTabs"},shouldShowSpinner_:function(querying,incremental,searchTerm){return querying&&!incremental&&searchTerm!=""},showSyncNotice_:function(hasSyncedResults,selectedPage){return hasSyncedResults&&selectedPage!="syncedTabs"},selectedPageChanged_:function(){this.unselectAll();this.historyViewChanged_()},historyViewChanged_:function(){requestAnimationFrame(function(){md_history.ensureLazyLoaded().then(function(){if(!this.$.content.selectedItem)return;this.scrollTarget=this.$.content.selectedItem.getContentScrollTarget();this._scrollHandler()}.bind(this))}.bind(this));this.recordHistoryPageView_()},getSelectedPage_:function(selectedPage,items){return selectedPage},closeDrawer_:function(){var drawer=this.$$("#drawer");if(drawer)drawer.close()},recordHistoryPageView_:function(){var histogramValue=HistoryPageViewHistogram.END;switch(this.selectedPage_){case"syncedTabs":histogramValue=this.isUserSignedIn_?HistoryPageViewHistogram.SYNCED_TABS:HistoryPageViewHistogram.SIGNIN_PROMO;break;default:switch(this.queryState_.range){case HistoryRange.ALL_TIME:histogramValue=HistoryPageViewHistogram.HISTORY;break;case HistoryRange.WEEK:histogramValue=HistoryPageViewHistogram.GROUPED_WEEK;break;case HistoryRange.MONTH:histogramValue=HistoryPageViewHistogram.GROUPED_MONTH;break}break}md_history.BrowserService.getInstance().recordHistogram("History.HistoryPageView",histogramValue,HistoryPageViewHistogram.END)}});
\ No newline at end of file diff --git a/chromium/chrome/browser/resources/md_history/app.html b/chromium/chrome/browser/resources/md_history/app.html index 574706423a3..6d1dc11988f 100644 --- a/chromium/chrome/browser/resources/md_history/app.html +++ b/chromium/chrome/browser/resources/md_history/app.html @@ -1,7 +1,6 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/html/cr/ui.html"> <link rel="import" href="chrome://resources/html/cr/ui/command.html"> -<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-media-query/iron-media-query.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-pages/iron-pages.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-scroll-target-behavior/iron-scroll-target-behavior.html"> @@ -21,10 +20,12 @@ display: block; height: 100%; overflow: hidden; + z-index: 0; } history-toolbar { background: var(--md-toolbar-color); + z-index: 2; } /* Sizing this with flex causes slow load performance, see @@ -32,6 +33,7 @@ #main-container { height: calc(100% - var(--toolbar-height)); position: relative; + z-index: 1; } :host([grouped_]) #main-container { @@ -55,12 +57,16 @@ display: none; } + #drawer { + z-index: 3; + } + #drawer-header { align-items: center; border-bottom: 1px solid rgba(0, 0, 0, 0.08); + box-sizing: border-box; display: flex; height: var(--toolbar-height); - margin-bottom: 5px; } h1 { @@ -99,7 +105,8 @@ query-start-time="[[queryResult_.info.queryStartTime]]" query-end-time="[[queryResult_.info.queryEndTime]]" has-drawer="[[hasDrawer_]]" - show-sync-notice="[[showSyncNotice_(hasSyncedResults, selectedPage_)]]"> + show-sync-notice="[[showSyncNotice_(hasSyncedResults, selectedPage_)]]" + show-menu-promo="[[showMenuPromo_]]"> </history-toolbar> <div id="main-container"> diff --git a/chromium/chrome/browser/resources/md_history/app.js b/chromium/chrome/browser/resources/md_history/app.js index 730ff7e0f8d..7f36d58d6d4 100644 --- a/chromium/chrome/browser/resources/md_history/app.js +++ b/chromium/chrome/browser/resources/md_history/app.js @@ -24,7 +24,6 @@ Polymer({ behaviors: [ Polymer.IronScrollTargetBehavior, - WebUIListenerBehavior, ], properties: { @@ -86,32 +85,50 @@ Polymer({ type: Boolean, reflectToAttribute: true, notify: true, - } + }, + + showMenuPromo_: { + type: Boolean, + value: function() { + return loadTimeData.getBoolean('showMenuPromo'); + }, + }, }, - // TODO(calamity): Replace these event listeners with data bound properties. listeners: { - 'cr-menu-tap': 'onMenuTap_', - 'history-checkbox-select': 'checkboxSelected', - 'unselect-all': 'unselectAll', + 'cr-toolbar-menu-promo-close': 'onCrToolbarMenuPromoClose_', + 'cr-toolbar-menu-promo-shown': 'onCrToolbarMenuPromoShown_', + 'cr-toolbar-menu-tap': 'onCrToolbarMenuTap_', 'delete-selected': 'deleteSelected', + 'history-checkbox-select': 'checkboxSelected', 'history-close-drawer': 'closeDrawer_', 'history-view-changed': 'historyViewChanged_', + 'opened-changed': 'onOpenedChanged_', + 'unselect-all': 'unselectAll', }, + /** @private {?function(!Event)} */ + boundOnCanExecute_: null, + + /** @private {?function(!Event)} */ + boundOnCommand_: null, + /** @override */ - ready: function() { + attached: function() { this.grouped_ = loadTimeData.getBoolean('groupByDomain'); cr.ui.decorate('command', cr.ui.Command); - document.addEventListener('canExecute', this.onCanExecute_.bind(this)); - document.addEventListener('command', this.onCommand_.bind(this)); + this.boundOnCanExecute_ = this.onCanExecute_.bind(this); + this.boundOnCommand_ = this.onCommand_.bind(this); + + document.addEventListener('canExecute', this.boundOnCanExecute_); + document.addEventListener('command', this.boundOnCommand_); }, /** @override */ - attached: function() { - this.addWebUIListener('sign-in-state-updated', - this.updateSignInState.bind(this)); + detached: function() { + document.removeEventListener('canExecute', this.boundOnCanExecute_); + document.removeEventListener('command', this.boundOnCommand_); }, onFirstRender: function() { @@ -130,7 +147,11 @@ Polymer({ } // Lazily load the remainder of the UI. - md_history.ensureLazyLoaded(); + md_history.ensureLazyLoaded().then(function() { + window.requestIdleCallback(function() { + document.fonts.load('bold 12px Roboto'); + }); + }); }, /** Overridden from IronScrollTargetBehavior */ @@ -140,13 +161,32 @@ Polymer({ }, /** @private */ - onMenuTap_: function() { + onCrToolbarMenuPromoClose_: function() { + this.showMenuPromo_ = false; + }, + + /** @private */ + onCrToolbarMenuPromoShown_: function() { + md_history.BrowserService.getInstance().menuPromoShown(); + }, + + /** @private */ + onCrToolbarMenuTap_: function() { var drawer = this.$$('#drawer'); if (drawer) drawer.toggle(); }, /** + * @param {!CustomEvent} e + * @private + */ + onOpenedChanged_: function(e) { + if (e.detail.value) + this.showMenuPromo_ = false; + }, + + /** * Listens for history-item being selected or deselected (through checkbox) * and changes the view of the top toolbar. * @param {{detail: {countAddition: number}}} e @@ -231,8 +271,11 @@ Polymer({ var syncedDeviceManagerElem = /** @type {HistorySyncedDeviceManagerElement} */this .$$('history-synced-device-manager'); - if (syncedDeviceManagerElem) - syncedDeviceManagerElem.tabSyncDisabled(); + if (syncedDeviceManagerElem) { + md_history.ensureLazyLoaded().then(function() { + syncedDeviceManagerElem.tabSyncDisabled(); + }); + } return; } @@ -298,13 +341,15 @@ Polymer({ // This allows the synced-device-manager to render so that it can be set as // the scroll target. requestAnimationFrame(function() { - // <iron-pages> can occasionally end up with no item selected during - // tests. - if (!this.$.content.selectedItem) - return; - this.scrollTarget = - this.$.content.selectedItem.getContentScrollTarget(); - this._scrollHandler(); + md_history.ensureLazyLoaded().then(function() { + // <iron-pages> can occasionally end up with no item selected during + // tests. + if (!this.$.content.selectedItem) + return; + this.scrollTarget = + this.$.content.selectedItem.getContentScrollTarget(); + this._scrollHandler(); + }.bind(this)); }.bind(this)); this.recordHistoryPageView_(); }, diff --git a/chromium/chrome/browser/resources/md_history/app.vulcanized.html b/chromium/chrome/browser/resources/md_history/app.vulcanized.html index 7024d681ce3..3839d6d49ed 100644 --- a/chromium/chrome/browser/resources/md_history/app.vulcanized.html +++ b/chromium/chrome/browser/resources/md_history/app.vulcanized.html @@ -712,319 +712,6 @@ iron-icon { </defs> </svg> </iron-iconset-svg> -<dom-module id="iron-a11y-announcer" assetpath="chrome://resources/polymer/v1_0/iron-a11y-announcer/" css-build="shadow"> - <template> - <style scope="iron-a11y-announcer">:host { - display: inline-block; - position: fixed; - clip: rect(0px,0px,0px,0px); -} - -</style> - <div aria-live$="[[mode]]">[[_text]]</div> - </template> - - </dom-module> -<style> -/* 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. */ - -<if expr="not chromeos"> -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), - url("chrome://resources/roboto/roboto-regular.woff2") format('woff2'); -} - -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), - url("chrome://resources/roboto/roboto-medium.woff2") format('woff2'); -} - -@font-face { - font-family: 'Roboto'; - font-style: normal; - font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), - url("chrome://resources/roboto/roboto-bold.woff2") format('woff2'); -} -</if> - -</style> -<style is="custom-style" css-build="shadow">html { - --paper-font-common-base_-_font-family: 'Roboto', 'Noto', sans-serif; --paper-font-common-base_-_-webkit-font-smoothing: antialiased;; - - --paper-font-common-code_-_font-family: 'Roboto Mono', 'Consolas', 'Menlo', monospace; --paper-font-common-code_-_-webkit-font-smoothing: antialiased;; - - --paper-font-common-expensive-kerning_-_text-rendering: optimizeLegibility;; - - --paper-font-common-nowrap_-_white-space: nowrap; --paper-font-common-nowrap_-_overflow: hidden; --paper-font-common-nowrap_-_text-overflow: ellipsis;; - - - - --paper-font-display4_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-display4_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-display4_-_white-space: var(--paper-font-common-nowrap_-_white-space); --paper-font-display4_-_overflow: var(--paper-font-common-nowrap_-_overflow); --paper-font-display4_-_text-overflow: var(--paper-font-common-nowrap_-_text-overflow); --paper-font-display4_-_font-size: 112px; --paper-font-display4_-_font-weight: 300; --paper-font-display4_-_letter-spacing: -.044em; --paper-font-display4_-_line-height: 120px;; - - --paper-font-display3_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-display3_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-display3_-_white-space: var(--paper-font-common-nowrap_-_white-space); --paper-font-display3_-_overflow: var(--paper-font-common-nowrap_-_overflow); --paper-font-display3_-_text-overflow: var(--paper-font-common-nowrap_-_text-overflow); --paper-font-display3_-_font-size: 56px; --paper-font-display3_-_font-weight: 400; --paper-font-display3_-_letter-spacing: -.026em; --paper-font-display3_-_line-height: 60px;; - - --paper-font-display2_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-display2_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-display2_-_font-size: 45px; --paper-font-display2_-_font-weight: 400; --paper-font-display2_-_letter-spacing: -.018em; --paper-font-display2_-_line-height: 48px;; - - --paper-font-display1_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-display1_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-display1_-_font-size: 34px; --paper-font-display1_-_font-weight: 400; --paper-font-display1_-_letter-spacing: -.01em; --paper-font-display1_-_line-height: 40px;; - - --paper-font-headline_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-headline_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-headline_-_font-size: 24px; --paper-font-headline_-_font-weight: 400; --paper-font-headline_-_letter-spacing: -.012em; --paper-font-headline_-_line-height: 32px;; - - --paper-font-title_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-title_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-title_-_white-space: var(--paper-font-common-nowrap_-_white-space); --paper-font-title_-_overflow: var(--paper-font-common-nowrap_-_overflow); --paper-font-title_-_text-overflow: var(--paper-font-common-nowrap_-_text-overflow); --paper-font-title_-_font-size: 20px; --paper-font-title_-_font-weight: 500; --paper-font-title_-_line-height: 28px;; - - --paper-font-subhead_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-subhead_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-subhead_-_font-size: 16px; --paper-font-subhead_-_font-weight: 400; --paper-font-subhead_-_line-height: 24px;; - - --paper-font-body2_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-body2_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-body2_-_font-size: 14px; --paper-font-body2_-_font-weight: 500; --paper-font-body2_-_line-height: 24px;; - - --paper-font-body1_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-body1_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-body1_-_font-size: 14px; --paper-font-body1_-_font-weight: 400; --paper-font-body1_-_line-height: 20px;; - - --paper-font-caption_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-caption_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-caption_-_white-space: var(--paper-font-common-nowrap_-_white-space); --paper-font-caption_-_overflow: var(--paper-font-common-nowrap_-_overflow); --paper-font-caption_-_text-overflow: var(--paper-font-common-nowrap_-_text-overflow); --paper-font-caption_-_font-size: 12px; --paper-font-caption_-_font-weight: 400; --paper-font-caption_-_letter-spacing: 0.011em; --paper-font-caption_-_line-height: 20px;; - - --paper-font-menu_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-menu_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-menu_-_white-space: var(--paper-font-common-nowrap_-_white-space); --paper-font-menu_-_overflow: var(--paper-font-common-nowrap_-_overflow); --paper-font-menu_-_text-overflow: var(--paper-font-common-nowrap_-_text-overflow); --paper-font-menu_-_font-size: 13px; --paper-font-menu_-_font-weight: 500; --paper-font-menu_-_line-height: 24px;; - - --paper-font-button_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-button_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-button_-_white-space: var(--paper-font-common-nowrap_-_white-space); --paper-font-button_-_overflow: var(--paper-font-common-nowrap_-_overflow); --paper-font-button_-_text-overflow: var(--paper-font-common-nowrap_-_text-overflow); --paper-font-button_-_font-size: 14px; --paper-font-button_-_font-weight: 500; --paper-font-button_-_letter-spacing: 0.018em; --paper-font-button_-_line-height: 24px; --paper-font-button_-_text-transform: uppercase;; - - --paper-font-code2_-_font-family: var(--paper-font-common-code_-_font-family); --paper-font-code2_-_-webkit-font-smoothing: var(--paper-font-common-code_-_-webkit-font-smoothing); --paper-font-code2_-_font-size: 14px; --paper-font-code2_-_font-weight: 700; --paper-font-code2_-_line-height: 20px;; - - --paper-font-code1_-_font-family: var(--paper-font-common-code_-_font-family); --paper-font-code1_-_-webkit-font-smoothing: var(--paper-font-common-code_-_-webkit-font-smoothing); --paper-font-code1_-_font-size: 14px; --paper-font-code1_-_font-weight: 500; --paper-font-code1_-_line-height: 20px;; -} - -</style> - - -<dom-module id="paper-input-container" assetpath="chrome://resources/polymer/v1_0/paper-input/" css-build="shadow"> - <template> - <style scope="paper-input-container">:host { - display: block; - padding: 8px 0; - - ; -} - -:host([inline]) { - display: inline-block; -} - -:host([disabled]) { - pointer-events: none; - opacity: 0.33; - - ; -} - -:host([hidden]) { - display: none !important; -} - -.floated-label-placeholder { - font-family: var(--paper-font-caption_-_font-family); -webkit-font-smoothing: var(--paper-font-caption_-_-webkit-font-smoothing); white-space: var(--paper-font-caption_-_white-space); overflow: var(--paper-font-caption_-_overflow); text-overflow: var(--paper-font-caption_-_text-overflow); font-size: var(--paper-font-caption_-_font-size); font-weight: var(--paper-font-caption_-_font-weight); letter-spacing: var(--paper-font-caption_-_letter-spacing); line-height: var(--paper-font-caption_-_line-height); -} - -.underline { - position: relative; -} - -.focused-line { - position: var(--layout-fit_-_position); top: var(--layout-fit_-_top); right: var(--layout-fit_-_right); bottom: var(--layout-fit_-_bottom); left: var(--layout-fit_-_left); - - background: var(--paper-input-container-focus-color,var(--primary-color));; - height: 2px; - - -webkit-transform-origin: center center; - transform-origin: center center; - -webkit-transform: scale3d(0,1,1); - transform: scale3d(0,1,1); - - display: var(--paper-input-container-underline-focus_-_display); -} - -.underline.is-highlighted .focused-line { - -webkit-transform: none; - transform: none; - -webkit-transition: -webkit-transform 0.25s; - transition: transform 0.25s; - - ; -} - -.underline.is-invalid .focused-line { - background: var(--paper-input-container-invalid-color,var(--error-color));; - -webkit-transform: none; - transform: none; - -webkit-transition: -webkit-transform 0.25s; - transition: transform 0.25s; - - ; -} - -.unfocused-line { - position: var(--layout-fit_-_position); top: var(--layout-fit_-_top); right: var(--layout-fit_-_right); bottom: var(--layout-fit_-_bottom); left: var(--layout-fit_-_left); - - background: var(--paper-input-container-color,var(--secondary-text-color));; - height: 1px; - - display: var(--paper-input-container-underline_-_display); -} - -:host([disabled]) .unfocused-line { - border-bottom: 1px dashed; - border-color: var(--paper-input-container-color,var(--secondary-text-color));; - background: transparent; - - ; -} - -.label-and-input-container { - -ms-flex: var(--layout-flex-auto_-_-ms-flex); -webkit-flex: var(--layout-flex-auto_-_-webkit-flex); flex: var(--layout-flex-auto_-_flex); - position: var(--layout-relative_-_position); - - width: 100%; - max-width: 100%; -} - -.input-content { - display: var(--layout-horizontal_-_display); -ms-flex-direction: var(--layout-horizontal_-_-ms-flex-direction); -webkit-flex-direction: var(--layout-horizontal_-_-webkit-flex-direction); flex-direction: var(--layout-horizontal_-_flex-direction); - -ms-flex-align: var(--layout-center_-_-ms-flex-align); -webkit-align-items: var(--layout-center_-_-webkit-align-items); align-items: var(--layout-center_-_align-items); - - position: relative; -} - -.input-content ::content label, .input-content ::content .paper-input-label { - position: absolute; - top: 0; - right: 0; - left: 0; - width: 100%; - font: inherit; - color: var(--paper-input-container-color,var(--secondary-text-color));; - -webkit-transition: -webkit-transform 0.25s, width 0.25s; - transition: transform 0.25s, width 0.25s; - -webkit-transform-origin: left top; - transform-origin: left top; - - white-space: var(--paper-font-common-nowrap_-_white-space); overflow: var(--paper-font-common-nowrap_-_overflow); text-overflow: var(--paper-font-common-nowrap_-_text-overflow); - font-family: var(--paper-font-subhead_-_font-family); -webkit-font-smoothing: var(--paper-font-subhead_-_-webkit-font-smoothing); font-size: var(--paper-font-subhead_-_font-size); font-weight: var(--paper-font-subhead_-_font-weight); line-height: var(--paper-font-subhead_-_line-height); - color: var(--paper-input-container-label_-_color, var(--paper-input-container-color,var(--secondary-text-color))); font-size: var(--paper-input-container-label_-_font-size, var(--paper-font-subhead_-_font-size)); - ; -} - -.input-content.label-is-floating ::content label, .input-content.label-is-floating ::content .paper-input-label { - -webkit-transform: translateY(-75%) scale(0.75); - transform: translateY(-75%) scale(0.75); - - - width: 133%; - - ; -} - -:host-context([dir="rtl"]) .input-content.label-is-floating ::content label, :host-context([dir="rtl"]) .input-content.label-is-floating ::content .paper-input-label { - width: 100%; - -webkit-transform-origin: right top; - transform-origin: right top; -} - -.input-content.label-is-highlighted ::content label, .input-content.label-is-highlighted ::content .paper-input-label { - color: var(--paper-input-container-focus-color,var(--primary-color));; - - ; -} - -.input-content.is-invalid ::content label, .input-content.is-invalid ::content .paper-input-label { - color: var(--paper-input-container-invalid-color,var(--error-color));; -} - -.input-content.label-is-hidden ::content label, .input-content.label-is-hidden ::content .paper-input-label { - visibility: hidden; -} - -.input-content ::content input, .input-content ::content textarea, .input-content ::content iron-autogrow-textarea, .input-content ::content .paper-input-input { - position: relative; - outline: none; - box-shadow: none; - padding: 0; - width: 100%; - max-width: 100%; - background: transparent; - border: none; - color: var(--paper-input-container-input-color,var(--primary-text-color));; - -webkit-appearance: none; - text-align: inherit; - vertical-align: bottom; - - font-family: var(--paper-font-subhead_-_font-family); -webkit-font-smoothing: var(--paper-font-subhead_-_-webkit-font-smoothing); font-size: var(--paper-font-subhead_-_font-size); font-weight: var(--paper-font-subhead_-_font-weight); line-height: var(--paper-font-subhead_-_line-height); - ; -} - -::content [prefix] { - font-family: var(--paper-font-subhead_-_font-family); -webkit-font-smoothing: var(--paper-font-subhead_-_-webkit-font-smoothing); font-size: var(--paper-font-subhead_-_font-size); font-weight: var(--paper-font-subhead_-_font-weight); line-height: var(--paper-font-subhead_-_line-height); - - ; - -ms-flex: var(--layout-flex-none_-_-ms-flex); -webkit-flex: var(--layout-flex-none_-_-webkit-flex); flex: var(--layout-flex-none_-_flex); -} - -::content [suffix] { - font-family: var(--paper-font-subhead_-_font-family); -webkit-font-smoothing: var(--paper-font-subhead_-_-webkit-font-smoothing); font-size: var(--paper-font-subhead_-_font-size); font-weight: var(--paper-font-subhead_-_font-weight); line-height: var(--paper-font-subhead_-_line-height); - - ; - -ms-flex: var(--layout-flex-none_-_-ms-flex); -webkit-flex: var(--layout-flex-none_-_-webkit-flex); flex: var(--layout-flex-none_-_flex); -} - -.input-content ::content input { - min-width: 0; -} - -.input-content ::content textarea { - resize: none; -} - -.add-on-content { - position: relative; -} - -.add-on-content.is-invalid ::content * { - color: var(--paper-input-container-invalid-color,var(--error-color));; -} - -.add-on-content.is-highlighted ::content * { - color: var(--paper-input-container-focus-color,var(--primary-color));; -} - -</style> - - <template is="dom-if" if="[[!noLabelFloat]]"> - <div class="floated-label-placeholder" aria-hidden="true"> </div> - </template> - - <div class$="[[_computeInputContentClass(noLabelFloat,alwaysFloatLabel,focused,invalid,_inputHasContent)]]"> - <content select="[prefix]" id="prefix"></content> - - <div class="label-and-input-container" id="labelAndInputContainer"> - <content select=":not([add-on]):not([prefix]):not([suffix])"></content> - </div> - - <content select="[suffix]"></content> - </div> - - <div class$="[[_computeUnderlineClass(focused,invalid)]]"> - <div class="unfocused-line"></div> - <div class="focused-line"></div> - </div> - - <div class$="[[_computeAddOnContentClass(focused,invalid)]]"> - <content id="addOnContent" select="[add-on]"></content> - </div> - </template> -</dom-module> - <dom-module id="paper-spinner-styles" assetpath="chrome://resources/polymer/v1_0/paper-spinner/" css-build="shadow"> <template> <style scope="paper-spinner-styles">:host { @@ -2161,13 +1848,39 @@ paper-spinner-lite[active] { transition: opacity 200ms; } -paper-input-container { - --paper-input-container-input-color: white; - --paper-input-container-underline_-_display: none;; - --paper-input-container-underline-focus_-_display: none;; - --paper-input-container-label_-_color: apply-shim-inherit; --paper-input-container-label_-_font-size: apply-shim-inherit;; - -webkit-padding-start: 2px; +#searchTerm { + -webkit-font-smoothing: antialiased; + -webkit-margin-start: 2px; flex: 1; + line-height: 185%; + position: relative; +} + +label { + bottom: 0; + cursor: text; + left: 0; + overflow: hidden; + position: absolute; + right: 0; + top: 0; + white-space: nowrap; +} + +:host([has-search-text_]) label { + visibility: hidden; +} + +input { + -webkit-appearance: none; + background: transparent; + border: none; + color: white; + font: inherit; + outline: none; + padding: 0; + position: relative; + width: 100%; } input[type='search']::-webkit-search-decoration, input[type='search']::-webkit-search-cancel-button, input[type='search']::-webkit-search-results-button { @@ -2186,7 +1899,7 @@ input[type='search']::-webkit-search-decoration, input[type='search']::-webkit-s opacity: 0.6; } -:host([narrow]:not([showing-search])) paper-input-container { +:host([narrow]:not([showing-search])) #searchTerm { display: none; } @@ -2209,12 +1922,13 @@ input[type='search']::-webkit-search-decoration, input[type='search']::-webkit-s </template> <paper-icon-button id="icon" icon="cr:search" title="[[label]]" tabindex$="[[computeIconTabIndex_(narrow)]]"> </paper-icon-button> - <paper-input-container id="searchTerm" on-search="onSearchTermSearch" on-keydown="onSearchTermKeydown" no-label-float=""> + <div id="searchTerm"> <label id="prompt" for="searchInput">[[label]]</label> - <input is="iron-input" id="searchInput" type="search" on-blur="onInputBlur_" incremental="" autofocus=""> - </paper-input-container> + <input id="searchInput" type="search" on-input="onSearchInput_" on-search="onSearchTermSearch" on-keydown="onSearchTermKeydown" on-focus="onInputFocus_" on-blur="onInputBlur_" incremental="" autofocus=""> + + </div> <template is="dom-if" if="[[hasSearchText_]]"> - <paper-icon-button icon="cr:cancel" id="clearSearch" title="[[clearLabel]]" on-tap="hideSearch_"> + <paper-icon-button icon="cr:cancel" id="clearSearch" title="[[clearLabel]]" on-tap="clearSearch_"> </paper-icon-button> </template> </template> @@ -2231,6 +1945,7 @@ input[type='search']::-webkit-search-decoration, input[type='search']::-webkit-s h1 { -webkit-margin-start: 6px; + -webkit-padding-end: 2px; flex: 1; font-size: 123%; font-weight: 400; @@ -2240,8 +1955,9 @@ h1 { } #leftContent { - -webkit-margin-start: 18px; + -webkit-padding-start: 18px; align-items: center; + box-sizing: border-box; display: flex; position: absolute; transition: opacity 100ms; @@ -2272,7 +1988,7 @@ h1 { } :host(:not([narrow_])) #leftContent { - max-width: calc((100% - var(--cr-toolbar-field-width) - 18px) / 2); + max-width: calc((100% - var(--cr-toolbar-field-width)) / 2); ; } @@ -2718,7 +2434,7 @@ paper-tabs { </style> <div id="toolbar-container"> - <cr-toolbar id="main-toolbar" page-name="$i18n{title}" clear-label="$i18n{clearSearch}" search-prompt="$i18n{searchPrompt}" hidden$="[[itemsSelected_]]" spinner-active="[[spinnerActive]]" show-menu="[[hasDrawer]]" show-menu-promo="[[showMenuPromo_]]" menu-label="$i18n{historyMenuButton}" menu-promo="$i18n{menuPromo}" close-menu-promo="$i18n{closeMenuPromo}" on-search-changed="onSearchChanged_" on-cr-menu-promo-shown="onMenuPromoShown_"> + <cr-toolbar id="main-toolbar" page-name="$i18n{title}" clear-label="$i18n{clearSearch}" search-prompt="$i18n{searchPrompt}" hidden$="[[itemsSelected_]]" spinner-active="[[spinnerActive]]" show-menu="[[hasDrawer]]" show-menu-promo="[[showMenuPromo]]" menu-label="$i18n{historyMenuButton}" menu-promo="$i18n{menuPromo}" close-menu-promo="$i18n{closeMenuPromo}" on-search-changed="onSearchChanged_"> <div class="more-actions"> <template is="dom-if" if="[[showSyncNotice]]"> <button is="paper-icon-button-light" id="info-button" on-click="onInfoButtonTap_" aria-label="$i18n{hasSyncedResultsDescription}"> @@ -2855,6 +2571,19 @@ paper-tabs { </dom-module> +<dom-module id="iron-a11y-announcer" assetpath="chrome://resources/polymer/v1_0/iron-a11y-announcer/" css-build="shadow"> + <template> + <style scope="iron-a11y-announcer">:host { + display: inline-block; + position: fixed; + clip: rect(0px,0px,0px,0px); +} + +</style> + <div aria-live$="[[mode]]">[[_text]]</div> + </template> + + </dom-module> <dom-module id="iron-list" assetpath="chrome://resources/polymer/v1_0/iron-list/" css-build="shadow"> <template> <style scope="iron-list">:host { @@ -3041,6 +2770,7 @@ button.more-vert-button div { --checked-color: rgb(68, 136, 255); display: block; outline: none; + pointer-events: none; } button { @@ -3074,6 +2804,7 @@ button { align-items: center; display: flex; min-height: var(--item-height); + pointer-events: auto; } :host([is-card-start]) #item-container { @@ -3231,11 +2962,13 @@ button { <div id="date-accessed" class="card-title"> [[cardTitle_(numberOfItems, item.dateRelativeDay, searchTerm)]] </div> - <div id="item-container"> - <button is="paper-icon-button-light" id="checkbox" on-mousedown="onCheckboxMousedown_" on-click="onCheckboxSelected_" disabled="[[selectionNotAllowed_()]]" role="checkbox" aria-checked$="[[getAriaChecked_(selected)]]" aria-label$="[[getEntrySummary_(item)]]"> + <div id="item-container" on-mousedown="onItemMousedown_" on-click="onItemClick_"> + <button is="paper-icon-button-light" id="checkbox" disabled="[[selectionNotAllowed_()]]" role="checkbox" aria-checked$="[[getAriaChecked_(selected)]]" aria-label$="[[getEntrySummary_(item)]]"> <div id="checkmark"></div> </button> - <span id="time-accessed">[[item.readableTimestamp]]</span> + <span id="time-accessed" on-mouseover="addTimeTitle_"> + [[item.readableTimestamp]] + </span> <div class="website-icon" id="icon"></div> <div id="title-and-domain"> <a href="[[item.url]]" id="title" class="website-title" title="[[item.title]]" on-click="onLinkClick_" on-contextmenu="onLinkRightClick_"> @@ -3348,11 +3081,11 @@ button.more-vert-button div { box-sizing: border-box; display: block; overflow: auto; - padding-top: var(--first-card-padding-top); } iron-list { margin: var(--card-sizing_-_margin); max-width: var(--card-sizing_-_max-width); min-width: var(--card-sizing_-_min-width); padding: var(--card-sizing_-_padding); width: var(--card-sizing_-_width); + margin-top: var(--first-card-padding-top); } </style> @@ -3565,7 +3298,7 @@ dialog .body { <paper-item id="menuMoreButton" class="menu-item" on-tap="onMoreFromSiteTap_"> $i18n{moreFromSite} </paper-item> - <paper-item id="menuRemoveButton" class="menu-item" on-tap="onRemoveFromHistoryTap_"> + <paper-item id="menuRemoveButton" class="menu-item" disabled="[[!canDeleteHistory_()]]" on-tap="onRemoveFromHistoryTap_"> $i18n{removeFromHistory} </paper-item> </cr-shared-menu> @@ -3580,6 +3313,79 @@ dialog .body { </iron-query-params> </template> </dom-module> +<style> +/* 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. */ + +<if expr="not chromeos and not is_android"> +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + src: local('Roboto'), local('Roboto-Regular'), + url("chrome://resources/roboto/roboto-regular.woff2") format('woff2'); +} + +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 500; + src: local('Roboto Medium'), local('Roboto-Medium'), + url("chrome://resources/roboto/roboto-medium.woff2") format('woff2'); +} + +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 700; + src: local('Roboto Bold'), local('Roboto-Bold'), + url("chrome://resources/roboto/roboto-bold.woff2") format('woff2'); +} +</if> + +</style> +<style is="custom-style" css-build="shadow">html { + --paper-font-common-base_-_font-family: 'Roboto', 'Noto', sans-serif; --paper-font-common-base_-_-webkit-font-smoothing: antialiased;; + + --paper-font-common-code_-_font-family: 'Roboto Mono', 'Consolas', 'Menlo', monospace; --paper-font-common-code_-_-webkit-font-smoothing: antialiased;; + + --paper-font-common-expensive-kerning_-_text-rendering: optimizeLegibility;; + + --paper-font-common-nowrap_-_white-space: nowrap; --paper-font-common-nowrap_-_overflow: hidden; --paper-font-common-nowrap_-_text-overflow: ellipsis;; + + + + --paper-font-display4_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-display4_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-display4_-_white-space: var(--paper-font-common-nowrap_-_white-space); --paper-font-display4_-_overflow: var(--paper-font-common-nowrap_-_overflow); --paper-font-display4_-_text-overflow: var(--paper-font-common-nowrap_-_text-overflow); --paper-font-display4_-_font-size: 112px; --paper-font-display4_-_font-weight: 300; --paper-font-display4_-_letter-spacing: -.044em; --paper-font-display4_-_line-height: 120px;; + + --paper-font-display3_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-display3_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-display3_-_white-space: var(--paper-font-common-nowrap_-_white-space); --paper-font-display3_-_overflow: var(--paper-font-common-nowrap_-_overflow); --paper-font-display3_-_text-overflow: var(--paper-font-common-nowrap_-_text-overflow); --paper-font-display3_-_font-size: 56px; --paper-font-display3_-_font-weight: 400; --paper-font-display3_-_letter-spacing: -.026em; --paper-font-display3_-_line-height: 60px;; + + --paper-font-display2_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-display2_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-display2_-_font-size: 45px; --paper-font-display2_-_font-weight: 400; --paper-font-display2_-_letter-spacing: -.018em; --paper-font-display2_-_line-height: 48px;; + + --paper-font-display1_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-display1_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-display1_-_font-size: 34px; --paper-font-display1_-_font-weight: 400; --paper-font-display1_-_letter-spacing: -.01em; --paper-font-display1_-_line-height: 40px;; + + --paper-font-headline_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-headline_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-headline_-_font-size: 24px; --paper-font-headline_-_font-weight: 400; --paper-font-headline_-_letter-spacing: -.012em; --paper-font-headline_-_line-height: 32px;; + + --paper-font-title_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-title_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-title_-_white-space: var(--paper-font-common-nowrap_-_white-space); --paper-font-title_-_overflow: var(--paper-font-common-nowrap_-_overflow); --paper-font-title_-_text-overflow: var(--paper-font-common-nowrap_-_text-overflow); --paper-font-title_-_font-size: 20px; --paper-font-title_-_font-weight: 500; --paper-font-title_-_line-height: 28px;; + + --paper-font-subhead_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-subhead_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-subhead_-_font-size: 16px; --paper-font-subhead_-_font-weight: 400; --paper-font-subhead_-_line-height: 24px;; + + --paper-font-body2_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-body2_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-body2_-_font-size: 14px; --paper-font-body2_-_font-weight: 500; --paper-font-body2_-_line-height: 24px;; + + --paper-font-body1_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-body1_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-body1_-_font-size: 14px; --paper-font-body1_-_font-weight: 400; --paper-font-body1_-_line-height: 20px;; + + --paper-font-caption_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-caption_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-caption_-_white-space: var(--paper-font-common-nowrap_-_white-space); --paper-font-caption_-_overflow: var(--paper-font-common-nowrap_-_overflow); --paper-font-caption_-_text-overflow: var(--paper-font-common-nowrap_-_text-overflow); --paper-font-caption_-_font-size: 12px; --paper-font-caption_-_font-weight: 400; --paper-font-caption_-_letter-spacing: 0.011em; --paper-font-caption_-_line-height: 20px;; + + --paper-font-menu_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-menu_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-menu_-_white-space: var(--paper-font-common-nowrap_-_white-space); --paper-font-menu_-_overflow: var(--paper-font-common-nowrap_-_overflow); --paper-font-menu_-_text-overflow: var(--paper-font-common-nowrap_-_text-overflow); --paper-font-menu_-_font-size: 13px; --paper-font-menu_-_font-weight: 500; --paper-font-menu_-_line-height: 24px;; + + --paper-font-button_-_font-family: var(--paper-font-common-base_-_font-family); --paper-font-button_-_-webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); --paper-font-button_-_white-space: var(--paper-font-common-nowrap_-_white-space); --paper-font-button_-_overflow: var(--paper-font-common-nowrap_-_overflow); --paper-font-button_-_text-overflow: var(--paper-font-common-nowrap_-_text-overflow); --paper-font-button_-_font-size: 14px; --paper-font-button_-_font-weight: 500; --paper-font-button_-_letter-spacing: 0.018em; --paper-font-button_-_line-height: 24px; --paper-font-button_-_text-transform: uppercase;; + + --paper-font-code2_-_font-family: var(--paper-font-common-code_-_font-family); --paper-font-code2_-_-webkit-font-smoothing: var(--paper-font-common-code_-_-webkit-font-smoothing); --paper-font-code2_-_font-size: 14px; --paper-font-code2_-_font-weight: 700; --paper-font-code2_-_line-height: 20px;; + + --paper-font-code1_-_font-family: var(--paper-font-common-code_-_font-family); --paper-font-code1_-_-webkit-font-smoothing: var(--paper-font-common-code_-_-webkit-font-smoothing); --paper-font-code1_-_font-size: 14px; --paper-font-code1_-_font-weight: 500; --paper-font-code1_-_line-height: 20px;; +} + +</style> <dom-module id="history-side-bar" assetpath="chrome://history/" css-build="shadow"> <template> <style scope="history-side-bar">[hidden] { @@ -3665,14 +3471,20 @@ button.more-vert-button div { } :host { - display: block; + display: flex; height: 100%; - padding-top: 5px; + overflow-x: hidden; + overflow-y: auto; width: var(--side-bar-width); } +:host([drawer]) { + height: calc(100% - var(--toolbar-height)); +} + div.separator { background-color: rgba(0, 0, 0, 0.08); + flex-shrink: 0; height: 1px; margin: 8px 0; } @@ -3682,7 +3494,7 @@ div.separator { } #clear-browsing-data iron-icon { - -webkit-margin-end: 24px; + -webkit-margin-end: 20px; color: var(--paper-grey-400); height: 20px; margin-bottom: 10px; @@ -3694,10 +3506,16 @@ iron-selector { -webkit-user-select: none; background-color: transparent; color: #5a5a5a; + display: flex; + flex: 1; + flex-direction: column; + padding-top: 8px; } iron-selector > a { font-family: var(--paper-font-subhead_-_font-family); -webkit-font-smoothing: var(--paper-font-subhead_-_-webkit-font-smoothing); font-size: var(--paper-font-subhead_-_font-size); font-weight: var(--paper-font-subhead_-_font-weight); line-height: var(--paper-font-subhead_-_line-height); + + -webkit-margin-end: 4px; -webkit-padding-start: 24px; align-items: center; box-sizing: border-box; @@ -3713,18 +3531,15 @@ iron-selector > a { iron-selector > a.iron-selected { color: var(--google-blue-500); - font-weight: 500; } -#footer { - bottom: 0; - color: var(--paper-grey-600); - position: absolute; - width: var(--side-bar-width); +#spacer { + flex: 1; } -:host([drawer]) #footer { - bottom: 120px; +#footer { + color: var(--paper-grey-600); + width: var(--side-bar-width); } #footer-text { @@ -3756,6 +3571,7 @@ iron-selector > a.iron-selected { <iron-icon icon="cr:open-in-new"></iron-icon> <paper-ripple id="cbd-ripple"></paper-ripple> </a> + <div id="spacer"></div> <div id="footer" hidden="[[!showFooter]]"> <div class="separator"></div> <div id="footer-text">$i18nRaw{sidebarFooter}</div> @@ -3851,15 +3667,18 @@ button.more-vert-button div { display: block; height: 100%; overflow: hidden; + z-index: 0; } history-toolbar { background: var(--md-toolbar-color); + z-index: 2; } #main-container { height: calc(100% - var(--toolbar-height)); position: relative; + z-index: 1; } :host([grouped_]) #main-container { @@ -3882,12 +3701,16 @@ history-toolbar { display: none; } +#drawer { + z-index: 3; +} + #drawer-header { align-items: center; border-bottom: 1px solid rgba(0, 0, 0, 0.08); + box-sizing: border-box; display: flex; height: var(--toolbar-height); - margin-bottom: 5px; } h1 { @@ -3918,7 +3741,7 @@ h1 { </history-router> <history-toolbar id="toolbar" spinner-active="[[shouldShowSpinner_(queryState_.querying, queryState_.incremental, - queryState_.searchTerm)]]" is-grouped-mode="{{grouped_}}" grouped-range="{{queryState_.range}}" search-term="{{queryState_.searchTerm}}" query-start-time="[[queryResult_.info.queryStartTime]]" query-end-time="[[queryResult_.info.queryEndTime]]" has-drawer="[[hasDrawer_]]" show-sync-notice="[[showSyncNotice_(hasSyncedResults, selectedPage_)]]"> + queryState_.searchTerm)]]" is-grouped-mode="{{grouped_}}" grouped-range="{{queryState_.range}}" search-term="{{queryState_.searchTerm}}" query-start-time="[[queryResult_.info.queryStartTime]]" query-end-time="[[queryResult_.info.queryEndTime]]" has-drawer="[[hasDrawer_]]" show-sync-notice="[[showSyncNotice_(hasSyncedResults, selectedPage_)]]" show-menu-promo="[[showMenuPromo_]]"> </history-toolbar> <div id="main-container"> diff --git a/chromium/chrome/browser/resources/md_history/compiled_resources2.gyp b/chromium/chrome/browser/resources/md_history/compiled_resources2.gyp index 425a4d46726..4bdffd0983a 100644 --- a/chromium/chrome/browser/resources/md_history/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/md_history/compiled_resources2.gyp @@ -77,7 +77,6 @@ '<(DEPTH)/ui/webui/resources/cr_elements/cr_toolbar/compiled_resources2.gyp:cr_toolbar', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util', - 'browser_service', ], 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], }, @@ -112,7 +111,6 @@ 'dependencies': [ # TODO(calamity): Add app-route elements after closure issues are fixed. '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:util', - '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior', '<(DEPTH)/ui/webui/resources/js/cr/ui/compiled_resources2.gyp:command', 'constants', 'history_toolbar', diff --git a/chromium/chrome/browser/resources/md_history/history_item.html b/chromium/chrome/browser/resources/md_history/history_item.html index 607800727f4..87bc8b16a5b 100644 --- a/chromium/chrome/browser/resources/md_history/history_item.html +++ b/chromium/chrome/browser/resources/md_history/history_item.html @@ -19,6 +19,7 @@ --checked-color: rgb(68, 136, 255); display: block; outline: none; + pointer-events: none; } /** Unresolved paper-icon-button-light styles. */ @@ -53,6 +54,7 @@ align-items: center; display: flex; min-height: var(--item-height); + pointer-events: auto; } :host([is-card-start]) #item-container { @@ -210,17 +212,19 @@ <div id="date-accessed" class="card-title"> [[cardTitle_(numberOfItems, item.dateRelativeDay, searchTerm)]] </div> - <div id="item-container"> + <div id="item-container" + on-mousedown="onItemMousedown_" + on-click="onItemClick_"> <button is="paper-icon-button-light" id="checkbox" - on-mousedown="onCheckboxMousedown_" - on-click="onCheckboxSelected_" disabled="[[selectionNotAllowed_()]]" role="checkbox" aria-checked$="[[getAriaChecked_(selected)]]" aria-label$="[[getEntrySummary_(item)]]"> <div id="checkmark"></div> </button> - <span id="time-accessed">[[item.readableTimestamp]]</span> + <span id="time-accessed" on-mouseover="addTimeTitle_"> + [[item.readableTimestamp]] + </span> <div class="website-icon" id="icon"></div> <div id="title-and-domain"> <a href="[[item.url]]" id="title" class="website-title" diff --git a/chromium/chrome/browser/resources/md_history/history_item.js b/chromium/chrome/browser/resources/md_history/history_item.js index e064ec6710e..df079c2c2c3 100644 --- a/chromium/chrome/browser/resources/md_history/history_item.js +++ b/chromium/chrome/browser/resources/md_history/history_item.js @@ -168,25 +168,35 @@ cr.define('md_history', function() { }, /** - * When a history-item is selected the toolbar is notified and increases - * or decreases its count of selected items accordingly. + * Toggle item selection whenever the checkbox or any non-interactive part + * of the item is clicked. * @param {MouseEvent} e * @private */ - onCheckboxSelected_: function(e) { - // TODO(calamity): Fire this event whenever |selected| changes. + onItemClick_: function(e) { + for (var i = 0; i < e.path.length; i++) { + var elem = e.path[i]; + if (elem.id != 'checkbox' && + (elem.nodeName == 'A' || elem.nodeName == 'BUTTON')) { + return; + } + } + + if (this.selectionNotAllowed_()) + return; + + this.$.checkbox.focus(); this.fire('history-checkbox-select', { element: this, shiftKey: e.shiftKey, }); - e.preventDefault(); }, /** * @param {MouseEvent} e * @private */ - onCheckboxMousedown_: function(e) { + onItemMousedown_: function(e) { // Prevent shift clicking a checkbox from selecting text. if (e.shiftKey) e.preventDefault(); @@ -262,7 +272,8 @@ cr.define('md_history', function() { return; browserService.recordHistogram( - 'HistoryPage.ClickPosition', this.index, UMA_MAX_BUCKET_VALUE); + 'HistoryPage.ClickPosition', + Math.min(this.index, UMA_MAX_BUCKET_VALUE), UMA_MAX_BUCKET_VALUE); if (this.index <= UMA_MAX_SUBSET_BUCKET_VALUE) { browserService.recordHistogram( @@ -300,6 +311,13 @@ cr.define('md_history', function() { return this.item.dateRelativeDay; return HistoryItem.searchResultsTitle(numberOfItems, search); }, + + /** @private */ + addTimeTitle_: function() { + var el = this.$['time-accessed']; + el.setAttribute('title', new Date(this.item.time).toString()); + this.unlisten(el, 'mouseover', 'addTimeTitle_'); + }, }); /** diff --git a/chromium/chrome/browser/resources/md_history/history_list.html b/chromium/chrome/browser/resources/md_history/history_list.html index f5b641b02bf..bfdb2da1d55 100644 --- a/chromium/chrome/browser/resources/md_history/history_list.html +++ b/chromium/chrome/browser/resources/md_history/history_list.html @@ -13,11 +13,11 @@ box-sizing: border-box; display: block; overflow: auto; - padding-top: var(--first-card-padding-top); } iron-list { @apply(--card-sizing); + margin-top: var(--first-card-padding-top); } </style> <div id="no-results" class="centered-message" diff --git a/chromium/chrome/browser/resources/md_history/history_toolbar.html b/chromium/chrome/browser/resources/md_history/history_toolbar.html index b6514206114..ab29c0ccb89 100644 --- a/chromium/chrome/browser/resources/md_history/history_toolbar.html +++ b/chromium/chrome/browser/resources/md_history/history_toolbar.html @@ -181,12 +181,11 @@ hidden$="[[itemsSelected_]]" spinner-active="[[spinnerActive]]" show-menu="[[hasDrawer]]" - show-menu-promo="[[showMenuPromo_]]" + show-menu-promo="[[showMenuPromo]]" menu-label="$i18n{historyMenuButton}" menu-promo="$i18n{menuPromo}" close-menu-promo="$i18n{closeMenuPromo}" - on-search-changed="onSearchChanged_" - on-cr-menu-promo-shown="onMenuPromoShown_"> + on-search-changed="onSearchChanged_"> <div class="more-actions"> <template is="dom-if" if="[[showSyncNotice]]"> <button is="paper-icon-button-light" id="info-button" diff --git a/chromium/chrome/browser/resources/md_history/history_toolbar.js b/chromium/chrome/browser/resources/md_history/history_toolbar.js index 8842be95ef7..882bf037278 100644 --- a/chromium/chrome/browser/resources/md_history/history_toolbar.js +++ b/chromium/chrome/browser/resources/md_history/history_toolbar.js @@ -67,12 +67,7 @@ Polymer({ // Whether to show the menu promo (a tooltip that points at the menu button // in narrow mode). - showMenuPromo_: { - type: Boolean, - value: function() { - return loadTimeData.getBoolean('showMenuPromo'); - }, - }, + showMenuPromo: Boolean, }, /** @return {CrToolbarSearchFieldElement} */ @@ -105,11 +100,6 @@ Polymer({ } }, - /** @private */ - onMenuPromoShown_: function() { - md_history.BrowserService.getInstance().menuPromoShown(); - }, - /** * @param {!CustomEvent} event * @private diff --git a/chromium/chrome/browser/resources/md_history/lazy_load.crisper.js b/chromium/chrome/browser/resources/md_history/lazy_load.crisper.js index 20b9cf5e975..b3f8a172ef3 100644 --- a/chromium/chrome/browser/resources/md_history/lazy_load.crisper.js +++ b/chromium/chrome/browser/resources/md_history/lazy_load.crisper.js @@ -23,4 +23,4 @@ var ForeignDeviceInternal;Polymer({is:"history-synced-device-manager",properties // Copyright 2016 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. -Polymer({is:"cr-dialog","extends":"dialog",created:function(){window.addEventListener("popstate",function(){if(this.open)this.cancel()}.bind(this))},cancel:function(){this.fire("cancel");HTMLDialogElement.prototype.close.call(this,"")},close:function(opt_returnValue){HTMLDialogElement.prototype.close.call(this,"success")},getCloseButton:function(){return this.$.close}});Polymer({is:"app-drawer",properties:{opened:{type:Boolean,value:false,notify:true,reflectToAttribute:true},persistent:{type:Boolean,value:false,reflectToAttribute:true},align:{type:String,value:"left"},position:{type:String,readOnly:true,value:"left",reflectToAttribute:true},swipeOpen:{type:Boolean,value:false,reflectToAttribute:true},noFocusTrap:{type:Boolean,value:false}},observers:["resetLayout(position)","_resetPosition(align, isAttached)"],_translateOffset:0,_trackDetails:null,_drawerState:0,_boundEscKeydownHandler:null,_firstTabStop:null,_lastTabStop:null,ready:function(){this.setScrollDirection("y");this._setTransitionDuration("0s")},attached:function(){Polymer.RenderStatus.afterNextRender(this,function(){this._setTransitionDuration("");this._boundEscKeydownHandler=this._escKeydownHandler.bind(this);this._resetDrawerState();this.listen(this,"track","_track");this.addEventListener("transitionend",this._transitionend.bind(this));this.addEventListener("keydown",this._tabKeydownHandler.bind(this))})},detached:function(){document.removeEventListener("keydown",this._boundEscKeydownHandler)},open:function(){this.opened=true},close:function(){this.opened=false},toggle:function(){this.opened=!this.opened},getWidth:function(){return this.$.contentContainer.offsetWidth},resetLayout:function(){this.debounce("_resetLayout",function(){this.fire("app-drawer-reset-layout")},1)},_isRTL:function(){return window.getComputedStyle(this).direction==="rtl"},_resetPosition:function(){switch(this.align){case"start":this._setPosition(this._isRTL()?"right":"left");return;case"end":this._setPosition(this._isRTL()?"left":"right");return}this._setPosition(this.align)},_escKeydownHandler:function(event){var ESC_KEYCODE=27;if(event.keyCode===ESC_KEYCODE){event.preventDefault();this.close()}},_track:function(event){if(this.persistent){return}event.preventDefault();switch(event.detail.state){case"start":this._trackStart(event);break;case"track":this._trackMove(event);break;case"end":this._trackEnd(event);break}},_trackStart:function(event){this._drawerState=this._DRAWER_STATE.TRACKING;this._setTransitionDuration("0s");this.style.visibility="visible";var rect=this.$.contentContainer.getBoundingClientRect();if(this.position==="left"){this._translateOffset=rect.left}else{this._translateOffset=rect.right-window.innerWidth}this._trackDetails=[]},_trackMove:function(event){this._translateDrawer(event.detail.dx+this._translateOffset);this._trackDetails.push({dx:event.detail.dx,timeStamp:Date.now()})},_trackEnd:function(event){var x=event.detail.dx+this._translateOffset;var drawerWidth=this.getWidth();var isPositionLeft=this.position==="left";var isInEndState=isPositionLeft?x>=0||x<=-drawerWidth:x<=0||x>=drawerWidth;if(!isInEndState){var trackDetails=this._trackDetails;this._trackDetails=null;this._flingDrawer(event,trackDetails);if(this._drawerState===this._DRAWER_STATE.FLINGING){return}}var halfWidth=drawerWidth/2;if(event.detail.dx<-halfWidth){this.opened=this.position==="right"}else if(event.detail.dx>halfWidth){this.opened=this.position==="left"}if(isInEndState){this._resetDrawerState()}this._setTransitionDuration("");this._resetDrawerTranslate();this.style.visibility=""},_calculateVelocity:function(event,trackDetails){var now=Date.now();var timeLowerBound=now-100;var trackDetail;var min=0;var max=trackDetails.length-1;while(min<=max){var mid=min+max>>1;var d=trackDetails[mid];if(d.timeStamp>=timeLowerBound){trackDetail=d;max=mid-1}else{min=mid+1}}if(trackDetail){var dx=event.detail.dx-trackDetail.dx;var dt=now-trackDetail.timeStamp||1;return dx/dt}return 0},_flingDrawer:function(event,trackDetails){var velocity=this._calculateVelocity(event,trackDetails);if(Math.abs(velocity)<this._MIN_FLING_THRESHOLD){return}this._drawerState=this._DRAWER_STATE.FLINGING;var x=event.detail.dx+this._translateOffset;var drawerWidth=this.getWidth();var isPositionLeft=this.position==="left";var isVelocityPositive=velocity>0;var isClosingLeft=!isVelocityPositive&&isPositionLeft;var isClosingRight=isVelocityPositive&&!isPositionLeft;var dx;if(isClosingLeft){dx=-(x+drawerWidth)}else if(isClosingRight){dx=drawerWidth-x}else{dx=-x}if(isVelocityPositive){velocity=Math.max(velocity,this._MIN_TRANSITION_VELOCITY);this.opened=this.position==="left"}else{velocity=Math.min(velocity,-this._MIN_TRANSITION_VELOCITY);this.opened=this.position==="right"}this._setTransitionDuration(this._FLING_INITIAL_SLOPE*dx/velocity+"ms");this._setTransitionTimingFunction(this._FLING_TIMING_FUNCTION);this._resetDrawerTranslate()},_transitionend:function(event){var target=Polymer.dom(event).rootTarget;if(target===this.$.contentContainer||target===this.$.scrim){if(this._drawerState===this._DRAWER_STATE.FLINGING){this._setTransitionDuration("");this._setTransitionTimingFunction("");this.style.visibility=""}this._resetDrawerState()}},_setTransitionDuration:function(duration){this.$.contentContainer.style.transitionDuration=duration;this.$.scrim.style.transitionDuration=duration},_setTransitionTimingFunction:function(timingFunction){this.$.contentContainer.style.transitionTimingFunction=timingFunction;this.$.scrim.style.transitionTimingFunction=timingFunction},_translateDrawer:function(x){var drawerWidth=this.getWidth();if(this.position==="left"){x=Math.max(-drawerWidth,Math.min(x,0));this.$.scrim.style.opacity=1+x/drawerWidth}else{x=Math.max(0,Math.min(x,drawerWidth));this.$.scrim.style.opacity=1-x/drawerWidth}this.translate3d(x+"px","0","0",this.$.contentContainer)},_resetDrawerTranslate:function(){this.$.scrim.style.opacity="";this.transform("",this.$.contentContainer)},_resetDrawerState:function(){var oldState=this._drawerState;if(this.opened){this._drawerState=this.persistent?this._DRAWER_STATE.OPENED_PERSISTENT:this._DRAWER_STATE.OPENED}else{this._drawerState=this._DRAWER_STATE.CLOSED}if(oldState!==this._drawerState){if(this._drawerState===this._DRAWER_STATE.OPENED){this._setKeyboardFocusTrap();document.addEventListener("keydown",this._boundEscKeydownHandler);document.body.style.overflow="hidden"}else{document.removeEventListener("keydown",this._boundEscKeydownHandler);document.body.style.overflow=""}if(oldState!==this._DRAWER_STATE.INIT){this.fire("app-drawer-transitioned")}}},_setKeyboardFocusTrap:function(){if(this.noFocusTrap){return}var focusableElementsSelector=['a[href]:not([tabindex="-1"])','area[href]:not([tabindex="-1"])','input:not([disabled]):not([tabindex="-1"])','select:not([disabled]):not([tabindex="-1"])','textarea:not([disabled]):not([tabindex="-1"])','button:not([disabled]):not([tabindex="-1"])','iframe:not([tabindex="-1"])','[tabindex]:not([tabindex="-1"])','[contentEditable=true]:not([tabindex="-1"])'].join(",");var focusableElements=Polymer.dom(this).querySelectorAll(focusableElementsSelector);if(focusableElements.length>0){this._firstTabStop=focusableElements[0];this._lastTabStop=focusableElements[focusableElements.length-1]}else{this._firstTabStop=null;this._lastTabStop=null}var tabindex=this.getAttribute("tabindex");if(tabindex&&parseInt(tabindex,10)>-1){this.focus()}else if(this._firstTabStop){this._firstTabStop.focus()}},_tabKeydownHandler:function(event){if(this.noFocusTrap){return}var TAB_KEYCODE=9;if(this._drawerState===this._DRAWER_STATE.OPENED&&event.keyCode===TAB_KEYCODE){if(event.shiftKey){if(this._firstTabStop&&Polymer.dom(event).localTarget===this._firstTabStop){event.preventDefault();this._lastTabStop.focus()}}else{if(this._lastTabStop&&Polymer.dom(event).localTarget===this._lastTabStop){event.preventDefault();this._firstTabStop.focus()}}}},_MIN_FLING_THRESHOLD:.2,_MIN_TRANSITION_VELOCITY:1.2,_FLING_TIMING_FUNCTION:"cubic-bezier(0.667, 1, 0.667, 1)",_FLING_INITIAL_SLOPE:1.5,_DRAWER_STATE:{INIT:0,OPENED:1,OPENED_PERSISTENT:2,CLOSED:3,TRACKING:4,FLINGING:5}});Polymer.IronFormElementBehavior={properties:{name:{type:String},value:{notify:true,type:String},required:{type:Boolean,value:false},_parentForm:{type:Object}},attached:function(){this.fire("iron-form-element-register")},detached:function(){if(this._parentForm){this._parentForm.fire("iron-form-element-unregister",{target:this})}}};Polymer.IronCheckedElementBehaviorImpl={properties:{checked:{type:Boolean,value:false,reflectToAttribute:true,notify:true,observer:"_checkedChanged"},toggles:{type:Boolean,value:true,reflectToAttribute:true},value:{type:String,value:"on",observer:"_valueChanged"}},observers:["_requiredChanged(required)"],created:function(){this._hasIronCheckedElementBehavior=true},_getValidity:function(_value){return this.disabled||!this.required||this.checked},_requiredChanged:function(){if(this.required){this.setAttribute("aria-required","true")}else{this.removeAttribute("aria-required")}},_checkedChanged:function(){this.active=this.checked;this.fire("iron-change")},_valueChanged:function(){if(this.value===undefined||this.value===null){this.value="on"}}};Polymer.IronCheckedElementBehavior=[Polymer.IronFormElementBehavior,Polymer.IronValidatableBehavior,Polymer.IronCheckedElementBehaviorImpl];Polymer.PaperCheckedElementBehaviorImpl={_checkedChanged:function(){Polymer.IronCheckedElementBehaviorImpl._checkedChanged.call(this);if(this.hasRipple()){if(this.checked){this._ripple.setAttribute("checked","")}else{this._ripple.removeAttribute("checked")}}},_buttonStateChanged:function(){Polymer.PaperRippleBehavior._buttonStateChanged.call(this);if(this.disabled){return}if(this.isAttached){this.checked=this.active}}};Polymer.PaperCheckedElementBehavior=[Polymer.PaperInkyFocusBehavior,Polymer.IronCheckedElementBehavior,Polymer.PaperCheckedElementBehaviorImpl];Polymer({is:"paper-checkbox",behaviors:[Polymer.PaperCheckedElementBehavior],hostAttributes:{role:"checkbox","aria-checked":false,tabindex:0},properties:{ariaActiveAttribute:{type:String,value:"aria-checked"}},attached:function(){var inkSize=this.getComputedStyleValue("--calculated-paper-checkbox-ink-size");if(inkSize==="-1px"){var checkboxSize=parseFloat(this.getComputedStyleValue("--calculated-paper-checkbox-size"));var defaultInkSize=Math.floor(8/3*checkboxSize);if(defaultInkSize%2!==checkboxSize%2){defaultInkSize++}this.customStyle["--paper-checkbox-ink-size"]=defaultInkSize+"px";this.updateStyles()}},_computeCheckboxClass:function(checked,invalid){var className="";if(checked){className+="checked "}if(invalid){className+="invalid"}return className},_computeCheckmarkClass:function(checked){return checked?"":"hidden"},_createRipple:function(){this._rippleContainer=this.$.checkboxContainer;return Polymer.PaperInkyFocusBehaviorImpl._createRipple.call(this)}});Polymer({is:"paper-tab",behaviors:[Polymer.IronControlState,Polymer.IronButtonState,Polymer.PaperRippleBehavior],properties:{link:{type:Boolean,value:false,reflectToAttribute:true}},hostAttributes:{role:"tab"},listeners:{down:"_updateNoink",tap:"_onTap"},attached:function(){this._updateNoink()},get _parentNoink(){var parent=Polymer.dom(this).parentNode;return!!parent&&!!parent.noink},_updateNoink:function(){this.noink=!!this.noink||!!this._parentNoink},_onTap:function(event){if(this.link){var anchor=this.queryEffectiveChildren("a");if(!anchor){return}if(event.target===anchor){return}anchor.click()}}});Polymer.IronMenubarBehaviorImpl={hostAttributes:{role:"menubar"},keyBindings:{left:"_onLeftKey",right:"_onRightKey"},_onUpKey:function(event){this.focusedItem.click();event.detail.keyboardEvent.preventDefault()},_onDownKey:function(event){this.focusedItem.click();event.detail.keyboardEvent.preventDefault()},get _isRTL(){return window.getComputedStyle(this)["direction"]==="rtl"},_onLeftKey:function(event){if(this._isRTL){this._focusNext()}else{this._focusPrevious()}event.detail.keyboardEvent.preventDefault()},_onRightKey:function(event){if(this._isRTL){this._focusPrevious()}else{this._focusNext()}event.detail.keyboardEvent.preventDefault()},_onKeydown:function(event){if(this.keyboardEventMatchesKeys(event,"up down left right esc")){return}this._focusWithKeyboardEvent(event)}};Polymer.IronMenubarBehavior=[Polymer.IronMenuBehavior,Polymer.IronMenubarBehaviorImpl];Polymer({is:"paper-tabs",behaviors:[Polymer.IronResizableBehavior,Polymer.IronMenubarBehavior],properties:{noink:{type:Boolean,value:false,observer:"_noinkChanged"},noBar:{type:Boolean,value:false},noSlide:{type:Boolean,value:false},scrollable:{type:Boolean,value:false},fitContainer:{type:Boolean,value:false},disableDrag:{type:Boolean,value:false},hideScrollButtons:{type:Boolean,value:false},alignBottom:{type:Boolean,value:false},selectable:{type:String,value:"paper-tab"},autoselect:{type:Boolean,value:false},autoselectDelay:{type:Number,value:0},_step:{type:Number,value:10},_holdDelay:{type:Number,value:1},_leftHidden:{type:Boolean,value:false},_rightHidden:{type:Boolean,value:false},_previousTab:{type:Object}},hostAttributes:{role:"tablist"},listeners:{"iron-resize":"_onTabSizingChanged","iron-items-changed":"_onTabSizingChanged","iron-select":"_onIronSelect","iron-deselect":"_onIronDeselect"},keyBindings:{"left:keyup right:keyup":"_onArrowKeyup"},created:function(){this._holdJob=null;this._pendingActivationItem=undefined;this._pendingActivationTimeout=undefined;this._bindDelayedActivationHandler=this._delayedActivationHandler.bind(this);this.addEventListener("blur",this._onBlurCapture.bind(this),true)},ready:function(){this.setScrollDirection("y",this.$.tabsContainer)},detached:function(){this._cancelPendingActivation()},_noinkChanged:function(noink){var childTabs=Polymer.dom(this).querySelectorAll("paper-tab");childTabs.forEach(noink?this._setNoinkAttribute:this._removeNoinkAttribute)},_setNoinkAttribute:function(element){element.setAttribute("noink","")},_removeNoinkAttribute:function(element){element.removeAttribute("noink")},_computeScrollButtonClass:function(hideThisButton,scrollable,hideScrollButtons){if(!scrollable||hideScrollButtons){return"hidden"}if(hideThisButton){return"not-visible"}return""},_computeTabsContentClass:function(scrollable,fitContainer){return scrollable?"scrollable"+(fitContainer?" fit-container":""):" fit-container"},_computeSelectionBarClass:function(noBar,alignBottom){if(noBar){return"hidden"}else if(alignBottom){return"align-bottom"}return""},_onTabSizingChanged:function(){this.debounce("_onTabSizingChanged",function(){this._scroll();this._tabChanged(this.selectedItem)},10)},_onIronSelect:function(event){this._tabChanged(event.detail.item,this._previousTab);this._previousTab=event.detail.item;this.cancelDebouncer("tab-changed")},_onIronDeselect:function(event){this.debounce("tab-changed",function(){this._tabChanged(null,this._previousTab);this._previousTab=null},1)},_activateHandler:function(){this._cancelPendingActivation();Polymer.IronMenuBehaviorImpl._activateHandler.apply(this,arguments)},_scheduleActivation:function(item,delay){this._pendingActivationItem=item;this._pendingActivationTimeout=this.async(this._bindDelayedActivationHandler,delay)},_delayedActivationHandler:function(){var item=this._pendingActivationItem;this._pendingActivationItem=undefined;this._pendingActivationTimeout=undefined;item.fire(this.activateEvent,null,{bubbles:true,cancelable:true})},_cancelPendingActivation:function(){if(this._pendingActivationTimeout!==undefined){this.cancelAsync(this._pendingActivationTimeout);this._pendingActivationItem=undefined;this._pendingActivationTimeout=undefined}},_onArrowKeyup:function(event){if(this.autoselect){this._scheduleActivation(this.focusedItem,this.autoselectDelay)}},_onBlurCapture:function(event){if(event.target===this._pendingActivationItem){this._cancelPendingActivation()}},get _tabContainerScrollSize(){return Math.max(0,this.$.tabsContainer.scrollWidth-this.$.tabsContainer.offsetWidth)},_scroll:function(e,detail){if(!this.scrollable){return}var ddx=detail&&-detail.ddx||0;this._affectScroll(ddx)},_down:function(e){this.async(function(){if(this._defaultFocusAsync){this.cancelAsync(this._defaultFocusAsync);this._defaultFocusAsync=null}},1)},_affectScroll:function(dx){this.$.tabsContainer.scrollLeft+=dx;var scrollLeft=this.$.tabsContainer.scrollLeft;this._leftHidden=scrollLeft===0;this._rightHidden=scrollLeft===this._tabContainerScrollSize},_onLeftScrollButtonDown:function(){this._scrollToLeft();this._holdJob=setInterval(this._scrollToLeft.bind(this),this._holdDelay)},_onRightScrollButtonDown:function(){this._scrollToRight();this._holdJob=setInterval(this._scrollToRight.bind(this),this._holdDelay)},_onScrollButtonUp:function(){clearInterval(this._holdJob);this._holdJob=null},_scrollToLeft:function(){this._affectScroll(-this._step)},_scrollToRight:function(){this._affectScroll(this._step)},_tabChanged:function(tab,old){if(!tab){this.$.selectionBar.classList.remove("expand");this.$.selectionBar.classList.remove("contract");this._positionBar(0,0);return}var r=this.$.tabsContent.getBoundingClientRect();var w=r.width;var tabRect=tab.getBoundingClientRect();var tabOffsetLeft=tabRect.left-r.left;this._pos={width:this._calcPercent(tabRect.width,w),left:this._calcPercent(tabOffsetLeft,w)};if(this.noSlide||old==null){this.$.selectionBar.classList.remove("expand");this.$.selectionBar.classList.remove("contract");this._positionBar(this._pos.width,this._pos.left);return}var oldRect=old.getBoundingClientRect();var oldIndex=this.items.indexOf(old);var index=this.items.indexOf(tab);var m=5;this.$.selectionBar.classList.add("expand");var moveRight=oldIndex<index;var isRTL=this._isRTL;if(isRTL){moveRight=!moveRight}if(moveRight){this._positionBar(this._calcPercent(tabRect.left+tabRect.width-oldRect.left,w)-m,this._left)}else{this._positionBar(this._calcPercent(oldRect.left+oldRect.width-tabRect.left,w)-m,this._calcPercent(tabOffsetLeft,w)+m)}if(this.scrollable){this._scrollToSelectedIfNeeded(tabRect.width,tabOffsetLeft)}},_scrollToSelectedIfNeeded:function(tabWidth,tabOffsetLeft){var l=tabOffsetLeft-this.$.tabsContainer.scrollLeft;if(l<0){this.$.tabsContainer.scrollLeft+=l}else{l+=tabWidth-this.$.tabsContainer.offsetWidth;if(l>0){this.$.tabsContainer.scrollLeft+=l}}},_calcPercent:function(w,w0){return 100*w/w0},_positionBar:function(width,left){width=width||0;left=left||0;this._width=width;this._left=left;this.transform("translateX("+left+"%) scaleX("+width/100+")",this.$.selectionBar)},_onBarTransitionEnd:function(e){var cl=this.$.selectionBar.classList;if(cl.contains("expand")){cl.remove("expand");cl.add("contract");this._positionBar(this._pos.width,this._pos.left)}else if(cl.contains("contract")){cl.remove("contract")}}});
\ No newline at end of file +Polymer({is:"cr-dialog","extends":"dialog",properties:{closeText:String,ignorePopstate:{type:Boolean,value:false}},ready:function(){window.addEventListener("popstate",function(){if(!this.ignorePopstate&&this.open)this.cancel()}.bind(this))},cancel:function(){this.fire("cancel");HTMLDialogElement.prototype.close.call(this,"")},close:function(opt_returnValue){HTMLDialogElement.prototype.close.call(this,"success")},getCloseButton:function(){return this.$.close}});Polymer({is:"app-drawer",properties:{opened:{type:Boolean,value:false,notify:true,reflectToAttribute:true},persistent:{type:Boolean,value:false,reflectToAttribute:true},align:{type:String,value:"left"},position:{type:String,readOnly:true,value:"left",reflectToAttribute:true},swipeOpen:{type:Boolean,value:false,reflectToAttribute:true},noFocusTrap:{type:Boolean,value:false}},observers:["resetLayout(position)","_resetPosition(align, isAttached)"],_translateOffset:0,_trackDetails:null,_drawerState:0,_boundEscKeydownHandler:null,_firstTabStop:null,_lastTabStop:null,ready:function(){this.setScrollDirection("y");this._setTransitionDuration("0s")},attached:function(){Polymer.RenderStatus.afterNextRender(this,function(){this._setTransitionDuration("");this._boundEscKeydownHandler=this._escKeydownHandler.bind(this);this._resetDrawerState();this.listen(this,"track","_track");this.addEventListener("transitionend",this._transitionend.bind(this));this.addEventListener("keydown",this._tabKeydownHandler.bind(this))})},detached:function(){document.removeEventListener("keydown",this._boundEscKeydownHandler)},open:function(){this.opened=true},close:function(){this.opened=false},toggle:function(){this.opened=!this.opened},getWidth:function(){return this.$.contentContainer.offsetWidth},resetLayout:function(){this.debounce("_resetLayout",function(){this.fire("app-drawer-reset-layout")},1)},_isRTL:function(){return window.getComputedStyle(this).direction==="rtl"},_resetPosition:function(){switch(this.align){case"start":this._setPosition(this._isRTL()?"right":"left");return;case"end":this._setPosition(this._isRTL()?"left":"right");return}this._setPosition(this.align)},_escKeydownHandler:function(event){var ESC_KEYCODE=27;if(event.keyCode===ESC_KEYCODE){event.preventDefault();this.close()}},_track:function(event){if(this.persistent){return}event.preventDefault();switch(event.detail.state){case"start":this._trackStart(event);break;case"track":this._trackMove(event);break;case"end":this._trackEnd(event);break}},_trackStart:function(event){this._drawerState=this._DRAWER_STATE.TRACKING;this._setTransitionDuration("0s");this.style.visibility="visible";var rect=this.$.contentContainer.getBoundingClientRect();if(this.position==="left"){this._translateOffset=rect.left}else{this._translateOffset=rect.right-window.innerWidth}this._trackDetails=[]},_trackMove:function(event){this._translateDrawer(event.detail.dx+this._translateOffset);this._trackDetails.push({dx:event.detail.dx,timeStamp:Date.now()})},_trackEnd:function(event){var x=event.detail.dx+this._translateOffset;var drawerWidth=this.getWidth();var isPositionLeft=this.position==="left";var isInEndState=isPositionLeft?x>=0||x<=-drawerWidth:x<=0||x>=drawerWidth;if(!isInEndState){var trackDetails=this._trackDetails;this._trackDetails=null;this._flingDrawer(event,trackDetails);if(this._drawerState===this._DRAWER_STATE.FLINGING){return}}var halfWidth=drawerWidth/2;if(event.detail.dx<-halfWidth){this.opened=this.position==="right"}else if(event.detail.dx>halfWidth){this.opened=this.position==="left"}if(isInEndState){this._resetDrawerState()}this._setTransitionDuration("");this._resetDrawerTranslate();this.style.visibility=""},_calculateVelocity:function(event,trackDetails){var now=Date.now();var timeLowerBound=now-100;var trackDetail;var min=0;var max=trackDetails.length-1;while(min<=max){var mid=min+max>>1;var d=trackDetails[mid];if(d.timeStamp>=timeLowerBound){trackDetail=d;max=mid-1}else{min=mid+1}}if(trackDetail){var dx=event.detail.dx-trackDetail.dx;var dt=now-trackDetail.timeStamp||1;return dx/dt}return 0},_flingDrawer:function(event,trackDetails){var velocity=this._calculateVelocity(event,trackDetails);if(Math.abs(velocity)<this._MIN_FLING_THRESHOLD){return}this._drawerState=this._DRAWER_STATE.FLINGING;var x=event.detail.dx+this._translateOffset;var drawerWidth=this.getWidth();var isPositionLeft=this.position==="left";var isVelocityPositive=velocity>0;var isClosingLeft=!isVelocityPositive&&isPositionLeft;var isClosingRight=isVelocityPositive&&!isPositionLeft;var dx;if(isClosingLeft){dx=-(x+drawerWidth)}else if(isClosingRight){dx=drawerWidth-x}else{dx=-x}if(isVelocityPositive){velocity=Math.max(velocity,this._MIN_TRANSITION_VELOCITY);this.opened=this.position==="left"}else{velocity=Math.min(velocity,-this._MIN_TRANSITION_VELOCITY);this.opened=this.position==="right"}this._setTransitionDuration(this._FLING_INITIAL_SLOPE*dx/velocity+"ms");this._setTransitionTimingFunction(this._FLING_TIMING_FUNCTION);this._resetDrawerTranslate()},_transitionend:function(event){var target=Polymer.dom(event).rootTarget;if(target===this.$.contentContainer||target===this.$.scrim){if(this._drawerState===this._DRAWER_STATE.FLINGING){this._setTransitionDuration("");this._setTransitionTimingFunction("");this.style.visibility=""}this._resetDrawerState()}},_setTransitionDuration:function(duration){this.$.contentContainer.style.transitionDuration=duration;this.$.scrim.style.transitionDuration=duration},_setTransitionTimingFunction:function(timingFunction){this.$.contentContainer.style.transitionTimingFunction=timingFunction;this.$.scrim.style.transitionTimingFunction=timingFunction},_translateDrawer:function(x){var drawerWidth=this.getWidth();if(this.position==="left"){x=Math.max(-drawerWidth,Math.min(x,0));this.$.scrim.style.opacity=1+x/drawerWidth}else{x=Math.max(0,Math.min(x,drawerWidth));this.$.scrim.style.opacity=1-x/drawerWidth}this.translate3d(x+"px","0","0",this.$.contentContainer)},_resetDrawerTranslate:function(){this.$.scrim.style.opacity="";this.transform("",this.$.contentContainer)},_resetDrawerState:function(){var oldState=this._drawerState;if(this.opened){this._drawerState=this.persistent?this._DRAWER_STATE.OPENED_PERSISTENT:this._DRAWER_STATE.OPENED}else{this._drawerState=this._DRAWER_STATE.CLOSED}if(oldState!==this._drawerState){if(this._drawerState===this._DRAWER_STATE.OPENED){this._setKeyboardFocusTrap();document.addEventListener("keydown",this._boundEscKeydownHandler);document.body.style.overflow="hidden"}else{document.removeEventListener("keydown",this._boundEscKeydownHandler);document.body.style.overflow=""}if(oldState!==this._DRAWER_STATE.INIT){this.fire("app-drawer-transitioned")}}},_setKeyboardFocusTrap:function(){if(this.noFocusTrap){return}var focusableElementsSelector=['a[href]:not([tabindex="-1"])','area[href]:not([tabindex="-1"])','input:not([disabled]):not([tabindex="-1"])','select:not([disabled]):not([tabindex="-1"])','textarea:not([disabled]):not([tabindex="-1"])','button:not([disabled]):not([tabindex="-1"])','iframe:not([tabindex="-1"])','[tabindex]:not([tabindex="-1"])','[contentEditable=true]:not([tabindex="-1"])'].join(",");var focusableElements=Polymer.dom(this).querySelectorAll(focusableElementsSelector);if(focusableElements.length>0){this._firstTabStop=focusableElements[0];this._lastTabStop=focusableElements[focusableElements.length-1]}else{this._firstTabStop=null;this._lastTabStop=null}var tabindex=this.getAttribute("tabindex");if(tabindex&&parseInt(tabindex,10)>-1){this.focus()}else if(this._firstTabStop){this._firstTabStop.focus()}},_tabKeydownHandler:function(event){if(this.noFocusTrap){return}var TAB_KEYCODE=9;if(this._drawerState===this._DRAWER_STATE.OPENED&&event.keyCode===TAB_KEYCODE){if(event.shiftKey){if(this._firstTabStop&&Polymer.dom(event).localTarget===this._firstTabStop){event.preventDefault();this._lastTabStop.focus()}}else{if(this._lastTabStop&&Polymer.dom(event).localTarget===this._lastTabStop){event.preventDefault();this._firstTabStop.focus()}}}},_MIN_FLING_THRESHOLD:.2,_MIN_TRANSITION_VELOCITY:1.2,_FLING_TIMING_FUNCTION:"cubic-bezier(0.667, 1, 0.667, 1)",_FLING_INITIAL_SLOPE:1.5,_DRAWER_STATE:{INIT:0,OPENED:1,OPENED_PERSISTENT:2,CLOSED:3,TRACKING:4,FLINGING:5}});Polymer({is:"paper-tab",behaviors:[Polymer.IronControlState,Polymer.IronButtonState,Polymer.PaperRippleBehavior],properties:{link:{type:Boolean,value:false,reflectToAttribute:true}},hostAttributes:{role:"tab"},listeners:{down:"_updateNoink",tap:"_onTap"},attached:function(){this._updateNoink()},get _parentNoink(){var parent=Polymer.dom(this).parentNode;return!!parent&&!!parent.noink},_updateNoink:function(){this.noink=!!this.noink||!!this._parentNoink},_onTap:function(event){if(this.link){var anchor=this.queryEffectiveChildren("a");if(!anchor){return}if(event.target===anchor){return}anchor.click()}}});Polymer.IronMenubarBehaviorImpl={hostAttributes:{role:"menubar"},keyBindings:{left:"_onLeftKey",right:"_onRightKey"},_onUpKey:function(event){this.focusedItem.click();event.detail.keyboardEvent.preventDefault()},_onDownKey:function(event){this.focusedItem.click();event.detail.keyboardEvent.preventDefault()},get _isRTL(){return window.getComputedStyle(this)["direction"]==="rtl"},_onLeftKey:function(event){if(this._isRTL){this._focusNext()}else{this._focusPrevious()}event.detail.keyboardEvent.preventDefault()},_onRightKey:function(event){if(this._isRTL){this._focusPrevious()}else{this._focusNext()}event.detail.keyboardEvent.preventDefault()},_onKeydown:function(event){if(this.keyboardEventMatchesKeys(event,"up down left right esc")){return}this._focusWithKeyboardEvent(event)}};Polymer.IronMenubarBehavior=[Polymer.IronMenuBehavior,Polymer.IronMenubarBehaviorImpl];Polymer({is:"paper-tabs",behaviors:[Polymer.IronResizableBehavior,Polymer.IronMenubarBehavior],properties:{noink:{type:Boolean,value:false,observer:"_noinkChanged"},noBar:{type:Boolean,value:false},noSlide:{type:Boolean,value:false},scrollable:{type:Boolean,value:false},fitContainer:{type:Boolean,value:false},disableDrag:{type:Boolean,value:false},hideScrollButtons:{type:Boolean,value:false},alignBottom:{type:Boolean,value:false},selectable:{type:String,value:"paper-tab"},autoselect:{type:Boolean,value:false},autoselectDelay:{type:Number,value:0},_step:{type:Number,value:10},_holdDelay:{type:Number,value:1},_leftHidden:{type:Boolean,value:false},_rightHidden:{type:Boolean,value:false},_previousTab:{type:Object}},hostAttributes:{role:"tablist"},listeners:{"iron-resize":"_onTabSizingChanged","iron-items-changed":"_onTabSizingChanged","iron-select":"_onIronSelect","iron-deselect":"_onIronDeselect"},keyBindings:{"left:keyup right:keyup":"_onArrowKeyup"},created:function(){this._holdJob=null;this._pendingActivationItem=undefined;this._pendingActivationTimeout=undefined;this._bindDelayedActivationHandler=this._delayedActivationHandler.bind(this);this.addEventListener("blur",this._onBlurCapture.bind(this),true)},ready:function(){this.setScrollDirection("y",this.$.tabsContainer)},detached:function(){this._cancelPendingActivation()},_noinkChanged:function(noink){var childTabs=Polymer.dom(this).querySelectorAll("paper-tab");childTabs.forEach(noink?this._setNoinkAttribute:this._removeNoinkAttribute)},_setNoinkAttribute:function(element){element.setAttribute("noink","")},_removeNoinkAttribute:function(element){element.removeAttribute("noink")},_computeScrollButtonClass:function(hideThisButton,scrollable,hideScrollButtons){if(!scrollable||hideScrollButtons){return"hidden"}if(hideThisButton){return"not-visible"}return""},_computeTabsContentClass:function(scrollable,fitContainer){return scrollable?"scrollable"+(fitContainer?" fit-container":""):" fit-container"},_computeSelectionBarClass:function(noBar,alignBottom){if(noBar){return"hidden"}else if(alignBottom){return"align-bottom"}return""},_onTabSizingChanged:function(){this.debounce("_onTabSizingChanged",function(){this._scroll();this._tabChanged(this.selectedItem)},10)},_onIronSelect:function(event){this._tabChanged(event.detail.item,this._previousTab);this._previousTab=event.detail.item;this.cancelDebouncer("tab-changed")},_onIronDeselect:function(event){this.debounce("tab-changed",function(){this._tabChanged(null,this._previousTab);this._previousTab=null},1)},_activateHandler:function(){this._cancelPendingActivation();Polymer.IronMenuBehaviorImpl._activateHandler.apply(this,arguments)},_scheduleActivation:function(item,delay){this._pendingActivationItem=item;this._pendingActivationTimeout=this.async(this._bindDelayedActivationHandler,delay)},_delayedActivationHandler:function(){var item=this._pendingActivationItem;this._pendingActivationItem=undefined;this._pendingActivationTimeout=undefined;item.fire(this.activateEvent,null,{bubbles:true,cancelable:true})},_cancelPendingActivation:function(){if(this._pendingActivationTimeout!==undefined){this.cancelAsync(this._pendingActivationTimeout);this._pendingActivationItem=undefined;this._pendingActivationTimeout=undefined}},_onArrowKeyup:function(event){if(this.autoselect){this._scheduleActivation(this.focusedItem,this.autoselectDelay)}},_onBlurCapture:function(event){if(event.target===this._pendingActivationItem){this._cancelPendingActivation()}},get _tabContainerScrollSize(){return Math.max(0,this.$.tabsContainer.scrollWidth-this.$.tabsContainer.offsetWidth)},_scroll:function(e,detail){if(!this.scrollable){return}var ddx=detail&&-detail.ddx||0;this._affectScroll(ddx)},_down:function(e){this.async(function(){if(this._defaultFocusAsync){this.cancelAsync(this._defaultFocusAsync);this._defaultFocusAsync=null}},1)},_affectScroll:function(dx){this.$.tabsContainer.scrollLeft+=dx;var scrollLeft=this.$.tabsContainer.scrollLeft;this._leftHidden=scrollLeft===0;this._rightHidden=scrollLeft===this._tabContainerScrollSize},_onLeftScrollButtonDown:function(){this._scrollToLeft();this._holdJob=setInterval(this._scrollToLeft.bind(this),this._holdDelay)},_onRightScrollButtonDown:function(){this._scrollToRight();this._holdJob=setInterval(this._scrollToRight.bind(this),this._holdDelay)},_onScrollButtonUp:function(){clearInterval(this._holdJob);this._holdJob=null},_scrollToLeft:function(){this._affectScroll(-this._step)},_scrollToRight:function(){this._affectScroll(this._step)},_tabChanged:function(tab,old){if(!tab){this.$.selectionBar.classList.remove("expand");this.$.selectionBar.classList.remove("contract");this._positionBar(0,0);return}var r=this.$.tabsContent.getBoundingClientRect();var w=r.width;var tabRect=tab.getBoundingClientRect();var tabOffsetLeft=tabRect.left-r.left;this._pos={width:this._calcPercent(tabRect.width,w),left:this._calcPercent(tabOffsetLeft,w)};if(this.noSlide||old==null){this.$.selectionBar.classList.remove("expand");this.$.selectionBar.classList.remove("contract");this._positionBar(this._pos.width,this._pos.left);return}var oldRect=old.getBoundingClientRect();var oldIndex=this.items.indexOf(old);var index=this.items.indexOf(tab);var m=5;this.$.selectionBar.classList.add("expand");var moveRight=oldIndex<index;var isRTL=this._isRTL;if(isRTL){moveRight=!moveRight}if(moveRight){this._positionBar(this._calcPercent(tabRect.left+tabRect.width-oldRect.left,w)-m,this._left)}else{this._positionBar(this._calcPercent(oldRect.left+oldRect.width-tabRect.left,w)-m,this._calcPercent(tabOffsetLeft,w)+m)}if(this.scrollable){this._scrollToSelectedIfNeeded(tabRect.width,tabOffsetLeft)}},_scrollToSelectedIfNeeded:function(tabWidth,tabOffsetLeft){var l=tabOffsetLeft-this.$.tabsContainer.scrollLeft;if(l<0){this.$.tabsContainer.scrollLeft+=l}else{l+=tabWidth-this.$.tabsContainer.offsetWidth;if(l>0){this.$.tabsContainer.scrollLeft+=l}}},_calcPercent:function(w,w0){return 100*w/w0},_positionBar:function(width,left){width=width||0;left=left||0;this._width=width;this._left=left;this.transform("translateX("+left+"%) scaleX("+width/100+")",this.$.selectionBar)},_onBarTransitionEnd:function(e){var cl=this.$.selectionBar.classList;if(cl.contains("expand")){cl.remove("expand");cl.add("contract");this._positionBar(this._pos.width,this._pos.left)}else if(cl.contains("contract")){cl.remove("contract")}}});
\ No newline at end of file diff --git a/chromium/chrome/browser/resources/md_history/lazy_load.html b/chromium/chrome/browser/resources/md_history/lazy_load.html index 35df3369ad7..0b489d2572e 100644 --- a/chromium/chrome/browser/resources/md_history/lazy_load.html +++ b/chromium/chrome/browser/resources/md_history/lazy_load.html @@ -4,7 +4,6 @@ <link rel="import" href="chrome://resources/cr_elements/cr_shared_menu/cr_shared_menu.html"> <link rel="import" href="chrome://resources/polymer/v1_0/app-layout/app-drawer/app-drawer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-tabs/paper-tab.html"> diff --git a/chromium/chrome/browser/resources/md_history/lazy_load.vulcanized.html b/chromium/chrome/browser/resources/md_history/lazy_load.vulcanized.html index 9aaca4b2b1f..9c958e047d9 100644 --- a/chromium/chrome/browser/resources/md_history/lazy_load.vulcanized.html +++ b/chromium/chrome/browser/resources/md_history/lazy_load.vulcanized.html @@ -679,6 +679,7 @@ button.more-vert-button div { :host { margin: var(--card-sizing_-_margin); max-width: var(--card-sizing_-_max-width); min-width: var(--card-sizing_-_min-width); padding: var(--card-sizing_-_padding); width: var(--card-sizing_-_width); + -webkit-tap-highlight-color: transparent; display: block; padding-bottom: var(--card-padding-between); } @@ -1096,7 +1097,7 @@ paper-spinner { </style> <div class="title-container"> <content select=".title"></content> - <paper-icon-button icon="cr:clear" on-tap="cancel" id="close"> + <paper-icon-button icon="cr:clear" on-tap="cancel" id="close" aria-label$="[[closeText]]"> </paper-icon-button> </div> <div class="body-container"> @@ -1225,184 +1226,6 @@ paper-spinner { </template> </dom-module> -<dom-module id="paper-checkbox" assetpath="chrome://resources/polymer/v1_0/paper-checkbox/" css-build="shadow"> - <template strip-whitespace=""> - <style scope="paper-checkbox">:host { - display: inline-block; - white-space: nowrap; - cursor: pointer; - --calculated-paper-checkbox-size: var(--paper-checkbox-size, 18px); - - --calculated-paper-checkbox-ink-size: var(--paper-checkbox-ink-size, -1px); - font-family: var(--paper-font-common-base_-_font-family); -webkit-font-smoothing: var(--paper-font-common-base_-_-webkit-font-smoothing); - line-height: 0; - -webkit-tap-highlight-color: transparent; -} - -:host([hidden]) { - display: none !important; -} - -:host(:focus) { - outline: none; -} - -.hidden { - display: none; -} - -#checkboxContainer { - display: inline-block; - position: relative; - width: var(--calculated-paper-checkbox-size); - height: var(--calculated-paper-checkbox-size); - min-width: var(--calculated-paper-checkbox-size); - margin: var(--paper-checkbox-margin, initial); - vertical-align: var(--paper-checkbox-vertical-align, middle); - background-color: var(--paper-checkbox-unchecked-background-color, transparent); -} - -#ink { - position: absolute; - - - top: calc(0px - (var(--calculated-paper-checkbox-ink-size) - var(--calculated-paper-checkbox-size)) / 2); - left: calc(0px - (var(--calculated-paper-checkbox-ink-size) - var(--calculated-paper-checkbox-size)) / 2); - width: var(--calculated-paper-checkbox-ink-size); - height: var(--calculated-paper-checkbox-ink-size); - color: var(--paper-checkbox-unchecked-ink-color, var(--primary-text-color)); - opacity: 0.6; - pointer-events: none; -} - -:host-context([dir="rtl"]) #ink { - right: calc(0px - (var(--calculated-paper-checkbox-ink-size) - var(--calculated-paper-checkbox-size)) / 2); - left: auto; -} - -#ink[checked] { - color: var(--paper-checkbox-checked-ink-color, var(--primary-color)); -} - -#checkbox { - position: relative; - box-sizing: border-box; - height: 100%; - border: solid 2px; - border-color: var(--paper-checkbox-unchecked-color, var(--primary-text-color)); - border-radius: 2px; - pointer-events: none; - -webkit-transition: background-color 140ms, border-color 140ms; - transition: background-color 140ms, border-color 140ms; -} - -#checkbox.checked #checkmark { - -webkit-animation: checkmark-expand 140ms ease-out forwards; - animation: checkmark-expand 140ms ease-out forwards; -} - -@-webkit-keyframes checkmark-expand { -0% { - -webkit-transform: scale(0, 0) rotate(45deg); -} - -100% { - -webkit-transform: scale(1, 1) rotate(45deg); -} - -} - -@keyframes checkmark-expand { -0% { - transform: scale(0, 0) rotate(45deg); -} - -100% { - transform: scale(1, 1) rotate(45deg); -} - -} - -#checkbox.checked { - background-color: var(--paper-checkbox-checked-color, var(--primary-color)); - border-color: var(--paper-checkbox-checked-color, var(--primary-color)); -} - -#checkmark { - position: absolute; - width: 36%; - height: 70%; - border-style: solid; - border-top: none; - border-left: none; - border-right-width: calc(2/15 * var(--calculated-paper-checkbox-size)); - border-bottom-width: calc(2/15 * var(--calculated-paper-checkbox-size)); - border-color: var(--paper-checkbox-checkmark-color, white); - -webkit-transform-origin: 97% 86%; - transform-origin: 97% 86%; - box-sizing: content-box; -} - -:host-context([dir="rtl"]) #checkmark { - -webkit-transform-origin: 50% 14%; - transform-origin: 50% 14%; -} - -#checkboxLabel { - position: relative; - display: inline-block; - vertical-align: middle; - padding-left: var(--paper-checkbox-label-spacing, 8px); - white-space: normal; - line-height: normal; - color: var(--paper-checkbox-label-color, var(--primary-text-color)); - ; -} - -:host([checked]) #checkboxLabel { - color: var(--paper-checkbox-label-checked-color, var(--paper-checkbox-label-color, var(--primary-text-color))); - ; -} - -:host-context([dir="rtl"]) #checkboxLabel { - padding-right: var(--paper-checkbox-label-spacing, 8px); - padding-left: 0; -} - -#checkboxLabel[hidden] { - display: none; -} - -:host([disabled]) #checkbox { - opacity: 0.5; - border-color: var(--paper-checkbox-unchecked-color, var(--primary-text-color)); -} - -:host([disabled][checked]) #checkbox { - background-color: var(--paper-checkbox-unchecked-color, var(--primary-text-color)); - opacity: 0.5; -} - -:host([disabled]) #checkboxLabel { - opacity: 0.65; -} - -#checkbox.invalid:not(.checked) { - border-color: var(--paper-checkbox-error-color, var(--error-color)); -} - -</style> - - <div id="checkboxContainer"> - <div id="checkbox" class$="[[_computeCheckboxClass(checked, invalid)]]"> - <div id="checkmark" class$="[[_computeCheckmarkClass(checked)]]"></div> - </div> - </div> - - <div id="checkboxLabel"><content></content></div> - </template> - - </dom-module> <dom-module id="paper-tab" assetpath="chrome://resources/polymer/v1_0/paper-tabs/" css-build="shadow"> <template> <style scope="paper-tab">:host { diff --git a/chromium/chrome/browser/resources/md_history/list_container.html b/chromium/chrome/browser/resources/md_history/list_container.html index 61df4607d4a..d28fac588e0 100644 --- a/chromium/chrome/browser/resources/md_history/list_container.html +++ b/chromium/chrome/browser/resources/md_history/list_container.html @@ -64,6 +64,7 @@ $i18n{moreFromSite} </paper-item> <paper-item id="menuRemoveButton" class="menu-item" + disabled="[[!canDeleteHistory_()]]" on-tap="onRemoveFromHistoryTap_"> $i18n{removeFromHistory} </paper-item> diff --git a/chromium/chrome/browser/resources/md_history/list_container.js b/chromium/chrome/browser/resources/md_history/list_container.js index b418b0ce74a..613fa147a81 100644 --- a/chromium/chrome/browser/resources/md_history/list_container.js +++ b/chromium/chrome/browser/resources/md_history/list_container.js @@ -263,8 +263,8 @@ Polymer({ var browserService = md_history.BrowserService.getInstance(); browserService.recordHistogram( - 'HistoryPage.RemoveEntryPosition', index, - UMA_MAX_BUCKET_VALUE); + 'HistoryPage.RemoveEntryPosition', + Math.min(index, UMA_MAX_BUCKET_VALUE), UMA_MAX_BUCKET_VALUE); if (index <= UMA_MAX_SUBSET_BUCKET_VALUE) { browserService.recordHistogram( 'HistoryPage.RemoveEntryPositionSubset', index, @@ -279,4 +279,9 @@ Polymer({ * @private */ getSelectedList_: function() { return this.$.content.selectedItem; }, + + /** @private */ + canDeleteHistory_: function() { + return loadTimeData.getBoolean('allowDeletingHistory'); + } }); diff --git a/chromium/chrome/browser/resources/md_history/side_bar.html b/chromium/chrome/browser/resources/md_history/side_bar.html index 7dbcc88b399..c4c8254cf94 100644 --- a/chromium/chrome/browser/resources/md_history/side_bar.html +++ b/chromium/chrome/browser/resources/md_history/side_bar.html @@ -11,14 +11,20 @@ <template> <style include="shared-style"> :host { - display: block; + display: flex; height: 100%; - padding-top: 5px; + overflow-x: hidden; + overflow-y: auto; width: var(--side-bar-width); } + :host([drawer]) { + height: calc(100% - var(--toolbar-height)); + } + div.separator { background-color: rgba(0, 0, 0, 0.08); + flex-shrink: 0; height: 1px; margin: 8px 0; } @@ -28,7 +34,7 @@ } #clear-browsing-data iron-icon { - -webkit-margin-end: 24px; + -webkit-margin-end: 20px; color: var(--paper-grey-400); height: 20px; margin-bottom: 10px; @@ -40,10 +46,16 @@ -webkit-user-select: none; background-color: transparent; color: #5a5a5a; + display: flex; + flex: 1; + flex-direction: column; + padding-top: 8px; } iron-selector > a { @apply(--paper-font-subhead); + /* Ensure the focus outline appears correctly (crbug.com/655503). */ + -webkit-margin-end: 4px; -webkit-padding-start: 24px; align-items: center; box-sizing: border-box; @@ -59,22 +71,17 @@ iron-selector > a.iron-selected { color: var(--google-blue-500); - font-weight: 500; + } + + #spacer { + flex: 1; } #footer { - bottom: 0; color: var(--paper-grey-600); - position: absolute; width: var(--side-bar-width); } - :host([drawer]) #footer { - /* This compensates the 120px by which app-drawer protrudes under - * the viewport. */ - bottom: 120px; - } - #footer-text { -webkit-padding-end: 16px; -webkit-padding-start: 24px; @@ -108,6 +115,7 @@ <iron-icon icon="cr:open-in-new"></iron-icon> <paper-ripple id="cbd-ripple"></paper-ripple> </a> + <div id="spacer"></div> <div id="footer" hidden="[[!showFooter]]"> <div class="separator"></div> <div id="footer-text">$i18nRaw{sidebarFooter}</div> diff --git a/chromium/chrome/browser/resources/md_history/synced_device_card.html b/chromium/chrome/browser/resources/md_history/synced_device_card.html index 9d50c2a52a6..c7fa695ccaa 100644 --- a/chromium/chrome/browser/resources/md_history/synced_device_card.html +++ b/chromium/chrome/browser/resources/md_history/synced_device_card.html @@ -16,6 +16,7 @@ <style include="shared-style"> :host { @apply(--card-sizing); + -webkit-tap-highlight-color: transparent; display: block; padding-bottom: var(--card-padding-between); } diff --git a/chromium/chrome/browser/resources/md_user_manager/create_profile.html b/chromium/chrome/browser/resources/md_user_manager/create_profile.html index 695fc6e7b20..4f93af6344a 100644 --- a/chromium/chrome/browser/resources/md_user_manager/create_profile.html +++ b/chromium/chrome/browser/resources/md_user_manager/create_profile.html @@ -97,6 +97,10 @@ margin-top: 24px; } + paper-checkbox + paper-checkbox { + margin-top: 16px; + } + #supervised-user-container { -webkit-padding-start: 32px; } @@ -156,7 +160,11 @@ <cr-profile-avatar-selector avatars="[[availableIcons_]]" selected-avatar-url="{{profileIconUrl_}}"> </cr-profile-avatar-selector> - <paper-checkbox checked="{{isSupervised_}}"> + <paper-checkbox id="createShortcutCheckbox" checked="{{createShortcut_}}" + hidden="[[!isProfileShortcutsEnabled_]]"> + $i18n{createDesktopShortcutLabel} + </paper-checkbox> + <paper-checkbox id="makeSupervisedCheckbox" checked="{{isSupervised_}}"> $i18n{manageProfilesSupervisedSignedInLabel} </paper-checkbox> <div id="supervised-user-container"> diff --git a/chromium/chrome/browser/resources/md_user_manager/create_profile.js b/chromium/chrome/browser/resources/md_user_manager/create_profile.js index d997d9e4567..ea4c28f2f00 100644 --- a/chromium/chrome/browser/resources/md_user_manager/create_profile.js +++ b/chromium/chrome/browser/resources/md_user_manager/create_profile.js @@ -90,6 +90,15 @@ Polymer({ }, /** + * if true, a desktop shortcut will be created for the new profile. + * @private {boolean} + */ + createShortcut_: { + type: Boolean, + value: true + }, + + /** * True if the new profile is a supervised profile. * @private {boolean} */ @@ -117,7 +126,19 @@ Polymer({ }, /** @private {!signin.ProfileBrowserProxy} */ - browserProxy_: Object + browserProxy_: Object, + + /** + * True if the profile shortcuts feature is enabled. + * @private + */ + isProfileShortcutsEnabled_: { + type: Boolean, + value: function() { + return loadTimeData.getBoolean('profileShortcutsEnabled'); + }, + readOnly: true + } }, listeners: { @@ -354,9 +375,11 @@ Polymer({ } this.hideMessage_(); this.createInProgress_ = true; + var createShortcut = this.isProfileShortcutsEnabled_ && + this.createShortcut_; this.browserProxy_.createProfile( - this.profileName_, this.profileIconUrl_, this.isSupervised_, '', - custodianProfilePath); + this.profileName_, this.profileIconUrl_, createShortcut, + this.isSupervised_, '', custodianProfilePath); }, /** @@ -371,9 +394,10 @@ Polymer({ var signedInUser = event.detail.signedInUser; this.hideMessage_(); this.createInProgress_ = true; + var createShortcut = this.isProfileShortcutsEnabled_; this.browserProxy_.createProfile( - supervisedUser.name, supervisedUser.iconURL, true, supervisedUser.id, - signedInUser.profilePath); + supervisedUser.name, supervisedUser.iconURL, createShortcut, + true /* isSupervised */, supervisedUser.id, signedInUser.profilePath); }, /** diff --git a/chromium/chrome/browser/resources/md_user_manager/profile_browser_proxy.js b/chromium/chrome/browser/resources/md_user_manager/profile_browser_proxy.js index 57a55d3dfd6..1712a8a16d0 100644 --- a/chromium/chrome/browser/resources/md_user_manager/profile_browser_proxy.js +++ b/chromium/chrome/browser/resources/md_user_manager/profile_browser_proxy.js @@ -67,14 +67,16 @@ cr.define('signin', function() { * @param {string} profileName Name of the new profile. * @param {string} profileIconUrl URL of the selected icon of the new * profile. + * @param {boolean} createShortcut if true a desktop shortcut will be + * created. * @param {boolean} isSupervised True if the new profile is supervised. * @param {string} supervisedUserId ID of the supervised user to be * imported. * @param {string} custodianProfilePath Profile path of the custodian if * the new profile is supervised. */ - createProfile: function(profileName, profileIconUrl, isSupervised, - supervisedUserId, custodianProfilePath) { + createProfile: function(profileName, profileIconUrl, createShortcut, + isSupervised, supervisedUserId, custodianProfilePath) { assertNotReached(); }, @@ -175,10 +177,10 @@ cr.define('signin', function() { }, /** @override */ - createProfile: function(profileName, profileIconUrl, isSupervised, - supervisedUserId, custodianProfilePath) { + createProfile: function(profileName, profileIconUrl, createShortcut, + isSupervised, supervisedUserId, custodianProfilePath) { chrome.send('createProfile', - [profileName, profileIconUrl, false, isSupervised, + [profileName, profileIconUrl, createShortcut, isSupervised, supervisedUserId, custodianProfilePath]); }, diff --git a/chromium/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.css b/chromium/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.css index d42ac9cb5c4..b1ae7f97ad1 100644 --- a/chromium/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.css +++ b/chromium/chrome/browser/resources/media_router/elements/media_router_container/media_router_container.css @@ -39,6 +39,7 @@ #device-missing a { color: var(--paper-blue-700); margin: 8px 0; + text-align: center; text-decoration: none; } diff --git a/chromium/chrome/browser/resources/media_router/elements/route_details/route_details.css b/chromium/chrome/browser/resources/media_router/elements/route_details/route_details.css index eaff052bf52..d2207455dee 100644 --- a/chromium/chrome/browser/resources/media_router/elements/route_details/route_details.css +++ b/chromium/chrome/browser/resources/media_router/elements/route_details/route_details.css @@ -5,7 +5,7 @@ #custom-controller { display: inline-block; - height: 136px; + height: 142px; width: 100%; } diff --git a/chromium/chrome/browser/resources/net_internals/log_view_painter.js b/chromium/chrome/browser/resources/net_internals/log_view_painter.js index 5969699e9ad..228de543abb 100644 --- a/chromium/chrome/browser/resources/net_internals/log_view_painter.js +++ b/chromium/chrome/browser/resources/net_internals/log_view_painter.js @@ -251,7 +251,7 @@ function writeParameters(entry, privacyStripping, out) { } // Use any parameter writer available for this event type. - var paramsWriter = getParamaterWriterForEventType(entry.type); + var paramsWriter = getParameterWriterForEventType(entry.type); var consumedParams = {}; if (paramsWriter) paramsWriter(entry, out, consumedParams); @@ -274,7 +274,7 @@ function writeParameters(entry, privacyStripping, out) { * consumed. If no writer is available for |eventType| then * returns null. */ -function getParamaterWriterForEventType(eventType) { +function getParameterWriterForEventType(eventType) { switch (eventType) { case EventType.HTTP_TRANSACTION_SEND_REQUEST_HEADERS: case EventType.HTTP_TRANSACTION_SEND_TUNNEL_HEADERS: @@ -287,8 +287,9 @@ function getParamaterWriterForEventType(eventType) { case EventType.CERT_VERIFIER_JOB: case EventType.SSL_CERTIFICATES_RECEIVED: return writeParamsForCertificates; + case EventType.CERT_CT_COMPLIANCE_CHECKED: case EventType.EV_CERT_CT_COMPLIANCE_CHECKED: - return writeParamsForCheckedEVCertificates; + return writeParamsForCheckedCertificates; case EventType.SSL_VERSION_FALLBACK: return writeParamsForSSLVersionFallback; @@ -650,7 +651,7 @@ function writeParamsForCertificates(entry, out, consumedParams) { } -function writeParamsForCheckedEVCertificates(entry, out, consumedParams) { +function writeParamsForCheckedCertificates(entry, out, consumedParams) { if (typeof(entry.params.certificate) == 'object') writeCertificateParam( entry.params.certificate, out, consumedParams, 'certificate'); diff --git a/chromium/chrome/browser/resources/ntp4/apps_page.js b/chromium/chrome/browser/resources/ntp4/apps_page.js index e1f4a0050fb..9e7b71e6d40 100644 --- a/chromium/chrome/browser/resources/ntp4/apps_page.js +++ b/chromium/chrome/browser/resources/ntp4/apps_page.js @@ -396,13 +396,8 @@ cr.define('ntp', function() { onClick_: function(e) { if (/** @type {MouseEvent} */(e).button > 1) return; - var url = !this.appData_.is_webstore ? '' : - appendParam(this.appData_.url, - 'utm_source', - 'chrome-ntp-icon'); - chrome.send('launchApp', - [this.appId, APP_LAUNCH.NTP_APPS_MAXIMIZED, url, + [this.appId, APP_LAUNCH.NTP_APPS_MAXIMIZED, 'chrome-ntp-icon', e.button, e.altKey, e.ctrlKey, e.metaKey, e.shiftKey]); // Don't allow the click to trigger a link or anything @@ -709,9 +704,9 @@ cr.define('ntp', function() { if (html) { // It's important that we don't attach this node to the document // because it might contain scripts. - var node = this.ownerDocument.createElement('div'); - node.innerHTML = html; - title = node.textContent; + var doc = document.implementation.createHTMLDocument(); + doc.body.innerHTML = html; + title = doc.body.textContent; } // Make sure title is >=1 and <=45 characters for Chrome app limits. diff --git a/chromium/chrome/browser/resources/ntp4/new_tab_theme.css b/chromium/chrome/browser/resources/ntp4/new_tab_theme.css index f5a66984bd8..56bb6889f34 100644 --- a/chromium/chrome/browser/resources/ntp4/new_tab_theme.css +++ b/chromium/chrome/browser/resources/ntp4/new_tab_theme.css @@ -78,11 +78,6 @@ body { background-color: $i18n{colorBackground}; } -.thumbnail-wrapper { - /* This shows through at the (rounded) thumbnail's corners. */ - background-color: $i18n{colorSectionBorder}; -} - .filler .thumbnail { border-color: $i18n{colorBackground}; } diff --git a/chromium/chrome/browser/resources/omnibox/omnibox.js b/chromium/chrome/browser/resources/omnibox/omnibox.js index 860ac7f4552..7fa1ef5ce49 100644 --- a/chromium/chrome/browser/resources/omnibox/omnibox.js +++ b/chromium/chrome/browser/resources/omnibox/omnibox.js @@ -407,19 +407,6 @@ } } - /** - * Helper to convert callback-based define() API to a promise-based API. - * @param {!Array<string>} moduleNames - * @return {!Promise} - */ - function importModules(moduleNames) { - return new Promise(function(resolve, reject) { - define(moduleNames, function(var_args) { - resolve(Array.prototype.slice.call(arguments, 0)); - }); - }); - } - // NOTE: Need to keep a global reference to the |pageImpl| such that it is not // garbage collected, which causes the pipe to close and future calls from C++ // to JS to get dropped. diff --git a/chromium/chrome/browser/resources/options/browser_options.html b/chromium/chrome/browser/resources/options/browser_options.html index 7c7f962c89e..56c1ddd86f2 100644 --- a/chromium/chrome/browser/resources/options/browser_options.html +++ b/chromium/chrome/browser/resources/options/browser_options.html @@ -134,7 +134,7 @@ </button> </span> <button id="storage-manager-button" - i18n-content="storageManagerButtonTitle" hidden> + i18n-content="storageManagerButtonTitle"> </button> </div> <div id="stylus-row" hidden> @@ -404,13 +404,12 @@ <div class="checkbox controlled-setting-with-label"> <label> <input + id="safeBrowsingExtendedReportingCheckbox" metric="Options_SafeBrowsingExtendedReportingCheckbox" - pref="safebrowsing.extended_reporting_enabled" type="checkbox"> <span> <span i18n-content="safeBrowsingEnableExtendedReporting"></span> - <span class="controlled-setting-indicator" - pref="safebrowsing.extended_reporting_enabled"></span> + <span class="controlled-setting-indicator"></span> </span> </label> </div> @@ -762,6 +761,21 @@ </if> </div> </section> +<if expr="chromeos"> + <section id="cups-printers-section" hidden> + <h3 i18n-content="advancedSectionTitleCupsPrint"></h3> + <div class="settings-row"> + <span i18n-content="cupsPrintOptionLabel"></span> + <a target="_blank" i18n-content="learnMore" + i18n-values="href:cupsPrintLearnMoreURL"> + </a> + </div> + <div class="settings-row"> + <button id="cupsPrintersManageButton" + i18n-content="cupsPrintersManageButton"></button> + </div> + </section> +</if> <if expr="enable_service_discovery"> <section id="cloudprint-options-mdns"> <h3 i18n-content="advancedSectionTitleCloudPrint"></h3> @@ -951,7 +965,7 @@ aria-labelledby="accessibility-autoclick-label" pref="settings.a11y.autoclick_delay_ms"> <!-- i18n strings contain the autoclick duration; if the autoclick - timing gets changed, then the 18n strings also needs to be + timing gets changed, then the i18n strings also needs to be updated. --> <option value="600" i18n-content="autoclickDelayExtremelyShort"></option> diff --git a/chromium/chrome/browser/resources/options/browser_options.js b/chromium/chrome/browser/resources/options/browser_options.js index e546ef636ff..b6294677663 100644 --- a/chromium/chrome/browser/resources/options/browser_options.js +++ b/chromium/chrome/browser/resources/options/browser_options.js @@ -6,6 +6,7 @@ cr.exportPath('options'); /** * @typedef {{actionLinkText: (string|undefined), + * accountInfo: (string|undefined), * childUser: (boolean|undefined), * hasError: (boolean|undefined), * hasUnrecoverableError: (boolean|undefined), @@ -15,6 +16,7 @@ cr.exportPath('options'); * signedIn: (boolean|undefined), * signinAllowed: (boolean|undefined), * signoutAllowed: (boolean|undefined), + * statusAction: (string|undefined), * statusText: (string|undefined), * supervisedUser: (boolean|undefined), * syncSystemEnabled: (boolean|undefined)}} @@ -361,14 +363,11 @@ cr.define('options', function() { chrome.send('coreOptionsUserMetricsAction', ['Options_ShowTouchpadSettings']); }; - if (loadTimeData.getBoolean('enableStorageManager')) { - $('storage-manager-button').hidden = false; - $('storage-manager-button').onclick = function(evt) { - PageManager.showPageByName('storage'); - chrome.send('coreOptionsUserMetricsAction', - ['Options_ShowStorageManager']); - }; - } + $('storage-manager-button').onclick = function(evt) { + PageManager.showPageByName('storage'); + chrome.send('coreOptionsUserMetricsAction', + ['Options_ShowStorageManager']); + }; } // Search section. @@ -681,6 +680,10 @@ cr.define('options', function() { chrome.send('defaultZoomFactorAction', [String(event.target.options[event.target.selectedIndex].value)]); }; + $('safeBrowsingExtendedReportingCheckbox').onchange = function(event) { + chrome.send('safeBrowsingExtendedReportingAction', + [event.target.checked]); + }; // Languages section. var showLanguageOptions = function(event) { @@ -718,6 +721,16 @@ cr.define('options', function() { }; } + // CUPS Print section (CrOS only). + if (cr.isChromeOS) { + if (loadTimeData.getBoolean('cupsPrintEnabled')) { + $('cups-printers-section').hidden = false; + $('cupsPrintersManageButton').onclick = function() { + chrome.send('showCupsPrintDevicesPage'); + }; + } + } + if (loadTimeData.getBoolean('cloudPrintShowMDnsOptions')) { $('cloudprint-options-mdns').hidden = false; $('cloudPrintDevicesPageButton').onclick = function() { @@ -1191,6 +1204,9 @@ cr.define('options', function() { loadTimeData.getString('syncButtonTextSignIn'); $('start-stop-sync-indicator').hidden = signInButton.hidden; + $('account-info').textContent = syncData.accountInfo; + $('account-info').hidden = !this.signedIn_; + // TODO(estade): can this just be textContent? $('sync-status-text').innerHTML = syncData.statusText; var statusSet = syncData.statusText.length != 0; @@ -1205,13 +1221,34 @@ cr.define('options', function() { $('sync-action-link').disabled = syncData.managed || !syncData.syncSystemEnabled; - // On Chrome OS, sign out the user and sign in again to get fresh - // credentials on auth errors. $('sync-action-link').onclick = function(event) { - if (cr.isChromeOS && syncData.hasError) - SyncSetupOverlay.doSignOutOnAuthError(); - else - SyncSetupOverlay.showSetupUI(); + switch (syncData.statusAction) { + case 'reauthenticate': + SyncSetupOverlay.startSignIn(false /* creatingSupervisedUser */); + break; + case 'signOutAndSignIn': +<if expr="chromeos"> + // On Chrome OS, sign out the user and sign in again to get fresh + // credentials on auth errors. + SyncSetupOverlay.doSignOutOnAuthError(); +</if> +<if expr="not chromeos"> + if (syncData.signoutAllowed) { + // Silently sign the user out without deleting their profile and + // prompt them to sign back in. + chrome.send('SyncSetupStopSyncing', [false /* deleteProfile */]); + SyncSetupOverlay.startSignIn(false /* creatingSupervisedUser */); + } else { + chrome.send('showDisconnectManagedProfileDialog'); + } +</if> + break; + case 'upgradeClient': + PageManager.showPageByName('help'); + break; + default: + SyncSetupOverlay.showSetupUI(); + } }; if (syncData.hasError) @@ -1887,6 +1924,15 @@ cr.define('options', function() { }, /** + * Set the checked state of the Safe Browsing Extended Reporting Enabled + * checkbox. + * @private + */ + setExtendedReportingEnabledCheckboxState_: function(checked) { + $('safeBrowsingExtendedReportingCheckbox').checked = checked; + }, + + /** * Set network prediction checkbox value. * * @param {{value: number, disabled: boolean}} pref Information about @@ -2349,27 +2395,28 @@ cr.define('options', function() { 'removeBluetoothDevice', 'scrollToSection', 'setAccountPictureManaged', - 'setWallpaperManaged', + 'setAllHotwordSectionsVisible', + 'setAudioHistorySectionVisible', 'setAutoOpenFileTypesDisplayed', 'setCanSetTime', + 'setExtendedReportingEnabledCheckboxState', 'setFontSize', + 'setHighContrastCheckboxState', 'setHotwordRetrainLinkVisible', + 'setMetricsReportingCheckboxState', + 'setMetricsReportingSettingVisibility', 'setNativeThemeButtonEnabled', 'setNetworkPredictionValue', 'setNowSectionVisible', - 'setHighContrastCheckboxState', - 'setAllHotwordSectionsVisible', - 'setMetricsReportingCheckboxState', - 'setMetricsReportingSettingVisibility', 'setProfilesInfo', 'setSpokenFeedbackCheckboxState', - 'setSystemTimezoneManaged', 'setSystemTimezoneAutomaticDetectionManaged', + 'setSystemTimezoneManaged', 'setThemesResetButtonEnabled', 'setVirtualKeyboardCheckboxState', + 'setWallpaperManaged', 'setupPageZoomSelector', 'setupProxySettingsButton', - 'setAudioHistorySectionVisible', 'showCreateProfileError', 'showCreateProfileSuccess', 'showCreateProfileWarning', diff --git a/chromium/chrome/browser/resources/options/content_settings.html b/chromium/chrome/browser/resources/options/content_settings.html index 1ce3c99e981..149be9d1553 100644 --- a/chromium/chrome/browser/resources/options/content_settings.html +++ b/chromium/chrome/browser/resources/options/content_settings.html @@ -624,30 +624,6 @@ </div> </div> </section> - <!-- Fullscreen filter --> - <!-- TODO(mgiuca): Delete this once per-site data deleted. - https://crbug.com/591896 --> - <section id="fullscreen-section"> - <h3 i18n-content="fullscreenTabLabel"></h3> - <p i18n-content="fullscreenDeprecated"></p> - <div class="settings-row"> - <button class="exceptions-list-button" contentType="fullscreen" - i18n-content="manageExceptions"></button> - </div> - </section> - <!-- Mouse Lock filter --> - <!-- TODO(mgiuca): Delete this once per-site data deleted. - https://crbug.com/591896 --> - <section id="mouselock-section"> - <h3 i18n-content="mouselockTabLabel"></h3> - <p i18n-content="mouselockDeprecated"></p> - <div> - <div class="settings-row"> - <button class="exceptions-list-button" contentType="mouselock" - i18n-content="manageExceptions"></button> - </div> - </div> - </section> <!-- PDF Plugin filter --> <section id="pdf-section"> <h3 i18n-content="pdfTabLabel" class="content-settings-header"></h3> diff --git a/chromium/chrome/browser/resources/options/content_settings_exceptions_area.html b/chromium/chrome/browser/resources/options/content_settings_exceptions_area.html index 4a16f4cfd87..7dfad1c5819 100644 --- a/chromium/chrome/browser/resources/options/content_settings_exceptions_area.html +++ b/chromium/chrome/browser/resources/options/content_settings_exceptions_area.html @@ -69,22 +69,6 @@ <div contentType="notifications"> <list mode="normal"></list> </div> - <div contentType="fullscreen"> - <list mode="normal"></list> - <div> - <span class="otr-explanation" i18n-content="otrExceptionsExplanation"> - </span> - <list mode="otr"></list> - </div> - </div> - <div contentType="mouselock"> - <list mode="normal"></list> - <div> - <span class="otr-explanation" i18n-content="otrExceptionsExplanation"> - </span> - <list mode="otr"></list> - </div> - </div> <div contentType="protectedContent"> <list mode="normal"></list> <div> diff --git a/chromium/chrome/browser/resources/options/content_settings_exceptions_area.js b/chromium/chrome/browser/resources/options/content_settings_exceptions_area.js index 9bcbc513813..9043b0886e4 100644 --- a/chromium/chrome/browser/resources/options/content_settings_exceptions_area.js +++ b/chromium/chrome/browser/resources/options/content_settings_exceptions_area.js @@ -17,7 +17,6 @@ cr.define('options.contentSettings', function() { function isEditableType(contentType) { // Exceptions of the following lists are not editable for now. return !(contentType == 'location' || - contentType == 'fullscreen' || contentType == 'media-stream-mic' || contentType == 'media-stream-camera' || contentType == 'midi-sysex' || @@ -118,12 +117,10 @@ cr.define('options.contentSettings', function() { select.appendChild(optionSession); } - if (this.contentType != 'fullscreen') { - var optionBlock = cr.doc.createElement('option'); - optionBlock.textContent = loadTimeData.getString('blockException'); - optionBlock.value = 'block'; - select.appendChild(optionBlock); - } + var optionBlock = cr.doc.createElement('option'); + optionBlock.textContent = loadTimeData.getString('blockException'); + optionBlock.value = 'block'; + select.appendChild(optionBlock); if (this.isEmbeddingRule()) { this.patternLabel.classList.add('sublabel'); @@ -180,7 +177,7 @@ cr.define('options.contentSettings', function() { // already-existing exceptions (which we assume are valid). this.inputValidityKnown = this.pattern; // This one tracks the actual validity of the pattern in the input. This - // starts off as true so as not to annoy the user when he adds a new and + // starts off as true so as not to annoy the user when they add a new and // empty input. this.inputIsValid = true; diff --git a/chromium/chrome/browser/resources/options/cookies_list.js b/chromium/chrome/browser/resources/options/cookies_list.js index c3b97c214b8..21f4d00bbfb 100644 --- a/chromium/chrome/browser/resources/options/cookies_list.js +++ b/chromium/chrome/browser/resources/options/cookies_list.js @@ -47,6 +47,9 @@ cr.define('options', function() { ['size', 'label_cache_storage_size'], ['modified', 'label_cache_storage_last_modified']], 'flash_lso': [['domain', 'label_cookie_domain']], + 'media_license': [['origin', 'label_media_license_origin'], + ['size', 'label_media_license_size'], + ['modified', 'label_media_license_last_modified']], }; /** @@ -256,6 +259,7 @@ cr.define('options', function() { channelIDs: 0, serviceWorker: false, cacheStorage: false, + mediaLicense: false, }; if (this.origin) this.origin.collectSummaryInfo(info); @@ -281,6 +285,8 @@ cr.define('options', function() { list.push(loadTimeData.getString('cookie_cache_storage')); if (info.flashLSO) list.push(loadTimeData.getString('cookie_flash_lso')); + if (info.mediaLicense) + list.push(loadTimeData.getString('cookie_media_license')); var text = ''; for (var i = 0; i < list.length; ++i) { @@ -505,6 +511,8 @@ cr.define('options', function() { info.cacheStorage = true; } else if (this.data.type == 'flash_lso') { info.flashLSO = true; + } else if (this.data.type == 'media_license') { + info.mediaLicense = true; } var apps = this.data.appsProtectingThis; diff --git a/chromium/chrome/browser/resources/options/options.html b/chromium/chrome/browser/resources/options/options.html index e06a163f340..efb9633f083 100644 --- a/chromium/chrome/browser/resources/options/options.html +++ b/chromium/chrome/browser/resources/options/options.html @@ -3,9 +3,6 @@ <head> <meta charset="utf-8"> <title i18n-content="optionsPageTitle"></title> -<if expr="chromeos"> -<link rel="import" href="chrome://settings-frame/options_polymer.html"> -</if> <link rel="stylesheet" href="chrome://resources/css/bubble.css"> <link rel="stylesheet" href="chrome://resources/css/bubble_button.css"> <link rel="stylesheet" href="chrome://resources/css/chrome_shared.css"> diff --git a/chromium/chrome/browser/resources/options/password_manager.js b/chromium/chrome/browser/resources/options/password_manager.js index 6263595fdd0..40975f63982 100644 --- a/chromium/chrome/browser/resources/options/password_manager.js +++ b/chromium/chrome/browser/resources/options/password_manager.js @@ -160,64 +160,24 @@ cr.define('options', function() { }, /** - * Updates the visibility of the list and empty list placeholder. + * Updates the list with the given entries and updates the visibility of the + * list and empty list placeholder. * @param {!cr.ui.List} list The list to toggle visilibility for. + * @param {!Array} entries The list of entries. */ - updateListVisibility_: function(list) { - var empty = list.dataModel.length == 0; + updateListAndVisibility_: function(list, entries) { + // Setting the dataModel results in a redraw of the viewport, which is why + // the visibility needs to be updated first. Otherwise, redraw will not + // render the updated entries when transitioning from a previously empty + // list to a non-empty one. The attribute list.hidden would be true in + // this case, resulting in |redraw()| not adding the new elements to the + // viewport and thus showing a empty list to the user + // (http://crbug.com/672869). + var empty = entries.length == 0; var listPlaceHolderID = list.id + '-empty-placeholder'; list.hidden = empty; $(listPlaceHolderID).hidden = !empty; - }, - - /** - * Updates eliding of origins. If there is no enough space to show the full - * origin, the origin is elided from the left with ellipsis. - * @param {!cr.ui.List} list The list to update eliding. - */ - updateOriginsEliding_: function(list) { - var entries = list.getElementsByClassName('deletable-item'); - if (entries.length == 0) - return; - var entry = entries[0]; - var computedStyle = window.getComputedStyle(entry.urlDiv); - var columnWidth = entry.urlDiv.offsetWidth - - parseInt(computedStyle.webkitMarginStart, 10) - - parseInt(computedStyle.webkitPaddingStart, 10); - - // We use a canvas context to compute text widths. This canvas is not - // part of the DOM and thus avoids layout thrashing when updating the - // contained text. - var canvas = document.createElement('canvas'); - var ctx = canvas.getContext('2d'); - ctx.font = computedStyle.font; - - for (var i = 0; i < entries.length; ++i) { - entry = entries[i]; - // For android://com.example, elide from the right. - if (!entry.isClickable) - continue; - var cellWidth = columnWidth; - if (entry.androidUriSuffix) - cellWidth -= entry.androidUriSuffix.offsetWidth; - var urlLink = entry.urlLink; - if (cellWidth <= 0) { - console.error('cellWidth <= 0. Skip origins eliding for ' + - urlLink.textContent); - continue; - } - - var textContent = urlLink.textContent; - if (ctx.measureText(textContent).width <= cellWidth) - continue; - - textContent = '…' + textContent.substring(1); - while (ctx.measureText(textContent).width > cellWidth) - textContent = '…' + textContent.substring(2); - - // Write the elided origin back to the DOM. - urlLink.textContent = textContent; - } + list.dataModel = new ArrayDataModel(entries); }, /** @@ -245,11 +205,7 @@ cr.define('options', function() { }; entries = entries.filter(filter); } - this.savedPasswordsList_.dataModel = new ArrayDataModel(entries); - this.updateListVisibility_(this.savedPasswordsList_); - // updateOriginsEliding_ should be called after updateListVisibility_, - // otherwise updateOrigins... might be not able to read width of elements. - this.updateOriginsEliding_(this.savedPasswordsList_); + this.updateListAndVisibility_(assert(this.savedPasswordsList_), entries); }, /** @@ -258,11 +214,8 @@ cr.define('options', function() { * @param {!Array} entries The list of password exception data. */ setPasswordExceptionsList_: function(entries) { - this.passwordExceptionsList_.dataModel = new ArrayDataModel(entries); - this.updateListVisibility_(this.passwordExceptionsList_); - // updateOriginsEliding_ should be called after updateListVisibility_, - // otherwise updateOrigins... might be not able to read width of elements. - this.updateOriginsEliding_(this.passwordExceptionsList_); + this.updateListAndVisibility_( + assert(this.passwordExceptionsList_), entries); }, /** diff --git a/chromium/chrome/browser/resources/options/password_manager_list.css b/chromium/chrome/browser/resources/options/password_manager_list.css index 43f7d607304..5deae3558df 100644 --- a/chromium/chrome/browser/resources/options/password_manager_list.css +++ b/chromium/chrome/browser/resources/options/password_manager_list.css @@ -71,3 +71,25 @@ input.inactive-item { overflow: hidden; text-overflow: ellipsis; } + +html[dir='ltr'] #saved-passwords-list .url, +html[dir='ltr'] #password-exceptions-list .url { + -webkit-margin-end: 1em; + -webkit-margin-start: 0; + -webkit-padding-end: 2em; + -webkit-padding-start: 1em; + direction: rtl; + text-align: left; +} + +html[dir='rtl'] #saved-passwords-list .url, +html[dir='rtl'] #password-exceptions-list .url { + -webkit-margin-end: 0; + -webkit-margin-start: 1em; + -webkit-padding-end: 1em; + -webkit-padding-start: 2em; + /* Explicitly mention the direction, which, while the same, is independent of + * the surrounding text the for URLs. */ + direction: rtl; + text-align: right; +} diff --git a/chromium/chrome/browser/resources/options/password_manager_list.js b/chromium/chrome/browser/resources/options/password_manager_list.js index 720efb7c570..9fd160f57fd 100644 --- a/chromium/chrome/browser/resources/options/password_manager_list.js +++ b/chromium/chrome/browser/resources/options/password_manager_list.js @@ -76,7 +76,6 @@ cr.define('options.passwordManager', function() { urlLink = item.ownerDocument.createElement('a'); urlLink.href = item.url; urlLink.setAttribute('target', '_blank'); - urlLink.dir = 'ltr'; } else { urlLink = item.ownerDocument.createElement('span'); } @@ -97,7 +96,7 @@ cr.define('options.passwordManager', function() { var urlDiv = cr.doc.createElement('div'); urlDiv.className = 'favicon-cell url'; urlDiv.setAttribute('title', getTitleForPasswordOrigin(item)); - urlDiv.style.backgroundImage = cr.icon.getFavicon('origin/' + item.url); + urlDiv.style.backgroundImage = cr.icon.getFavicon(item.url); item.urlLink = createUrlLink(item, urlDiv); urlDiv.appendChild(item.urlLink); diff --git a/chromium/chrome/browser/resources/options/sync_section.html b/chromium/chrome/browser/resources/options/sync_section.html index 1cb7e90b3a3..f43b440a585 100644 --- a/chromium/chrome/browser/resources/options/sync_section.html +++ b/chromium/chrome/browser/resources/options/sync_section.html @@ -26,6 +26,7 @@ </if> <!-- chromeos --> <div id="sync-status" class="settings-row" hidden> + <span id="account-info" hidden></span> <span id="sync-status-text"></span> <a is="action-link" id="sync-action-link"></a> </div> diff --git a/chromium/chrome/browser/resources/options/sync_setup_overlay.js b/chromium/chrome/browser/resources/options/sync_setup_overlay.js index f9d2524f2f7..12dc97d09a2 100644 --- a/chromium/chrome/browser/resources/options/sync_setup_overlay.js +++ b/chromium/chrome/browser/resources/options/sync_setup_overlay.js @@ -811,7 +811,7 @@ cr.define('options', function() { * @private */ doSignOutOnAuthError_: function() { - chrome.send('SyncSetupDoSignOutOnAuthError'); + chrome.send('AttemptUserExit'); }, }; diff --git a/chromium/chrome/browser/resources/pdf/elements/viewer-page-indicator/viewer-page-indicator.js b/chromium/chrome/browser/resources/pdf/elements/viewer-page-indicator/viewer-page-indicator.js index 2cf279b68b1..4af00a2cff1 100644 --- a/chromium/chrome/browser/resources/pdf/elements/viewer-page-indicator/viewer-page-indicator.js +++ b/chromium/chrome/browser/resources/pdf/elements/viewer-page-indicator/viewer-page-indicator.js @@ -42,6 +42,14 @@ Polymer({ document.documentElement.clientHeight); this.style.top = percent * (document.documentElement.clientHeight - this.offsetHeight) + 'px'; +<if expr="is_macosx"> + // On the Mac, if overlay scrollbars are enabled, prevent them from + // overlapping the triangle. + if (window.innerWidth == document.body.scrollWidth) + this.style.right = '16px'; + else + this.style.right = '0px'; +</if> this.style.opacity = 1; clearTimeout(this.timerId); diff --git a/chromium/chrome/browser/resources/pdf/gesture_detector.js b/chromium/chrome/browser/resources/pdf/gesture_detector.js new file mode 100644 index 00000000000..fde4650d92b --- /dev/null +++ b/chromium/chrome/browser/resources/pdf/gesture_detector.js @@ -0,0 +1,164 @@ +// Copyright 2016 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. + +'use strict'; + +/** + * A class that listens for touch events and produces events when these + * touches form gestures (e.g. pinching). + */ +class GestureDetector { + /** + * Constructs a GestureDetector. + * @param {!Element} element The element to monitor for touch gestures. + */ + constructor(element) { + this.element_ = element; + + this.element_.addEventListener( + 'touchstart', this.onTouchStart_.bind(this), { passive: false }); + this.element_.addEventListener( + 'touchmove', this.onTouch_.bind(this), { passive: true }); + this.element_.addEventListener( + 'touchend', this.onTouch_.bind(this), { passive: true }); + this.element_.addEventListener( + 'touchcancel', this.onTouch_.bind(this), { passive: true }); + + this.pinchStartEvent_ = null; + this.lastEvent_ = null; + + this.listeners_ = new Map([ + ['pinchstart', []], + ['pinchupdate', []], + ['pinchend', []] + ]); + } + + /** + * Add a |listener| to be notified of |type| events. + * @param {string} type The event type to be notified for. + * @param {Function} listener The callback. + */ + addEventListener(type, listener) { + if (this.listeners_.has(type)) { + this.listeners_.get(type).push(listener); + } + } + + /** + * Call the relevant listeners with the given |pinchEvent|. + * @private + * @param {!Object} pinchEvent The event to notify the listeners of. + */ + notify_(pinchEvent) { + let listeners = this.listeners_.get(pinchEvent.type); + + for (let l of listeners) + l(pinchEvent); + } + + /** + * The callback for touchstart events on the element. + * @private + * @param {!TouchEvent} event Touch event on the element. + */ + onTouchStart_(event) { + // We must preventDefault if there is a two finger touch. By doing so + // native pinch-zoom does not interfere with our way of handling the event. + if (event.touches.length == 2) { + event.preventDefault(); + this.pinchStartEvent_ = event; + this.lastEvent_ = event; + this.notify_({ + type: 'pinchstart', + center: GestureDetector.center_(event) + }); + } + } + + /** + * The callback for touch move, end, and cancel events on the element. + * @private + * @param {!TouchEvent} event Touch event on the element. + */ + onTouch_(event) { + if (!this.pinchStartEvent_) + return; + + // Check if the pinch ends with the current event. + if (event.touches.length < 2 || + this.lastEvent_.touches.length !== event.touches.length) { + let startScaleRatio = GestureDetector.pinchScaleRatio_( + this.lastEvent_, this.pinchStartEvent_); + let center = GestureDetector.center_(this.lastEvent_); + let endEvent = { + type: 'pinchend', + startScaleRatio: startScaleRatio, + center: center + }; + this.pinchStartEvent_ = null; + this.lastEvent_ = null; + this.notify_(endEvent); + return; + } + + let scaleRatio = GestureDetector.pinchScaleRatio_(event, this.lastEvent_); + let startScaleRatio = GestureDetector.pinchScaleRatio_( + event, this.pinchStartEvent_); + let center = GestureDetector.center_(event); + this.notify_({ + type: 'pinchupdate', + scaleRatio: scaleRatio, + direction: scaleRatio > 1.0 ? 'in' : 'out', + startScaleRatio: startScaleRatio, + center: center + }); + + this.lastEvent_ = event; + } + + /** + * Computes the change in scale between this touch event + * and a previous one. + * @private + * @param {!TouchEvent} event Latest touch event on the element. + * @param {!TouchEvent} prevEvent A previous touch event on the element. + * @return {?number} The ratio of the scale of this event and the + * scale of the previous one. + */ + static pinchScaleRatio_(event, prevEvent) { + let distance1 = GestureDetector.distance_(prevEvent); + let distance2 = GestureDetector.distance_(event); + return distance1 === 0 ? null : distance2 / distance1; + } + + /** + * Computes the distance between fingers. + * @private + * @param {!TouchEvent} event Touch event with at least 2 touch points. + * @return {number} Distance between touch[0] and touch[1]. + */ + static distance_(event) { + let touch1 = event.touches[0]; + let touch2 = event.touches[1]; + let dx = touch1.clientX - touch2.clientX; + let dy = touch1.clientY - touch2.clientY; + return Math.sqrt(dx * dx + dy * dy); + } + + /** + * Computes the midpoint between fingers. + * @private + * @param {!TouchEvent} event Touch event with at least 2 touch points. + * @return {!Object} Midpoint between touch[0] and touch[1]. + */ + static center_(event) { + let touch1 = event.touches[0]; + let touch2 = event.touches[1]; + return { + x: (touch1.clientX + touch2.clientX) / 2, + y: (touch1.clientY + touch2.clientY) / 2 + }; + } +}; diff --git a/chromium/chrome/browser/resources/pdf/index.html b/chromium/chrome/browser/resources/pdf/index.html index deb4574c61b..2bc79f81506 100644 --- a/chromium/chrome/browser/resources/pdf/index.html +++ b/chromium/chrome/browser/resources/pdf/index.html @@ -34,6 +34,7 @@ <script src="navigator.js"></script> <script src="viewport_scroller.js"></script> <script src="zoom_manager.js"></script> +<script src="gesture_detector.js"></script> <script src="pdf_scripting_api.js"></script> <script src="chrome://resources/js/util.js"></script> <script src="browser_api.js"></script> diff --git a/chromium/chrome/browser/resources/pdf/pdf.js b/chromium/chrome/browser/resources/pdf/pdf.js index f3828af7181..14aebcf8cdd 100644 --- a/chromium/chrome/browser/resources/pdf/pdf.js +++ b/chromium/chrome/browser/resources/pdf/pdf.js @@ -191,6 +191,15 @@ function PDFViewer(browserApi) { this.zoomToolbar_.addEventListener('zoom-out', this.viewport_.zoomOut.bind(this.viewport_)); + this.gestureDetector_ = new GestureDetector(this.plugin_); + this.gestureDetector_.addEventListener( + 'pinchstart', this.viewport_.pinchZoomStart.bind(this.viewport_)); + this.sentPinchEvent_ = false; + this.gestureDetector_.addEventListener( + 'pinchupdate', this.onPinchUpdate_.bind(this)); + this.gestureDetector_.addEventListener( + 'pinchend', this.onPinchEnd_.bind(this)); + if (toolbarEnabled) { this.toolbar_ = $('toolbar'); this.toolbar_.hidden = false; @@ -658,6 +667,19 @@ PDFViewer.prototype = { this.plugin_.postMessage({ type: 'stopScrolling' }); + + if (this.viewport_.pinchPhase == Viewport.PinchPhase.PINCH_START) { + var position = this.viewport_.position; + var zoom = this.viewport_.zoom; + var pinchPhase = this.viewport_.pinchPhase; + this.plugin_.postMessage({ + type: 'viewport', + zoom: zoom, + xOffset: position.x, + yOffset: position.y, + pinchPhase: pinchPhase + }); + } }, /** @@ -668,17 +690,55 @@ PDFViewer.prototype = { afterZoom_: function() { var position = this.viewport_.position; var zoom = this.viewport_.zoom; + var pinchVector = this.viewport_.pinchPanVector || {x: 0, y: 0}; + var pinchCenter = this.viewport_.pinchCenter || {x: 0, y: 0}; + var pinchPhase = this.viewport_.pinchPhase; + this.plugin_.postMessage({ type: 'viewport', zoom: zoom, xOffset: position.x, - yOffset: position.y + yOffset: position.y, + pinchPhase: pinchPhase, + pinchX: pinchCenter.x, + pinchY: pinchCenter.y, + pinchVectorX: pinchVector.x, + pinchVectorY: pinchVector.y }); this.zoomManager_.onPdfZoomChange(); }, /** * @private + * A callback that's called when an update to a pinch zoom is detected. + * @param {!Object} e the pinch event. + */ + onPinchUpdate_: function(e) { + // Throttle number of pinch events to one per frame. + if (!this.sentPinchEvent_) { + this.sentPinchEvent_ = true; + window.requestAnimationFrame(function() { + this.sentPinchEvent_ = false; + this.viewport_.pinchZoom(e); + }.bind(this)); + } + }, + + /** + * @private + * A callback that's called when the end of a pinch zoom is detected. + * @param {!Object} e the pinch event. + */ + onPinchEnd_: function(e) { + // Using rAF for pinch end prevents pinch updates scheduled by rAF getting + // sent after the pinch end. + window.requestAnimationFrame(function() { + this.viewport_.pinchZoomEnd(e); + }.bind(this)); + }, + + /** + * @private * A callback that's called after the viewport changes. */ viewportChanged_: function() { diff --git a/chromium/chrome/browser/resources/pdf/viewport.js b/chromium/chrome/browser/resources/pdf/viewport.js index 18fb6c2ad40..80a5a06ac64 100644 --- a/chromium/chrome/browser/resources/pdf/viewport.js +++ b/chromium/chrome/browser/resources/pdf/viewport.js @@ -15,6 +15,36 @@ function getIntersectionHeight(rect1, rect2) { } /** + * Makes sure that the scale level doesn't get out of the limits. + * @param {number} scale The new scale level. + * @return {number} The scale clamped within the limits. + */ +function clampScale(scale) { + return Math.min(5, Math.max(0.25, scale)); +} + +/** + * Computes vector between two points. + * @param {!Object} p1 The first point. + * @param {!Object} p2 The second point. + * @return {!Object} The vector. + */ +function vectorDelta(p1, p2) { + return { + x: p2.x - p1.x, + y: p2.y - p1.y + }; +} + +function frameToPluginCoordinate(coordinateInFrame) { + var container = $('plugin'); + return { + x: coordinateInFrame.x - container.getBoundingClientRect().left, + y: coordinateInFrame.y - container.getBoundingClientRect().top + }; +} + +/** * Create a new viewport. * @constructor * @param {Window} window the window @@ -49,6 +79,11 @@ function Viewport(window, this.fittingType_ = Viewport.FittingType.NONE; this.defaultZoom_ = defaultZoom; this.topToolbarHeight_ = topToolbarHeight; + this.prevScale_ = 1; + this.pinchPhase_ = Viewport.PinchPhase.PINCH_NONE; + this.pinchPanVector_ = null; + this.pinchCenter_ = null; + this.firstPinchCenterInFrame_ = null; window.addEventListener('scroll', this.updateViewport_.bind(this)); window.addEventListener('resize', this.resize_.bind(this)); @@ -65,6 +100,19 @@ Viewport.FittingType = { }; /** + * Enumeration of pinch states. + * This should match PinchPhase enum in pdf/out_of_process_instance.h + * @enum {number} + */ +Viewport.PinchPhase = { + PINCH_NONE: 0, + PINCH_START: 1, + PINCH_UPDATE_ZOOM_OUT: 2, + PINCH_UPDATE_ZOOM_IN: 3, + PINCH_END: 4 +}; + +/** * The increment to scroll a page by in pixels when up/down/left/right arrow * keys are pressed. Usually we just let the browser handle scrolling on the * window when these keys are pressed but in certain cases we need to simulate @@ -227,6 +275,29 @@ Viewport.prototype = { }, /** + * @type {Viewport.PinchPhase} The phase of the current pinch gesture for + * the viewport. + */ + get pinchPhase() { + return this.pinchPhase_; + }, + + /** + * @type {Object} The panning caused by the current pinch gesture (as + * the deltas of the x and y coordinates). + */ + get pinchPanVector() { + return this.pinchPanVector_; + }, + + /** + * @type {Object} The coordinates of the center of the current pinch gesture. + */ + get pinchCenter() { + return this.pinchCenter_; + }, + + /** * @private * Used to wrap a function that might perform zooming on the viewport. This is * required so that we can notify the plugin that zooming is in progress @@ -266,6 +337,54 @@ Viewport.prototype = { }, /** + * @private + * Sets the zoom of the viewport. + * Same as setZoomInternal_ but for pinch zoom we have some more operations. + * @param {number} scaleDelta The zoom delta. + * @param {!Object} center The pinch center in content coordinates. + */ + setPinchZoomInternal_: function(scaleDelta, center) { + assert(this.allowedToChangeZoom_, + 'Called Viewport.setPinchZoomInternal_ without calling ' + + 'Viewport.mightZoom_.'); + this.zoom_ = clampScale(this.zoom_ * scaleDelta); + + var newCenterInContent = this.frameToContent(center); + var delta = { + x: (newCenterInContent.x - this.oldCenterInContent.x), + y: (newCenterInContent.y - this.oldCenterInContent.y) + }; + + // Record the scroll position (relative to the pinch center). + var currentScrollPos = { + x: this.position.x - delta.x * this.zoom_, + y: this.position.y - delta.y * this.zoom_ + }; + + this.contentSizeChanged_(); + // Scroll to the scaled scroll position. + this.position = { + x: currentScrollPos.x, + y: currentScrollPos.y + }; + }, + + /** + * @private + * Converts a point from frame to content coordinates. + * @param {!Object} framePoint The frame coordinates. + * @return {!Object} The content coordinates. + */ + frameToContent: function(framePoint) { + // TODO(mcnee) Add a helper Point class to avoid duplicating operations + // on plain {x,y} objects. + return { + x: (framePoint.x + this.position.x) / this.zoom_, + y: (framePoint.y + this.position.y) / this.zoom_ + }; + }, + + /** * Sets the zoom to the given zoom level. * @param {number} newZoom the zoom level to zoom to. */ @@ -499,6 +618,79 @@ Viewport.prototype = { }, /** + * Pinch zoom event handler. + * @param {!Object} e The pinch event. + */ + pinchZoom: function(e) { + this.mightZoom_(function() { + this.pinchPhase_ = e.direction == 'out' ? + Viewport.PinchPhase.PINCH_UPDATE_ZOOM_OUT : + Viewport.PinchPhase.PINCH_UPDATE_ZOOM_IN; + + var scaleDelta = e.startScaleRatio / this.prevScale_; + this.pinchPanVector_ = + vectorDelta(e.center, this.firstPinchCenterInFrame_); + + var needsScrollbars = this.documentNeedsScrollbars_( + clampScale(this.zoom_ * scaleDelta)); + + this.pinchCenter_ = e.center; + + // If there's no horizontal scrolling, keep the content centered so the + // user can't zoom in on the non-content area. + // TODO(mcnee) Investigate other ways of scaling when we don't have + // horizontal scrolling. We want to keep the document centered, + // but this causes a potentially awkward transition when we start + // using the gesture center. + if (!needsScrollbars.horizontal) { + this.pinchCenter_ = { + x: this.window_.innerWidth / 2, + y: this.window_.innerHeight / 2 + }; + } else if (this.keepContentCentered_) { + this.oldCenterInContent = + this.frameToContent(frameToPluginCoordinate(e.center)); + this.keepContentCentered_ = false; + } + + this.setPinchZoomInternal_( + scaleDelta, frameToPluginCoordinate(e.center)); + this.updateViewport_(); + this.prevScale_ = e.startScaleRatio; + }.bind(this)); + }, + + pinchZoomStart: function(e) { + this.pinchPhase_ = Viewport.PinchPhase.PINCH_START; + this.prevScale_ = 1; + this.oldCenterInContent = + this.frameToContent(frameToPluginCoordinate(e.center)); + + var needsScrollbars = this.documentNeedsScrollbars_(this.zoom_); + this.keepContentCentered_ = !needsScrollbars.horizontal; + // We keep track of begining of the pinch. + // By doing so we will be able to compute the pan distance. + this.firstPinchCenterInFrame_ = e.center; + }, + + pinchZoomEnd: function(e) { + this.mightZoom_(function() { + this.pinchPhase_ = Viewport.PinchPhase.PINCH_END; + var scaleDelta = e.startScaleRatio / this.prevScale_; + this.pinchCenter_ = e.center; + + this.setPinchZoomInternal_( + scaleDelta, frameToPluginCoordinate(e.center)); + this.updateViewport_(); + }.bind(this)); + + this.pinchPhase_ = Viewport.PinchPhase.PINCH_NONE; + this.pinchPanVector_ = null; + this.pinchCenter_ = null; + this.firstPinchCenterInFrame_ = null; + }, + + /** * Go to the given page index. * @param {number} page the index of the page to go to. zero-based. */ diff --git a/chromium/chrome/browser/resources/plugin_metadata/plugins_linux.json b/chromium/chrome/browser/resources/plugin_metadata/plugins_linux.json index f26d7e43459..bb76f81a753 100644 --- a/chromium/chrome/browser/resources/plugin_metadata/plugins_linux.json +++ b/chromium/chrome/browser/resources/plugin_metadata/plugins_linux.json @@ -1,5 +1,5 @@ { - "x-version": 18, + "x-version": 19, "google-talk": { "mime_types": [ ], @@ -80,9 +80,9 @@ ], "versions": [ { - "version": "23.0.0.207", + "version": "24.0.0.194", "status": "up_to_date", - "reference": "https://helpx.adobe.com/security/products/flash-player/apsb16-37.html" + "reference": "https://helpx.adobe.com/security/products/flash-player/apsb17-02.html" } ], "lang": "en-US", diff --git a/chromium/chrome/browser/resources/plugin_metadata/plugins_mac.json b/chromium/chrome/browser/resources/plugin_metadata/plugins_mac.json index ec1b241b19d..4275e0dd7f4 100644 --- a/chromium/chrome/browser/resources/plugin_metadata/plugins_mac.json +++ b/chromium/chrome/browser/resources/plugin_metadata/plugins_mac.json @@ -1,5 +1,5 @@ { - "x-version": 24, + "x-version": 25, "google-talk": { "mime_types": [ ], @@ -115,9 +115,9 @@ ], "versions": [ { - "version": "23.0.0.207", + "version": "24.0.0.194", "status": "requires_authorization", - "reference": "https://helpx.adobe.com/security/products/flash-player/apsb16-37.html" + "reference": "https://helpx.adobe.com/security/products/flash-player/apsb17-02.html" } ], "lang": "en-US", diff --git a/chromium/chrome/browser/resources/plugin_metadata/plugins_win.json b/chromium/chrome/browser/resources/plugin_metadata/plugins_win.json index 01f8670b550..3d2ff8b20a5 100644 --- a/chromium/chrome/browser/resources/plugin_metadata/plugins_win.json +++ b/chromium/chrome/browser/resources/plugin_metadata/plugins_win.json @@ -1,5 +1,5 @@ { - "x-version": 33, + "x-version": 34, "google-talk": { "mime_types": [ ], @@ -137,9 +137,9 @@ ], "versions": [ { - "version": "23.0.0.207", + "version": "24.0.0.194", "status": "requires_authorization", - "reference": "https://helpx.adobe.com/security/products/flash-player/apsb16-37.html" + "reference": "https://helpx.adobe.com/security/products/flash-player/apsb17-02.html" } ], "lang": "en-US", diff --git a/chromium/chrome/browser/resources/plugins.css b/chromium/chrome/browser/resources/plugins.css index 75da6196866..f721353e6af 100644 --- a/chromium/chrome/browser/resources/plugins.css +++ b/chromium/chrome/browser/resources/plugins.css @@ -229,10 +229,6 @@ body.show-tmi-mode .show-in-tmi-mode { margin-top: 0.2em; } -.always-allow { - -webkit-margin-start: 30px; -} - button { font-size: 104%; } diff --git a/chromium/chrome/browser/resources/plugins.html b/chromium/chrome/browser/resources/plugins.html index c5fbbcf44bf..8a130447c44 100644 --- a/chromium/chrome/browser/resources/plugins.html +++ b/chromium/chrome/browser/resources/plugins.html @@ -123,22 +123,6 @@ i18n-content="pluginDisabledByPolicy">(DISABLED_BY_POLICY)</span> <span jsdisplay="enabled_mode == 'enabledByPolicy'" i18n-content="pluginEnabledByPolicy">(ENABLED_BY_POLICY)</span> - <span guest-visibility="disabled"> - <a - class="disable-plugin-link" - jsvalues=".path:path" - jsdisplay="enabled_mode == 'enabledByUser'" - href="#" - i18n-content="disable" - >DISABLE</a> - <a - class="enable-plugin-link" - jsvalues=".path:path" - jsdisplay="enabled_mode == 'disabledByUser'" - href="#" - i18n-content="enable" - >ENABLE</a> - </span> </td> </tr></table></div> <table><tr jsdisplay="mime_types.length > 0"> @@ -172,22 +156,6 @@ </div> </div> <div class="plugin-actions" guest-visibility="disabled"> - <span> - <a - class="disable-group-link" - jsvalues=".path:name" - jsdisplay="enabled_mode == 'enabledByUser'" - href="#" - i18n-content="disable" - >DISABLE</a> - <a - class="enable-group-link" - jsvalues=".path:name" - jsdisplay="enabled_mode == 'disabledByUser'" - href="#" - i18n-content="enable" - >ENABLE</a> - </span> <input class="always-allow" type="checkbox" jsvalues= diff --git a/chromium/chrome/browser/resources/plugins.js b/chromium/chrome/browser/resources/plugins.js index 8c8bccee1d4..90d6e88816a 100644 --- a/chromium/chrome/browser/resources/plugins.js +++ b/chromium/chrome/browser/resources/plugins.js @@ -77,7 +77,7 @@ function loadShowDetailsFromPrefs(showDetails) { * type: 'BROWSER PLUGIN', * mime_types: [ * { - * description: 'New Guy Media', + * description: 'New Media Type', * file_extensions: ['mfp'], * mime_type: 'application/x-my-first' * }, @@ -261,19 +261,6 @@ function isPluginPolicyClickToPlay(plugin) { return plugin.policy_click_to_play == true; } -/** - * Helper to convert callback-based define() API to a promise-based API. - * @param {!Array<string>} moduleNames - * @return {!Promise} - */ -function importModules(moduleNames) { - return new Promise(function(resolve, reject) { - define(moduleNames, function(var_args) { - resolve(Array.prototype.slice.call(arguments, 0)); - }); - }); -} - // NOTE: Need to keep a global reference to the |pageImpl| such that it is not // garbage collected, which causes the pipe to close and future calls from C++ // to JS to get dropped. This also allows tests to make direct calls on it. diff --git a/chromium/chrome/browser/resources/popular_sites_internals.css b/chromium/chrome/browser/resources/popular_sites_internals.css deleted file mode 100644 index ee4c1d4225e..00000000000 --- a/chromium/chrome/browser/resources/popular_sites_internals.css +++ /dev/null @@ -1,48 +0,0 @@ -/* 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. */ - -html { - font-size: 20px; -} - -#info > div { - width: 100%; -} - -#info h2 { - color: rgb(74, 142, 230); - font-size: 100%; - margin-bottom: 0; -} - -#info .err { - color: red; -} - -#info .section { - display: inline-block; - margin-left: auto; - margin-right: auto; -} - -#info .section.hidden { - display: none; -} - -.section-details { - width: 100%; -} - -.section-details .detail, -.section-details .value { - width: 50%; -} - -.section-details tr:nth-child(odd) { - background: rgb(239, 243, 255); -} - -#json-value { - font-size: 75%; -} diff --git a/chromium/chrome/browser/resources/popular_sites_internals.html b/chromium/chrome/browser/resources/popular_sites_internals.html deleted file mode 100644 index ece5541aa08..00000000000 --- a/chromium/chrome/browser/resources/popular_sites_internals.html +++ /dev/null @@ -1,80 +0,0 @@ -<!-- -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. ---> -<!DOCTYPE html> -<html> -<head> -<meta charset="utf-8"> -<if expr="is_android or is_ios"> -<meta name="viewport" content="width=device-width, initial-scale=1.0, - maximum-scale=1.0, user-scalable=no"> -</if> -<title>Popular Sites Internals</title> -<link rel="stylesheet" href="chrome://resources/css/text_defaults.css"> -<link rel="stylesheet" href="chrome://resources/css/list.css"> -<link rel="stylesheet" href="popular_sites_internals.css"> -<script src="chrome://resources/js/cr.js"></script> -<script src="chrome://resources/js/jstemplate_compiled.js"></script> -<script src="chrome://resources/js/load_time_data.js"></script> -<script src="chrome://resources/js/util.js"></script> -<script src="popular_sites_internals.js"></script> -</head> - -<body> -<div id="info"> - <div class="section" jsskip="true"> - <h2>Download</h2> - <table class="section-details"> - <tr> - <td class="detail">URL (takes precedence over Country and Version)</td> - <td class="value"><input id="override-url" type="text"></td> - </tr> - <tr> - <td class="detail">Override Country</td> - <td class="value"><input id="override-country" type="text"></td> - </tr> - <tr> - <td class="detail">Override Version</td> - <td class="value"><input id="override-version" type="text"></td> - </tr> - <tr> - <td class="detail"> - <input id="submit-update" type="submit" value="Update"> - </td> - <td id="download-result" class="value"></td> - </tr> - </table> - </div> - - <div class="section"> - <h2>Info</h2> - <table class="section-details"> - <tr> - <td class="detail">URL</td> - <td class="value" jscontent="url"></td> - </tr> - </table> - </div> - - <div class="section"> - <h2>Sites</h2> - <table class="section-details"> - <tr jsselect="sites"> - <td class="detail" jscontent="title"></td> - <td class="value" jscontent="url"></td> - </tr> - <tr jsskip="true"> - <td class="detail"> - <input id="view-json" type="submit" value="View JSON"> - </td> - <td class="value"><pre id="json-value"></pre></td> - </tr> - </table> - </div> -</div> - -</body> -</html> - diff --git a/chromium/chrome/browser/resources/popular_sites_internals.js b/chromium/chrome/browser/resources/popular_sites_internals.js deleted file mode 100644 index 10a4010716a..00000000000 --- a/chromium/chrome/browser/resources/popular_sites_internals.js +++ /dev/null @@ -1,62 +0,0 @@ -// 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('chrome.popular_sites_internals', function() { - 'use strict'; - - function initialize() { - function submitUpdate(event) { - $('download-result').textContent = ''; - chrome.send('update', [$('override-url').value, - $('override-country').value, - $('override-version').value]); - event.preventDefault(); - } - - $('submit-update').addEventListener('click', submitUpdate); - - function viewJson(event) { - $('json-value').textContent = ''; - chrome.send('viewJson'); - event.preventDefault(); - } - - $('view-json').addEventListener('click', viewJson); - - chrome.send('registerForEvents'); - } - - function receiveOverrides(url, country, version) { - $('override-url').value = url; - $('override-country').value = country; - $('override-version').value = version; - } - - function receiveDownloadResult(result) { - $('download-result').textContent = result; - } - - function receiveSites(sites) { - jstProcess(new JsEvalContext(sites), $('info')); - // Also clear the json string, since it's likely stale now. - $('json-value').textContent = ''; - } - - function receiveJson(json) { - $('json-value').textContent = json; - } - - // Return an object with all of the exports. - return { - initialize: initialize, - receiveOverrides: receiveOverrides, - receiveDownloadResult: receiveDownloadResult, - receiveSites: receiveSites, - receiveJson: receiveJson, - }; -}); - -document.addEventListener('DOMContentLoaded', - chrome.popular_sites_internals.initialize); - diff --git a/chromium/chrome/browser/resources/print_preview/data/app_state.js b/chromium/chrome/browser/resources/print_preview/data/app_state.js index 4275725bca6..fb5b95530da 100644 --- a/chromium/chrome/browser/resources/print_preview/data/app_state.js +++ b/chromium/chrome/browser/resources/print_preview/data/app_state.js @@ -103,6 +103,7 @@ cr.define('print_preview', function() { IS_COLLATE_ENABLED: 'isCollateEnabled', IS_FIT_TO_PAGE_ENABLED: 'isFitToPageEnabled', IS_CSS_BACKGROUND_ENABLED: 'isCssBackgroundEnabled', + SCALING: 'scaling', VENDOR_OPTIONS: 'vendorOptions' }; @@ -205,6 +206,9 @@ cr.define('print_preview', function() { this.state_[AppState.Field.RECENT_DESTINATIONS].length = AppState.NUM_DESTINATIONS_; } + if (!loadTimeData.getBoolean('scalingEnabled')) + this.state_[AppState.Field.SCALING] = 100; + }, /** diff --git a/chromium/chrome/browser/resources/print_preview/data/destination_store.js b/chromium/chrome/browser/resources/print_preview/data/destination_store.js index 1123540cd1e..2258b65a74e 100644 --- a/chromium/chrome/browser/resources/print_preview/data/destination_store.js +++ b/chromium/chrome/browser/resources/print_preview/data/destination_store.js @@ -308,62 +308,304 @@ cr.define('print_preview', function() { * Delay in milliseconds before the destination store ignores the initial * destination ID and just selects any printer (since the initial destination * was not found). - * @type {number} + * @private {number} * @const - * @private */ DestinationStore.AUTO_SELECT_TIMEOUT_ = 15000; /** * Amount of time spent searching for privet destination, in milliseconds. - * @type {number} + * @private {number} * @const - * @private */ DestinationStore.PRIVET_SEARCH_DURATION_ = 5000; /** * Maximum amount of time spent searching for extension destinations, in * milliseconds. - * @type {number} + * @private {number} * @const - * @private */ DestinationStore.EXTENSION_SEARCH_DURATION_ = 5000; /** + * Human readable names for media sizes in the cloud print CDD. + * https://developers.google.com/cloud-print/docs/cdd + * @private {Object<string>} + * @const + */ + DestinationStore.MEDIA_DISPLAY_NAMES_ = { + 'ISO_2A0': '2A0', + 'ISO_A0': 'A0', + 'ISO_A0X3': 'A0x3', + 'ISO_A1': 'A1', + 'ISO_A10': 'A10', + 'ISO_A1X3': 'A1x3', + 'ISO_A1X4': 'A1x4', + 'ISO_A2': 'A2', + 'ISO_A2X3': 'A2x3', + 'ISO_A2X4': 'A2x4', + 'ISO_A2X5': 'A2x5', + 'ISO_A3': 'A3', + 'ISO_A3X3': 'A3x3', + 'ISO_A3X4': 'A3x4', + 'ISO_A3X5': 'A3x5', + 'ISO_A3X6': 'A3x6', + 'ISO_A3X7': 'A3x7', + 'ISO_A3_EXTRA': 'A3 Extra', + 'ISO_A4': 'A4', + 'ISO_A4X3': 'A4x3', + 'ISO_A4X4': 'A4x4', + 'ISO_A4X5': 'A4x5', + 'ISO_A4X6': 'A4x6', + 'ISO_A4X7': 'A4x7', + 'ISO_A4X8': 'A4x8', + 'ISO_A4X9': 'A4x9', + 'ISO_A4_EXTRA': 'A4 Extra', + 'ISO_A4_TAB': 'A4 Tab', + 'ISO_A5': 'A5', + 'ISO_A5_EXTRA': 'A5 Extra', + 'ISO_A6': 'A6', + 'ISO_A7': 'A7', + 'ISO_A8': 'A8', + 'ISO_A9': 'A9', + 'ISO_B0': 'B0', + 'ISO_B1': 'B1', + 'ISO_B10': 'B10', + 'ISO_B2': 'B2', + 'ISO_B3': 'B3', + 'ISO_B4': 'B4', + 'ISO_B5': 'B5', + 'ISO_B5_EXTRA': 'B5 Extra', + 'ISO_B6': 'B6', + 'ISO_B6C4': 'B6C4', + 'ISO_B7': 'B7', + 'ISO_B8': 'B8', + 'ISO_B9': 'B9', + 'ISO_C0': 'C0', + 'ISO_C1': 'C1', + 'ISO_C10': 'C10', + 'ISO_C2': 'C2', + 'ISO_C3': 'C3', + 'ISO_C4': 'C4', + 'ISO_C5': 'C5', + 'ISO_C6': 'C6', + 'ISO_C6C5': 'C6C5', + 'ISO_C7': 'C7', + 'ISO_C7C6': 'C7C6', + 'ISO_C8': 'C8', + 'ISO_C9': 'C9', + 'ISO_DL': 'Envelope DL', + 'ISO_RA0': 'RA0', + 'ISO_RA1': 'RA1', + 'ISO_RA2': 'RA2', + 'ISO_SRA0': 'SRA0', + 'ISO_SRA1': 'SRA1', + 'ISO_SRA2': 'SRA2', + 'JIS_B0': 'B0 (JIS)', + 'JIS_B1': 'B1 (JIS)', + 'JIS_B10': 'B10 (JIS)', + 'JIS_B2': 'B2 (JIS)', + 'JIS_B3': 'B3 (JIS)', + 'JIS_B4': 'B4 (JIS)', + 'JIS_B5': 'B5 (JIS)', + 'JIS_B6': 'B6 (JIS)', + 'JIS_B7': 'B7 (JIS)', + 'JIS_B8': 'B8 (JIS)', + 'JIS_B9': 'B9 (JIS)', + 'JIS_EXEC': 'Executive (JIS)', + 'JPN_CHOU2': 'Choukei 2', + 'JPN_CHOU3': 'Choukei 3', + 'JPN_CHOU4': 'Choukei 4', + 'JPN_HAGAKI': 'Hagaki', + 'JPN_KAHU': 'Kahu Envelope', + 'JPN_KAKU2': 'Kaku 2', + 'JPN_OUFUKU': 'Oufuku Hagaki', + 'JPN_YOU4': 'You 4', + 'NA_10X11': '10x11', + 'NA_10X13': '10x13', + 'NA_10X14': '10x14', + 'NA_10X15': '10x15', + 'NA_11X12': '11x12', + 'NA_11X15': '11x15', + 'NA_12X19': '12x19', + 'NA_5X7': '5x7', + 'NA_6X9': '6x9', + 'NA_7X9': '7x9', + 'NA_9X11': '9x11', + 'NA_A2': 'A2', + 'NA_ARCH_A': 'Arch A', + 'NA_ARCH_B': 'Arch B', + 'NA_ARCH_C': 'Arch C', + 'NA_ARCH_D': 'Arch D', + 'NA_ARCH_E': 'Arch E', + 'NA_ASME_F': 'ASME F', + 'NA_B_PLUS': 'B-plus', + 'NA_C': 'C', + 'NA_C5': 'C5', + 'NA_D': 'D', + 'NA_E': 'E', + 'NA_EDP': 'EDP', + 'NA_EUR_EDP': 'European EDP', + 'NA_EXECUTIVE': 'Executive', + 'NA_F': 'F', + 'NA_FANFOLD_EUR': 'FanFold European', + 'NA_FANFOLD_US': 'FanFold US', + 'NA_FOOLSCAP': 'FanFold German Legal', + 'NA_GOVT_LEGAL': 'Government Legal', + 'NA_GOVT_LETTER': 'Government Letter', + 'NA_INDEX_3X5': 'Index 3x5', + 'NA_INDEX_4X6': 'Index 4x6', + 'NA_INDEX_4X6_EXT': 'Index 4x6 ext', + 'NA_INDEX_5X8': '5x8', + 'NA_INVOICE': 'Invoice', + 'NA_LEDGER': 'Tabloid', // Ledger in portrait is called Tabloid. + 'NA_LEGAL': 'Legal', + 'NA_LEGAL_EXTRA': 'Legal extra', + 'NA_LETTER': 'Letter', + 'NA_LETTER_EXTRA': 'Letter extra', + 'NA_LETTER_PLUS': 'Letter plus', + 'NA_MONARCH': 'Monarch', + 'NA_NUMBER_10': 'Envelope #10', + 'NA_NUMBER_11': 'Envelope #11', + 'NA_NUMBER_12': 'Envelope #12', + 'NA_NUMBER_14': 'Envelope #14', + 'NA_NUMBER_9': 'Envelope #9', + 'NA_PERSONAL': 'Personal', + 'NA_QUARTO': 'Quarto', + 'NA_SUPER_A': 'Super A', + 'NA_SUPER_B': 'Super B', + 'NA_WIDE_FORMAT': 'Wide format', + 'OM_DAI_PA_KAI': 'Dai-pa-kai', + 'OM_FOLIO': 'Folio', + 'OM_FOLIO_SP': 'Folio SP', + 'OM_INVITE': 'Invite Envelope', + 'OM_ITALIAN': 'Italian Envelope', + 'OM_JUURO_KU_KAI': 'Juuro-ku-kai', + 'OM_LARGE_PHOTO': 'Large photo', + 'OM_OFICIO': 'Oficio', + 'OM_PA_KAI': 'Pa-kai', + 'OM_POSTFIX': 'Postfix Envelope', + 'OM_SMALL_PHOTO': 'Small photo', + 'PRC_1': 'prc1 Envelope', + 'PRC_10': 'prc10 Envelope', + 'PRC_16K': 'prc 16k', + 'PRC_2': 'prc2 Envelope', + 'PRC_3': 'prc3 Envelope', + 'PRC_32K': 'prc 32k', + 'PRC_4': 'prc4 Envelope', + 'PRC_5': 'prc5 Envelope', + 'PRC_6': 'prc6 Envelope', + 'PRC_7': 'prc7 Envelope', + 'PRC_8': 'prc8 Envelope', + 'ROC_16K': 'ROC 16K', + 'ROC_8K': 'ROC 8k', + }; + + /** * Localizes printer capabilities. * @param {!Object} capabilities Printer capabilities to localize. * @return {!Object} Localized capabilities. * @private */ DestinationStore.localizeCapabilities_ = function(capabilities) { + if (!capabilities.printer) + return capabilities; + var mediaSize = capabilities.printer.media_size; - if (mediaSize) { - var mediaDisplayNames = { - 'ISO_A0': 'A0', - 'ISO_A1': 'A1', - 'ISO_A2': 'A2', - 'ISO_A3': 'A3', - 'ISO_A4': 'A4', - 'ISO_A5': 'A5', - 'NA_LEGAL': 'Legal', - 'NA_LETTER': 'Letter', - 'NA_LEDGER': 'Tabloid' - }; - for (var i = 0, media; media = mediaSize.option[i]; i++) { - // No need to patch capabilities with localized names provided. - if (!media.custom_display_name_localized) { - media.custom_display_name = - media.custom_display_name || - mediaDisplayNames[media.name] || - media.name; - } + if (!mediaSize) + return capabilities; + + for (var i = 0, media; media = mediaSize.option[i]; i++) { + // No need to patch capabilities with localized names provided. + if (!media.custom_display_name_localized) { + media.custom_display_name = + media.custom_display_name || + DestinationStore.MEDIA_DISPLAY_NAMES_[media.name] || + media.name; } } return capabilities; }; + /** + * Compare two media sizes by their names. + * @param {!Object} a Media to compare. + * @param {!Object} b Media to compare. + * @return {number} 1 if a > b, -1 if a < b, or 0 if a == b. + * @private + */ + DestinationStore.compareMediaNames_ = function(a, b) { + var nameA = a.custom_display_name_localized || a.custom_display_name; + var nameB = b.custom_display_name_localized || b.custom_display_name; + return nameA == nameB ? 0 : (nameA > nameB ? 1 : -1); + }; + + /** + * Sort printer media sizes. + * @param {!Object} capabilities Printer capabilities to localize. + * @return {!Object} Localized capabilities. + * @private + */ + DestinationStore.sortMediaSizes_ = function(capabilities) { + if (!capabilities.printer) + return capabilities; + + var mediaSize = capabilities.printer.media_size; + if (!mediaSize) + return capabilities; + + // For the standard sizes, separate into categories, as seen in the Cloud + // Print CDD guide: + // - North American + // - Chinese + // - ISO + // - Japanese + // - Other metric + // Otherwise, assume they are custom sizes. + var categoryStandardNA = []; + var categoryStandardCN = []; + var categoryStandardISO = []; + var categoryStandardJP = []; + var categoryStandardMisc = []; + var categoryCustom = []; + for (var i = 0, media; media = mediaSize.option[i]; i++) { + var name = media.name || 'CUSTOM'; + var category; + if (name.startsWith('NA_')) { + category = categoryStandardNA; + } else if (name.startsWith('PRC_') || name.startsWith('ROC_') || + name == 'OM_DAI_PA_KAI' || name == 'OM_JUURO_KU_KAI' || + name == 'OM_PA_KAI') { + category = categoryStandardCN; + } else if (name.startsWith('ISO_')) { + category = categoryStandardISO; + } else if (name.startsWith('JIS_') || name.startsWith('JPN_')) { + category = categoryStandardJP; + } else if (name.startsWith('OM_')) { + category = categoryStandardMisc; + } else { + assert(name == 'CUSTOM', 'Unknown media size. Assuming custom'); + category = categoryCustom; + } + category.push(media); + } + + // For each category, sort by name. + categoryStandardNA.sort(DestinationStore.compareMediaNames_); + categoryStandardCN.sort(DestinationStore.compareMediaNames_); + categoryStandardISO.sort(DestinationStore.compareMediaNames_); + categoryStandardJP.sort(DestinationStore.compareMediaNames_); + categoryStandardMisc.sort(DestinationStore.compareMediaNames_); + categoryCustom.sort(DestinationStore.compareMediaNames_); + + // Then put it all back together. + mediaSize.option = categoryStandardNA; + mediaSize.option.push(...categoryStandardCN, ...categoryStandardISO, + ...categoryStandardJP, ...categoryStandardMisc, ...categoryCustom); + return capabilities; + }; + DestinationStore.prototype = { __proto__: cr.EventTarget.prototype, @@ -378,9 +620,8 @@ cr.define('print_preview', function() { return this.destinations_.filter(function(destination) { return !destination.account || destination.account == opt_account; }); - } else { - return this.destinations_.slice(0); } + return this.destinations_.slice(0); }, /** @@ -1076,7 +1317,7 @@ cr.define('print_preview', function() { * @param {print_preview.Destination=} opt_destination The only destination * that was changed or skipped if possibly more than one destination was * changed. Used as a hint to limit destination search scope against - * {@code autoSelectMatchingDestination_). + * {@code autoSelectMatchingDestination_}. */ destinationsInserted_: function(opt_destination) { cr.dispatchSimpleEvent( @@ -1097,12 +1338,14 @@ cr.define('print_preview', function() { * Updates an existing print destination with capabilities and display name * information. If the destination doesn't already exist, it will be added. * @param {!print_preview.Destination} destination Destination to update. - * @return {!print_preview.Destination} The existing destination that was - * updated or {@code null} if it was the new destination. * @private */ updateDestination_: function(destination) { assert(destination.constructor !== Array, 'Single printer expected'); + destination.capabilities_ = DestinationStore.localizeCapabilities_( + destination.capabilities_); + destination.capabilities_ = DestinationStore.sortMediaSizes_( + destination.capabilities_); var existingDestination = this.destinationMap_[this.getKey_(destination)]; if (existingDestination != null) { existingDestination.capabilities = destination.capabilities; @@ -1118,8 +1361,6 @@ cr.define('print_preview', function() { this, DestinationStore.EventType.SELECTED_DESTINATION_CAPABILITIES_READY); } - - return existingDestination; }, /** diff --git a/chromium/chrome/browser/resources/print_preview/data/print_ticket_store.js b/chromium/chrome/browser/resources/print_preview/data/print_ticket_store.js index e776e50f4ba..c3abdf2812f 100644 --- a/chromium/chrome/browser/resources/print_preview/data/print_ticket_store.js +++ b/chromium/chrome/browser/resources/print_preview/data/print_ticket_store.js @@ -110,6 +110,14 @@ cr.define('print_preview', function() { new print_preview.ticket_items.PageRange(this.documentInfo_); /** + * Scaling ticket item. + * @type {!print_preview.ticket_items.Scaling} + * @private + */ + this.scaling_ = new print_preview.ticket_items.Scaling( + this.appState_, this.destinationStore_, this.documentInfo_); + + /** * Custom margins ticket item. * @type {!print_preview.ticket_items.CustomMargins} * @private @@ -283,6 +291,10 @@ cr.define('print_preview', function() { return this.pageRange_; }, + get scaling() { + return this.scaling_; + }, + get selectionOnly() { return this.selectionOnly_; }, @@ -374,6 +386,12 @@ cr.define('print_preview', function() { print_preview.AppState.Field.IS_FIT_TO_PAGE_ENABLED))); } if (this.appState_.hasField( + print_preview.AppState.Field.SCALING)) { + this.scaling_.updateValue( + /** @type {!Object} */(this.appState_.getField( + print_preview.AppState.Field.SCALING))); + } + if (this.appState_.hasField( print_preview.AppState.Field.IS_CSS_BACKGROUND_ENABLED)) { this.cssBackground_.updateValue( /** @type {!Object} */(this.appState_.getField( diff --git a/chromium/chrome/browser/resources/print_preview/data/ticket_items/scaling.js b/chromium/chrome/browser/resources/print_preview/data/ticket_items/scaling.js new file mode 100644 index 00000000000..c7f3a37fb58 --- /dev/null +++ b/chromium/chrome/browser/resources/print_preview/data/ticket_items/scaling.js @@ -0,0 +1,101 @@ +// Copyright (c) 2016 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('print_preview.ticket_items', function() { + 'use strict'; + + /** + * Scaling ticket item whose value is a {@code string} that indicates what the + * scaling (in percent) of the document should be. The ticket item is backed + * by a string since the user can textually input the scaling value. + * @param {!print_preview.AppState} appState App state to persist item value. + * @param {!print_preview.DocumentInfo} documentInfo Information about the + * document to print. + * @param {!print_preview.DestinationStore} destinationStore Used to determine + * whether fit to page should be available. + * @constructor + * @extends {print_preview.ticket_items.TicketItem} + */ + function Scaling(appState, destinationStore, documentInfo) { + print_preview.ticket_items.TicketItem.call( + this, + appState, + print_preview.AppState.Field.SCALING, + destinationStore, + documentInfo); + }; + + /** + * Maximum scaling percentage + * @private {number} + * @const + */ + Scaling.MAX_VAL = 200; + + /** + * Minimum scaling percentage + * @private {number} + * @const + */ + Scaling.MIN_VAL = 10; + + Scaling.prototype = { + __proto__: print_preview.ticket_items.TicketItem.prototype, + + /** @override */ + wouldValueBeValid: function(value) { + if (/[^\d]+/.test(value)) { + return false; + } + var scaling = parseInt(value, 10); + return scaling >= Scaling.MIN_VAL && scaling <= Scaling.MAX_VAL; + }, + + /** @override */ + isValueEqual: function(value) { + return this.getValueAsNumber() == value; + }, + + /** + * @param {number} The desired scaling percentage. + * @return {number} Nearest valid scaling percentage + */ + getNearestValidValue: function(value) { + return Math.min(Math.max(value, Scaling.MIN_VAL), Scaling.MAX_VAL); + }, + + /** @override */ + isCapabilityAvailable: function() { + // This is not a function of the printer, but should be disabled if we are + // saving a PDF to a PDF. + var knownSizeToSaveAsPdf = + (!this.getDocumentInfoInternal().isModifiable || + this.getDocumentInfoInternal().hasCssMediaStyles) && + this.getSelectedDestInternal() && + this.getSelectedDestInternal().id == + print_preview.Destination.GooglePromotedId.SAVE_AS_PDF; + return !knownSizeToSaveAsPdf; + }, + + /** @return {number} The scaling percentage indicated by the ticket item. */ + getValueAsNumber: function() { + return parseInt(this.getValue(), 10); + }, + + /** @override */ + getDefaultValueInternal: function() { + return '100'; + }, + + /** @override */ + getCapabilityNotAvailableValueInternal: function() { + return '100'; + }, + }; + + // Export + return { + Scaling: Scaling + }; +}); diff --git a/chromium/chrome/browser/resources/print_preview/native_layer.js b/chromium/chrome/browser/resources/print_preview/native_layer.js index 127e993c3d9..c242f890409 100644 --- a/chromium/chrome/browser/resources/print_preview/native_layer.js +++ b/chromium/chrome/browser/resources/print_preview/native_layer.js @@ -287,7 +287,7 @@ cr.define('print_preview', function() { 'deviceName': destination == null ? 'foo' : destination.id, 'generateDraftData': documentInfo.isModifiable, 'fitToPageEnabled': printTicketStore.fitToPage.getValue(), - + 'scaleFactor': printTicketStore.scaling.getValueAsNumber(), // NOTE: Even though the following fields don't directly relate to the // preview, they still need to be included. 'duplex': printTicketStore.duplex.getValue() ? @@ -367,6 +367,7 @@ cr.define('print_preview', function() { 'printWithCloudPrint': !destination.isLocal, 'printWithPrivet': destination.isPrivet, 'printWithExtension': destination.isExtension, + 'scaleFactor': printTicketStore.scaling.getValueAsNumber(), 'deviceName': destination.id, 'isFirstRequest': false, 'requestID': -1, @@ -660,13 +661,17 @@ cr.define('print_preview', function() { * @param {number} pageCount The number of pages. * @param {number} previewResponseId The preview request id that resulted in * this response. + * @param {number} fitToPageScaling The scaling percentage required to fit + * the document to page, rounded to the nearest integer. * @private */ - onDidGetPreviewPageCount_: function(pageCount, previewResponseId) { + onDidGetPreviewPageCount_: function(pageCount, previewResponseId, + fitToPageScaling) { var pageCountChangeEvent = new Event( NativeLayer.EventType.PAGE_COUNT_READY); pageCountChangeEvent.pageCount = pageCount; pageCountChangeEvent.previewResponseId = previewResponseId; + pageCountChangeEvent.fitToPageScaling = fitToPageScaling; this.dispatchEvent(pageCountChangeEvent); }, diff --git a/chromium/chrome/browser/resources/print_preview/preview_generator.js b/chromium/chrome/browser/resources/print_preview/preview_generator.js index 597300f9fe3..8313ed736b6 100644 --- a/chromium/chrome/browser/resources/print_preview/preview_generator.js +++ b/chromium/chrome/browser/resources/print_preview/preview_generator.js @@ -93,6 +93,14 @@ cr.define('print_preview', function() { this.isFitToPageEnabled_ = false; /** + * The scaling factor (in percent) for the document. Ignored if fit to page + * is true. + * @type {number} + * @private + */ + this.scalingValue_ = 100; + + /** * Page ranges setting used used to generate the last preview. * @type {!Array<object<{from: number, to: number}>>} * @private @@ -177,6 +185,7 @@ cr.define('print_preview', function() { this.printTicketStore_.headerFooter.getValue(); this.colorValue_ = this.printTicketStore_.color.getValue(); this.isFitToPageEnabled_ = this.printTicketStore_.fitToPage.getValue(); + this.scalingValue_ = this.printTicketStore_.scaling.getValueAsNumber(); this.pageRanges_ = this.printTicketStore_.pageRange.getPageRanges(); this.marginsType_ = this.printTicketStore_.marginsType.getValue(); this.isCssBackgroundEnabled_ = @@ -275,6 +284,7 @@ cr.define('print_preview', function() { !ticketStore.landscape.isValueEqual(this.isLandscapeEnabled_) || !ticketStore.headerFooter.isValueEqual(this.isHeaderFooterEnabled_) || !ticketStore.color.isValueEqual(this.colorValue_) || + !ticketStore.scaling.isValueEqual(this.scalingValue_) || !ticketStore.fitToPage.isValueEqual(this.isFitToPageEnabled_) || this.pageRanges_ == null || !areRangesEqual(ticketStore.pageRange.getPageRanges(), diff --git a/chromium/chrome/browser/resources/print_preview/previewarea/preview_area.js b/chromium/chrome/browser/resources/print_preview/previewarea/preview_area.js index b2163bea8d5..b96dfaeac06 100644 --- a/chromium/chrome/browser/resources/print_preview/previewarea/preview_area.js +++ b/chromium/chrome/browser/resources/print_preview/previewarea/preview_area.js @@ -369,6 +369,10 @@ cr.define('print_preview', function() { this.printTicketStore_.selectionOnly, print_preview.ticket_items.TicketItem.EventType.CHANGE, this.onTicketChange_.bind(this)); + this.tracker.add( + this.printTicketStore_.scaling, + print_preview.ticket_items.TicketItem.EventType.CHANGE, + this.onTicketChange_.bind(this)); if (this.checkPluginCompatibility_()) { this.previewGenerator_ = new print_preview.PreviewGenerator( diff --git a/chromium/chrome/browser/resources/print_preview/print_preview.html b/chromium/chrome/browser/resources/print_preview/print_preview.html index 6294da754f0..05cb0fed976 100644 --- a/chromium/chrome/browser/resources/print_preview/print_preview.html +++ b/chromium/chrome/browser/resources/print_preview/print_preview.html @@ -16,6 +16,7 @@ <link rel="stylesheet" href="settings/destination_settings.css"> <link rel="stylesheet" href="settings/color_settings.css"> <link rel="stylesheet" href="settings/copies_settings.css"> + <link rel="stylesheet" href="settings/settings_box.css"> <link rel="stylesheet" href="settings/page_settings.css"> <link rel="stylesheet" href="settings/margin_settings.css"> <link rel="stylesheet" href="settings/media_size_settings.css"> @@ -69,6 +70,7 @@ <include src="settings/media_size_settings.html"> <include src="settings/margin_settings.html"> <include src="settings/dpi_settings.html"> + <include src="settings/scaling_settings.html"> <include src="settings/other_options_settings.html"> <include src="settings/advanced_options_settings.html"> <include src="settings/more_settings.html"> diff --git a/chromium/chrome/browser/resources/print_preview/print_preview.js b/chromium/chrome/browser/resources/print_preview/print_preview.js index f220da8eaeb..0c5f7c9cda4 100644 --- a/chromium/chrome/browser/resources/print_preview/print_preview.js +++ b/chromium/chrome/browser/resources/print_preview/print_preview.js @@ -19,6 +19,13 @@ cr.define('print_preview', function() { print_preview.Component.call(this); /** + * Whether the print scaling feature is enabled. + * @type {boolean} + * @private + */ + this.scalingEnabled_ = loadTimeData.getBoolean('scalingEnabled'); + + /** * Used to communicate with Chromium's print system. * @type {!print_preview.NativeLayer} * @private @@ -115,15 +122,6 @@ cr.define('print_preview', function() { this.addChild(this.copiesSettings_); /** - * Component that renders the media size settings. - * @type {!print_preview.MediaSizeSettings} - * @private - */ - this.mediaSizeSettings_ = - new print_preview.MediaSizeSettings(this.printTicketStore_.mediaSize); - this.addChild(this.mediaSizeSettings_); - - /** * Component that renders the layout settings. * @type {!print_preview.LayoutSettings} * @private @@ -141,6 +139,15 @@ cr.define('print_preview', function() { new print_preview.ColorSettings(this.printTicketStore_.color); this.addChild(this.colorSettings_); + /** + * Component that renders the media size settings. + * @type {!print_preview.MediaSizeSettings} + * @private + */ + this.mediaSizeSettings_ = + new print_preview.MediaSizeSettings(this.printTicketStore_.mediaSize); + this.addChild(this.mediaSizeSettings_); + /** * Component that renders a select box for choosing margin settings. * @type {!print_preview.MarginSettings} @@ -159,6 +166,18 @@ cr.define('print_preview', function() { new print_preview.DpiSettings(this.printTicketStore_.dpi); this.addChild(this.dpiSettings_); + if (this.scalingEnabled_) { + /** + * Component that renders the scaling settings. + * @type {!print_preview.ScalingSettings} + * @private + */ + this.scalingSettings_ = + new print_preview.ScalingSettings(this.printTicketStore_.scaling, + this.printTicketStore_.fitToPage); + this.addChild(this.scalingSettings_); + } + /** * Component that renders miscellaneous print options. * @type {!print_preview.OtherOptionsSettings} @@ -201,6 +220,10 @@ cr.define('print_preview', function() { this.dpiSettings_, this.otherOptionsSettings_, this.advancedOptionsSettings_]; + if (this.scalingEnabled_) { + settingsSections.splice(8, 0, this.scalingSettings_); + } + /** * Component representing more/less settings button. * @type {!print_preview.MoreSettings} @@ -349,6 +372,12 @@ cr.define('print_preview', function() { this.nativeLayer_, print_preview.NativeLayer.EventType.PRINT_PRESET_OPTIONS, this.onPrintPresetOptionsFromDocument_.bind(this)); + if (this.scalingEnabled_) { + this.tracker.add( + this.nativeLayer_, + print_preview.NativeLayer.EventType.PAGE_COUNT_READY, + this.onPageCountReady_.bind(this)); + } this.tracker.add( this.nativeLayer_, print_preview.NativeLayer.EventType.PRIVET_PRINT_FAILED, @@ -468,11 +497,13 @@ cr.define('print_preview', function() { this.destinationSettings_.decorate($('destination-settings')); this.pageSettings_.decorate($('page-settings')); this.copiesSettings_.decorate($('copies-settings')); - this.mediaSizeSettings_.decorate($('media-size-settings')); this.layoutSettings_.decorate($('layout-settings')); this.colorSettings_.decorate($('color-settings')); + this.mediaSizeSettings_.decorate($('media-size-settings')); this.marginSettings_.decorate($('margin-settings')); this.dpiSettings_.decorate($('dpi-settings')); + if (this.scalingEnabled_) + this.scalingSettings_.decorate($('scaling-settings')); this.otherOptionsSettings_.decorate($('other-options-settings')); this.advancedOptionsSettings_.decorate($('advanced-options-settings')); this.advancedSettings_.decorate($('advanced-settings')); @@ -495,11 +526,13 @@ cr.define('print_preview', function() { this.destinationSettings_.isEnabled = isEnabled; this.pageSettings_.isEnabled = isEnabled; this.copiesSettings_.isEnabled = isEnabled; - this.mediaSizeSettings_.isEnabled = isEnabled; this.layoutSettings_.isEnabled = isEnabled; this.colorSettings_.isEnabled = isEnabled; + this.mediaSizeSettings_.isEnabled = isEnabled; this.marginSettings_.isEnabled = isEnabled; this.dpiSettings_.isEnabled = isEnabled; + if (this.scalingEnabled_) + this.scalingSettings_.isEnabled = isEnabled; this.otherOptionsSettings_.isEnabled = isEnabled; this.advancedOptionsSettings_.isEnabled = isEnabled; }, @@ -1000,6 +1033,20 @@ cr.define('print_preview', function() { }, /** + * Called when the Page Count Ready message is received to update the fit to + * page scaling value in the scaling settings. + * @param {Event} event Event object representing the page count ready + * message + * @private + */ + onPageCountReady_: function(event) { + if (event.fitToPageScaling >= 0) { + this.scalingSettings_.updateFitToPageScaling( + event.fitToPageScaling); + } + }, + + /** * Called when privet printing fails. * @param {Event} event Event object representing the failure. * @private @@ -1269,6 +1316,7 @@ cr.define('print_preview', function() { <include src="data/ticket_items/duplex.js"> <include src="data/ticket_items/header_footer.js"> <include src="data/ticket_items/media_size.js"> +<include src="data/ticket_items/scaling.js"> <include src="data/ticket_items/landscape.js"> <include src="data/ticket_items/margins_type.js"> <include src="data/ticket_items/page_range.js"> @@ -1286,14 +1334,15 @@ cr.define('print_preview', function() { <include src="settings/settings_section.js"> <include src="settings/settings_section_select.js"> +<include src="settings/destination_settings.js"> <include src="settings/page_settings.js"> <include src="settings/copies_settings.js"> -<include src="settings/dpi_settings.js"> -<include src="settings/media_size_settings.js"> <include src="settings/layout_settings.js"> <include src="settings/color_settings.js"> +<include src="settings/media_size_settings.js"> <include src="settings/margin_settings.js"> -<include src="settings/destination_settings.js"> +<include src="settings/dpi_settings.js"> +<include src="settings/scaling_settings.js"> <include src="settings/other_options_settings.js"> <include src="settings/advanced_options_settings.js"> <include src="settings/advanced_settings/advanced_settings.js"> diff --git a/chromium/chrome/browser/resources/print_preview/settings/copies_settings.css b/chromium/chrome/browser/resources/print_preview/settings/copies_settings.css index e053e8bfe4f..e2e1b6f9848 100644 --- a/chromium/chrome/browser/resources/print_preview/settings/copies_settings.css +++ b/chromium/chrome/browser/resources/print_preview/settings/copies_settings.css @@ -2,64 +2,11 @@ * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ -#copies-settings input.copies { - height: 29px; - position: relative; - width: 2.75em; -} - -#copies-settings-box { - margin: 10px 0; -} - -#copies-settings input.copies.invalid { - background: rgb(255, 240, 240); - color: rgb(140, 20, 20); -} - -#copies-settings button.increment:focus, -#copies-settings button.decrement:focus, -#copies-settings:focus { - z-index: 1; -} - #copies-settings .collate-container { -webkit-padding-start: 16px; display: inline-block; } -#copies-settings button.increment, -#copies-settings button.decrement { - -webkit-padding-end: 0; - -webkit-padding-start: 0; - font-weight: 600; - height: 29px; - margin: 0; - min-width: 0; - position: relative; - width: 2em; -} - -#copies-settings button.increment { - -webkit-margin-start: -5px; - border-radius: 0; -} - -#copies-settings button.decrement { - -webkit-margin-start: -5px; - border-bottom-left-radius: 0; - border-bottom-right-radius: 3px; - border-top-left-radius: 0; - border-top-right-radius: 3px; -} - -html[dir='rtl'] #copies-settings button.decrement { - border-bottom-left-radius: 3px; - border-bottom-right-radius: 0; - border-top-left-radius: 3px; - border-top-right-radius: 0; -} - #copies-settings .collate-container label { - padding-top: 6px; + padding: 0; } diff --git a/chromium/chrome/browser/resources/print_preview/settings/copies_settings.html b/chromium/chrome/browser/resources/print_preview/settings/copies_settings.html index 42c7bff00c1..5116d70404f 100644 --- a/chromium/chrome/browser/resources/print_preview/settings/copies_settings.html +++ b/chromium/chrome/browser/resources/print_preview/settings/copies_settings.html @@ -1,24 +1,20 @@ <div id="copies-settings" class="two-column" hidden> <div class="left-column"> - <h1 id="copies-label" i18n-content="copiesLabel"></h1> + <h1 id="copies-label">$i18n{copiesLabel}</h1> </div> <div class="right-column"> - <div id="copies-settings-box"> - <input class="copies" type="text" value="1" maxlength="3" - aria-labelledby="copies-label" aria-live="polite" id="copies"> - <button class="increment" - i18n-values="title:incrementTitle;aria-label:incrementTitle" - aria-controls="copies">+</button> - <button class="decrement" - i18n-values="title:decrementTitle;aria-label:decrementTitle" - aria-controls="copies">–</button> + <div class="settings-box" id="copies-settings-box"> + <input class="user-value" type="number" value="1" maxlength="3" + max="999" min="1" + aria-labelledby="copies-label" id="copies"> <div class="collate-container checkbox" aria-live="polite" hidden><label> <input class="collate" type="checkbox" checked aria-labelledby="copies-collate-label"> - <span id="copies-collate-label" i18n-content="optionCollate"></span> + <span id="copies-collate-label">$i18n{optionCollate}</span> </label></div> </div> - <span class="hint" i18n-content="copiesInstruction" aria-live="polite"> + <span class="hint" aria-live="polite" aria-hidden="true"> + $i18n{copiesInstruction}</span> </span> </div> </div> diff --git a/chromium/chrome/browser/resources/print_preview/settings/copies_settings.js b/chromium/chrome/browser/resources/print_preview/settings/copies_settings.js index ce5d5ef92e1..6ac9a998372 100644 --- a/chromium/chrome/browser/resources/print_preview/settings/copies_settings.js +++ b/chromium/chrome/browser/resources/print_preview/settings/copies_settings.js @@ -32,7 +32,7 @@ cr.define('print_preview', function() { this.collateTicketItem_ = collateTicketItem; /** - * Timeout used to delay processing of the copies input. + * Timeout used to delay processing of the copies input in ms * @type {?number} * @private */ @@ -44,6 +44,13 @@ cr.define('print_preview', function() { * @private */ this.isEnabled_ = true; + + /** + * The element for the user input value. + * @type {HTMLElement} + * @private + */ + this.inputField_ = null; }; /** @@ -51,7 +58,7 @@ cr.define('print_preview', function() { * @type {number} * @private */ - CopiesSettings.TEXTFIELD_DELAY_ = 250; + CopiesSettings.TEXTFIELD_DELAY_MS_ = 250; CopiesSettings.prototype = { __proto__: print_preview.SettingsSection.prototype, @@ -68,41 +75,31 @@ cr.define('print_preview', function() { /** @override */ set isEnabled(isEnabled) { - this.getChildElement('input.copies').disabled = !isEnabled; + this.inputField_.disabled = !isEnabled; this.getChildElement('input.collate').disabled = !isEnabled; this.isEnabled_ = isEnabled; if (isEnabled) { this.updateState_(); - } else { - this.getChildElement('button.increment').disabled = true; - this.getChildElement('button.decrement').disabled = true; } }, /** @override */ enterDocument: function() { + this.inputField_ = this.getChildElement('input.user-value'); print_preview.SettingsSection.prototype.enterDocument.call(this); this.tracker.add( - this.getChildElement('input.copies'), + this.inputField_, 'keydown', this.onTextfieldKeyDown_.bind(this)); this.tracker.add( - this.getChildElement('input.copies'), + this.inputField_, 'input', this.onTextfieldInput_.bind(this)); this.tracker.add( - this.getChildElement('input.copies'), + this.inputField_, 'blur', this.onTextfieldBlur_.bind(this)); this.tracker.add( - this.getChildElement('button.increment'), - 'click', - this.onButtonClicked_.bind(this, 1)); - this.tracker.add( - this.getChildElement('button.decrement'), - 'click', - this.onButtonClicked_.bind(this, -1)); - this.tracker.add( this.getChildElement('input.collate'), 'click', this.onCollateCheckboxClick_.bind(this)); @@ -122,29 +119,18 @@ cr.define('print_preview', function() { */ updateState_: function() { if (this.isAvailable()) { - if (this.getChildElement('input.copies').value != - this.copiesTicketItem_.getValue()) { - this.getChildElement('input.copies').value = - this.copiesTicketItem_.getValue(); - } + if (this.inputField_.value != this.copiesTicketItem_.getValue()) + this.inputField_.value = this.copiesTicketItem_.getValue(); var currentValueGreaterThan1 = false; if (this.copiesTicketItem_.isValid()) { - this.getChildElement('input.copies').classList.remove('invalid'); + this.inputField_.classList.remove('invalid'); fadeOutElement(this.getChildElement('.hint')); var currentValue = this.copiesTicketItem_.getValueAsNumber(); - var currentValueGreaterThan1 = currentValue > 1; - this.getChildElement('button.increment').disabled = - !this.isEnabled_ || - !this.copiesTicketItem_.wouldValueBeValid(currentValue + 1); - this.getChildElement('button.decrement').disabled = - !this.isEnabled_ || - !this.copiesTicketItem_.wouldValueBeValid(currentValue - 1); + currentValueGreaterThan1 = currentValue > 1; } else { - this.getChildElement('input.copies').classList.add('invalid'); + this.inputField_.classList.add('invalid'); fadeInElement(this.getChildElement('.hint')); - this.getChildElement('button.increment').disabled = true; - this.getChildElement('button.decrement').disabled = true; } if (!(this.getChildElement('.collate-container').hidden = @@ -158,25 +144,12 @@ cr.define('print_preview', function() { }, /** - * Called whenever the increment/decrement buttons are clicked. - * @param {number} delta Must be 1 for an increment button click and -1 for - * a decrement button click. - * @private - */ - onButtonClicked_: function(delta) { - // Assumes text field has a valid number. - var newValue = - parseInt(this.getChildElement('input.copies').value, 10) + delta; - this.copiesTicketItem_.updateValue(newValue + ''); - }, - - /** * Called after a timeout after user input into the textfield. * @private */ onTextfieldTimeout_: function() { this.textfieldTimeout_ = null; - var copiesVal = this.getChildElement('input.copies').value; + var copiesVal = this.inputField_.value; if (copiesVal != '') { this.copiesTicketItem_.updateValue(copiesVal); } @@ -188,12 +161,12 @@ cr.define('print_preview', function() { * @private */ onTextfieldKeyDown_: function(event) { - if (event.keyCode == 13 /*enter*/) { - if (this.textfieldTimeout_) { - clearTimeout(this.textfieldTimeout_); - } - this.onTextfieldTimeout_(); - } + if (event.keyCode != 'Enter') + return; + + if (this.textfieldTimeout_) + clearTimeout(this.textfieldTimeout_); + this.onTextfieldTimeout_(); }, /** @@ -206,7 +179,8 @@ cr.define('print_preview', function() { clearTimeout(this.textfieldTimeout_); } this.textfieldTimeout_ = setTimeout( - this.onTextfieldTimeout_.bind(this), CopiesSettings.TEXTFIELD_DELAY_); + this.onTextfieldTimeout_.bind(this), + CopiesSettings.TEXTFIELD_DELAY_MS_); }, /** @@ -215,12 +189,15 @@ cr.define('print_preview', function() { * @private */ onTextfieldBlur_: function() { - if (this.getChildElement('input.copies').value == '') { - // Do it asynchronously to avoid moving focus to Print button in - // PrintHeader.onTicketChange_. - setTimeout((function() { - this.copiesTicketItem_.updateValue('1'); - }).bind(this), 0); + if (this.inputField_.value == '') { + if (this.copiesTicketItem_.getValue() == '1') { + // No need to update the ticket, but change the display to match. + this.inputField_.value = '1'; + } else { + setTimeout((function() { + this.copiesTicketItem_.updateValue('1'); + }).bind(this), 0); + } } }, diff --git a/chromium/chrome/browser/resources/print_preview/settings/scaling_settings.html b/chromium/chrome/browser/resources/print_preview/settings/scaling_settings.html new file mode 100644 index 00000000000..26b3f2a5351 --- /dev/null +++ b/chromium/chrome/browser/resources/print_preview/settings/scaling_settings.html @@ -0,0 +1,13 @@ +<div id="scaling-settings" class="two-column" hidden> + <div class="left-column"> + <h1 id="scaling-label">$i18n{scalingLabel}</h1> + </div> + <div class="right-column"> + <div class="settings-box"> + <input class="user-value" aria-labelledby="scaling-label" + type="number" value="100" max="200" min="10" maxlength="3"> + </div> + <span class="hint" aria-live="polite" aria-hidden="true"> + $i18n{scalingInstruction}</span> + </div> +</div> diff --git a/chromium/chrome/browser/resources/print_preview/settings/scaling_settings.js b/chromium/chrome/browser/resources/print_preview/settings/scaling_settings.js new file mode 100644 index 00000000000..9ac5438c86f --- /dev/null +++ b/chromium/chrome/browser/resources/print_preview/settings/scaling_settings.js @@ -0,0 +1,289 @@ +// Copyright (c) 2016 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('print_preview', function() { + 'use strict'; + + /** + * Component that renders the scaling settings UI. + * @param {!print_preview.ticket_items.scalingTicketItem} scalingTicketItem + * Used to read and write the scaling value. + * @param {!print_preview.ticket_items.fitToPageticketItem} + * fitToPageTicketItem Used to read the fit to page value. + * @constructor + * @extends {print_preview.SettingsSection} + */ + function ScalingSettings(scalingTicketItem, fitToPageTicketItem) { + print_preview.SettingsSection.call(this); + + /** + * Used to read and write the scaling value. + * @private {!print_preview.ticket_items.Scaling} + */ + this.scalingTicketItem_ = scalingTicketItem; + + /** + * Used to read the fit to page value + * @private {!print_preview.ticket_items.FitToPage} + */ + this.fitToPageTicketItem_ = fitToPageTicketItem; + + /** + * The scaling percentage required to fit the document to page + * @private {number} + */ + this.fitToPageScaling_ = 100; + + /** + * Timeout used to delay processing of the scaling input, in ms. + * @private {?number} + */ + this.textfieldTimeout_ = null; + + /** + * Whether this component is enabled or not. + * @private {boolean} + */ + this.isEnabled_ = true; + + /** + * The textfield input element + * @private {HTMLElement} + */ + this.inputField_ = null; + + }; + + /** + * Delay in milliseconds before processing the textfield. + * @private {number} + * @const + */ + ScalingSettings.TEXTFIELD_DELAY_MS_ = 250; + + ScalingSettings.prototype = { + __proto__: print_preview.SettingsSection.prototype, + + /** @override */ + isAvailable: function() { + return this.scalingTicketItem_.isCapabilityAvailable(); + }, + + /** @override */ + hasCollapsibleContent: function() { + return this.isAvailable(); + }, + + /** @override */ + set isEnabled(isEnabled) { + this.inputField_.disabled = !isEnabled; + this.isEnabled_ = isEnabled; + if (isEnabled) + this.updateState_(); + }, + + /** @override */ + enterDocument: function() { + this.inputField_ = this.getChildElement('input.user-value'); + print_preview.SettingsSection.prototype.enterDocument.call(this); + this.tracker.add( + this.inputField_, + 'keydown', + this.onTextfieldKeyDown_.bind(this)); + this.tracker.add( + this.inputField_, + 'input', + this.onTextfieldInput_.bind(this)); + this.tracker.add( + this.inputField_, + 'blur', + this.onTextfieldBlur_.bind(this)); + this.tracker.add( + this.scalingTicketItem_, + print_preview.ticket_items.TicketItem.EventType.CHANGE, + this.updateState_.bind(this)); + this.tracker.add( + this.fitToPageTicketItem_, + print_preview.ticket_items.TicketItem.EventType.CHANGE, + this.onFitToPageChange_.bind(this)); + }, + + /** + * @return {boolean} true if fit to page is available and selected. + * @private + */ + isFitToPageSelected: function() { + return this.fitToPageTicketItem_.isCapabilityAvailable() && + this.fitToPageTicketItem_.getValue(); + }, + + /** + * @return {number} The current input field value as an integer. + * @private + */ + getInputAsNumber: function() { + return (/[^\d]+/.test(this.inputField_.value)) ? + 0 : // Return an invalid scaling so that the hint will display. + parseInt(this.inputField_.value, 10); + }, + + /** + * Display the fit to page scaling in the scaling field if there is a valid + * fit to page scaling value. If not, make the field blank. + * @private + */ + displayFitToPageScaling: function() { + this.inputField_.value = this.fitToPageScaling_ || ''; + }, + + /** + * Updates the fit to page scaling value of the scalings settings UI. + * @param {number} fitToPageScaling The updated percentage scaling required + * to fit the document to page. + */ + updateFitToPageScaling: function(fitToPageScaling) { + this.fitToPageScaling_ = fitToPageScaling; + // Display the new value if fit to page is checked. + if (this.isFitToPageSelected()) + this.displayFitToPageScaling(); + }, + + /** + * Updates the state of the scaling settings UI controls. + * @private + */ + updateState_: function() { + if (this.isAvailable()) { + var displayedValue = this.getInputAsNumber(); + var inputString = this.inputField_.value; + // Display should be updated to match the ticket item unless displayed + // value is invalid and non-blank or fit to page is checked. In these + // cases, the ticket item is not updated and retains its last valid, + // user specified value. + if ((inputString == '' || + (displayedValue !== this.scalingTicketItem_.getValueAsNumber() && + this.scalingTicketItem_.wouldValueBeValid(inputString))) && + !this.isFitToPageSelected()) { + this.inputField_.value = this.scalingTicketItem_.getValue(); + displayedValue = this.getInputAsNumber(); + inputString = this.inputField_.value; + } + + // If fit to page is selected and the value matches the fit to page + // scaling, or if the value is valid, no hint is displayed + if (this.scalingTicketItem_.wouldValueBeValid(inputString) || + (this.isFitToPageSelected() && + (displayedValue == this.fitToPageScaling_ || + (!this.fitToPageScaling_ && inputString == '')))) { + this.inputField_.classList.remove('invalid'); + fadeOutElement(this.getChildElement('.hint')); + } else { + // Invalid value. Display the hint. + this.inputField_.classList.add('invalid'); + fadeInElement(this.getChildElement('.hint')); + } + + } + this.updateUiStateInternal(); + }, + + /** + * Helper function to adjust the scaling display if fit to page is checked + * by the user. + * @private + */ + onFitToPageChange_: function() { + if (this.isFitToPageSelected()) { + // Fit to page was checked. Set scaling to the fit to page scaling. + this.displayFitToPageScaling(); + } else if (this.fitToPageTicketItem_.isCapabilityAvailable() && + (this.getInputAsNumber() == this.fitToPageScaling_ || + this.inputField_.value == '')) { + // Fit to page unchecked. Return to last scaling. + this.inputField_.value = this.scalingTicketItem_.getValue(); + } + }, + + /** + * Called after a timeout after user input into the textfield. + * @private + */ + onTextfieldTimeout_: function() { + this.textfieldTimeout_ = null; + var scalingValue = this.inputField_.value; + if (scalingValue == '') + return; + if (this.scalingTicketItem_.wouldValueBeValid(scalingValue)) { + if (scalingValue === this.scalingTicketItem_.getValue()) { + // Make sure this still gets called in case returning to a valid + // value. + this.updateState_(); + } + if (this.isFitToPageSelected() && + parseInt(scalingValue, 10) != this.fitToPageScaling_) { + // User modified value away from fit to page. + this.fitToPageTicketItem_.updateValue(false); + } + this.scalingTicketItem_.updateValue(scalingValue); + this.inputField_.value = scalingValue; + } else { + this.updateState_(); + } + }, + + /** + * Called when a key is pressed on the custom input. + * @param {!Event} event Contains the key that was pressed. + * @private + */ + onTextfieldKeyDown_: function(event) { + if (event.keyCode != 'Enter') + return; + + if (this.textfieldTimeout_) + clearTimeout(this.textfieldTimeout_); + this.onTextfieldTimeout_(); + }, + + /** + * Called when a input event occurs on the textfield. Starts an input + * timeout. + * @private + */ + onTextfieldInput_: function() { + if (this.textfieldTimeout_) { + clearTimeout(this.textfieldTimeout_); + } + this.textfieldTimeout_ = setTimeout( + this.onTextfieldTimeout_.bind(this), + ScalingSettings.TEXTFIELD_DELAY_MS_); + }, + + /** + * Called when the focus leaves the textfield. If the textfield is empty, + * its value is set to the fit to page value if fit to page is checked and + * 100 otherwise. + * @private + */ + onTextfieldBlur_: function() { + if (this.inputField_.value == '') { + if (this.isFitToPageSelected()) { + this.displayFitToPageScaling(); + } else { + if (this.scalingTicketItem_.getValue() == '100') + // No need to update the ticket, but change the display to match. + this.inputField_.value = '100'; + else + this.scalingTicketItem_.updateValue('100'); + } + } + }, + + }; + + // Export + return { + ScalingSettings: ScalingSettings + }; +}); diff --git a/chromium/chrome/browser/resources/print_preview/settings/settings_box.css b/chromium/chrome/browser/resources/print_preview/settings/settings_box.css new file mode 100644 index 00000000000..cf48b061b00 --- /dev/null +++ b/chromium/chrome/browser/resources/print_preview/settings/settings_box.css @@ -0,0 +1,8 @@ +/* Copyright (c) 2016 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. */ + +.settings-box input.user-value.invalid { + background: rgb(255, 240, 240); + color: rgb(140, 20, 20); +} diff --git a/chromium/chrome/browser/resources/safe_browsing/download_file_types.asciipb b/chromium/chrome/browser/resources/safe_browsing/download_file_types.asciipb index 077cdeaabab..29790bdbd2e 100644 --- a/chromium/chrome/browser/resources/safe_browsing/download_file_types.asciipb +++ b/chromium/chrome/browser/resources/safe_browsing/download_file_types.asciipb @@ -8,7 +8,7 @@ ## ## Top level settings ## -version_id: 5 +version_id: 8 sampled_ping_probability: 0.01 default_file_type { uma_value: 18 @@ -2659,4 +2659,9 @@ file_types { danger_level: ALLOW_ON_USER_GESTURE auto_open_hint: DISALLOW_AUTO_OPEN } + platform_settings { + platform: PLATFORM_LINUX + danger_level: ALLOW_ON_USER_GESTURE + auto_open_hint: DISALLOW_AUTO_OPEN + } } diff --git a/chromium/chrome/browser/resources/safe_browsing/gen_file_type_proto.py b/chromium/chrome/browser/resources/safe_browsing/gen_file_type_proto.py index be43adc28a5..3ec8c238dcd 100755 --- a/chromium/chrome/browser/resources/safe_browsing/gen_file_type_proto.py +++ b/chromium/chrome/browser/resources/safe_browsing/gen_file_type_proto.py @@ -17,6 +17,15 @@ import subprocess import sys import traceback +# If the script is run in a virtualenv (https://virtualenv.pypa.io/en/stable/), +# then no google.protobuf library should be brought in from site-packages. +# Passing -S into the interpreter in a virtualenv actually destroys the ability +# to import standard library functions like optparse, so this script should not +# be wrapped if we're in a virtualenv. +def IsInVirtualEnv(): + # This is the way used by pip and other software to detect virtualenv. + return hasattr(sys, 'real_prefix') + def ImportProtoModules(paths): """Import the protobuf modiles we need. |paths| is list of import paths""" @@ -208,8 +217,12 @@ def main(): parser.print_help() return 1 - if opts.wrap: - # Run this script again with different args to the interpreter. + if opts.wrap and not IsInVirtualEnv(): + # Run this script again with different args to the interpreter to suppress + # the inclusion of libraries, like google.protobuf, from site-packages, + # which is checked before sys.path when resolving imports. We want to + # specifically import the libraries injected into the sys.path in + # ImportProtoModules(). command = [sys.executable, '-S', '-s', sys.argv[0]] if opts.type is not None: command += ['-t', opts.type] diff --git a/chromium/chrome/browser/resources/settings/a11y_page/a11y_page.html b/chromium/chrome/browser/resources/settings/a11y_page/a11y_page.html index f0f24882ea0..808671a5552 100644 --- a/chromium/chrome/browser/resources/settings/a11y_page/a11y_page.html +++ b/chromium/chrome/browser/resources/settings/a11y_page/a11y_page.html @@ -30,8 +30,7 @@ $i18n{manageAccessibilityFeatures} <div class="secondary">$i18n{moreFeaturesLinkDescription}</div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"> - </button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> </neon-animatable> <template is="dom-if" route-path="/manageAccessibility"> diff --git a/chromium/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html b/chromium/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html index 57331023e85..594bffe3261 100644 --- a/chromium/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html +++ b/chromium/chrome/browser/resources/settings/a11y_page/manage_a11y_page.html @@ -117,7 +117,8 @@ <div>$i18n{delayBeforeClickLabel}</div> <settings-dropdown-menu pref="{{prefs.settings.a11y.autoclick_delay_ms}}" - menu-options="[[autoClickDelayOptions_]]"> + menu-options="[[autoClickDelayOptions_]]" + disabled="[[!prefs.settings.a11y.autoclick.value]]"> </settings-dropdown-menu> </div> <settings-checkbox label="$i18n{tapDraggingLabel}" @@ -136,8 +137,7 @@ <div class="middle"> <div>$i18n{mouseSettingsTitle}</div> <div class="secondary">$i18n{mouseSettingsDescription}</div> - <button class="icon-arrow-right" is="paper-icon-button-light"> - </button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> </div> diff --git a/chromium/chrome/browser/resources/settings/a11y_page/manage_a11y_page.js b/chromium/chrome/browser/resources/settings/a11y_page/manage_a11y_page.js index c8c2437d2e6..5d5f101b8a4 100644 --- a/chromium/chrome/browser/resources/settings/a11y_page/manage_a11y_page.js +++ b/chromium/chrome/browser/resources/settings/a11y_page/manage_a11y_page.js @@ -23,6 +23,9 @@ Polymer({ readOnly: true, type: Array, value: function() { + // These values correspond to the i18n values in settings_strings.grdp. + // If these values get changed then those strings need to be changed as + // well. return [ {value: 600, name: loadTimeData.getString('delayBeforeClickExtremelyShort')}, diff --git a/chromium/chrome/browser/resources/settings/about_page/about_page.html b/chromium/chrome/browser/resources/settings/about_page/about_page.html index c896e490d5d..6b28c21ca1c 100644 --- a/chromium/chrome/browser/resources/settings/about_page/about_page.html +++ b/chromium/chrome/browser/resources/settings/about_page/about_page.html @@ -83,14 +83,16 @@ <div class="settings-box two-line"> <iron-icon hidden="[[!shouldShowUpdateStatusIcon_( - currentUpdateStatusEvent_)]]" - icon$="[[getIcon_(currentUpdateStatusEvent_)]]" - src="[[getIconSrc_(currentUpdateStatusEvent_)]]"> + obsoleteSystemInfo_, currentUpdateStatusEvent_)]]" + icon$="[[getIcon_( + obsoleteSystemInfo_, currentUpdateStatusEvent_)]]" + src="[[getIconSrc_( + obsoleteSystemInfo_, currentUpdateStatusEvent_)]]"> </iron-icon> <div class="start"> <div id="updateStatusMessage" hidden="[[!shouldShowUpdateStatusMessage_( - currentUpdateStatusEvent_)]]" + obsoleteSystemInfo_, currentUpdateStatusEvent_)]]" <if expr="not chromeos"> inner-h-t-m-l="[[getUpdateStatusMessage_( currentUpdateStatusEvent_)]]"> @@ -130,7 +132,8 @@ $i18n{aboutRelaunchAndPowerwash} </paper-button> <paper-button id="checkForUpdates" class="secondary-button" - hidden="[[!shouldShowCheckUpdates_(currentUpdateStatusEvent_)]]" + hidden="[[!shouldShowCheckUpdates_( + currentUpdateStatusEvent_)]]" on-tap="onCheckUpdatesTap_"> $i18n{aboutCheckForUpdates} </paper-button> diff --git a/chromium/chrome/browser/resources/settings/about_page/about_page.js b/chromium/chrome/browser/resources/settings/about_page/about_page.js index dc61dbb1f5c..966bee8e2b6 100644 --- a/chromium/chrome/browser/resources/settings/about_page/about_page.js +++ b/chromium/chrome/browser/resources/settings/about_page/about_page.js @@ -13,7 +13,10 @@ Polymer({ properties: { /** @private {?UpdateStatusChangedEvent} */ - currentUpdateStatusEvent_: Object, + currentUpdateStatusEvent_: { + type: Object, + value: {message: '', progress: 0, status: UpdateStatus.DISABLED}, + }, <if expr="chromeos"> /** @private */ @@ -170,7 +173,15 @@ Polymer({ progressPercent); } </if> - return this.i18n('aboutUpgradeUpdating', progressPercent); + if (this.currentUpdateStatusEvent_.progress > 0) { + // NOTE(dbeam): some platforms (i.e. Mac) always send 0% while + // updating (they don't support incremental upgrade progress). Though + // it's certainly quite possible to validly end up here with 0% on + // platforms that support incremental progress, nobody really likes + // seeing that they're 0% done with something. + return this.i18n('aboutUpgradeUpdatingPercent', progressPercent); + } + return this.i18n('aboutUpgradeUpdating'); default: var message = this.currentUpdateStatusEvent_.message; return message ? diff --git a/chromium/chrome/browser/resources/settings/advanced_page/advanced_page.html b/chromium/chrome/browser/resources/settings/advanced_page/advanced_page.html index d1c9a1890c7..45db38c758d 100644 --- a/chromium/chrome/browser/resources/settings/advanced_page/advanced_page.html +++ b/chromium/chrome/browser/resources/settings/advanced_page/advanced_page.html @@ -10,8 +10,6 @@ <link rel="import" href="/settings_page/settings_page_visibility.html"> <link rel="import" href="/settings_page/settings_section.html"> <link rel="import" href="/settings_page_css.html"> -<link rel="import" href="/site_settings/constants.html"> -<link rel="import" href="/site_settings/site_settings_category.html"> <if expr="chromeos"> <link rel="import" href="/bluetooth_page/bluetooth_page.html"> diff --git a/chromium/chrome/browser/resources/settings/appearance_page/appearance_browser_proxy.html b/chromium/chrome/browser/resources/settings/appearance_page/appearance_browser_proxy.html index 4b8d2b5b0e7..b7dd3eff8c4 100644 --- a/chromium/chrome/browser/resources/settings/appearance_page/appearance_browser_proxy.html +++ b/chromium/chrome/browser/resources/settings/appearance_page/appearance_browser_proxy.html @@ -1,2 +1,3 @@ <link rel="href" src="chrome://resources/html/cr.html"> +<link rel="href" src="chrome://resources/html/load_time_data.html"> <script src="/appearance_page/appearance_browser_proxy.js"></script> diff --git a/chromium/chrome/browser/resources/settings/appearance_page/appearance_browser_proxy.js b/chromium/chrome/browser/resources/settings/appearance_page/appearance_browser_proxy.js index 8982f699f94..5f72e279810 100644 --- a/chromium/chrome/browser/resources/settings/appearance_page/appearance_browser_proxy.js +++ b/chromium/chrome/browser/resources/settings/appearance_page/appearance_browser_proxy.js @@ -7,16 +7,27 @@ cr.define('settings', function() { function AppearanceBrowserProxy() {} AppearanceBrowserProxy.prototype = { + /** @return {!Promise<number>} */ + getDefaultZoom: assertNotReached, + /** - * @return {!Promise<boolean>} Whether the theme may be reset. + * @param {string} themeId + * @return {!Promise<!chrome.management.ExtensionInfo>} Theme info. */ - getResetThemeEnabled: assertNotReached, + getThemeInfo: assertNotReached, + + /** @return {boolean} Whether the current profile is supervised. */ + isSupervised: assertNotReached, <if expr="chromeos"> openWallpaperManager: assertNotReached, </if> - resetTheme: assertNotReached, + useDefaultTheme: assertNotReached, + +<if expr="is_linux and not chromeos"> + useSystemTheme: assertNotReached, +</if> }; /** @@ -29,8 +40,22 @@ cr.define('settings', function() { AppearanceBrowserProxyImpl.prototype = { /** @override */ - getResetThemeEnabled: function() { - return cr.sendWithPromise('getResetThemeEnabled'); + getDefaultZoom: function() { + return new Promise(function(resolve) { + chrome.settingsPrivate.getDefaultZoom(resolve); + }); + }, + + /** @override */ + getThemeInfo: function(themeId) { + return new Promise(function(resolve) { + chrome.management.get(themeId, resolve); + }); + }, + + /** @override */ + isSupervised: function() { + return loadTimeData.getBoolean('isSupervised'); }, <if expr="chromeos"> @@ -41,9 +66,16 @@ cr.define('settings', function() { </if> /** @override */ - resetTheme: function() { - chrome.send('resetTheme'); + useDefaultTheme: function() { + chrome.send('useDefaultTheme'); }, + +<if expr="is_linux and not chromeos"> + /** @override */ + useSystemTheme: function() { + chrome.send('useSystemTheme'); + }, +</if> }; return { diff --git a/chromium/chrome/browser/resources/settings/appearance_page/appearance_page.html b/chromium/chrome/browser/resources/settings/appearance_page/appearance_page.html index 9edaef5a47d..bf801205ab0 100644 --- a/chromium/chrome/browser/resources/settings/appearance_page/appearance_page.html +++ b/chromium/chrome/browser/resources/settings/appearance_page/appearance_page.html @@ -1,7 +1,7 @@ <link rel="import" href="chrome://resources/html/i18n_behavior.html"> +<link rel="import" href="chrome://resources/html/md_select_css.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html"> @@ -10,16 +10,27 @@ <link rel="import" href="/controls/settings_dropdown_menu.html"> <link rel="import" href="/controls/settings_input.html"> <link rel="import" href="/controls/settings_radio_group.html"> -<link rel="import" href="/icons.html"> <link rel="import" href="/route.html"> <link rel="import" href="/settings_page/settings_animated_pages.html"> <link rel="import" href="/settings_page/settings_subpage.html"> <link rel="import" href="/settings_shared_css.html"> +<link rel="import" href="/settings_vars_css.html"> <link rel="import" href="appearance_fonts_page.html"> <dom-module id="settings-appearance-page"> <template> - <style include="settings-shared"></style> + <style include="settings-shared md-select"> + :host { + --paper-input-container-label: { + font-size: inherit; + font-weight: inherit; + }; + } + + .secondary-button ~ .secondary-button { + -webkit-margin-start: 12px; + } + </style> <settings-animated-pages id="pages" section="appearance"> <neon-animatable route-path="default"> <if expr="chromeos"> @@ -27,33 +38,54 @@ on-tap="openWallpaperManager_" actionable hidden="[[!pageVisibility.setWallpaper]]"> <div class="start"> - <div>$i18n{setWallpaper}</div> + $i18n{setWallpaper} <div class="secondary">$i18n{openWallpaperApp}</div> </div> <button class="icon-external" is="paper-icon-button-light"></button> </div> <div class="settings-box two-line" - hidden="[[!pageVisibility.setTheme]]" actionable> + hidden="[[!pageVisibility.setTheme]]"> </if> <if expr="not chromeos"> <div class="settings-box two-line first" - hidden="[[!pageVisibility.setTheme]]" actionable> + hidden="[[!pageVisibility.setTheme]]"> </if> - <div class="start two-line" on-tap="openThemesGallery_"> + <div class="start two-line" on-tap="onThemesTap_" actionable> <div class="flex"> - <div>$i18n{theme}</div> + <div>$i18n{themes}</div> <div class="secondary">[[themeSublabel_]]</div> </div> <button class="icon-external" is="paper-icon-button-light"></button> </div> - <template is="dom-if" if="[[allowResetTheme_]]"> +<if expr="not is_linux or chromeos"> + <template is="dom-if" if="[[prefs.extensions.theme.id.value]]"> <div class="secondary-action"> - <paper-button id="resetTheme" on-tap="resetTheme_" + <paper-button id="useDefault" on-tap="onUseDefaultTap_" class="secondary-button"> $i18n{resetToDefaultTheme} </paper-button> </div> </template> +</if> +<if expr="is_linux and not chromeos"> + <div class="secondary-action" hidden="[[!showThemesSecondary_( + prefs.extensions.theme.id.value, useSystemTheme_)]]"> + <template is="dom-if" if="[[showUseClassic_( + prefs.extensions.theme.id.value, useSystemTheme_)]]" restamp> + <paper-button id="useDefault" on-tap="onUseDefaultTap_" + class="secondary-button"> + $i18n{useClassicTheme} + </paper-button> + </template> + <template is="dom-if" if="[[showUseSystem_( + prefs.extensions.theme.id.value, useSystemTheme_)]]" restamp> + <paper-button id="useSystem" on-tap="onUseSystemTap_" + class="secondary-button"> + $i18n{useSystemTheme} + </paper-button> + </template> + </div> +</if> </div> <div class="settings-box" hidden="[[!pageVisibility.homeButton]]"> @@ -78,6 +110,7 @@ managed. --> <settings-input no-label-float pref="{{prefs.homepage}}" label="$i18n{exampleDotCom}" + can-tab="[[!prefs.homepage_is_newtabpage.value]]" stop-keyboard-event-propagation> </settings-input> </controlled-radio-button> @@ -110,15 +143,23 @@ <div>$i18n{customizeFonts}</div> <div class="secondary">$i18n{chooseFonts}</div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"> - </button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="settings-box" hidden="[[!pageVisibility.pageZoom]]"> <div class="start">$i18n{pageZoom}</div> - <settings-dropdown-menu id="pageZoom" pref="{{defaultZoomLevel_}}" - menu-options="[[pageZoomOptions_]]"> - </settings-dropdown-menu> + <div class="md-select-wrapper"> + <select id="zoomLevel" class="md-select" + on-change="onZoomLevelChange_"> + <template is="dom-repeat" items="[[pageZoomLevels_]]"> + <option value="[[item]]" + selected$="[[zoomValuesEqual_(item, defaultZoom_)]]"> + [[formatZoom_(item)]]% + </option> + </template> + </select> + <span class="md-select-underline"></span> + </div> </div> </neon-animatable> <template is="dom-if" route-path="/fonts"> diff --git a/chromium/chrome/browser/resources/settings/appearance_page/appearance_page.js b/chromium/chrome/browser/resources/settings/appearance_page/appearance_page.js index 5b7462bd931..e5f2dc33033 100644 --- a/chromium/chrome/browser/resources/settings/appearance_page/appearance_page.js +++ b/chromium/chrome/browser/resources/settings/appearance_page/appearance_page.js @@ -20,38 +20,19 @@ Polymer({ behaviors: [I18nBehavior], properties: { - /** @private {!settings.AppearanceBrowserProxy} */ - browserProxy_: Object, - /** - * Preferences state. + * Dictionary defining page visibility. + * @type {!AppearancePageVisibility} */ + pageVisibility: Object, + prefs: { type: Object, notify: true, }, - /** - * @private - */ - allowResetTheme_: { - notify: true, - type: Boolean, - value: false, - }, - - /** - * @private - */ - defaultZoomLevel_: { - notify: true, - type: Object, - value: function() { - return { - type: chrome.settingsPrivate.PrefType.NUMBER, - }; - }, - }, + /** @private */ + defaultZoom_: Number, /** * List of options for the font size drop-down menu. @@ -73,45 +54,56 @@ Polymer({ /** * List of options for the page zoom drop-down menu. - * @type {!DropdownMenuOptionList} + * @type {!Array<number>} */ - pageZoomOptions_: { + pageZoomLevels_: { readOnly: true, type: Array, value: [ - {value: 25, name: '25%'}, - {value: 33, name: '33%'}, - {value: 50, name: '50%'}, - {value: 67, name: '67%'}, - {value: 75, name: '75%'}, - {value: 80, name: '80%'}, - {value: 90, name: '90%'}, - {value: 100, name: '100%'}, - {value: 110, name: '110%'}, - {value: 125, name: '125%'}, - {value: 150, name: '150%'}, - {value: 175, name: '175%'}, - {value: 200, name: '200%'}, - {value: 250, name: '250%'}, - {value: 300, name: '300%'}, - {value: 400, name: '400%'}, - {value: 500, name: '500%'}, + // TODO(dbeam): get these dynamically from C++ instead. + 1 / 4, + 1 / 3, + 1 / 2, + 2 / 3, + 3 / 4, + 4 / 5, + 9 / 10, + 1, + 11 / 10, + 5 / 4, + 3 / 2, + 7 / 4, + 2, + 5 / 2, + 3, + 4, + 5, ], }, /** @private */ themeSublabel_: String, - /** - * Dictionary defining page visibility. - * @type {!AppearancePageVisibility} - */ - pageVisibility: Object, + /** @private */ + useSystemTheme_: { + type: Boolean, + value: false, // Can only be true on Linux, but value exists everywhere. + }, }, + /** @private {?settings.AppearanceBrowserProxy} */ + browserProxy_: null, + + /** @private {string} */ + themeUrl_: '', + observers: [ - 'themeChanged_(prefs.extensions.theme.id.value)', - 'zoomLevelChanged_(defaultZoomLevel_.value)', + 'themeChanged_(prefs.extensions.theme.id.value, useSystemTheme_)', + +<if expr="is_linux and not chromeos"> + // NOTE: this pref only exists on Linux. + 'useSystemThemePrefChanged_(prefs.extensions.theme.use_system.value)', +</if> ], created: function() { @@ -120,22 +112,20 @@ Polymer({ ready: function() { this.$.defaultFontSize.menuOptions = this.fontSizeOptions_; - this.$.pageZoom.menuOptions = this.pageZoomOptions_; // TODO(dschuyler): Look into adding a listener for the // default zoom percent. - chrome.settingsPrivate.getDefaultZoomPercent( - this.zoomPrefChanged_.bind(this)); + this.browserProxy_.getDefaultZoom().then(function(zoom) { + this.defaultZoom_ = zoom; + }.bind(this)); }, - /** @override */ - attached: function() { - // Query the initial state. - this.browserProxy_.getResetThemeEnabled().then( - this.setResetThemeEnabled.bind(this)); - - // Set up the change event listener. - cr.addWebUIListener('reset-theme-enabled-changed', - this.setResetThemeEnabled.bind(this)); + /** + * @param {number} zoom + * @return {number} A zoom easier read by users. + * @private + */ + formatZoom_: function(zoom) { + return Math.round(zoom * 100); }, /** @@ -150,21 +140,14 @@ Polymer({ return homepage || this.i18n('exampleDotCom'); }, - /** - * @param {boolean} enabled Whether the theme reset is available. - */ - setResetThemeEnabled: function(enabled) { - this.allowResetTheme_ = enabled; - }, - /** @private */ onCustomizeFontsTap_: function() { settings.navigateTo(settings.Route.FONTS); }, /** @private */ - openThemesGallery_: function() { - window.open(loadTimeData.getString('themesGalleryUrl')); + onThemesTap_: function() { + window.open(this.themeUrl_ || loadTimeData.getString('themesGalleryUrl')); }, <if expr="chromeos"> @@ -178,42 +161,88 @@ Polymer({ </if> /** @private */ - resetTheme_: function() { - this.browserProxy_.resetTheme(); + onUseDefaultTap_: function() { + this.browserProxy_.useDefaultTheme(); }, +<if expr="is_linux and not chromeos"> /** - * @param {string} themeId The theme ID. + * @param {boolean} useSystemTheme * @private */ - themeChanged_: function(themeId) { - if (themeId) { - chrome.management.get(themeId, - function(info) { - this.themeSublabel_ = info.name; - }.bind(this)); - } else { - this.themeSublabel_ = this.i18n('chooseFromWebStore'); - } + useSystemThemePrefChanged_: function(useSystemTheme) { + this.useSystemTheme_ = useSystemTheme; + }, + + /** + * @param {string} themeId + * @param {boolean} useSystemTheme + * @return {boolean} Whether to show the "USE CLASSIC" button. + * @private + */ + showUseClassic_: function(themeId, useSystemTheme) { + return !!themeId || useSystemTheme; }, /** - * @param {number} percent The integer percentage of the page zoom. + * @param {string} themeId + * @param {boolean} useSystemTheme + * @return {boolean} Whether to show the "USE GTK+" button. * @private */ - zoomPrefChanged_: function(percent) { - this.set('defaultZoomLevel_.value', percent); + showUseSystem_: function(themeId, useSystemTheme) { + return (!!themeId || !useSystemTheme) && !this.browserProxy_.isSupervised(); + }, + + /** + * @param {string} themeId + * @param {boolean} useSystemTheme + * @return {boolean} Whether to show the secondary area where "USE CLASSIC" + * and "USE GTK+" buttons live. + * @private + */ + showThemesSecondary_: function(themeId, useSystemTheme) { + return this.showUseClassic_(themeId, useSystemTheme) || + this.showUseSystem_(themeId, useSystemTheme); + }, + + /** @private */ + onUseSystemTap_: function() { + this.browserProxy_.useSystemTheme(); }, +</if> /** - * @param {number} percent The integer percentage of the page zoom. + * @param {string} themeId + * @param {boolean} useSystemTheme * @private */ - zoomLevelChanged_: function(percent) { - // The |percent| may be undefined on startup. - if (percent === undefined) + themeChanged_: function(themeId, useSystemTheme) { + if (themeId) { + assert(!useSystemTheme); + + this.browserProxy_.getThemeInfo(themeId).then(function(info) { + this.themeSublabel_ = info.name; + }.bind(this)); + + this.themeUrl_ = `https://chrome.google.com/webstore/detail/${themeId}`; return; - chrome.settingsPrivate.setDefaultZoomPercent(percent); + } + + var i18nId; +<if expr="is_linux and not chromeos"> + i18nId = useSystemTheme ? 'systemTheme' : 'classicTheme'; +</if> +<if expr="not is_linux or chromeos"> + i18nId = 'chooseFromWebStore'; +</if> + this.themeSublabel_ = this.i18n(i18nId); + this.themeUrl_ = ''; + }, + + /** @private */ + onZoomLevelChange_: function() { + chrome.settingsPrivate.setDefaultZoom(parseFloat(this.$.zoomLevel.value)); }, /** @@ -223,5 +252,16 @@ Polymer({ */ getFirst_: function(bookmarksBarVisible) { return !bookmarksBarVisible ? 'first' : ''; - } + }, + + /** + * @see content::ZoomValuesEqual(). + * @param {number} zoom1 + * @param {number} zoom2 + * @return {boolean} + * @private + */ + zoomValuesEqual_: function(zoom1, zoom2) { + return Math.abs(zoom1 - zoom2) <= 0.001; + }, }); diff --git a/chromium/chrome/browser/resources/settings/appearance_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/appearance_page/compiled_resources2.gyp index 29c7905ea7f..e57d770b239 100644 --- a/chromium/chrome/browser/resources/settings/appearance_page/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/settings/appearance_page/compiled_resources2.gyp @@ -21,7 +21,10 @@ 'dependencies': [ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', '<(EXTERNS_GYP):chrome_send', + '<(EXTERNS_GYP):management', + '<(EXTERNS_GYP):settings_private', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, @@ -31,7 +34,6 @@ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', - '<(EXTERNS_GYP):management', '<(EXTERNS_GYP):settings_private', '<(EXTERNS_GYP):chrome_send', '../compiled_resources2.gyp:route', diff --git a/chromium/chrome/browser/resources/settings/appearance_page/fonts_browser_proxy.js b/chromium/chrome/browser/resources/settings/appearance_page/fonts_browser_proxy.js index 75649d97378..b8b1263af39 100644 --- a/chromium/chrome/browser/resources/settings/appearance_page/fonts_browser_proxy.js +++ b/chromium/chrome/browser/resources/settings/appearance_page/fonts_browser_proxy.js @@ -5,7 +5,6 @@ /** * @typedef {{ * fontList: Array<{0: string, 1: (string|undefined), 2: (string|undefined)}>, - * encodingList: Array<{0: string, 1: string}>, * extensionUrl: string * }} */ @@ -17,8 +16,8 @@ cr.define('settings', function() { FontsBrowserProxy.prototype = { /** - * @return {!Promise<!FontsData>} Fonts, encodings and the advanced font - * settings extension URL. + * @return {!Promise<!FontsData>} Fonts and the advanced font settings + * extension URL. */ fetchFontsData: assertNotReached, diff --git a/chromium/chrome/browser/resources/settings/basic_page/basic_page.html b/chromium/chrome/browser/resources/settings/basic_page/basic_page.html index c9db620bf40..82817962147 100644 --- a/chromium/chrome/browser/resources/settings/basic_page/basic_page.html +++ b/chromium/chrome/browser/resources/settings/basic_page/basic_page.html @@ -30,7 +30,7 @@ <template is="dom-if" if="[[showPage(pageVisibility.internet)]]" restamp> <settings-section page-title="$i18n{internetPageTitle}" section="internet"> - <settings-internet-page> + <settings-internet-page prefs="{{prefs}}"> </settings-internet-page> </settings-section> </template> diff --git a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_dialog.html b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_dialog.html index 479d1911f77..d017296c467 100644 --- a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_dialog.html +++ b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_dialog.html @@ -5,11 +5,9 @@ <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner.html"> <link rel="import" href="/bluetooth_page/bluetooth_device_list_item.html"> -<link rel="import" href="/icons.html"> <link rel="import" href="/settings_shared_css.html"> <dom-module id="bluetooth-device-dialog"> diff --git a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html index 1f843f23def..ecc6567ac0b 100644 --- a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html +++ b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.html @@ -1,10 +1,10 @@ +<link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> +<link rel="import" href="chrome://resources/html/i18n_behavior.html"> <link rel="import" href="chrome://resources/html/polymer.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-dropdown/iron-dropdown.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.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-icon-button/paper-icon-button.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html"> <link rel="import" href="/settings_shared_css.html"> <dom-module id="bluetooth-device-list-item"> @@ -31,21 +31,18 @@ <span class="flex"></span> <span hidden$="[[!device.connecting]]">$i18n{bluetoothConnecting}</span> <div hidden$="[[!device.paired]]"> - <paper-icon-button icon="cr:more-vert" toggles - active="{{dropdownOpened}}" tabindex$="[[tabindex]]"> + <paper-icon-button icon="cr:more-vert" on-tap="onMenuButtonTap_" + tabindex$="[[tabindex]]"> </paper-icon-button> - <iron-dropdown opened="{{dropdownOpened}}" on-tap="menuSelected_" - vertical-align="auto" horizontal-align="right"> - <div class="dropdown-content"> - <paper-item id="connect" hidden$="[[device.connected]]"> - $i18n{bluetoothConnect} - </paper-item> - <paper-item id="disconnect" hidden$="[[!device.connected]]"> - $i18n{bluetoothDisconnect} - </paper-item> - <paper-item id="remove">$i18n{bluetoothRemove}</paper-item> - </div> - </iron-dropdown> + <dialog id="dotsMenu" is="cr-action-menu"> + <button class="dropdown-item" role="option" + on-tap="onConnectActionTap_"> + [[getConnectActionText_(device.connected)]] + </button> + <button class="dropdown-item" role="option" on-tap="onRemoveTap_"> + $i18n{bluetoothRemove} + </button> + </dialog> </div> </div> </template> diff --git a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.js b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.js index 265200451df..c72b2e42d10 100644 --- a/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.js +++ b/chromium/chrome/browser/resources/settings/bluetooth_page/bluetooth_device_list_item.js @@ -9,6 +9,8 @@ Polymer({ is: 'bluetooth-device-list-item', + behaviors: [I18nBehavior], + properties: { /** * The bluetooth device. @@ -20,15 +22,42 @@ Polymer({ }, /** - * @param {Event} e + * @param {!Event} event * @private */ - menuSelected_: function(e) { - e.currentTarget.opened = false; + onMenuButtonTap_: function(event) { + let button = /** @type {!HTMLElement} */ (event.target); + let menu = /** @type {!CrActionMenuElement} */ (this.$.dotsMenu); + menu.showAt(button); + event.stopPropagation(); + }, + + /** @private */ + onConnectActionTap_: function() { + let action = this.isDisconnected_(this.device) ? 'connect' : 'disconnect'; this.fire('device-event', { - action: e.target.id, + action: action, device: this.device, }); + /** @type {!CrActionMenuElement} */ (this.$.dotsMenu).close(); + }, + + /** @private */ + onRemoveTap_: function() { + this.fire('device-event', { + action: 'remove', + device: this.device, + }); + /** @type {!CrActionMenuElement} */ (this.$.dotsMenu).close(); + }, + + /** + * @param {boolean} connected + * @return {string} The text to display for the connect/disconnect menu item. + * @private + */ + getConnectActionText_: function(connected) { + return this.i18n(connected ? 'bluetoothDisconnect' : 'bluetoothConnect'); }, /** diff --git a/chromium/chrome/browser/resources/settings/bluetooth_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/bluetooth_page/compiled_resources2.gyp index 16ba8055781..9b6f54fee76 100644 --- a/chromium/chrome/browser/resources/settings/bluetooth_page/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/settings/bluetooth_page/compiled_resources2.gyp @@ -34,7 +34,9 @@ { 'target_name': 'bluetooth_device_list_item', 'dependencies': [ + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior', '<(EXTERNS_GYP):bluetooth', + '<(DEPTH)/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp:cr_action_menu', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_entry.html b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_entry.html index 3624031882d..9620696d582 100644 --- a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_entry.html +++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_entry.html @@ -2,7 +2,6 @@ <link rel="import" href="/certificate_manager_page/certificates_browser_proxy.html"> <link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.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-dropdown/iron-dropdown.html"> <link rel="import" href="/settings_shared_css.html"> <link rel="import" href="/certificate_manager_page/certificate_subentry.html"> diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.html b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.html index 8325fb23c05..52956157ef7 100644 --- a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.html +++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.html @@ -1,6 +1,7 @@ <link rel="import" href="chrome://resources/html/polymer.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_lazy_render/cr_lazy_render.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-dropdown/iron-dropdown.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> <link rel="import" href="/certificate_manager_page/certificate_manager_types.html"> <link rel="import" href="/certificate_manager_page/certificates_browser_proxy.html"> @@ -9,13 +10,6 @@ <dom-module id="settings-certificate-subentry"> <template> <style include="settings-shared"> - .dropdown-content { - background: white; - /* TODO(dpapad): Use a CSS variable for box-shadow and unify with other - * such menus (like in search engines section) */ - box-shadow: 0 2px 6px grey; - } - .name { flex: auto; } @@ -36,33 +30,29 @@ $i18n{certificateManagerUntrusted} </div> <div class="name">[[model.name]]</div> - <paper-icon-button id="dots" icon="cr:more-vert" toggles - active="{{menuOpened}}"></paper-icon-button> - <!-- TODO(dpapad): Figure out RTL for this menu --> - <template is="dom-if" if="[[menuOpened]]"> - <iron-dropdown vertical-align="auto" horizontal-align="right" - opened="{{menuOpened}}"> - <div class="dropdown-content"> - <button class="dropdown-item" role="option" id="view" - on-tap="onViewTap_"> - $i18n{certificateManagerView} - </button> - <button class="dropdown-item" role="option" id="edit" - hidden$="[[!canEdit_(certificateType, model)]]" - on-tap="onEditTap_"> - $i18n{certificateManagerEdit} - </button> - <button class="dropdown-item" role="option" id="export" - hidden$="[[!canExport_(certificateType, model)]]" - on-tap="onExportTap_"> - $i18n{certificateManagerExport} - </button> - <button class="dropdown-item" role="option" id="delete" - hidden$="[[!canDelete_(model)]]" on-tap="onDeleteTap_"> - $i18n{certificateManagerDelete} - </button> - </div> - </iron-dropdown> + <paper-icon-button id="dots" icon="cr:more-vert" + on-tap="onDotsTap_"></paper-icon-button> + <template is="cr-lazy-render" id="menu"> + <dialog is="cr-action-menu"> + <button class="dropdown-item" role="option" id="view" + on-tap="onViewTap_"> + $i18n{certificateManagerView} + </button> + <button class="dropdown-item" role="option" id="edit" + hidden$="[[!canEdit_(certificateType, model)]]" + on-tap="onEditTap_"> + $i18n{certificateManagerEdit} + </button> + <button class="dropdown-item" role="option" id="export" + hidden$="[[!canExport_(certificateType, model)]]" + on-tap="onExportTap_"> + $i18n{certificateManagerExport} + </button> + <button class="dropdown-item" role="option" id="delete" + hidden$="[[!canDelete_(model)]]" on-tap="onDeleteTap_"> + $i18n{certificateManagerDelete} + </button> + </dialog> </template> <div> </template> diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.js b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.js index faad749557b..715320dd05a 100644 --- a/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.js +++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/certificate_subentry.js @@ -151,6 +151,13 @@ Polymer({ /** @private */ closePopupMenu_: function() { - this.$$('iron-dropdown').close(); + this.$$('dialog[is=cr-action-menu]').close(); + }, + + /** @private */ + onDotsTap_: function() { + var actionMenu = /** @type {!CrActionMenuElement} */( + this.$.menu.get()); + actionMenu.showAt(assert(this.$$('paper-icon-button'))); }, }); diff --git a/chromium/chrome/browser/resources/settings/certificate_manager_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/certificate_manager_page/compiled_resources2.gyp index 6e92bf3c351..e974577eedc 100644 --- a/chromium/chrome/browser/resources/settings/certificate_manager_page/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/settings/certificate_manager_page/compiled_resources2.gyp @@ -42,9 +42,11 @@ { 'target_name': 'certificate_subentry', 'dependencies': [ - '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', 'certificate_manager_types', 'certificates_browser_proxy', + '<(DEPTH)/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp:cr_action_menu', + '<(DEPTH)/ui/webui/resources/cr_elements/cr_lazy_render/compiled_resources2.gyp:cr_lazy_render', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, diff --git a/chromium/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html b/chromium/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html index 56465f1aabe..e4348446879 100644 --- a/chromium/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html +++ b/chromium/chrome/browser/resources/settings/clear_browsing_data_dialog/clear_browsing_data_dialog.html @@ -110,7 +110,7 @@ } </style> - <dialog is="cr-dialog" id="dialog"> + <dialog is="cr-dialog" id="dialog" ignore-popstate> <div class="title">$i18n{clearBrowsingData}</div> <div class="body"> <div class="row"> diff --git a/chromium/chrome/browser/resources/settings/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/compiled_resources2.gyp index 09caa83f7ac..e383ecd09ed 100644 --- a/chromium/chrome/browser/resources/settings/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/settings/compiled_resources2.gyp @@ -4,6 +4,53 @@ { 'targets': [ { + 'target_name': 'direction_delegate', + 'dependencies': [ + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', + ], + 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + { + 'target_name': 'extension_control_browser_proxy', + 'dependencies': [ + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', + '<(EXTERNS_GYP):chrome_send', + ], + 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + { + 'target_name': 'global_scroll_target_behavior', + 'dependencies': [ + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', + ], + 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + { + 'target_name': 'lifetime_browser_proxy', + 'dependencies': [ + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', + '<(EXTERNS_GYP):chrome_send', + ], + 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + { + 'target_name': 'route', + 'dependencies': [ + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', + ], + 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + { + 'target_name': 'search_settings', + 'dependencies': [ + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', + ], + 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + { 'target_name': 'settings_resources', 'type': 'none', 'dependencies': [ @@ -41,36 +88,5 @@ 'system_page/compiled_resources2.gyp:*', ], }, - { - 'target_name': 'direction_delegate', - 'dependencies': [ - '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', - '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', - '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', - ], - 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], - }, - { - 'target_name': 'lifetime_browser_proxy', - 'dependencies': [ - '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', - '<(EXTERNS_GYP):chrome_send', - ], - 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], - }, - { - 'target_name': 'route', - 'dependencies': [ - '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', - ], - 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], - }, - { - 'target_name': 'search_settings', - 'dependencies': [ - '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', - ], - 'includes': ['../../../../third_party/closure_compiler/compile_js2.gypi'], - }, ], } diff --git a/chromium/chrome/browser/resources/settings/controls/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/controls/compiled_resources2.gyp index 83eb90479d0..4c12ee9b348 100644 --- a/chromium/chrome/browser/resources/settings/controls/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/settings/controls/compiled_resources2.gyp @@ -23,6 +23,15 @@ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, { + 'target_name': 'extension_controlled_indicator', + 'dependencies': [ + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior', + '../compiled_resources2.gyp:extension_control_browser_proxy', + ], + 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + { 'target_name': 'pref_control_behavior', 'dependencies': [ '../prefs/compiled_resources2.gyp:prefs_types', @@ -30,18 +39,23 @@ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, { - 'target_name': 'settings_checkbox', + 'target_name': 'settings_boolean_control_behavior', 'dependencies': [ '<(DEPTH)/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp:cr_policy_indicator_behavior', '<(DEPTH)/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp:cr_policy_pref_behavior', - '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', - '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', - '<(EXTERNS_GYP):settings_private', + '../prefs/compiled_resources2.gyp:prefs_types', 'pref_control_behavior', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, { + 'target_name': 'settings_checkbox', + 'dependencies': [ + 'settings_boolean_control_behavior', + ], + 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + { 'target_name': 'settings_dropdown_menu', 'dependencies': [ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', @@ -77,5 +91,12 @@ ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, + { + 'target_name': 'settings_toggle_button', + 'dependencies': [ + 'settings_boolean_control_behavior', + ], + 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], + }, ], } diff --git a/chromium/chrome/browser/resources/settings/controls/controlled_button.js b/chromium/chrome/browser/resources/settings/controls/controlled_button.js index 36392dbfdd8..ac4428f3383 100644 --- a/chromium/chrome/browser/resources/settings/controls/controlled_button.js +++ b/chromium/chrome/browser/resources/settings/controls/controlled_button.js @@ -21,7 +21,7 @@ Polymer({ * @private */ computeControlled_: function() { - return this.isPrefPolicyControlled(assert(this.pref)); + return this.pref.enforcement == chrome.settingsPrivate.Enforcement.ENFORCED; }, /** diff --git a/chromium/chrome/browser/resources/settings/controls/controlled_radio_button.html b/chromium/chrome/browser/resources/settings/controls/controlled_radio_button.html index a9d2f4e4883..88e43a657cf 100644 --- a/chromium/chrome/browser/resources/settings/controls/controlled_radio_button.html +++ b/chromium/chrome/browser/resources/settings/controls/controlled_radio_button.html @@ -29,8 +29,8 @@ } </style> - <paper-radio-button name="{{name}}" disabled="[[controlled_]]" - checked="{{checked}}"> + <paper-radio-button id="radioButton" name="{{name}}" checked="{{checked}}" + disabled="[[controlled_]]" tabindex$="[[tabindex]]"> <content></content> </paper-radio-button> diff --git a/chromium/chrome/browser/resources/settings/controls/controlled_radio_button.js b/chromium/chrome/browser/resources/settings/controls/controlled_radio_button.js index 33dc95979e7..cf697206d0d 100644 --- a/chromium/chrome/browser/resources/settings/controls/controlled_radio_button.js +++ b/chromium/chrome/browser/resources/settings/controls/controlled_radio_button.js @@ -21,6 +21,10 @@ Polymer({ }, }, + listeners: { + 'focus': 'onFocus_', + }, + /** * @return {boolean} Whether the button is disabled. * @private @@ -49,4 +53,9 @@ Polymer({ e.preventDefault(); e.stopPropagation(); }, + + /** Focuses the internal radio button when the row is selected. */ + onFocus_: function() { + this.$.radioButton.focus(); + }, }); diff --git a/chromium/chrome/browser/resources/settings/controls/extension_controlled_indicator.html b/chromium/chrome/browser/resources/settings/controls/extension_controlled_indicator.html new file mode 100644 index 00000000000..1baef10a328 --- /dev/null +++ b/chromium/chrome/browser/resources/settings/controls/extension_controlled_indicator.html @@ -0,0 +1,37 @@ +<link rel="import" href="chrome://resources/html/i18n_behavior.html"> +<link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> +<link rel="import" href="/extension_control_browser_proxy.html"> + +<dom-module id="extension-controlled-indicator"> + <template> + <style include="settings-shared"> + :host { + -webkit-margin-start: 36px; + align-items: center; + display: flex; + min-height: var(--settings-row-min-height); + } + + img { + -webkit-margin-end: 16px; + height: var(--settings-icon-size); + width: var(--settings-icon-size); + } + + span { + -webkit-margin-end: 8px; + flex: 1; + } + </style> + <img src="chrome://extension-icon/[[extensionId]]/40/1"> + <span inner-h-t-m-l="[[getLabel_(extensionId, extensionName)]]"></span> + <template is="dom-if" if="[[extensionCanBeDisabled]]"> + <paper-button class="secondary-button" on-tap="onDisableTap_"> + $i18n{disable} + </paper-button> + </template> + </template> +</dom-module> + +<script src="/controls/extension_controlled_indicator.js"></script> diff --git a/chromium/chrome/browser/resources/settings/controls/extension_controlled_indicator.js b/chromium/chrome/browser/resources/settings/controls/extension_controlled_indicator.js new file mode 100644 index 00000000000..35527c16400 --- /dev/null +++ b/chromium/chrome/browser/resources/settings/controls/extension_controlled_indicator.js @@ -0,0 +1,36 @@ +// Copyright 2016 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. + +Polymer({ + is: 'extension-controlled-indicator', + + behaviors: [I18nBehavior], + + properties: { + extensionCanBeDisabled: Boolean, + extensionId: String, + extensionName: String, + }, + + /** + * @param {string} extensionId + * @param {string} extensionName + * @return {string} + * @private + */ + getLabel_: function(extensionId, extensionName) { + var manageUrl = 'chrome://extensions/?id=' + assert(this.extensionId); + return this.i18n('controlledByExtension', + `<a href="${manageUrl}" target="_blank">` + + assert(this.extensionName) + '</a>'); + }, + + /** @private */ + onDisableTap_: function() { + assert(this.extensionCanBeDisabled); + settings.ExtensionControlBrowserProxyImpl.getInstance().disableExtension( + assert(this.extensionId)); + this.fire('extension-disable'); + }, +}); diff --git a/chromium/chrome/browser/resources/settings/controls/settings_boolean_control_behavior.html b/chromium/chrome/browser/resources/settings/controls/settings_boolean_control_behavior.html new file mode 100644 index 00000000000..4b0a917d2f0 --- /dev/null +++ b/chromium/chrome/browser/resources/settings/controls/settings_boolean_control_behavior.html @@ -0,0 +1,5 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_behavior.html"> +<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_indicator.html"> +<link rel="import" href="/controls/pref_control_behavior.html"> +<script src="settings_boolean_control_behavior.js"></script> diff --git a/chromium/chrome/browser/resources/settings/controls/settings_boolean_control_behavior.js b/chromium/chrome/browser/resources/settings/controls/settings_boolean_control_behavior.js new file mode 100644 index 00000000000..0a2a053d663 --- /dev/null +++ b/chromium/chrome/browser/resources/settings/controls/settings_boolean_control_behavior.js @@ -0,0 +1,125 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview + * A behavior to help controls that handle a boolean preference, such as + * checkbox and toggle button. + */ + +/** @polymerBehavior SettingsBooleanControlBehavior */ +var SettingsBooleanControlBehaviorImpl = { + properties: { + /** Whether the control should represent the inverted value. */ + inverted: { + type: Boolean, + value: false, + }, + + /** Whether the control is checked. */ + checked: { + type: Boolean, + value: false, + notify: true, + observer: 'checkedChanged_', + reflectToAttribute: true, + }, + + /** Disabled property for the element. */ + disabled: { + type: Boolean, + value: false, + notify: true, + reflectToAttribute: true, + }, + + /** + * If true, do not automatically set the preference value. This allows the + * container to confirm the change first then call either sendPrefChange + * or resetToPrefValue accordingly. + */ + noSetPref: { + type: Boolean, + value: false, + }, + + /** The main label. */ + label: { + type: String, + value: '', + }, + + /** Additional (optional) sub-label. */ + subLabel: { + type: String, + value: '', + }, + }, + + observers: [ + 'prefValueChanged_(pref.value)', + ], + + /** Reset the checked state to match the current pref value. */ + resetToPrefValue: function() { + this.checked = this.getNewValue_(this.pref.value); + }, + + /** Update the pref to the current |checked| value. */ + sendPrefChange: function() { + /** @type {boolean} */ var newValue = this.getNewValue_(this.checked); + // Ensure that newValue is the correct type for the pref type, either + // a boolean or a number. + if (this.pref.type == chrome.settingsPrivate.PrefType.NUMBER) { + this.set('pref.value', newValue ? 1 : 0); + return; + } + this.set('pref.value', newValue); + }, + + /** + * Polymer observer for pref.value. + * @param {*} prefValue + * @private + */ + prefValueChanged_: function(prefValue) { + this.checked = this.getNewValue_(prefValue); + }, + + /** + * Polymer observer for checked. + * @private + */ + checkedChanged_: function() { + if (!this.pref || this.noSetPref) + return; + this.sendPrefChange(); + }, + + /** + * @param {*} value + * @return {boolean} The value as a boolean, inverted if |inverted| is true. + * @private + */ + getNewValue_: function(value) { + return this.inverted ? !value : !!value; + }, + + /** + * @param {boolean} disabled + * @param {!chrome.settingsPrivate.PrefObject} pref + * @return {boolean} Whether the checkbox should be disabled. + * @private + */ + controlDisabled_: function(disabled, pref) { + return disabled || this.isPrefPolicyControlled(pref); + }, +}; + +/** @polymerBehavior */ +var SettingsBooleanControlBehavior = [ + CrPolicyPrefBehavior, + PrefControlBehavior, + SettingsBooleanControlBehaviorImpl, +]; diff --git a/chromium/chrome/browser/resources/settings/controls/settings_checkbox.html b/chromium/chrome/browser/resources/settings/controls/settings_checkbox.html index b0712c65b92..d84314ea1f7 100644 --- a/chromium/chrome/browser/resources/settings/controls/settings_checkbox.html +++ b/chromium/chrome/browser/resources/settings/controls/settings_checkbox.html @@ -1,8 +1,6 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html"> -<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_behavior.html"> -<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_indicator.html"> -<link rel="import" href="/controls/pref_control_behavior.html"> +<link rel="import" href="/controls/settings_boolean_control_behavior.html"> <link rel="import" href="/settings_shared_css.html"> <dom-module id="settings-checkbox"> @@ -19,10 +17,6 @@ min-height: var(--settings-row-min-height); } - .secondary:not(:empty) { - @apply(--settings-secondary); - } - paper-checkbox:not([disabled]) { width: 100%; } @@ -37,11 +31,11 @@ </style> <div id="outerRow" noSubLabel$="[[!subLabel]]"> <paper-checkbox id="checkbox" checked="{{checked}}" - disabled="[[checkboxDisabled_(disabled, pref)]]"> + disabled="[[controlDisabled_(disabled, pref)]]"> <div>[[label]]</div> <div class="secondary">[[subLabel]]</div> </paper-checkbox> - <template is="dom-if" if="[[pref.policySource]]"> + <template is="dom-if" if="[[pref.controlledBy]]"> <cr-policy-pref-indicator pref="[[pref]]"></cr-policy-pref-indicator> </template> </div> diff --git a/chromium/chrome/browser/resources/settings/controls/settings_checkbox.js b/chromium/chrome/browser/resources/settings/controls/settings_checkbox.js index 7dabd988baf..6528fec6279 100644 --- a/chromium/chrome/browser/resources/settings/controls/settings_checkbox.js +++ b/chromium/chrome/browser/resources/settings/controls/settings_checkbox.js @@ -5,100 +5,9 @@ /** * @fileoverview * `settings-checkbox` is a checkbox that controls a supplied preference. - * - * Example: - * <settings-checkbox pref="{{prefs.settings.enableFoo}}" - * label="Enable foo setting." subLabel="(bar also)"> - * </settings-checkbox> */ Polymer({ is: 'settings-checkbox', - behaviors: [CrPolicyPrefBehavior, PrefControlBehavior], - - properties: { - /** Whether the checkbox should represent the inverted value. */ - inverted: { - type: Boolean, - value: false, - }, - - /** Whether the checkbox is checked. */ - checked: { - type: Boolean, - value: false, - notify: true, - observer: 'checkedChanged_', - reflectToAttribute: true - }, - - /** Disabled property for the element. */ - disabled: { - type: Boolean, - value: false, - notify: true, - reflectToAttribute: true - }, - - /** Checkbox label. */ - label: { - type: String, - value: '', - }, - - /** Additional sub-label for the checkbox. */ - subLabel: { - type: String, - value: '', - }, - }, - - observers: [ - 'prefValueChanged_(pref.value)' - ], - - /** - * Polymer observer for pref.value. - * @param {*} prefValue - * @private - */ - prefValueChanged_: function(prefValue) { - this.checked = this.getNewValue_(prefValue); - }, - - /** - * Polymer observer for checked. - * @private - */ - checkedChanged_: function() { - if (!this.pref) - return; - /** @type {boolean} */ var newValue = this.getNewValue_(this.checked); - // Ensure that newValue is the correct type for the pref type, either - // a boolean or a number. - if (this.pref.type == chrome.settingsPrivate.PrefType.NUMBER) { - this.set('pref.value', newValue ? 1 : 0); - return; - } - this.set('pref.value', newValue); - }, - - /** - * @param {*} value - * @return {boolean} The value as a boolean, inverted if |inverted| is true. - * @private - */ - getNewValue_: function(value) { - return this.inverted ? !value : !!value; - }, - - /** - * @param {boolean} disabled - * @param {!chrome.settingsPrivate.PrefObject} pref - * @return {boolean} Whether the checkbox should be disabled. - * @private - */ - checkboxDisabled_: function(disabled, pref) { - return disabled || this.isPrefPolicyControlled(pref); - }, + behaviors: [SettingsBooleanControlBehavior], }); diff --git a/chromium/chrome/browser/resources/settings/controls/settings_dropdown_menu.html b/chromium/chrome/browser/resources/settings/controls/settings_dropdown_menu.html index 63d24e2d546..b98a55781bb 100644 --- a/chromium/chrome/browser/resources/settings/controls/settings_dropdown_menu.html +++ b/chromium/chrome/browser/resources/settings/controls/settings_dropdown_menu.html @@ -1,24 +1,27 @@ +<link rel="import" href="chrome://resources/html/md_select_css.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="/controls/pref_control_behavior.html"> <link rel="import" href="/i18n_setup.html"> -<link rel="import" href="/md_select_css.html"> <link rel="import" href="/prefs/pref_util.html"> <link rel="import" href="/settings_shared_css.html"> +<link rel="import" href="/settings_vars_css.html"> <dom-module id="settings-dropdown-menu"> <template> - <style include="settings-shared md-select"></style> + <style include="settings-shared md-select"> + /* Hide "Custom" value when unselectable. */ + option:disabled { + display: none; + } + </style> <div class="md-select-wrapper"> <select class="md-select" id="dropdownMenu" on-change="onChange_" - value="[[selected_]]" disabled="[[shouldDisableMenu_(disabled, menuOptions)]]"> <template is="dom-repeat" items="[[menuOptions]]"> - <option value="[[item.value]]" data-value$="[[item.value]]"> - [[item.name]] - </option> + <option value="[[item.value]]">[[item.name]]</option> </template> <option value="[[notFoundValue_]]" - hidden$="[[!isSelectedNotFound_(selected_)]]"> + disabled="[[!showNotFoundValue_(menuOptions, pref.value)]]"> $i18n{custom} </option> </select> diff --git a/chromium/chrome/browser/resources/settings/controls/settings_dropdown_menu.js b/chromium/chrome/browser/resources/settings/controls/settings_dropdown_menu.js index 06061fbffc0..aaf0834b585 100644 --- a/chromium/chrome/browser/resources/settings/controls/settings_dropdown_menu.js +++ b/chromium/chrome/browser/resources/settings/controls/settings_dropdown_menu.js @@ -47,18 +47,13 @@ Polymer({ }, /** - * The current selected value, as a string. - * @private - */ - selected_: String, - - /** - * The value of the 'custom' item. + * The value of the "custom" item. * @private */ notFoundValue_: { type: String, value: 'SETTINGS_DROPDOWN_NOT_FOUND_ITEM', + readOnly: true, }, }, @@ -75,13 +70,13 @@ Polymer({ * @private */ onChange_: function() { - this.selected_ = this.$.dropdownMenu.value; + var selected = this.$.dropdownMenu.value; - if (this.selected_ == this.notFoundValue_) + if (selected == this.notFoundValue_) return; var prefValue = Settings.PrefUtil.stringToPrefValue( - this.selected_, assert(this.pref)); + selected, assert(this.pref)); if (prefValue !== undefined) this.set('pref.value', prefValue); }, @@ -99,22 +94,30 @@ Polymer({ return menuItem.value == prefValue; }); - // Need to wait for the dom-repeat to render, before assigning a value to - // |selected_|, otherwise select#value is not populated correctly. + // Wait for the dom-repeat to populate the <select> before setting + // <select>#value so the correct option gets selected. this.async(function() { - this.selected_ = option == undefined ? + this.$.dropdownMenu.value = option == undefined ? this.notFoundValue_ : Settings.PrefUtil.prefToString(assert(this.pref)); }.bind(this)); }, /** - * @param {string} selected + * @param {?DropdownMenuOptionList} menuOptions + * @param {string} prefValue * @return {boolean} * @private */ - isSelectedNotFound_: function(selected) { - return this.menuOptions.length > 0 && selected == this.notFoundValue_; + showNotFoundValue_: function(menuOptions, prefValue) { + // Don't show "Custom" before the options load. + if (!menuOptions || !menuOptions.length) + return false; + + var option = menuOptions.find(function(menuItem) { + return menuItem.value == prefValue; + }); + return !option; }, /** diff --git a/chromium/chrome/browser/resources/settings/controls/settings_input.html b/chromium/chrome/browser/resources/settings/controls/settings_input.html index d8bd05e7666..aec34aa8554 100644 --- a/chromium/chrome/browser/resources/settings/controls/settings_input.html +++ b/chromium/chrome/browser/resources/settings/controls/settings_input.html @@ -8,6 +8,7 @@ <template> <style> :host { + -webkit-margin-start: 4px; cursor: auto; display: inline-block; } @@ -18,9 +19,10 @@ no-label-float="[[noLabelFloat]]" pattern="[[pattern]]" readonly$="[[readonly]]" required="[[required]]" type="[[type]]" on-blur="onBlur_" disabled="[[isDisabled_(disabled, pref)]]" - stop-keyboard-event-propagation$="[[stopKeyboardEventPropagation]]"> + stop-keyboard-event-propagation$="[[stopKeyboardEventPropagation]]" + tabindex$="[[getTabindex_(canTab)]]"> </paper-input> - <template is="dom-if" if="[[pref.policySource]]"> + <template is="dom-if" if="[[pref.contolledBy]]"> <cr-policy-pref-indicator pref="[[pref]]"></cr-policy-pref-indicator> </template> </div> diff --git a/chromium/chrome/browser/resources/settings/controls/settings_input.js b/chromium/chrome/browser/resources/settings/controls/settings_input.js index 1de44bb6490..012a8bcaecc 100644 --- a/chromium/chrome/browser/resources/settings/controls/settings_input.js +++ b/chromium/chrome/browser/resources/settings/controls/settings_input.js @@ -36,6 +36,8 @@ Polymer({ reflectToAttribute: true }, + canTab: Boolean, + /* Properties for paper-input. This is not strictly necessary. * Though it does define the types for the closure compiler. */ errorMessage: { type: String }, @@ -78,6 +80,16 @@ Polymer({ }, /** + * Gets a tab index for this control if it can be tabbed to. + * @param {boolean} canTab + * @return {number} + * @private + */ + getTabindex_: function(canTab) { + return canTab ? 0 : -1; + }, + + /** * Blur method for paper-input. Only update the pref value on a blur event. * @private */ diff --git a/chromium/chrome/browser/resources/settings/controls/settings_toggle_button.html b/chromium/chrome/browser/resources/settings/controls/settings_toggle_button.html new file mode 100644 index 00000000000..1b3f2c2d559 --- /dev/null +++ b/chromium/chrome/browser/resources/settings/controls/settings_toggle_button.html @@ -0,0 +1,42 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html"> +<link rel="import" href="/controls/settings_boolean_control_behavior.html"> +<link rel="import" href="/settings_shared_css.html"> + +<dom-module id="settings-toggle-button"> + <template> + <style include="settings-shared"> + #outerRow { + align-items: center; + display: flex; + min-height: var(--settings-row-two-line-min-height); + width: 100%; + } + + #outerRow[noSubLabel] { + min-height: var(--settings-row-min-height); + } + + paper-toggle-button:not([checked]) .secondary { + @apply(--settings-secondary-unchecked); + } + + cr-policy-pref-indicator { + -webkit-margin-end: var(--checkbox-spacing); + } + </style> + <div id="outerRow" noSubLabel$="[[!subLabel]]"> + <div class="flex"> + <div>[[label]]</div> + <div class="secondary">[[subLabel]]</div> + </div> + <template is="dom-if" if="[[pref.controlledBy]]"> + <cr-policy-pref-indicator pref="[[pref]]"></cr-policy-pref-indicator> + </template> + <paper-toggle-button id="control" checked="{{checked}}" + disabled="[[controlDisabled_(disabled, pref)]]"> + </paper-toggle-button> + </div> + </template> + <script src="settings_toggle_button.js"></script> +</dom-module> diff --git a/chromium/chrome/browser/resources/settings/controls/settings_toggle_button.js b/chromium/chrome/browser/resources/settings/controls/settings_toggle_button.js new file mode 100644 index 00000000000..95b99a79dc7 --- /dev/null +++ b/chromium/chrome/browser/resources/settings/controls/settings_toggle_button.js @@ -0,0 +1,13 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview + * `settings-toggle-button` is a toggle that controls a supplied preference. + */ +Polymer({ + is: 'settings-toggle-button', + + behaviors: [SettingsBooleanControlBehavior], +}); diff --git a/chromium/chrome/browser/resources/settings/date_time_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/date_time_page/compiled_resources2.gyp index e05707e948e..04756b71421 100644 --- a/chromium/chrome/browser/resources/settings/date_time_page/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/settings/date_time_page/compiled_resources2.gyp @@ -6,10 +6,12 @@ { 'target_name': 'date_time_page', 'dependencies': [ + '../controls/compiled_resources2.gyp:settings_dropdown_menu', '../prefs/compiled_resources2.gyp:prefs_behavior', - '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-checkbox/compiled_resources2.gyp:paper-checkbox-extracted', + '../prefs/compiled_resources2.gyp:prefs_types', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, diff --git a/chromium/chrome/browser/resources/settings/date_time_page/date_time_page.html b/chromium/chrome/browser/resources/settings/date_time_page/date_time_page.html index adfd8074117..840d2606b31 100644 --- a/chromium/chrome/browser/resources/settings/date_time_page/date_time_page.html +++ b/chromium/chrome/browser/resources/settings/date_time_page/date_time_page.html @@ -1,23 +1,57 @@ +<link rel="import" href="chrome://resources/html/cr.html"> <link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html"> <link rel="import" href="/controls/settings_checkbox.html"> +<link rel="import" href="/controls/settings_dropdown_menu.html"> +<link rel="import" href="/i18n_setup.html"> +<link rel="import" href="/prefs/prefs_behavior.html"> +<link rel="import" href="/prefs/prefs_types.html"> <link rel="import" href="/settings_shared_css.html"> <dom-module id="settings-date-time-page"> <template> - <style include="settings-shared"></style> + <style include="settings-shared"> + settings-dropdown-menu { + --md-select-width: 400px; + } + + cr-policy-pref-indicator { + -webkit-margin-start: var(--checkbox-spacing); + } + </style> <div class="settings-box first"> - <!-- TODO(michaelpg): Time zone dropdown menu. --> + <settings-dropdown-menu pref="{{prefs.cros.system.timezone}}" + menu-options="[[timeZoneList_]]" + disabled="[[timeZoneAutoDetect_]]"> + </settings-dropdown-menu> + </div> + <div class="settings-box continuation"> + <paper-checkbox + id="timeZoneAutoDetectCheckbox" + checked="[[timeZoneAutoDetect_]]" + disabled="[[hasTimeZoneAutoDetectPolicy_]]" + on-change="onTimeZoneAutoDetectCheckboxChange_"> + $i18n{timeZoneGeolocation} + </paper-checkbox> + <template is="dom-if" if="[[hasTimeZoneAutoDetectPolicy_]]"> + <cr-policy-pref-indicator pref="[[timeZonePolicyPref_]]"> + </cr-policy-pref-indicator> + </template> + </div> + <div class="settings-box continuation"> <settings-checkbox pref="{{prefs.settings.clock.use_24hour_clock}}" label="$i18n{use24HourClock}"> </settings-checkbox> </div> - <paper-checkbox class="settings-box continuation" - id="timeZoneDetectionCheckbox" - hidden="[[hideTimeZoneDetection_]]" - on-change="onTimeZoneDetectionCheckboxChange_"> - $i18n{timeZoneGeolocation} - </paper-checkbox> + <div class="settings-box" id="setDateTime" actionable + on-tap="onSetDateTimeTap_" hidden$="[[!canSetDateTime_]]"> + <div class="start"> + <div>$i18n{setDateTime}</div> + </div> + <button class="subpage-arrow" is="paper-icon-button-light"></button> + </div> </template> - <script src="date_time_page.js"></script> + <script src="/date_time_page/date_time_page.js"></script> </dom-module> diff --git a/chromium/chrome/browser/resources/settings/date_time_page/date_time_page.js b/chromium/chrome/browser/resources/settings/date_time_page/date_time_page.js index 75ad8ebb655..3c7fb7d116e 100644 --- a/chromium/chrome/browser/resources/settings/date_time_page/date_time_page.js +++ b/chromium/chrome/browser/resources/settings/date_time_page/date_time_page.js @@ -11,139 +11,214 @@ cr.exportPath('settings'); /** - * Possible values of the system time-zone auto-detection policy. Must stay in - * sync with AutomaticTimezoneDetectionType in chrome_device_policy.proto. + * Describes the status of the auto-detect policy. * @enum {number} - * @const */ -settings.AutomaticTimezoneDetectionPolicy = { - USERS_DECIDE: 0, - DISABLED: 1, - IP_ONLY: 2, - SEND_WIFI_ACCESS_POINTS: 3, +settings.TimeZoneAutoDetectPolicy = { + NONE: 0, + FORCED_ON: 1, + FORCED_OFF: 2, }; Polymer({ is: 'settings-date-time-page', - behaviors: [PrefsBehavior], + behaviors: [PrefsBehavior, WebUIListenerBehavior], properties: { - /** Preferences state. */ - prefs: { - type: Object, - notify: true, + /** + * The time zone auto-detect policy. + * @private {settings.TimeZoneAutoDetectPolicy} + */ + timeZoneAutoDetectPolicy_: { + type: Boolean, + value: function() { + if (!loadTimeData.valueExists('timeZoneAutoDetectValueFromPolicy')) + return settings.TimeZoneAutoDetectPolicy.NONE; + return loadTimeData.getBoolean('timeZoneAutoDetectValueFromPolicy') ? + settings.TimeZoneAutoDetectPolicy.FORCED_ON : + settings.TimeZoneAutoDetectPolicy.FORCED_OFF; + }, }, /** - * If the time zone is managed at the system level, the user cannot control - * any time zone settings. + * Whether a policy controls the time zone auto-detect setting. * @private */ - systemTimeZoneManaged_: { + hasTimeZoneAutoDetectPolicy_: { type: Boolean, - value: function() { - return loadTimeData.getBoolean('systemTimeZoneManaged'); - }, + computed: + 'computeHasTimeZoneAutoDetectPolicy_(timeZoneAutoDetectPolicy_)', }, /** - * If the time zone auto-detection setting is managed at the system level, - * the user cannot override the setting unless the policy is USERS_DECIDE. + * The effective time zone auto-detect setting. * @private */ - systemTimeZoneDetectionManaged_: { + timeZoneAutoDetect_: { type: Boolean, - value: function() { - return loadTimeData.getBoolean( - 'systemTimeZoneDetectionManaged'); - }, + computed: 'computeTimeZoneAutoDetect_(' + + 'timeZoneAutoDetectPolicy_,' + + 'prefs.settings.resolve_timezone_by_geolocation.value)', }, /** - * Value of the system time zone auto-detection policy, or null if system - * time zone auto-detection is not managed. - * @private {?settings.AutomaticTimezoneDetectionPolicy} + * A fake preference to provide cr-policy-pref-indicator with policy info. + * @private {!chrome.settingsPrivate.PrefObject|undefined} + */ + fakeTimeZonePolicyPref_: Object, + + /** + * Initialized with the current time zone so the menu displays the + * correct value. The full option list is fetched lazily if necessary by + * maybeGetTimeZoneList_. + * @private {!DropdownMenuOptionList} */ - systemTimeZoneDetectionPolicyValue_: { - type: Number, + timeZoneList_: { + type: Array, value: function() { - return loadTimeData.valueExists('systemTimeZoneDetectionPolicyValue') ? - /** @type {settings.AutomaticTimezoneDetectionPolicy} */( - loadTimeData.getInteger('systemTimeZoneDetectionPolicyValue')) : - null; + return [{ + name: loadTimeData.getString('timeZoneName'), + value: loadTimeData.getString('timeZoneID'), + }]; }, }, /** - * Hides the time zone auto-detection feature when the - * --disable-timezone-tracking-option flag is set. + * Whether date and time are settable. Normally the date and time are forced + * by network time, so default to false to initially hide the button. * @private */ - hideTimeZoneDetection_: { + canSetDateTime_: { type: Boolean, - value: function() { - return loadTimeData.valueExists('hideTimeZoneDetection') && - loadTimeData.getBoolean('hideTimeZoneDetection'); - }, - readOnly: true, + value: false, }, }, observers: [ - // TODO(michaelpg): Implement a BrowserProxy to listen for policy changes. - 'updateTimeZoneDetectionCheckbox_(' + - 'prefs.settings.resolve_timezone_by_geolocation.value,' + - 'systemTimeZoneManaged_,' + - 'systemTimeZoneDetectionManaged_,' + - 'systemTimeZoneDetectionPolicyValue_)', + 'maybeGetTimeZoneList_(' + + 'prefs.cros.system.timezone.value, timeZoneAutoDetect_)', ], + attached: function() { + this.addWebUIListener( + 'time-zone-auto-detect-policy', + this.onTimeZoneAutoDetectPolicyChanged_.bind(this)); + this.addWebUIListener( + 'can-set-date-time-changed', this.onCanSetDateTimeChanged_.bind(this)); + + chrome.send('dateTimePageReady'); + this.maybeGetTimeZoneList_(); + }, + /** - * Processes all the time zone preferences and policy interactions in one - * observer function instead of complicating the HTML with computed bindings. - * @param {boolean} userPrefValue - * @param {boolean} systemTimeZoneManaged - * @param {boolean} systemTimeZoneDetectionManaged - * @param {?settings.AutomaticTimezoneDetectionPolicy} - * systemTimeZoneDetectionPolicyValue + * @param {boolean} managed Whether the auto-detect setting is controlled. + * @param {boolean} valueFromPolicy The value of the auto-detect setting + * forced by policy. + * @private */ - updateTimeZoneDetectionCheckbox_(userPrefValue, - systemTimeZoneManaged, - systemTimeZoneDetectionManaged, - systemTimeZoneDetectionPolicyValue) { - // Do nothing if the feature is disabled by a flag. - if (this.hideTimeZoneDetection_) + onTimeZoneAutoDetectPolicyChanged_: function(managed, valueFromPolicy) { + if (!managed) { + this.timeZoneAutoDetectPolicy_ = settings.TimeZoneAutoDetectPolicy.NONE; + this.fakeTimeZonePolicyPref_ = undefined; return; + } - var checkbox = this.$.timeZoneDetectionCheckbox; + this.timeZoneAutoDetectPolicy_ = valueFromPolicy ? + settings.TimeZoneAutoDetectPolicy.FORCED_ON : + settings.TimeZoneAutoDetectPolicy.FORCED_OFF; + + if (!this.fakeTimeZonePolicyPref_) { + this.fakeTimeZonePolicyPref_ = { + key: 'fakeTimeZonePref', + type: chrome.settingsPrivate.PrefType.NUMBER, + value: 0, + controlledBy: chrome.settingsPrivate.ControlledBy.DEVICE_POLICY, + enforcement: chrome.settingsPrivate.Enforcement.ENFORCED, + }; + } + }, - // Time zone auto-detection is disabled when the time zone is managed. - if (systemTimeZoneManaged) { - checkbox.disabled = true; - checkbox.checked = false; - return; + /** + * @param {boolean} canSetDateTime Whether date and time are settable. + * @private + */ + onCanSetDateTimeChanged_: function(canSetDateTime) { + this.canSetDateTime_ = canSetDateTime; + }, + + /** + * @param {!Event} e + * @private + */ + onTimeZoneAutoDetectCheckboxChange_: function(e) { + this.setPrefValue( + 'settings.resolve_timezone_by_geolocation', e.target.checked); + }, + + /** @private */ + onSetDateTimeTap_: function() { + chrome.send('showSetDateTimeUI'); + }, + + /** + * @param {settings.TimeZoneAutoDetectPolicy} timeZoneAutoDetectPolicy + * @return {boolean} + * @private + */ + computeHasTimeZoneAutoDetectPolicy_: function(timeZoneAutoDetectPolicy) { + return timeZoneAutoDetectPolicy != settings.TimeZoneAutoDetectPolicy.NONE; + }, + + /** + * @param {settings.TimeZoneAutoDetectPolicy} timeZoneAutoDetectPolicy + * @param {boolean} prefValue Value of the geolocation pref. + * @return {boolean} Whether time zone auto-detect is enabled. + * @private + */ + computeTimeZoneAutoDetect_: function(timeZoneAutoDetectPolicy, prefValue) { + switch (timeZoneAutoDetectPolicy) { + case settings.TimeZoneAutoDetectPolicy.NONE: + return prefValue; + case settings.TimeZoneAutoDetectPolicy.FORCED_ON: + return true; + case settings.TimeZoneAutoDetectPolicy.FORCED_OFF: + return false; + default: + assertNotReached(); } + }, + + /** + * Fetches the list of time zones if necessary. + * @private + */ + maybeGetTimeZoneList_: function() { + // Only fetch the list once. + if (this.timeZoneList_.length > 1 || !CrSettingsPrefs.isInitialized) + return; - // The time zone auto-detection policy may force-disable auto-detection. - if (systemTimeZoneDetectionManaged && - systemTimeZoneDetectionPolicyValue != - settings.AutomaticTimezoneDetectionPolicy.USERS_DECIDE) { - checkbox.disabled = true; - checkbox.checked = - systemTimeZoneDetectionPolicyValue != - settings.AutomaticTimezoneDetectionPolicy.DISABLED; + // If auto-detect is enabled, we only need the current time zone. + if (this.timeZoneAutoDetect_ && + this.getPref('cros.system.timezone').value == + this.timeZoneList_[0].value) { return; } - // If there is no policy, or the policy is USERS_DECIDE, the pref is used. - checkbox.disabled = false; - checkbox.checked = userPrefValue; + cr.sendWithPromise('getTimeZones').then(this.setTimeZoneList_.bind(this)); }, - /** @param {!Event} e */ - onTimeZoneDetectionCheckboxChange_: function(e) { - this.setPrefValue( - 'settings.resolve_timezone_by_geolocation', e.target.checked); + /** + * Converts the C++ response into an array of menu options. + * @param {!Array<!Array<string>>} timeZones C++ time zones response. + * @private + */ + setTimeZoneList_: function(timeZones) { + this.timeZoneList_ = timeZones.map(function(timeZonePair) { + return { + name: timeZonePair[1], + value: timeZonePair[0], + }; + }); }, }); diff --git a/chromium/chrome/browser/resources/settings/device_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/device_page/compiled_resources2.gyp index ea121df6782..ffcc5dda5ac 100644 --- a/chromium/chrome/browser/resources/settings/device_page/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/settings/device_page/compiled_resources2.gyp @@ -33,6 +33,7 @@ 'dependencies': [ '../compiled_resources2.gyp:route', '../prefs/compiled_resources2.gyp:prefs_types', + '../controls/compiled_resources2.gyp:settings_dropdown_menu', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', @@ -51,7 +52,6 @@ { 'target_name': 'display', 'dependencies': [ - '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-button/compiled_resources2.gyp:paper-button-extracted', '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-slider/compiled_resources2.gyp:paper-slider-extracted', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior', @@ -65,7 +65,6 @@ 'target_name': 'display_layout', 'dependencies': [ '<(DEPTH)/third_party/polymer/v1_0/components-chromium/iron-resizable-behavior/compiled_resources2.gyp:iron-resizable-behavior-extracted', - '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-button/compiled_resources2.gyp:paper-button-extracted', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', '<(EXTERNS_GYP):system_display', '<(INTERFACES_GYP):system_display_interface', diff --git a/chromium/chrome/browser/resources/settings/device_page/device_page.html b/chromium/chrome/browser/resources/settings/device_page/device_page.html index 79db53b46e1..b86367e2f5e 100644 --- a/chromium/chrome/browser/resources/settings/device_page/device_page.html +++ b/chromium/chrome/browser/resources/settings/device_page/device_page.html @@ -4,7 +4,6 @@ <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html"> -<link rel="import" href="/controls/settings_dropdown_menu.html"> <link rel="import" href="/device_page/device_page_browser_proxy.html"> <link rel="import" href="/device_page/display.html"> <link rel="import" href="/device_page/keyboard.html"> @@ -30,39 +29,34 @@ <div class="middle"> [[getPointersTitle_(hasMouse_, hasTouchpad_)]] </div> - <button class="icon-arrow-right" is="paper-icon-button-light"> - </button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div id="keyboardRow" class="settings-box" on-tap="onKeyboardTap_" actionable> <iron-icon icon="settings:keyboard"></iron-icon> <div class="middle">$i18n{keyboardTitle}</div> - <button class="icon-arrow-right" is="paper-icon-button-light"> - </button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <template is="dom-if" if="[[stylusAllowed_]]"> <div id="stylusRow" class="settings-box" on-tap="onStylusTap_" actionable> <iron-icon icon="settings:note"></iron-icon> <div class="middle">$i18n{stylusTitle}</div> - <button class="icon-arrow-right" is="paper-icon-button-light"> - </button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> </template> <div id="displayRow" class="settings-box" on-tap="onDisplayTap_" actionable> <iron-icon icon="settings:desktop-windows"></iron-icon> <div class="middle">$i18n{displayTitle}</div> - <button class="icon-arrow-right" is="paper-icon-button-light"> - </button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <template is="dom-if" if="[[showStorageManager_]]"> <div id="storageRow" class="settings-box" on-tap="onStorageTap_" actionable> <iron-icon icon="settings:storage"></iron-icon> <div class="middle">$i18n{storageTitle}</div> - <button class="icon-arrow-right" is="paper-icon-button-light"> - </button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> </template> </neon-animatable> diff --git a/chromium/chrome/browser/resources/settings/device_page/display.html b/chromium/chrome/browser/resources/settings/device_page/display.html index 95c476363fb..be9b6f39325 100644 --- a/chromium/chrome/browser/resources/settings/device_page/display.html +++ b/chromium/chrome/browser/resources/settings/device_page/display.html @@ -1,24 +1,35 @@ <link rel="import" href="chrome://resources/html/i18n_behavior.html"> +<link rel="import" href="chrome://resources/html/md_select_css.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-dropdown-menu/paper-dropdown-menu-light.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-listbox/paper-listbox.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-slider/paper-slider.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-tabs/paper-tabs.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html"> <link rel="import" href="/device_page/display_layout.html"> <link rel="import" href="/device_page/display_overscan_dialog.html"> <link rel="import" href="/settings_shared_css.html"> +<link rel="import" href="/settings_vars_css.html"> <dom-module id="settings-display"> <template> - <style include="settings-shared"> + <style include="settings-shared md-select"> .settings-box.embedded { align-self: stretch; margin-left: 20px; padding: 0; } + :host { + --paper-tabs-selection-bar-color: var(--paper-blue-500); + } + + .display-tabs { + width: 100%; + } + display-layout { align-self: stretch; flex: 1 1; @@ -30,6 +41,10 @@ margin: 10px 0; } + .title-text { + margin-top: 10px; + } + .info-text { color: var(--paper-grey-500); margin-top: 5px; @@ -38,31 +53,62 @@ .settings-box > paper-button:first-child { padding-left: 0 } + + paper-tab { + text-transform: uppercase; + } + </style> <div class="settings-box first layout vertical self-stretch"> - <h2>$i18n{displayArrangement}</h2> + <div class="title-text layout self-start"> + $i18n{displayArrangementTitle} + </div> + <div class="secondary layout self-start"> + $i18n{displayArrangementText} + </div> <display-layout id="displayLayout" selected-display="[[selectedDisplay]]" on-select-display="onSelectDisplay_"> </display-layout> </div> + <div hidden="[[!showDisplayTabMenu_(displays)]]" class="settings-box"> + <paper-tabs noink selected="[[selectedDisplay.id]]" class="display-tabs" + on-iron-select="onSelectDisplayTab_" attr-for-selected="display-id"> + <template is="dom-repeat" items="[[displays]]"> + <paper-tab display-id="[[item.id]]">[[item.name]]</paper-tab> + </template> + </paper-tabs> + </div> + <div hidden="[[showDisplayTabMenu_(displays)]]" + class="settings-box line-only"></div> <div class="settings-box layout vertical first"> <h2>[[selectedDisplay.name]]</h2> - <div class="settings-box embedded first"> - <paper-checkbox class="flex" checked="[[isMirrored_(displays)]]" - hidden$="[[!showMirror_(displays)]]" on-tap="onMirroredTap_"> - $i18n{displayMirror} - </paper-checkbox> - <paper-button - hidden$="[[!showMakePrimary_(selectedDisplay, primaryDisplayId)]]" - on-tap="onMakePrimaryTap_"> - $i18n{displayMakePrimary} - </paper-button> + <div class="settings-box embedded first two-line" + hidden$="[[!showMirror_(displays)]]"> + <div class="start"> + <div>$i18n{displayMirror}</div> + <div class="secondary">[[getDisplayMirrorText_(displays)]]</div> + </div> + <paper-toggle-button checked="[[isMirrored_(displays)]]" + on-tap="onMirroredTap_"> </div> - <div class="settings-box embedded horizontal justified"> + <div class="settings-box embedded" + hidden$="[[!showDisplaySelectMenu_(displays, selectedDisplay)]]"> + <div class="start">$i18n{displayScreenTitle}</div> + <div class="md-select-wrapper"> + <select class="md-select" on-change="updatePrimaryDisplay_" + value="[[getDisplaySelectMenuIndex_( + selectedDisplay, primaryDisplayId)]]"> + <option value="0">$i18n{displayScreenPrimary}</option> + <option value="1">$i18n{displayScreenExtended}</option> + </select> + <span class="md-select-underline"></span> + </div> + </div> + <div class="settings-box embedded two-line"> <div class="start textarea layout vertical"> <div>$i18n{displayResolutionTitle}</div> - <div class="info-text layout self-start"> + <div class="secondary layout self-start"> [[getResolutionText_(selectedDisplay, immediateSelectedModeIndex_)]] </div> </div> @@ -76,26 +122,25 @@ </div> <div class="settings-box embedded"> <div class="start textarea">$i18n{displayOrientation}</div> - <paper-dropdown-menu-light vertical-align="auto" no-label-float> - <paper-listbox class="dropdown-content" - selected="[[selectedDisplay.rotation]]" - attr-for-selected="value" - on-iron-activate="onSetOrientation_"> - <button class="dropdown-item" role="option" value="0"> - $i18n{displayOrientationStandard} - </button> - <button class="dropdown-item" role="option" value="90">90</button> - <button class="dropdown-item" role="option" value="180">180</button> - <button class="dropdown-item" role="option" value="270">270</button> - </paper-listbox> - </paper-dropdown-menu-light> + <div class="md-select-wrapper"> + <select class="md-select" value="[[selectedDisplay.rotation]]" + on-change="onOrientationChange_"> + <option value="0">$i18n{displayOrientationStandard}</option> + <option value="90">90</option> + <option value="180">180</option> + <option value="270">270</option> + </select> + <span class="md-select-underline"></span> + </div> </div> - <div class="settings-box embedded" - hidden$="[[selectedDisplay.isInternal]]"> - <paper-button disabled="[[selectedDisplay.isInternal]]" - on-tap="onOverscanTap_"> - $i18n{displayOverscanPageTitle} - </paper-button> + <div id="subpage-trigger" class="settings-box embedded two-line" + on-tap="onOverscanTap_" hidden$="[[selectedDisplay.isInternal]]" + actionable> + <div class="start"> + <div>$i18n{displayOverscanPageTitle}</div> + <div class="secondary">$i18n{displayOverscanPageText}</div> + </div> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <settings-display-overscan-dialog id="displayOverscan" diff --git a/chromium/chrome/browser/resources/settings/device_page/display.js b/chromium/chrome/browser/resources/settings/device_page/display.js index 5b83b075579..0f71276edd6 100644 --- a/chromium/chrome/browser/resources/settings/device_page/display.js +++ b/chromium/chrome/browser/resources/settings/device_page/display.js @@ -161,13 +161,48 @@ Polymer({ }, /** + * @param {!Array<!chrome.system.display.DisplayUnitInfo>} displays + * @return {boolean} + * @private + */ + showDisplayTabMenu_: function(displays) { + return displays.length > 1; + }, + + /** + * Returns false if the display select menu has to be hidden. + * @param {!Array<!chrome.system.display.DisplayUnitInfo>} displays * @param {!chrome.system.display.DisplayUnitInfo} selectedDisplay - * @param {string} primaryDisplayId * @return {boolean} * @private */ - showMakePrimary_: function(selectedDisplay, primaryDisplayId) { - return !!selectedDisplay && selectedDisplay.id != primaryDisplayId; + showDisplaySelectMenu_: function(displays, selectedDisplay) { + return displays.length > 1 && !selectedDisplay.isPrimary; + }, + + /** + * Returns the select menu index indicating whether the display currently is + * primary or extended. + * @param {!chrome.system.display.DisplayUnitInfo} selectedDisplay + * @param {string} primaryDisplayId + * @return {number} Retruns 0 if the display is primary else returns 1. + * @private + */ + getDisplaySelectMenuIndex_: function(selectedDisplay, primaryDisplayId) { + if (selectedDisplay && selectedDisplay.id == primaryDisplayId) + return 0; + return 1; + }, + + /** + * Returns the i18n string for the text to be used for mirroring settings. + * @param {!Array<!chrome.system.display.DisplayUnitInfo>} displays + * @return {string} i18n string for mirroring settings text. + * @private + */ + getDisplayMirrorText_: function(displays) { + return this.i18n( + this.isMirrored_(displays) ? 'displayMirrorOn' : 'displayMirrorOff'); }, /** @@ -245,12 +280,29 @@ Polymer({ } }, - /** @private */ - onMakePrimaryTap_: function() { + /** + * Handles event when a display tab is selected. + * @param {!{detail: !{item: !{displayId: string}}}} e + * @private + */ + onSelectDisplayTab_: function(e) { + this.onSelectDisplay_({detail: e.detail.item.displayId}); + }, + + /** + * Handles the event when an option from display select menu is selected. + * @param {!{target: !HTMLSelectElement}} e + * @private + */ + updatePrimaryDisplay_: function(e) { + /** @const {number} */ var PRIMARY_DISP_IDX = 0; if (!this.selectedDisplay) return; if (this.selectedDisplay.id == this.primaryDisplayId) return; + if (e.target.value != PRIMARY_DISP_IDX) + return; + /** @type {!chrome.system.display.DisplayProperties} */ var properties = { isPrimary: true }; @@ -279,12 +331,13 @@ Polymer({ }, /** - * @param {!{detail: !{selected: string}}} e + * @param {!Event} event * @private */ - onSetOrientation_: function(e) { + onOrientationChange_: function(event) { + let target = /** @type {!HTMLSelectElement} */ (event.target); /** @type {!chrome.system.display.DisplayProperties} */ var properties = { - rotation: parseInt(e.detail.selected, 10) + rotation: parseInt(target.value, 10) }; settings.display.systemDisplayApi.setDisplayProperties( this.selectedDisplay.id, properties, diff --git a/chromium/chrome/browser/resources/settings/device_page/display_layout.html b/chromium/chrome/browser/resources/settings/device_page/display_layout.html index fda6b748192..ef6f04ffd58 100644 --- a/chromium/chrome/browser/resources/settings/device_page/display_layout.html +++ b/chromium/chrome/browser/resources/settings/device_page/display_layout.html @@ -1,6 +1,6 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-resizable-behavior/iron-resizable-behavior.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-material/paper-material.html"> <link rel="import" href="/device_page/drag_behavior.html"> <link rel="import" href="/device_page/layout_behavior.html"> <link rel="import" href="/settings_shared_css.html"> @@ -11,30 +11,33 @@ /* Use relative position with no offset so that display divs (children), which have absolute positions, are offset from the displayArea div. */ #displayArea { - border: lightgrey solid 1px; height: 100%; + overflow: hidden; position: relative; width: 100%; } + /* Note: the size of the border / box shadow affects the style generated in getDivStyle_ and getMirrorDivStyle_ */ .display { align-items: center; - background: var(--paper-grey-200); - border: var(--paper-grey-200) solid 1px; - box-shadow: 2px 2px var(--paper-grey-400); + background: var(--paper-grey-100); + color: var(--paper-grey-700); cursor: default; display: flex; + font-size: 13px; + font-weight: 500; justify-content: center; + margin: 4px; + padding: 3px; position: absolute; + text-align: center; } .display[selected] { - border: var(--google-blue-500) solid 2px; - box-shadow: none; + border: var(--google-blue-500) solid 1px; } .display.mirror { border: var(--google-blue-500) solid 1px; - box-shadow: none; } .highlight-left { border-left: var(--google-blue-700) solid 1px; @@ -53,16 +56,16 @@ <template is="dom-repeat" items="[[displays]]"> <div id="_mirror_[[item.id]]" class="display mirror" hidden$="[[!mirroring]]" - style$="[[getMirrorDivStyle_(item.id, item.bounds, visualScale)]]" + style$="[[getMirrorDivStyle_(item.id, item.bounds, visualScale)]]"> </div> </template> <template is="dom-repeat" items="[[displays]]"> - <div id="_[[item.id]]" class="display" draggable="[[dragEnabled]]" + <paper-material id="_[[item.id]]" class="display" elevation="1" + draggable="[[dragEnabled]]" on-tap="onSelectDisplayTap_" style$="[[getDivStyle_(item.id, item.bounds, visualScale)]]" - selected$="[[isSelected_(item, selectedDisplay)]]" - on-tap="onSelectDisplayTap_"> + selected$="[[isSelected_(item, selectedDisplay)]]"> [[item.name]] - </div> + </paper-material> </template> </div> </template> diff --git a/chromium/chrome/browser/resources/settings/device_page/display_layout.js b/chromium/chrome/browser/resources/settings/device_page/display_layout.js index eb1931f825f..d2b4623f0fb 100644 --- a/chromium/chrome/browser/resources/settings/device_page/display_layout.js +++ b/chromium/chrome/browser/resources/settings/device_page/display_layout.js @@ -141,13 +141,17 @@ Polymer({ */ getDivStyle_: function(id, displayBounds, visualScale, opt_mirrored) { // This matches the size of the box-shadow or border in CSS. - /** @const {number} */ var BORDER = opt_mirrored ? 1 : 2; + /** @const {number} */ var BORDER = 1; + /** @const {number} */ var MARGIN = 4; /** @const {number} */ var OFFSET = opt_mirrored ? -4 : 0; + /** @const {number} */ var PADDING = 3; var bounds = this.getCalculatedDisplayBounds(id, true /* notest */); if (!bounds) return ''; - var height = Math.round(bounds.height * this.visualScale) - BORDER * 2; - var width = Math.round(bounds.width * this.visualScale) - BORDER * 2; + var height = Math.round(bounds.height * this.visualScale) - BORDER * 2 - + MARGIN * 2 - PADDING * 2; + var width = Math.round(bounds.width * this.visualScale) - BORDER * 2 - + MARGIN * 2 - PADDING * 2; var left = OFFSET + Math.round(this.visualOffset_.left + (bounds.left * this.visualScale)); var top = OFFSET + @@ -179,12 +183,13 @@ Polymer({ /** * @param {!{model: !{item: !chrome.system.display.DisplayUnitInfo}, - * target: !PaperButtonElement}} e + * target: !HTMLDivElement}} e * @private */ onSelectDisplayTap_: function(e) { this.fire('select-display', e.model.item.id); // Force active in case the selected display was clicked. + // TODO(dpapad): Ask @stevenjb, why are we setting 'active' on a div? e.target.active = true; }, @@ -192,7 +197,7 @@ Polymer({ * @param {string} id * @param {?DragPosition} amount */ - onDrag_(id, amount) { + onDrag_: function(id, amount) { id = id.substr(1); // Skip prefix var newBounds; diff --git a/chromium/chrome/browser/resources/settings/device_page/keyboard.html b/chromium/chrome/browser/resources/settings/device_page/keyboard.html index 8f2f5e0f3b9..6b111be75f1 100644 --- a/chromium/chrome/browser/resources/settings/device_page/keyboard.html +++ b/chromium/chrome/browser/resources/settings/device_page/keyboard.html @@ -16,7 +16,7 @@ <div class="start">$i18n{keyboardKeySearch}</div> <settings-dropdown-menu pref="{{prefs.settings.language.xkb_remap_search_key_to}}" - menu-options="[[keyMapTargetsWithCapsLock_]]"> + menu-options="[[keyMapTargets_]]"> </settings-dropdown-menu> </div> <div class="settings-box"> @@ -38,7 +38,7 @@ <div class="start">$i18n{keyboardKeyCapsLock}</div> <settings-dropdown-menu pref="{{prefs.settings.language.remap_caps_lock_key_to}}" - menu-options="[[keyMapTargetsWithCapsLock_]]"> + menu-options="[[keyMapTargets_]]"> </settings-dropdown-menu> </div> </template> @@ -52,6 +52,20 @@ </div> </template> <div class="settings-box"> + <div class="start">$i18n{keyboardKeyEscape}</div> + <settings-dropdown-menu + pref="{{prefs.settings.language.remap_escape_key_to}}" + menu-options="[[keyMapTargets_]]"> + </settings-dropdown-menu> + </div> + <div class="settings-box"> + <div class="start">$i18n{keyboardKeyBackspace}</div> + <settings-dropdown-menu + pref="{{prefs.settings.language.remap_backspace_key_to}}" + menu-options="[[keyMapTargets_]]"> + </settings-dropdown-menu> + </div> + <div class="settings-box"> <settings-checkbox pref="{{prefs.settings.language.send_function_keys}}" label="$i18n{keyboardSendFunctionKeys}" diff --git a/chromium/chrome/browser/resources/settings/device_page/keyboard.js b/chromium/chrome/browser/resources/settings/device_page/keyboard.js index 968d0013005..f4a4534ea63 100644 --- a/chromium/chrome/browser/resources/settings/device_page/keyboard.js +++ b/chromium/chrome/browser/resources/settings/device_page/keyboard.js @@ -6,15 +6,22 @@ * @fileoverview * 'settings-keyboard' is the settings subpage with keyboard settings. */ +cr.exportPath('settings'); -// TODO(michaelpg): The docs below are duplicates of settings_dropdown_menu, -// because we can't depend on settings_dropdown_menu in compiled_resources2.gyp -// withhout first converting settings_dropdown_menu to compiled_resources2.gyp. -// After the conversion, we should remove these. -/** @typedef {{name: string, value: (number|string)}} */ -var DropdownMenuOption; -/** @typedef {!Array<!DropdownMenuOption>} */ -var DropdownMenuOptionList; +/** + * Modifier key IDs corresponding to the ModifierKey enumerators in + * /ui/base/ime/chromeos/ime_keyboard.h. + * @enum {number} + */ +settings.ModifierKey = { + SEARCH_KEY: 0, + CONTROL_KEY: 1, + ALT_KEY: 2, + VOID_KEY: 3, // Represents a disabled key. + CAPS_LOCK_KEY: 4, + ESCAPE_KEY: 5, + BACKSPACE_KEY: 6, +}; Polymer({ is: 'settings-keyboard', @@ -36,12 +43,6 @@ Polymer({ keyMapTargets_: Object, /** - * @private {!DropdownMenuOptionList} Menu items for key mapping, including - * Caps Lock. - */ - keyMapTargetsWithCapsLock_: Object, - - /** * Auto-repeat delays (in ms) for the corresponding slider values, from * long to short. The values were chosen to provide a large range while * giving several options near the defaults. @@ -78,20 +79,29 @@ Polymer({ * @private */ setUpKeyMapTargets_: function() { - this.keyMapTargets_ = [ - {value: 0, name: loadTimeData.getString('keyboardKeySearch')}, - {value: 1, name: loadTimeData.getString('keyboardKeyCtrl')}, - {value: 2, name: loadTimeData.getString('keyboardKeyAlt')}, - {value: 3, name: loadTimeData.getString('keyboardKeyDisabled')}, - {value: 5, name: loadTimeData.getString('keyboardKeyEscape')}, - ]; - - var keyMapTargetsWithCapsLock = this.keyMapTargets_.slice(); - // Add Caps Lock, for keys allowed to be mapped to Caps Lock. - keyMapTargetsWithCapsLock.splice(4, 0, { - value: 4, name: loadTimeData.getString('keyboardKeyCapsLock'), - }); - this.keyMapTargetsWithCapsLock_ = keyMapTargetsWithCapsLock; + // Ordering is according to UX, but values match settings.ModifierKey. + this.keyMapTargets_ = [{ + value: settings.ModifierKey.SEARCH_KEY, + name: loadTimeData.getString('keyboardKeySearch'), + }, { + value: settings.ModifierKey.CONTROL_KEY, + name: loadTimeData.getString('keyboardKeyCtrl') + }, { + value: settings.ModifierKey.ALT_KEY, + name: loadTimeData.getString('keyboardKeyAlt') + }, { + value: settings.ModifierKey.CAPS_LOCK_KEY, + name: loadTimeData.getString('keyboardKeyCapsLock') + }, { + value: settings.ModifierKey.ESCAPE_KEY, + name: loadTimeData.getString('keyboardKeyEscape') + }, { + value: settings.ModifierKey.BACKSPACE_KEY, + name: loadTimeData.getString('keyboardKeyBackspace') + }, { + value: settings.ModifierKey.VOID_KEY, + name: loadTimeData.getString('keyboardKeyDisabled') + }]; }, /** diff --git a/chromium/chrome/browser/resources/settings/device_page/storage.html b/chromium/chrome/browser/resources/settings/device_page/storage.html index a012cf467e5..26acedcb2c4 100644 --- a/chromium/chrome/browser/resources/settings/device_page/storage.html +++ b/chromium/chrome/browser/resources/settings/device_page/storage.html @@ -2,7 +2,7 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.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-progress/paper-progress.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html"> <link rel="import" href="/device_page/drive_cache_dialog.html"> <link rel="import" href="/prefs/prefs.html"> <link rel="import" href="/route.html"> @@ -14,17 +14,17 @@ progress { -webkit-appearance: none; display: block; - height: 40px; + height: 28px; width: 100%; } progress::-webkit-progress-bar { - background-color: rgb(232, 232, 232); + background-color: rgba(0, 0, 0, 0.06); border-radius: 2px; } progress::-webkit-progress-value { - background-color: rgb(167, 225, 251); + background-color: rgb(0, 175, 255); border-radius: 2px; } @@ -38,8 +38,8 @@ iron-icon { --iron-icon-fill-color: rgb(255, 176, 0); - --iron-icon-height: 20px; - --iron-icon-width: 20px; + --iron-icon-height: 32px; + --iron-icon-width: 32px; } #criticallyLowMessage iron-icon { @@ -47,37 +47,41 @@ } .storage-size { - color: rgb(145, 145, 145); + color: var(--paper-grey-600); } .message-area { + -webkit-padding-end: 48px; + -webkit-padding-start: 16px; background-color: var(--google-grey-100); border-radius: 2px; - margin: 10px 0; - padding: 20px 20px 6px; + display: flex; + margin: 14px 0 16px; + padding-bottom: 12px; + padding-top: 16px; width: 100%; } - .message-title { - align-items: center; - display: flex; - margin-bottom: 16px; + .message-area > iron-icon { + -webkit-padding-end: 16px; + flex: none; } - .message-title span { + .message-title { font-size: 115%; - margin: 0 10px; } - .message-area > div:not(.message-title) { + .message-description { color: rgb(90, 90, 90); + font-size: 92%; + line-height: 1.6em; margin: 1em 0; } #barArea { display: flex; flex-direction: column; - margin: 12px 0 20px; + margin: 24px 0 54px; width: 100%; } @@ -92,16 +96,14 @@ .bar-label .vertical-line { align-self: center; - background-color: rgb(223, 223, 223); - height: 10px; + background-color: rgba(0, 0, 0, 0.17); + height: 8px; + margin-bottom: 4px; width: 1px; } - .bar-label span { - font-size: 85%; - } - .bar-label .wrapper { + color: rgb(51, 51, 51); text-align: center; white-space: nowrap; } @@ -127,23 +129,29 @@ <div class="settings-box first" hidden$="[[!isSpaceLow_(sizeStat_.spaceState)]]"> <div class="message-area"> - <div class="message-title"> - <iron-icon icon="cr:warning"></iron-icon> - <span>$i18n{storageSpaceLowMessageTitle}</span> + <iron-icon icon="cr:warning"></iron-icon> + <div class="message"> + <div class="message-title">$i18n{storageSpaceLowMessageTitle}</div> + <div class="message-description"> + <span>$i18n{storageSpaceLowMessageLine1}</span> + <span>$i18n{storageSpaceLowMessageLine2}</span> + </div> </div> - <div>$i18n{storageSpaceLowMessageLine1}</div> - <div>$i18n{storageSpaceLowMessageLine2}</div> </div> </div> <div class="settings-box first" hidden$="[[!isSpaceCriticallyLow_(sizeStat_.spaceState)]]"> <div id="criticallyLowMessage" class="message-area"> - <div class="message-title"> - <iron-icon icon="cr:warning"></iron-icon> - <span>$i18n{storageSpaceCriticallyLowMessageTitle}</span> + <iron-icon icon="cr:warning"></iron-icon> + <div class="message"> + <div class="message-title"> + $i18n{storageSpaceCriticallyLowMessageTitle} + </div> + <div class="message-description"> + <span>$i18n{storageSpaceCriticallyLowMessageLine1}</span> + <span>$i18n{storageSpaceCriticallyLowMessageLine2}</span> + </div> </div> - <div>$i18n{storageSpaceCriticallyLowMessageLine1}</div> - <div>$i18n{storageSpaceCriticallyLowMessageLine2}</div> </div> </div> <div class="settings-box first"> @@ -173,6 +181,7 @@ <div id="downloadsSize" class="storage-size"> $i18n{storageSizeComputing} </div> + <button class="icon-external" is="paper-icon-button-light"></button> </div> <div class="settings-box" on-tap="onDriveCacheTap_" hidden$="[[!driveEnabled_]]" actionable> @@ -180,12 +189,14 @@ <div id="driveCacheSize" class="storage-size"> $i18n{storageSizeComputing} </div> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="settings-box" on-tap="onBrowsingDataTap_" actionable> <div class="start">$i18n{storageItemBrowsingData}</div> <div id="browsingDataSize" class="storage-size"> $i18n{storageSizeComputing} </div> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="settings-box" on-tap="onAndroidTap_" hidden$="[[!androidEnabled_]]" actionable> @@ -193,12 +204,14 @@ <div id="androidSize" class="storage-size"> $i18n{storageSizeComputing} </div> + <button class="icon-external" is="paper-icon-button-light"></button> </div> <div class="settings-box" on-tap="onOtherUsersTap_" actionable> <div class="start">$i18n{storageItemOtherUsers}</div> <div id="otherUsersSize" class="storage-size"> $i18n{storageSizeComputing} </div> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <settings-drive-cache-dialog id="storageDriveCache"> </settings-drive-cache-dialog> diff --git a/chromium/chrome/browser/resources/settings/device_page/stylus.html b/chromium/chrome/browser/resources/settings/device_page/stylus.html index 6e818a50b66..42fb14ebebf 100644 --- a/chromium/chrome/browser/resources/settings/device_page/stylus.html +++ b/chromium/chrome/browser/resources/settings/device_page/stylus.html @@ -16,6 +16,7 @@ <div class="settings-box continuation"> <settings-checkbox + disabled="[[!prefs.settings.enable_stylus_tools.value]]" pref="{{prefs.settings.launch_palette_on_eject_event}}" label="$i18n{stylusAutoOpenStylusTools}"> </settings-checkbox> diff --git a/chromium/chrome/browser/resources/settings/downloads_page/downloads_page.html b/chromium/chrome/browser/resources/settings/downloads_page/downloads_page.html index c580b10b4f8..a5a3867affd 100644 --- a/chromium/chrome/browser/resources/settings/downloads_page/downloads_page.html +++ b/chromium/chrome/browser/resources/settings/downloads_page/downloads_page.html @@ -2,7 +2,6 @@ <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html"> <link rel="import" href="/controls/controlled_button.html"> <link rel="import" href="/controls/settings_checkbox.html"> -<link rel="import" href="/controls/settings_input.html"> <link rel="import" href="/settings_shared_css.html"> <dom-module id="settings-downloads-page"> diff --git a/chromium/chrome/browser/resources/settings/extension_control_browser_proxy.html b/chromium/chrome/browser/resources/settings/extension_control_browser_proxy.html new file mode 100644 index 00000000000..1135be58d42 --- /dev/null +++ b/chromium/chrome/browser/resources/settings/extension_control_browser_proxy.html @@ -0,0 +1,3 @@ +<link rel="import" href="chrome://resources/html/assert.html"> +<link rel="import" href="chrome://resources/html/cr.html"> +<script src="/extension_control_browser_proxy.js"></script> diff --git a/chromium/chrome/browser/resources/settings/extension_control_browser_proxy.js b/chromium/chrome/browser/resources/settings/extension_control_browser_proxy.js new file mode 100644 index 00000000000..adbbd794efd --- /dev/null +++ b/chromium/chrome/browser/resources/settings/extension_control_browser_proxy.js @@ -0,0 +1,42 @@ +// Copyright 2016 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('settings', function() { + /** @interface */ + function ExtensionControlBrowserProxy() {} + + ExtensionControlBrowserProxy.prototype = { + // TODO(dbeam): should be be returning !Promise<boolean> to indicate whether + // it succeeded? + /** @param {string} extensionId */ + disableExtension: assertNotReached, + + /** @param {string} extensionId */ + manageExtension: assertNotReached, + }; + + /** + * @implements {settings.ExtensionControlBrowserProxy} + * @constructor + */ + function ExtensionControlBrowserProxyImpl() {} + cr.addSingletonGetter(ExtensionControlBrowserProxyImpl); + + ExtensionControlBrowserProxyImpl.prototype = { + /** @override */ + disableExtension: function(extensionId) { + chrome.send('disableExtension', [extensionId]); + }, + + /** @override */ + manageExtension: function(extensionId) { + window.open('chrome://extensions?id=' + extensionId); + }, + }; + + return { + ExtensionControlBrowserProxy: ExtensionControlBrowserProxy, + ExtensionControlBrowserProxyImpl: ExtensionControlBrowserProxyImpl, + }; +}); diff --git a/chromium/chrome/browser/resources/settings/global_scroll_target_behavior.html b/chromium/chrome/browser/resources/settings/global_scroll_target_behavior.html new file mode 100644 index 00000000000..71c083ae4ba --- /dev/null +++ b/chromium/chrome/browser/resources/settings/global_scroll_target_behavior.html @@ -0,0 +1,2 @@ +<link rel="import" href="chrome://resources/html/cr.html"> +<script src="global_scroll_target_behavior.js"></script> diff --git a/chromium/chrome/browser/resources/settings/global_scroll_target_behavior.js b/chromium/chrome/browser/resources/settings/global_scroll_target_behavior.js new file mode 100644 index 00000000000..80623632864 --- /dev/null +++ b/chromium/chrome/browser/resources/settings/global_scroll_target_behavior.js @@ -0,0 +1,45 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview |GlobalScrollTargetBehavior| allows an element to be aware of + * the global scroll target. |scrollTarget| will be populated async by + * |setGlobalScrollTarget|. |setGlobalScrollTarget| should only be called once. + */ + +cr.define('settings', function() { + var scrollTargetResolver = new PromiseResolver(); + + /** @polymerBehavior */ + var GlobalScrollTargetBehavior = { + properties: { + /** + * Read only property for the scroll target. + * @type {HTMLElement} + */ + scrollTarget: { + type: Object, + readOnly: true, + }, + }, + + /** @override */ + attached: function() { + scrollTargetResolver.promise.then(this._setScrollTarget.bind(this)); + }, + }; + + /** + * This should only be called once. + * @param {HTMLElement} scrollTarget + */ + var setGlobalScrollTarget = function(scrollTarget) { + scrollTargetResolver.resolve(scrollTarget); + }; + + return { + GlobalScrollTargetBehavior: GlobalScrollTargetBehavior, + setGlobalScrollTarget: setGlobalScrollTarget, + }; +}); diff --git a/chromium/chrome/browser/resources/settings/icons.html b/chromium/chrome/browser/resources/settings/icons.html index 8a0f9e6b645..8026e538307 100644 --- a/chromium/chrome/browser/resources/settings/icons.html +++ b/chromium/chrome/browser/resources/settings/icons.html @@ -18,11 +18,6 @@ <path fill="none" d="M1 1h22v22H1z"></path> </g> - <!-- The Google Cloud Printing icon in the Chrome Settings page. --> - <g id="cloud-printing"> - <path d="M16.8 20.4H7.2v-6h9.6v6zm2.55-13.16C18.67 3.79 15.64 1.2 12 1.2c-2.89 0-5.4 1.64-6.65 4.04C2.34 5.56 0 8.11 0 11.2c0 2.9 2.064 5.322 4.8 5.878V22.8h14.4v-5.62c2.665-.108 4.8-2.288 4.8-4.98 0-2.64-2.05-4.78-4.65-4.96z" fill-rule="evenodd"></path> - </g> - <!-- These icons are copied from Polymer's iron-icons and kept in sorted order. See http://goo.gl/Y1OdAq for instructions on adding additional icons. @@ -83,6 +78,7 @@ <g id="note"><path d="M3 17.25V21h3.75L17.81 9.94l-3.75-3.75L3 17.25zM20.71 7.04c.39-.39.39-1.02 0-1.41l-2.34-2.34c-.39-.39-1.02-.39-1.41 0l-1.83 1.83 3.75 3.75 1.83-1.83z"></path></g> </if> <g id="notifications"><path d="M12 22c1.1 0 2-.9 2-2h-4c0 1.1.89 2 2 2zm6-6v-5c0-3.07-1.64-5.64-4.5-6.32V4c0-.83-.67-1.5-1.5-1.5s-1.5.67-1.5 1.5v.68C7.63 5.36 6 7.92 6 11v5l-2 2v1h16v-1l-2-2z"></path></g> + <g id="pdf"><path d="M7 11.5h1v-1H7v1zM19 3H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2zm-9.5 8.5c0 .83-.67 1.5-1.5 1.5H7v2H5.5V9H8c.83 0 1.5.67 1.5 1.5v1zm10-1H17v1h1.5V13H17v2h-1.5V9h4v1.5zm-5 3c0 .83-.67 1.5-1.5 1.5h-2.5V9H13c.83 0 1.5.67 1.5 1.5v3zm-2.5 0h1v-3h-1v3z"></path><path fill="none" d="M0 0h24v24H0z"></path></g> <g id="palette"><path d="M12 3c-4.97 0-9 4.03-9 9s4.03 9 9 9c.83 0 1.5-.67 1.5-1.5 0-.39-.15-.74-.39-1.01-.23-.26-.38-.61-.38-.99 0-.83.67-1.5 1.5-1.5H16c2.76 0 5-2.24 5-5 0-4.42-4.03-8-9-8zm-5.5 9c-.83 0-1.5-.67-1.5-1.5S5.67 9 6.5 9 8 9.67 8 10.5 7.33 12 6.5 12zm3-4C8.67 8 8 7.33 8 6.5S8.67 5 9.5 5s1.5.67 1.5 1.5S10.33 8 9.5 8zm5 0c-.83 0-1.5-.67-1.5-1.5S13.67 5 14.5 5s1.5.67 1.5 1.5S15.33 8 14.5 8zm3 4c-.83 0-1.5-.67-1.5-1.5S16.67 9 17.5 9s1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"></path></g> <g id="people"><path d="M16 11c1.66 0 2.99-1.34 2.99-3S17.66 5 16 5c-1.66 0-3 1.34-3 3s1.34 3 3 3zm-8 0c1.66 0 2.99-1.34 2.99-3S9.66 5 8 5C6.34 5 5 6.34 5 8s1.34 3 3 3zm0 2c-2.33 0-7 1.17-7 3.5V19h14v-2.5c0-2.33-4.67-3.5-7-3.5zm8 0c-.29 0-.62.02-.97.05 1.16.84 1.97 1.97 1.97 3.45V19h6v-2.5c0-2.33-4.67-3.5-7-3.5z"></path></g> <g id="photo"><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"></path></g> diff --git a/chromium/chrome/browser/resources/settings/images/arrow_down.svg b/chromium/chrome/browser/resources/settings/images/arrow_down.svg deleted file mode 100644 index 8ca43cd9caf..00000000000 --- a/chromium/chrome/browser/resources/settings/images/arrow_down.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" width="24px" height="24px" viewBox="0 0 24 24" fill="#757575"><g><path d="M 0 0 L 24 0 L 12 12 z"/></g></svg> diff --git a/chromium/chrome/browser/resources/settings/images/help_outline.svg b/chromium/chrome/browser/resources/settings/images/help_outline.svg new file mode 100644 index 00000000000..ad586abee40 --- /dev/null +++ b/chromium/chrome/browser/resources/settings/images/help_outline.svg @@ -0,0 +1,4 @@ +<svg fill="#757575" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"> + <path d="M0 0h24v24H0z" fill="none"/> + <path d="M11 18h2v-2h-2v2zm1-16C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm0-14c-2.21 0-4 1.79-4 4h2c0-1.1.9-2 2-2s2 .9 2 2c0 2-3 1.75-3 5h2c0-2.25 3-2.5 3-5 0-2.21-1.79-4-4-4z"/> +</svg>
\ No newline at end of file diff --git a/chromium/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp index f1dd5bc2b1f..54926e652c5 100644 --- a/chromium/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/settings/internet_page/compiled_resources2.gyp @@ -76,8 +76,12 @@ { 'target_name': 'network_proxy', 'dependencies': [ + '../controls/compiled_resources2.gyp:settings_checkbox', + '../prefs/compiled_resources2.gyp:prefs_behavior', '<(DEPTH)/ui/webui/resources/cr_elements/network/compiled_resources2.gyp:cr_onc_types', '<(DEPTH)/ui/webui/resources/cr_elements/policy/compiled_resources2.gyp:cr_policy_network_behavior', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, diff --git a/chromium/chrome/browser/resources/settings/internet_page/internet_detail_page.html b/chromium/chrome/browser/resources/settings/internet_page/internet_detail_page.html index d98144179e5..a5d8f57f176 100644 --- a/chromium/chrome/browser/resources/settings/internet_page/internet_detail_page.html +++ b/chromium/chrome/browser/resources/settings/internet_page/internet_detail_page.html @@ -1,5 +1,4 @@ <link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html"> -<link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/cr_elements/network/cr_network_icon.html"> <link rel="import" href="chrome://resources/cr_elements/network/cr_onc_types.html"> <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html"> @@ -10,7 +9,7 @@ <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> +<link rel="import" href="/prefs/prefs.html"> <link rel="import" href="/route.html"> <link rel="import" href="internet_shared_css.html"> <link rel="import" href="network_apnlist.html"> @@ -233,7 +232,8 @@ network-properties="[[networkProperties]]"> </network-nameservers> <span class="subtitle">$i18n{networkSectionProxy}</span> - <network-proxy editable on-proxy-change="onProxyChange_" + <network-proxy editable prefs="{{prefs}}" + on-proxy-change="onProxyChange_" network-properties="[[networkProperties]]"> </network-proxy> </template> diff --git a/chromium/chrome/browser/resources/settings/internet_page/internet_detail_page.js b/chromium/chrome/browser/resources/settings/internet_page/internet_detail_page.js index a1ddb8e17c7..e37ad1ad976 100644 --- a/chromium/chrome/browser/resources/settings/internet_page/internet_detail_page.js +++ b/chromium/chrome/browser/resources/settings/internet_page/internet_detail_page.js @@ -31,6 +31,12 @@ Polymer({ observer: 'networkPropertiesChanged_', }, + /** Preferences state. */ + prefs: { + type: Object, + notify: true, + }, + /** * Highest priority connected network or null. * @type {?CrOnc.NetworkStateProperties} diff --git a/chromium/chrome/browser/resources/settings/internet_page/internet_page.html b/chromium/chrome/browser/resources/settings/internet_page/internet_page.html index 03f941768e1..21a0d91152a 100644 --- a/chromium/chrome/browser/resources/settings/internet_page/internet_page.html +++ b/chromium/chrome/browser/resources/settings/internet_page/internet_page.html @@ -4,6 +4,7 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html"> +<link rel="import" href="/prefs/prefs.html"> <link rel="import" href="/route.html"> <link rel="import" href="/settings_page/settings_animated_pages.html"> <link rel="import" href="/settings_page/settings_subpage.html"> @@ -63,7 +64,7 @@ </neon-animatable> <template is="dom-if" route-path="/networkDetail" no-search> <settings-subpage page-title="$i18n{internetDetailPageTitle}"> - <settings-internet-detail-page + <settings-internet-detail-page prefs="{{prefs}}" default-network="[[defaultNetwork]]" networking-private="[[networkingPrivate]]"> </settings-internet-detail-page> diff --git a/chromium/chrome/browser/resources/settings/internet_page/internet_page.js b/chromium/chrome/browser/resources/settings/internet_page/internet_page.js index ac3239e79fa..8f3f6071fa0 100644 --- a/chromium/chrome/browser/resources/settings/internet_page/internet_page.js +++ b/chromium/chrome/browser/resources/settings/internet_page/internet_page.js @@ -22,6 +22,12 @@ Polymer({ value: chrome.networkingPrivate, }, + /** Preferences state. */ + prefs: { + type: Object, + notify: true, + }, + /** * The network type for the known networks subpage. * @private diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_apnlist.html b/chromium/chrome/browser/resources/settings/internet_page/network_apnlist.html index e1d8ec88abb..45bcd06c2ab 100644 --- a/chromium/chrome/browser/resources/settings/internet_page/network_apnlist.html +++ b/chromium/chrome/browser/resources/settings/internet_page/network_apnlist.html @@ -1,27 +1,25 @@ <link rel="import" href="chrome://resources/cr_elements/network/cr_onc_types.html"> +<link rel="import" href="chrome://resources/html/md_select_css.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-dropdown-menu/paper-dropdown-menu-light.html"> +<link rel="import" href="/settings_vars_css.html"> <link rel="import" href="internet_shared_css.html"> <link rel="import" href="network_property_list.html"> <dom-module id="network-apnlist"> <template> - <style include="internet-shared"></style> + <style include="internet-shared md-select"></style> <div class="settings-box first"> <div class="start">$i18n{networkSectionAccessPoint}</div> - <paper-dropdown-menu-light vertical-align="auto" no-label-float> - <paper-listbox id="selectApn" - class="dropdown-content" on-iron-activate="onSelectApnChange_" - selected="{{selectedApn_}}" attr-for-selected="value"> + <div class="md-select-wrapper"> + <select id="selectApn" class="md-select" on-change="onSelectApnChange_" + value="[[selectedApn_]]"> <template is="dom-repeat" items="[[apnSelectList_]]"> - <button class="dropdown-item" role="option" - value="[[item.AccessPointName]]"> - [[apnDesc_(item)]] - </button> + <option value="[[item.AccessPointName]]">[[apnDesc_(item)]]</option> </template> - </paper-listbox> - </paper-dropdown-menu-light> + </select> + <span class="md-select-underline"></span> + </div> </div> <div class="settings-box continuation single-column" diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_apnlist.js b/chromium/chrome/browser/resources/settings/internet_page/network_apnlist.js index c6270f6b9de..594e094afb4 100644 --- a/chromium/chrome/browser/resources/settings/internet_page/network_apnlist.js +++ b/chromium/chrome/browser/resources/settings/internet_page/network_apnlist.js @@ -139,11 +139,11 @@ Polymer({ result.push(otherApn); this.apnSelectList_ = result; - this.selectedApn_ = - (activeApn && activeApn.AccessPointName) || otherApn.AccessPointName; - // We need to flush the DOM here, otherwise the paper-dropdown-menu-light - // will not update to correctly display the selected AccessPointName. - Polymer.dom.flush(); + // Set selectedApn_ after dom-repeat has been stamped. + this.async(function() { + this.selectedApn_ = + (activeApn && activeApn.AccessPointName) || otherApn.AccessPointName; + }.bind(this)); }, /** @@ -177,16 +177,18 @@ Polymer({ /** * Event triggered when the selectApn selection changes. - * @param {!{detail: !{selected: string}}} event + * @param {!Event} event * @private */ onSelectApnChange_: function(event) { - /** @type {string} */ var accessPointName = event.detail.selected; + let target = /** @type {!HTMLSelectElement} */(event.target); + var accessPointName = target.value; // When selecting 'Other', don't set a change event unless a valid // non-default value has been set for Other. if (this.isOtherSelected_(accessPointName) && (!this.otherApn_ || !this.otherApn_.AccessPointName || this.otherApn_.AccessPointName == this.DefaultAccessPointName)) { + this.selectedApn_ = accessPointName; return; } this.sendApnChange_(accessPointName); diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_nameservers.html b/chromium/chrome/browser/resources/settings/internet_page/network_nameservers.html index 963739d45d6..d58bb82ce52 100644 --- a/chromium/chrome/browser/resources/settings/internet_page/network_nameservers.html +++ b/chromium/chrome/browser/resources/settings/internet_page/network_nameservers.html @@ -1,25 +1,24 @@ +<link rel="import" href="chrome://resources/cr_elements/network/cr_onc_types.html"> +<link rel="import" href="chrome://resources/html/md_select_css.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input-container.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-dropdown-menu/paper-dropdown-menu-light.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-listbox/paper-listbox.html"> -<link rel="import" href="chrome://resources/cr_elements/network/cr_onc_types.html"> +<link rel="import" href="/settings_vars_css.html"> <link rel="import" href="internet_shared_css.html"> <dom-module id="network-nameservers"> <template> - <style include="internet-shared"></style> + <style include="internet-shared md-select"></style> <div class="settings-box first"> <div class="start">$i18n{networkSectionNameservers}</div> - <paper-dropdown-menu-light vertical-align="auto" no-label-float> - <paper-listbox class="dropdown-content" on-iron-activate="onTypeChange_" - selected="[[nameserversType_]]" attr-for-selected="value"> + <div class="md-select-wrapper"> + <select id="nameserverType" class="md-select" on-change="onTypeChange_" + value="[[nameserversType_]]"> <template is="dom-repeat" items="[[nameserverTypeNames_]]"> - <button class="dropdown-item" role="option" value="[[item]]"> - [[nameserverTypeDesc_(item)]] - </button> + <option value="[[item]]">[[nameserverTypeDesc_(item)]]</option> </template> - </paper-listbox> - </paper-dropdown-menu-light> + </select> + <span class="md-select-underline"></span> + </div> </div> <div class="settings-box continuation single-column" diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_nameservers.js b/chromium/chrome/browser/resources/settings/internet_page/network_nameservers.js index cec1b79e122..db50135fcbb 100644 --- a/chromium/chrome/browser/resources/settings/internet_page/network_nameservers.js +++ b/chromium/chrome/browser/resources/settings/internet_page/network_nameservers.js @@ -108,13 +108,16 @@ Polymer({ * @private */ setNameservers_: function(nameserversType, nameservers) { - this.nameserversType_ = nameserversType; if (nameserversType == 'custom') { // Add empty entries for unset custom nameservers. for (let i = nameservers.length; i < this.MAX_NAMESERVERS; ++i) nameservers[i] = ''; } this.nameservers_ = nameservers; + // Set nameserversType_ after dom-repeat has been stamped. + this.async(function() { + this.nameserversType_ = nameserversType; + }.bind(this)); }, /** @@ -142,13 +145,14 @@ Polymer({ /** * Event triggered when the selected type changes. Updates nameservers and * sends the change value if necessary. - * @param {!{detail: !{selected: string}}} e + * @param {!Event} event * @private */ - onTypeChange_: function(e) { + onTypeChange_: function(event) { if (this.nameserversType_ == 'custom') this.savedNameservers_ = this.nameservers_; - var type = e.detail.selected; + let target = /** @type {!HTMLSelectElement} */ (event.target); + let type = target.value; this.nameserversType_ = type; if (type == 'custom') { // Restore the saved nameservers. diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_property_list.html b/chromium/chrome/browser/resources/settings/internet_page/network_property_list.html index d5063729559..eccd35d2245 100644 --- a/chromium/chrome/browser/resources/settings/internet_page/network_property_list.html +++ b/chromium/chrome/browser/resources/settings/internet_page/network_property_list.html @@ -33,7 +33,8 @@ <div class="layout horizontal" hidden$="[[isEditable_(item, '', propertyDict, editFieldTypes)]]"> <div class="secondary">[[getPropertyValue_(item, propertyDict)]]</div> - <cr-policy-network-indicator property="[[propertyDict]]"> + <cr-policy-network-indicator + property="[[getProperty_(item, propertyDict)]]"> </cr-policy-network-indicator> </div> <!-- Editable string property value --> diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_property_list.js b/chromium/chrome/browser/resources/settings/internet_page/network_property_list.js index 7179dc90d01..47db12a9cd3 100644 --- a/chromium/chrome/browser/resources/settings/internet_page/network_property_list.js +++ b/chromium/chrome/browser/resources/settings/internet_page/network_property_list.js @@ -148,6 +148,15 @@ Polymer({ /** * @param {string} key The property key. + * @return {*} The managed property dictionary associated with |key|. + * @private + */ + getProperty_: function(key) { + return this.get(key, this.propertyDict); + }, + + /** + * @param {string} key The property key. * @return {string} The text to display for the property value. * @private */ diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_proxy.html b/chromium/chrome/browser/resources/settings/internet_page/network_proxy.html index 8a3e58d7263..56b59a1f950 100644 --- a/chromium/chrome/browser/resources/settings/internet_page/network_proxy.html +++ b/chromium/chrome/browser/resources/settings/internet_page/network_proxy.html @@ -1,21 +1,28 @@ +<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html"> <link rel="import" href="chrome://resources/cr_elements/network/cr_onc_types.html"> <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_behavior.html"> <link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_network_indicator.html"> +<link rel="import" href="chrome://resources/cr_elements/policy/cr_policy_pref_indicator.html"> +<link rel="import" href="chrome://resources/html/i18n_behavior.html"> +<link rel="import" href="chrome://resources/html/md_select_css.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-dropdown-menu/paper-dropdown-menu-light.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input-container.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html"> +<link rel="import" href="/controls/settings_checkbox.html"> +<link rel="import" href="/i18n_setup.html"> +<link rel="import" href="/prefs/prefs_behavior.html"> +<link rel="import" href="/settings_vars_css.html"> <link rel="import" href="internet_shared_css.html"> -<link rel="import" href="network_property_list.html"> <link rel="import" href="network_proxy_exclusions.html"> <link rel="import" href="network_proxy_input.html"> <dom-module id="network-proxy"> <template> - <style include="internet-shared"> - cr-policy-network-indicator { + <style include="internet-shared md-select"> + cr-policy-network-indicator, + cr-policy-pref-indicator { -webkit-margin-end: 10px; } @@ -28,6 +35,10 @@ flex: none; } + .settings-box.indent { + @apply(--settings-list-frame-padding); + } + #exceptionsDiv { padding: 10px 0; } @@ -40,62 +51,84 @@ padding: 10px 0; } </style> + <!-- Policy indicator --> <div class="settings-box first single-column" - hidden$="[[!isNetworkPolicyControlled( - networkProperties.ProxySettings.Type)]]"> - <div class="layout horizontal center"> + hidden$="[[!isControlled(networkProperties.ProxySettings.Type)]]"> + <div class="layout horizontal center" + hidden$="[[!getShowNetworkPolicyIndicator_(networkProperties)]]"> <cr-policy-network-indicator property="[[networkProperties.ProxySettings.Type]]"> </cr-policy-network-indicator> - <div>$i18n{networkProxyEnforced}</div> + <div>$i18n{networkProxyEnforcedPolicy}</div> </div> + <div class="layout horizontal center" + hidden$="[[!getShowPrefPolicyIndicator_(networkProperties)]]"> + <cr-policy-pref-indicator pref="[[prefs.proxy]]"> + </cr-policy-pref-indicator> + <div>$i18n{networkProxyControlledExtension}</div> + </div> + </div> + + <!-- Allow shared proxies --> + <div class="settings-box continuation" + hidden$="[[!getShowAllowShared_( + networkProperties.ProxySettings.Type)]]"> + <settings-checkbox id="allowShared" + pref="{{prefs.settings.use_shared_proxies}}" + no-set-pref label="$i18n{networkProxyAllowShared}" + on-change="onAllowSharedProxiesChange_"> + </settings-checkbox> </div> <!-- Proxy type dropdown --> <div class="settings-box continuation"> <div class="start">$i18n{networkProxyConnectionType}</div> - <paper-dropdown-menu-light vertical-align="auto" no-label-float> - <paper-listbox class="dropdown-content" on-iron-activate="onTypeChange_" - selected="[[proxy.Type]]" attr-for-selected="value"> + <div class="md-select-wrapper"> + <select id="proxyType" class="md-select" on-change="onTypeChange_" + value="[[proxy.Type]]" + disabled="[[!isProxyEditable_(networkProperties, editable, + useSharedProxies_)]]"> <template is="dom-repeat" items="[[proxyTypes_]]"> - <button class="dropdown-item" role="option" value="[[item]]"> - [[proxyTypeDesc_(item)]] - </button> + <option value="[[item]]">[[getProxyTypeDesc_(item)]]</option> </template> - </paper-listbox> - </paper-dropdown-menu-light> + </select> + <span class="md-select-underline"></span> + </div> </div> <!-- Autoconfiguration (PAC) --> - <div class="settings-box continuation" + <div class="settings-box continuation indent" hidden$="[[!matches_(proxy.Type, ProxySettingsType_.PAC)]]"> <div>$i18n{networkProxyAutoConfig}</div> <paper-input no-label-float class="middle" value="{{proxy.PAC}}" - disabled="[[isNetworkPolicyEnforced( - networkProperties.ProxySettings.PAC)]]" + disabled="[[!isEditable_(networkProperties.ProxySettings.PAC, + useSharedProxies_)]]" on-blur="onProxyInputChange_"> </paper-input> </div> <!-- Web Proxy Auto Discovery (WPAD) --> - <div class="settings-box continuation" + <div class="settings-box continuation indent" hidden$="[[!matches_(proxy.Type, ProxySettingsType_.WPAD)]]"> <div>$i18n{networkSectionWpad}</div> <div class="middle">[[WPAD]]</div> </div> <!-- Manual --> - <div id="proxyDiv" class="settings-box continuation single-column" + <div id="proxyDiv" class="settings-box continuation single-column indent" hidden$="[[!matches_(proxy.Type, ProxySettingsType_.MANUAL)]]"> - <paper-checkbox checked="{{useSameProxy_}}"> + <paper-checkbox checked="{{useSameProxy_}}" + disabled="[[!isProxyEditable_(networkProperties, editable, + useSharedProxies_)]]"> $i18n{networkProxyUseSame} </paper-checkbox> <div hidden$="[[!useSameProxy_]]" class="layout vertical"> <network-proxy-input on-proxy-change="onProxyInputChange_" - editable="[[isPropertyEditable_(editable, networkProperties, - 'ProxySettings.Manual.HTTPProxy')]]" + editable="[[isEditable_( + networkProperties.ProxySettings.Manual.HTTPProxy.Host, + editable, useSharedProxies_)]]" value="{{proxy.Manual.HTTPProxy}}" label="$i18n{networkProxy}"> </network-proxy-input> @@ -103,35 +136,41 @@ <div hidden$="[[useSameProxy_]]" class="layout vertical"> <network-proxy-input on-proxy-change="onProxyInputChange_" - editable="[[isPropertyEditable_(editable, networkProperties, - 'ProxySettings.Manual.HTTPProxy)')]]" + editable="[[isEditable_( + networkProperties.ProxySettings.Manual.HTTPProxy.Host, + editable, useSharedProxies_)]]" value="{{proxy.Manual.HTTPProxy}}" label="$i18n{networkProxyHttp}"> </network-proxy-input> <network-proxy-input on-proxy-change="onProxyInputChange_" - editable="[[isPropertyEditable_(editable, networkProperties, - 'ProxySettings.Manual.SecureHTTPProxy)')]]" + editable="[[isEditable_( + networkProperties.ProxySettings.Manual.SecureHTTPProxy.Host, + editable, useSharedProxies_)]]" value="{{proxy.Manual.SecureHTTPProxy}}" label="$i18n{networkProxyShttp}"> </network-proxy-input> <network-proxy-input on-proxy-change="onProxyInputChange_" - editable="[[isPropertyEditable_(editable, networkProperties, - 'ProxySettings.Manual.FTPProxy)')]]" + editable="[[isEditable_( + networkProperties.ProxySettings.Manual.FTPProxy.Host, + editable, useSharedProxies_)]]" value="{{proxy.Manual.FTPProxy}}" label="$i18n{networkProxyFtp}"> </network-proxy-input> <network-proxy-input on-proxy-change="onProxyInputChange_" - editable="[[isPropertyEditable_(editable, networkProperties, - 'ProxySettings.Manual.SOCKS)')]]" + editable="[[isEditable_( + networkProperties.ProxySettings.Manual.SOCKS.Host, + editable, useSharedProxies_)]]" value="{{proxy.Manual.SOCKS}}" label="$i18n{networkProxySocks}"> </network-proxy-input> </div> - <div id="exceptionsDiv"> + <div id="exceptionsDiv" + hidden="[[!isProxyEditable_(networkProperties, editable, + useSharedProxies_)]]"> <div>$i18n{networkProxyExceptionList}</div> <network-proxy-exclusions on-proxy-change="onProxyExclusionsChange_" exclusions="{{proxy.ExcludeDomains}}"> @@ -146,6 +185,23 @@ </div> </div> </div> + + <!-- Confirm Allow shared proxies dialog --> + <dialog is="cr-dialog" id="confirmAllowSharedDialog" + on-cancel="onAllowSharedDialogCancel_"> + <div class="title">$i18n{networkProxyAllowSharedWarningTitle}</div> + <div class="body">$i18n{networkProxyAllowSharedWarningMessage}</div> + <div class="button-container"> + <paper-button class="cancel-button" + on-tap="onAllowSharedDialogCancel_"> + $i18n{cancel} + </paper-button> + <paper-button class="action-button" + on-tap="onAllowSharedDialogConfirm_"> + $i18n{confirm} + </paper-button> + </div> + </dialog> </template> <script src="network_proxy.js"></script> </dom-module> diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_proxy.js b/chromium/chrome/browser/resources/settings/internet_page/network_proxy.js index cc22995f52c..974de27c389 100644 --- a/chromium/chrome/browser/resources/settings/internet_page/network_proxy.js +++ b/chromium/chrome/browser/resources/settings/internet_page/network_proxy.js @@ -9,7 +9,7 @@ Polymer({ is: 'network-proxy', - behaviors: [CrPolicyNetworkBehavior], + behaviors: [CrPolicyNetworkBehavior, I18nBehavior, PrefsBehavior], properties: { /** @@ -56,6 +56,12 @@ Polymer({ }, /** + * Reflects prefs.settings.use_shared_proxies for data binding. + * @private + */ + useSharedProxies_: Boolean, + + /** * Array of proxy configuration types. * @private {!Array<string>} * @const @@ -88,6 +94,10 @@ Polymer({ }, }, + observers: [ + 'useSharedProxiesChanged_(prefs.settings.use_shared_proxies.value)', + ], + /** * Saved Manual properties so that switching to another type does not loose * any set properties while the UI is open. @@ -103,14 +113,35 @@ Polymer({ savedExcludeDomains_: undefined, /** - * Polymer networkProperties changed method. + * Set to true the first time we receive a manual proxy. Used to set the + * initial |useSameProxy_| value. + * @private {boolean} */ + receivedManualProxy_: false, + + /** @private */ networkPropertiesChanged_: function() { + this.updateProxy_(); + }, + + /** @private */ + updateProxy_: function() { if (!this.networkProperties) return; /** @type {!CrOnc.ProxySettings} */ var proxy = this.createDefaultProxySettings_(); + + // For shared networks with unmanaged proxy settings, ignore any saved + // proxy settings (use the default values). + if (this.isShared_()) { + let property = this.getProxySettingsTypeProperty_(); + if (!this.isControlled(property) && !this.useSharedProxies_) { + this.setProxyAsync_(proxy); + return; // Proxy settings will be ignored. + } + } + /** @type {!chrome.networkingPrivate.ManagedProxySettings|undefined} */ var proxySettings = this.networkProperties.ProxySettings; if (proxySettings) { @@ -127,6 +158,14 @@ Polymer({ CrOnc.getSimpleActiveProperties(proxySettings.Manual.FTPProxy)); proxy.Manual.SOCKS = /** @type {!CrOnc.ProxyLocation|undefined} */ ( CrOnc.getSimpleActiveProperties(proxySettings.Manual.SOCKS)); + if (!this.receivedManualProxy_) { + let json_http = JSON.stringify(proxy.Manual.HTTPProxy); + this.useSameProxy_ = + json_http == JSON.stringify(proxy.Manual.SecureHTTPProxy) && + json_http == JSON.stringify(proxy.Manual.FTPProxy) && + json_http == JSON.stringify(proxy.Manual.SOCKS); + this.receivedManualProxy_ = true; + } } if (proxySettings.ExcludeDomains) { proxy.ExcludeDomains = /** @type {!Array<string>|undefined} */ ( @@ -139,16 +178,42 @@ Polymer({ proxy.ExcludeDomains = proxy.ExcludeDomains || this.savedExcludeDomains_; proxy.Manual = proxy.Manual || this.savedManual_; - this.proxy = proxy; - // Set the Web Proxy Auto Discovery URL. var ipv4 = CrOnc.getIPConfigForType(this.networkProperties, CrOnc.IPType.IPV4); this.WPAD = (ipv4 && ipv4.WebProxyAutoDiscoveryUrl) || ''; + + this.setProxyAsync_(proxy); + }, + + /** + * @param {!CrOnc.ProxySettings} proxy + * @private + */ + setProxyAsync_: function(proxy) { + // Set this.proxy after dom-repeat has been stamped. + this.async(function() { + this.proxy = proxy; + }.bind(this)); + }, + + /** @private */ + useSameProxyChanged_: function() { + if (!this.receivedManualProxy_) + return; + this.sendProxyChange_(); + }, + + /** @private */ + useSharedProxiesChanged_: function() { + let pref = this.getPref('settings.use_shared_proxies'); + this.useSharedProxies_ = !!pref && !!pref.value; + this.updateProxy_(); }, /** * @return {CrOnc.ProxySettings} An empty/default proxy settings object. + * @private */ createDefaultProxySettings_: function() { return { @@ -165,14 +230,8 @@ Polymer({ }, /** - * Polymer useSameProxy changed method. - */ - useSameProxyChanged_: function() { - this.sendProxyChange_(); - }, - - /** * Called when the proxy changes in the UI. + * @private */ sendProxyChange_: function() { if (this.proxy.Type == CrOnc.ProxySettingsType.MANUAL) { @@ -205,12 +264,13 @@ Polymer({ /** * Event triggered when the selected proxy type changes. - * @param {!{detail: !{selected: string}}} e + * @param {!Event} event * @private */ - onTypeChange_: function(e) { + onTypeChange_: function(event) { + let target = /** @type {!HTMLSelectElement} */ (event.target); var type = /** @type {chrome.networkingPrivate.ProxySettingsType} */ ( - e.detail.selected); + target.value); this.set('proxy.Type', type); this.sendProxyChange_(); }, @@ -253,30 +313,83 @@ Polymer({ * @return {string} The description for |proxyType|. * @private */ - proxyTypeDesc_: function(proxyType) { - // TODO(stevenjb): Translate. + getProxyTypeDesc_: function(proxyType) { if (proxyType == CrOnc.ProxySettingsType.MANUAL) - return 'Manual proxy configuration'; + return this.i18n('networkProxyTypeManual'); if (proxyType == CrOnc.ProxySettingsType.PAC) - return 'Automatic proxy configuration'; + return this.i18n('networkProxyTypePac'); if (proxyType == CrOnc.ProxySettingsType.WPAD) - return 'Web proxy autodiscovery'; - return 'Direct Internet connection'; + return this.i18n('networkProxyTypeWpad'); + return this.i18n('networkProxyTypeDirect'); + }, + + /** + * @return {!CrOnc.ManagedProperty|undefined} + * @private + */ + getProxySettingsTypeProperty_: function() { + return /** @type {!CrOnc.ManagedProperty|undefined} */ ( + this.get('ProxySettings.Type', this.networkProperties)); }, /** - * @param {boolean} editable - * @param {!CrOnc.NetworkProperties} networkProperties - * @param {string} key - * @return {boolean} Whether the property is editable. + * @return {boolean} * @private */ - isPropertyEditable_: function(editable, networkProperties, key) { - if (!editable) - return false; - var property = /** @type {!CrOnc.ManagedProperty|undefined} */ ( - this.get(key, networkProperties)); - return !this.isNetworkPolicyEnforced(property); + getShowNetworkPolicyIndicator_: function() { + let property = this.getProxySettingsTypeProperty_(); + return !!property && !this.isExtensionControlled(property) && + this.isNetworkPolicyEnforced(property); + }, + + /** + * @return {boolean} + * @private + */ + getShowPrefPolicyIndicator_: function() { + let property = this.getProxySettingsTypeProperty_(); + return !!property && this.isExtensionControlled(property); + }, + + /** + * @param {!CrOnc.ManagedProperty} property + * @return {boolean} + * @private + */ + getShowAllowShared_: function(property) { + return !this.isControlled(property) && this.isShared_(); + }, + + /** + * @param {!CrOnc.ManagedProperty|undefined} property + * @return {boolean} Whether the property setting is enforced. + * @private + */ + isEditable_: function(property) { + return this.editable && !this.isNetworkPolicyEnforced(property) && + !this.isExtensionControlled(property) && + (!this.isShared_() || this.useSharedProxies_); + }, + + /** + * @return {boolean} + * @private + */ + isShared_: function() { + return this.networkProperties.Source == 'Device' || + this.networkProperties.Source == 'DevicePolicy'; + }, + + /** + * Used to check the editable state for proxy related UI that may or may + * not be directly controlled by a policy. We use the enforced state of the + * 'ProxySettings.Type' property for these controls. + * @return {boolean} Whether the proxy control is editable. + * @private + */ + isProxyEditable_: function() { + let property = this.getProxySettingsTypeProperty_(); + return !!property && this.isEditable_(property); }, /** @@ -287,5 +400,36 @@ Polymer({ */ matches_: function(property, value) { return property == value; - } + }, + + /** + * Handles the change event for the shared proxy checkbox. Shows a + * confirmation dialog. + * @param {Event} event + * @private + */ + onAllowSharedProxiesChange_: function(event) { + this.$.confirmAllowSharedDialog.showModal(); + }, + + /** + * Handles the shared proxy confirmation dialog 'Confirm' button. + * @private + */ + onAllowSharedDialogConfirm_: function() { + /** @type {!SettingsCheckboxElement} */ (this.$.allowShared) + .sendPrefChange(); + this.$.confirmAllowSharedDialog.close(); + }, + + /** + * Handles the shared proxy confirmation dialog 'Cancel' button or a cancel + * event. + * @private + */ + onAllowSharedDialogCancel_: function() { + /** @type {!SettingsCheckboxElement} */ (this.$.allowShared) + .resetToPrefValue(); + this.$.confirmAllowSharedDialog.close(); + }, }); diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_proxy_exclusions.html b/chromium/chrome/browser/resources/settings/internet_page/network_proxy_exclusions.html index ddf6ae5e8c9..0421eb4f968 100644 --- a/chromium/chrome/browser/resources/settings/internet_page/network_proxy_exclusions.html +++ b/chromium/chrome/browser/resources/settings/internet_page/network_proxy_exclusions.html @@ -24,7 +24,7 @@ <div class="layout horizontal center" tabindex="0" > <div class="flex">[[item]]</div> <iron-icon class="favicon-image" icon="cr:clear" - on-tap="onRemoveTap_" tabindex="0"> + on-tap="onRemoveTap_" tabindex="0" hidden="[[!editable]]"> </iron-icon> </div> </template> diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_proxy_exclusions.js b/chromium/chrome/browser/resources/settings/internet_page/network_proxy_exclusions.js index 2d408b7cf92..83dbb2ce9d0 100644 --- a/chromium/chrome/browser/resources/settings/internet_page/network_proxy_exclusions.js +++ b/chromium/chrome/browser/resources/settings/internet_page/network_proxy_exclusions.js @@ -13,6 +13,12 @@ Polymer({ is: 'network-proxy-exclusions', properties: { + /** Whether or not the proxy values can be edited. */ + editable: { + type: Boolean, + value: false, + }, + /** * The list of exclusions. * @type {!Array<string>} diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_proxy_input.html b/chromium/chrome/browser/resources/settings/internet_page/network_proxy_input.html index 58757090077..a9d4ab63b3e 100644 --- a/chromium/chrome/browser/resources/settings/internet_page/network_proxy_input.html +++ b/chromium/chrome/browser/resources/settings/internet_page/network_proxy_input.html @@ -1,4 +1,5 @@ <link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-input/iron-input.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input-container.html"> <link rel="import" href="internet_shared_css.html"> @@ -18,12 +19,12 @@ <div class="layout horizontal center"> <div class="flex">[[label]]</div> <paper-input-container no-label-float> - <input is="iron-input" value="{{value.Host}}" disabled="[[!editable]]" + <input is="iron-input" bind-value="{{value.Host}}" disabled="[[!editable]]" on-blur="onValueChange_"> </paper-input-container> <div>$i18n{networkProxyPort}</div> <paper-input-container no-label-float id="port"> - <input is="iron-input" value="{{value.Host}}" disabled="[[!editable]]" + <input is="iron-input" bind-value="{{value.Port}}" disabled="[[!editable]]" on-blur="onValueChange_"> </paper-input-container> </div> diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_siminfo.html b/chromium/chrome/browser/resources/settings/internet_page/network_siminfo.html index 192fb01f935..f1db2d21459 100644 --- a/chromium/chrome/browser/resources/settings/internet_page/network_siminfo.html +++ b/chromium/chrome/browser/resources/settings/internet_page/network_siminfo.html @@ -7,7 +7,6 @@ <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html"> <link rel="import" href="/icons.html"> <link rel="import" href="internet_shared_css.html"> -<link rel="import" href="network_property_list.html"> <dom-module id="network-siminfo"> <template> diff --git a/chromium/chrome/browser/resources/settings/internet_page/network_summary_item.html b/chromium/chrome/browser/resources/settings/internet_page/network_summary_item.html index 7319ebb1160..11201905130 100644 --- a/chromium/chrome/browser/resources/settings/internet_page/network_summary_item.html +++ b/chromium/chrome/browser/resources/settings/internet_page/network_summary_item.html @@ -5,7 +5,7 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-keys-behavior/iron-a11y-keys-behavior.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html"> <link rel="import" href="/settings_shared_css.html"> @@ -23,7 +23,7 @@ network-siminfo { padding: 0 var(--settings-box-row-padding); } - + .button-row { align-items: center; display: flex; diff --git a/chromium/chrome/browser/resources/settings/languages_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/languages_page/compiled_resources2.gyp index 0ec9d7f35a1..fdf6d9f7593 100644 --- a/chromium/chrome/browser/resources/settings/languages_page/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/settings/languages_page/compiled_resources2.gyp @@ -25,10 +25,10 @@ 'dependencies': [ '../compiled_resources2.gyp:lifetime_browser_proxy', '../compiled_resources2.gyp:route', + '<(DEPTH)/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp:cr_action_menu', '../settings_page/compiled_resources2.gyp:settings_animated_pages', '<(DEPTH)/third_party/polymer/v1_0/components-chromium/paper-checkbox/compiled_resources2.gyp:paper-checkbox-extracted', '<(DEPTH)/ui/webui/resources/cr_elements/cr_lazy_render/compiled_resources2.gyp:cr_lazy_render', - '<(DEPTH)/ui/webui/resources/cr_elements/cr_shared_menu/compiled_resources2.gyp:cr_shared_menu', '<(DEPTH)/ui/webui/resources/js/chromeos/compiled_resources2.gyp:ui_account_tweaks', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', diff --git a/chromium/chrome/browser/resources/settings/languages_page/edit_dictionary_page.html b/chromium/chrome/browser/resources/settings/languages_page/edit_dictionary_page.html index 4612d916401..9d02481fad8 100644 --- a/chromium/chrome/browser/resources/settings/languages_page/edit_dictionary_page.html +++ b/chromium/chrome/browser/resources/settings/languages_page/edit_dictionary_page.html @@ -1,7 +1,6 @@ <link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-a11y-keys/iron-a11y-keys.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> @@ -16,10 +15,6 @@ flex-direction: column; } - #addWordRow { - display: flex; - } - #newWord { flex: .5; } @@ -32,17 +27,19 @@ iron-list .word { flex: 1; } + + paper-button { + -webkit-margin-start: 16px; + } </style> - <div class="settings-box block"> - <div id="addWordRow"> - <iron-a11y-keys id="keys" keys="enter esc" - on-keys-pressed="onKeysPress_"></iron-a11y-keys> - <paper-input id="newWord" no-label-float - label="$i18n{addDictionaryWordLabel}"></paper-input> - <paper-button on-tap="onAddWordTap_"> - $i18n{addDictionaryWordButton} - </paper-button> - </div> + <div class="settings-box"> + <iron-a11y-keys id="keys" keys="enter esc" + on-keys-pressed="onKeysPress_"></iron-a11y-keys> + <paper-input id="newWord" no-label-float + label="$i18n{addDictionaryWordLabel}"></paper-input> + <paper-button on-tap="onAddWordTap_"> + $i18n{addDictionaryWordButton} + </paper-button> </div> <div class="settings-box block"> <h2>$i18n{customDictionaryWords}</h2> diff --git a/chromium/chrome/browser/resources/settings/languages_page/languages.js b/chromium/chrome/browser/resources/settings/languages_page/languages.js index ee4c8166ba9..790a45fba91 100644 --- a/chromium/chrome/browser/resources/settings/languages_page/languages.js +++ b/chromium/chrome/browser/resources/settings/languages_page/languages.js @@ -57,14 +57,6 @@ Polymer({ }, /** - * Object containing all preferences. - */ - prefs: { - type: Object, - notify: true, - }, - - /** * This element, as a LanguageHelper instance for API usage. * @type {!LanguageHelper} */ diff --git a/chromium/chrome/browser/resources/settings/languages_page/languages_page.html b/chromium/chrome/browser/resources/settings/languages_page/languages_page.html index 27b4bc4cb11..c664a0dca74 100644 --- a/chromium/chrome/browser/resources/settings/languages_page/languages_page.html +++ b/chromium/chrome/browser/resources/settings/languages_page/languages_page.html @@ -2,15 +2,13 @@ <link rel="import" href="chrome://resources/html/cr.html"> <link rel="import" href="chrome://resources/html/polymer.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/neon-animation/neon-animatable.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.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_expand_button/cr_expand_button.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_shared_menu/cr_shared_menu.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> -<link rel="import" href="/icons.html"> <link rel="import" href="/languages_page/add_languages_dialog.html"> <link rel="import" href="/languages_page/languages.html"> <link rel="import" href="/lifetime_browser_proxy.html"> @@ -41,19 +39,15 @@ margin-top: 4px; } - cr-shared-menu { - --cr-shared-menu-width: 320px; - } - - cr-shared-menu.complex .dropdown-item { + dialog[is='cr-action-menu'].complex .dropdown-item { min-height: 36px; } - cr-shared-menu:not(.complex) hr { + dialog[is='cr-action-menu']:not(.complex) hr { display: none; } - cr-shared-menu.complex hr { + dialog[is='cr-action-menu'].complex hr { /* Override user-agent border and margin. */ border: none; /* TODO(michaelpg): Update to whatever variable is used for the darker, @@ -65,6 +59,11 @@ paper-checkbox.dropdown-item { --checkbox-margin-start: 0; } + + #uiLanguageItem:focus, + #offerTranslations:focus { + background-color: transparent; + } </style> <settings-languages languages="{{languages}}" prefs="{{prefs}}" language-helper="{{languageHelper}}"> @@ -117,7 +116,7 @@ </template> </if> <paper-icon-button id="more-[[item.language.code]]" - icon="cr:more-vert" on-tap="toggleMenu_"> + icon="cr:more-vert" on-tap="onDotsTap_"> </paper-icon-button> </div> </template> @@ -199,7 +198,7 @@ </iron-collapse> </if> <template is="cr-lazy-render" id="menu"> - <cr-shared-menu + <dialog is="cr-action-menu" class$="[[getMenuClass_(prefs.translate.enabled.value)]]"> <if expr="chromeos or is_win"> <paper-checkbox id="uiLanguageItem" class="dropdown-item" @@ -212,7 +211,7 @@ $i18n{displayInThisLanguage} </paper-checkbox> </if> - <paper-checkbox class="dropdown-item" + <paper-checkbox id="offerTranslations" class="dropdown-item" checked="[[detailLanguage_.translateEnabled]]" on-change="onTranslateCheckboxChange_" hidden="[[!prefs.translate.enabled.value]]" @@ -244,7 +243,7 @@ hidden="[[!detailLanguage_.removable]]"> $i18n{removeLanguage} </button> - </cr-shared-menu> + </dialog> </template> </neon-animatable> <if expr="chromeos"> diff --git a/chromium/chrome/browser/resources/settings/languages_page/languages_page.js b/chromium/chrome/browser/resources/settings/languages_page/languages_page.js index 19a0538498b..1ba3d569d5f 100644 --- a/chromium/chrome/browser/resources/settings/languages_page/languages_page.js +++ b/chromium/chrome/browser/resources/settings/languages_page/languages_page.js @@ -185,7 +185,7 @@ Polymer({ // Reset the chosen UI language to the actual UI language. this.languageHelper.resetUILanguage(); } - /** @type {!CrSharedMenuElement} */(this.$.menu.get()).closeMenu(); + /** @type {!CrActionMenuElement} */(this.$.menu.get()).close(); }, /** @@ -215,7 +215,7 @@ Polymer({ this.languageHelper.disableTranslateLanguage( this.detailLanguage_.language.code); } - /** @type {!CrSharedMenuElement} */(this.$.menu.get()).closeMenu(); + /** @type {!CrActionMenuElement} */(this.$.menu.get()).close(); }, /** @@ -235,7 +235,7 @@ Polymer({ * @private */ onMoveToTopTap_: function() { - /** @type {!CrSharedMenuElement} */(this.$.menu.get()).closeMenu(); + /** @type {!CrActionMenuElement} */(this.$.menu.get()).close(); this.languageHelper.moveLanguageToFront(this.detailLanguage_.language.code); }, @@ -244,7 +244,7 @@ Polymer({ * @private */ onMoveUpTap_: function() { - /** @type {!CrSharedMenuElement} */(this.$.menu.get()).closeMenu(); + /** @type {!CrActionMenuElement} */(this.$.menu.get()).close(); this.languageHelper.moveLanguage(this.detailLanguage_.language.code, -1); }, @@ -253,7 +253,7 @@ Polymer({ * @private */ onMoveDownTap_: function() { - /** @type {!CrSharedMenuElement} */(this.$.menu.get()).closeMenu(); + /** @type {!CrActionMenuElement} */(this.$.menu.get()).close(); this.languageHelper.moveLanguage(this.detailLanguage_.language.code, 1); }, @@ -262,7 +262,7 @@ Polymer({ * @private */ onRemoveLanguageTap_: function() { - /** @type {!CrSharedMenuElement} */(this.$.menu.get()).closeMenu(); + /** @type {!CrActionMenuElement} */(this.$.menu.get()).close(); this.languageHelper.disableLanguage(this.detailLanguage_.language.code); }, @@ -449,29 +449,27 @@ Polymer({ }, /** - * Opens or closes the shared menu at the location of the tapped item. * @param {!Event} e * @private */ - toggleMenu_: function(e) { - e.stopPropagation(); // Prevent the tap event from closing the menu. - + onDotsTap_: function(e) { this.detailLanguage_ = /** @type {!{model: !{item: !LanguageState}}} */(e).model.item; // Ensure the template has been stamped. - var menu = /** @type {?CrSharedMenuElement} */(this.$.menu.getIfExists()); + var menu = /** @type {?CrActionMenuElement} */( + this.$.menu.getIfExists()); if (!menu) { - menu = /** @type {!CrSharedMenuElement} */(this.$.menu.get()); + menu = /** @type {!CrActionMenuElement} */(this.$.menu.get()); this.initializeMenu_(menu); } - menu.toggleMenu(/** @type {!Element} */(e.target)); + menu.showAt(/** @type {!Element} */ (e.target)); }, /** * Applies Chrome OS session tweaks to the menu. - * @param {!CrSharedMenuElement} menu + * @param {!CrActionMenuElement} menu * @private */ initializeMenu_: function(menu) { diff --git a/chromium/chrome/browser/resources/settings/md_select_css.html b/chromium/chrome/browser/resources/settings/md_select_css.html deleted file mode 100644 index 2a28fc24629..00000000000 --- a/chromium/chrome/browser/resources/settings/md_select_css.html +++ /dev/null @@ -1,49 +0,0 @@ -<link rel="import" href="/settings_vars_css.html"> - -<dom-module id="md-select"> - <template> - <style> - .md-select { - -webkit-appearance: none; - background: url(images/arrow_down.svg) 97% 70% no-repeat; - background-size: 0.9em; - border-bottom: 1px solid var(--paper-grey-300); - border-left: none; - /* Override Mac's default border-radius */ - border-radius: 0; - border-right: none; - border-top: none; - color: var(--primary-text-color); - cursor: pointer; - font-family: inherit; - font-size: inherit; - outline: none; - padding: 3px 0; - width: 200px; - } - - :host-context([dir=rtl]) .md-select { - background-position-x: 3%; - } - - .md-select-underline { - border-top: 2px solid var(--google-blue-500); - display: block; - position: relative; - top: -1px; - transform: scale3d(0, 1, 1); - transition: transform 200ms ease-in; - width: 100%; - } - - .md-select:focus + .md-select-underline { - transform: scale3d(1, 1, 1); - transition: transform 200ms ease-out; - } - - .md-select-wrapper { - display: inline-block; - } - </style> - </template> -</dom-module> diff --git a/chromium/chrome/browser/resources/settings/on_startup_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/on_startup_page/compiled_resources2.gyp index 2607a4be58b..b937368b823 100644 --- a/chromium/chrome/browser/resources/settings/on_startup_page/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/settings/on_startup_page/compiled_resources2.gyp @@ -4,7 +4,18 @@ { 'targets': [ { + 'target_name': 'on_startup_browser_proxy', + 'dependencies': [ + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', + ], + 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + { 'target_name': 'on_startup_page', + 'dependencies': [ + 'on_startup_browser_proxy', + ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, { @@ -31,6 +42,8 @@ { 'target_name': 'startup_url_entry', 'dependencies': [ + '<(DEPTH)/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp:cr_action_menu', + '<(DEPTH)/ui/webui/resources/cr_elements/cr_lazy_render/compiled_resources2.gyp:cr_lazy_render', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:icon', 'startup_urls_page_browser_proxy', diff --git a/chromium/chrome/browser/resources/settings/on_startup_page/on_startup_browser_proxy.html b/chromium/chrome/browser/resources/settings/on_startup_page/on_startup_browser_proxy.html new file mode 100644 index 00000000000..f30b3b1fb5d --- /dev/null +++ b/chromium/chrome/browser/resources/settings/on_startup_page/on_startup_browser_proxy.html @@ -0,0 +1,3 @@ +<link rel="import" href="chrome://resources/html/assert.html"> +<link rel="import" href="chrome://resources/html/cr.html"> +<script src="/on_startup_page/on_startup_browser_proxy.js"></script> diff --git a/chromium/chrome/browser/resources/settings/on_startup_page/on_startup_browser_proxy.js b/chromium/chrome/browser/resources/settings/on_startup_page/on_startup_browser_proxy.js new file mode 100644 index 00000000000..a99f6185b54 --- /dev/null +++ b/chromium/chrome/browser/resources/settings/on_startup_page/on_startup_browser_proxy.js @@ -0,0 +1,35 @@ +// Copyright 2016 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. + +/** @typedef {{id: string, name: string, canBeDisabled: boolean}} */ +var NtpExtension; + +cr.define('settings', function() { + /** @interface */ + function OnStartupBrowserProxy() {} + + OnStartupBrowserProxy.prototype = { + /** @return {!Promise<?NtpExtension>} */ + getNtpExtension: assertNotReached, + }; + + /** + * @constructor + * @implements {settings.OnStartupBrowserProxy} + */ + function OnStartupBrowserProxyImpl() {} + cr.addSingletonGetter(OnStartupBrowserProxyImpl); + + OnStartupBrowserProxyImpl.prototype = { + /** @override */ + getNtpExtension: function() { + return cr.sendWithPromise('getNtpExtension'); + }, + }; + + return { + OnStartupBrowserProxy: OnStartupBrowserProxy, + OnStartupBrowserProxyImpl: OnStartupBrowserProxyImpl, + }; +}); diff --git a/chromium/chrome/browser/resources/settings/on_startup_page/on_startup_page.html b/chromium/chrome/browser/resources/settings/on_startup_page/on_startup_page.html index 841f56b9f76..1145e0706ab 100644 --- a/chromium/chrome/browser/resources/settings/on_startup_page/on_startup_page.html +++ b/chromium/chrome/browser/resources/settings/on_startup_page/on_startup_page.html @@ -1,7 +1,9 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html"> <link rel="import" href="/controls/controlled_radio_button.html"> +<link rel="import" href="/controls/extension_controlled_indicator.html"> <link rel="import" href="/controls/settings_radio_group.html"> +<link rel="import" href="/on_startup_page/on_startup_browser_proxy.html"> <link rel="import" href="/on_startup_page/startup_urls_page.html"> <link rel="import" href="/settings_shared_css.html"> @@ -15,6 +17,15 @@ pref="[[prefs.session.restore_on_startup]]"> $i18n{onStartupOpenNewTab} </controlled-radio-button> + <template is="dom-if" if="[[showIndicator_( + ntpExtension_, prefs.session.restore_on_startup.value)]]"> + <extension-controlled-indicator + extension-id="[[ntpExtension_.id]]" + extension-name="[[ntpExtension_.name]]" + extension-can-be-disabled="[[ntpExtension_.canBeDisabled]]" + on-extension-disable="getNtpExtension_"> + </extension-controlled-indicator> + </template> <controlled-radio-button name="[[prefValues_.CONTINUE]]" pref="[[prefs.session.restore_on_startup]]"> $i18n{onStartupContinue} diff --git a/chromium/chrome/browser/resources/settings/on_startup_page/on_startup_page.js b/chromium/chrome/browser/resources/settings/on_startup_page/on_startup_page.js index bdce9f05365..313c41530de 100644 --- a/chromium/chrome/browser/resources/settings/on_startup_page/on_startup_page.js +++ b/chromium/chrome/browser/resources/settings/on_startup_page/on_startup_page.js @@ -18,14 +18,14 @@ Polymer({ is: 'settings-on-startup-page', properties: { - /** - * Preferences state. - */ prefs: { type: Object, notify: true, }, + /** @private {?NtpExtension} */ + ntpExtension_: Object, + /** * Enum values for the 'session.restore_on_startup' preference. * @private {!Object<string, number>} @@ -34,13 +34,36 @@ Polymer({ readOnly: true, type: Object, value: { - OPEN_NEW_TAB: 5, CONTINUE: 1, + OPEN_NEW_TAB: 5, OPEN_SPECIFIC: 4, }, }, }, + /** @override */ + attached: function() { + this.getNtpExtension_(); + }, + + /** @private */ + getNtpExtension_: function() { + settings.OnStartupBrowserProxyImpl.getInstance().getNtpExtension().then( + function(ntpExtension) { + this.ntpExtension_ = ntpExtension; + }.bind(this)); + }, + + /** + * @param {?NtpExtension} ntpExtension + * @param {number} restoreOnStartup Value of prefs.session.restore_on_startup. + * @return {boolean} + * @private + */ + showIndicator_: function(ntpExtension, restoreOnStartup) { + return !!ntpExtension && restoreOnStartup == this.prefValues_.OPEN_NEW_TAB; + }, + /** * Determine whether to show the user defined startup pages. * @param {number} restoreOnStartup Enum value from prefValues_. diff --git a/chromium/chrome/browser/resources/settings/on_startup_page/startup_url_dialog.html b/chromium/chrome/browser/resources/settings/on_startup_page/startup_url_dialog.html index 5de20105c7d..a235d6af3df 100644 --- a/chromium/chrome/browser/resources/settings/on_startup_page/startup_url_dialog.html +++ b/chromium/chrome/browser/resources/settings/on_startup_page/startup_url_dialog.html @@ -12,8 +12,8 @@ <div class="title">[[dialogTitle_]]</div> <div class="body"> <paper-input always-float-label id="url" + label="$i18n{onStartupSiteUrl}" value="{{url_}}" on-input="validate_"> - $i18n{onStartupSiteUrl} </paper-input> </div> <div class="button-container"> diff --git a/chromium/chrome/browser/resources/settings/on_startup_page/startup_url_entry.html b/chromium/chrome/browser/resources/settings/on_startup_page/startup_url_entry.html index c99283d3501..724cd4ce894 100644 --- a/chromium/chrome/browser/resources/settings/on_startup_page/startup_url_entry.html +++ b/chromium/chrome/browser/resources/settings/on_startup_page/startup_url_entry.html @@ -1,7 +1,8 @@ +<link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_lazy_render/cr_lazy_render.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/html/icon.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-dropdown/iron-dropdown.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> <link rel="import" href="/on_startup_page/startup_urls_page_browser_proxy.html"> <link rel="import" href="/settings_shared_css.html"> @@ -21,22 +22,19 @@ <div class="text-elide">[[model.title]]</div> <div class="text-elide secondary">[[model.url]]</div> </div> - <paper-icon-button id="dots" icon="cr:more-vert" toggles - active="{{menuOpened}}" tabindex$="[[tabindex]]"> + <paper-icon-button id="dots" icon="cr:more-vert" tabindex$="[[tabindex]]" + on-tap="onDotsTap_"> </paper-icon-button> - <template is="dom-if" if="[[menuOpened]]"> - <iron-dropdown vertical-align="auto" horizontal-align="right" - opened="{{menuOpened}}"> - <div class="dropdown-content"> - <button class="dropdown-item" role="option" on-tap="onEditTap_"> - $i18n{onStartupEdit} - </button> - <button class="dropdown-item" role="option" id="remove" - on-tap="onRemoveTap_"> - $i18n{onStartupRemove} - </button> - </div> - </iron-dropdown> + <template is="cr-lazy-render" id="menu"> + <dialog is="cr-action-menu"> + <button class="dropdown-item" role="option" on-tap="onEditTap_"> + $i18n{onStartupEdit} + </button> + <button class="dropdown-item" role="option" id="remove" + on-tap="onRemoveTap_"> + $i18n{onStartupRemove} + </button> + </dialog> </template> </div> </template> diff --git a/chromium/chrome/browser/resources/settings/on_startup_page/startup_url_entry.js b/chromium/chrome/browser/resources/settings/on_startup_page/startup_url_entry.js index e0882229482..e3e93dda2bb 100644 --- a/chromium/chrome/browser/resources/settings/on_startup_page/startup_url_entry.js +++ b/chromium/chrome/browser/resources/settings/on_startup_page/startup_url_entry.js @@ -36,14 +36,21 @@ Polymer({ /** @private */ onRemoveTap_: function() { - this.$$('iron-dropdown').close(); + this.$$('dialog[is=cr-action-menu]').close(); settings.StartupUrlsPageBrowserProxyImpl.getInstance().removeStartupPage( this.model.modelIndex); }, /** @private */ onEditTap_: function() { - this.$$('iron-dropdown').close(); + this.$$('dialog[is=cr-action-menu]').close(); this.fire(settings.EDIT_STARTUP_URL_EVENT, this.model); }, + + /** @private */ + onDotsTap_: function() { + var actionMenu = /** @type {!CrActionMenuElement} */( + this.$.menu.get()); + actionMenu.showAt(assert(this.$.dots)); + }, }); diff --git a/chromium/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html b/chromium/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html index a00e970f7c0..4abc08282d2 100644 --- a/chromium/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html +++ b/chromium/chrome/browser/resources/settings/on_startup_page/startup_urls_page.html @@ -1,5 +1,6 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html"> <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="chrome://resources/cr_elements/cr_scrollable_behavior.html"> <link rel="import" href="/settings_shared_css.html"> @@ -35,7 +36,8 @@ on-tap="onUseCurrentPagesTap_">$i18n{onStartupUseCurrent}</div> </div> <template is="dom-if" if="[[showStartupUrlDialog_]]" restamp> - <settings-startup-url-dialog model="[[startupUrlDialogModel_]]"> + <settings-startup-url-dialog model="[[startupUrlDialogModel_]]" + on-close="destroyUrlDialog_"> </settings-startup-url-dialog> </template> </template> diff --git a/chromium/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js b/chromium/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js index a7dbf30bbb2..1d24c367bed 100644 --- a/chromium/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js +++ b/chromium/chrome/browser/resources/settings/on_startup_page/startup_urls_page.js @@ -33,6 +33,10 @@ Polymer({ attached: function() { this.browserProxy_ = settings.StartupUrlsPageBrowserProxyImpl.getInstance(); this.addWebUIListener('update-startup-pages', function(startupPages) { + // If an "edit" URL dialog was open, close it, because the underlying page + // might have just been removed (and model indices have changed anyway). + if (this.startupUrlDialogModel_) + this.destroyUrlDialog_(); this.startupPages_ = startupPages; this.updateScrollableContents(); }.bind(this)); @@ -40,31 +44,20 @@ Polymer({ this.addEventListener(settings.EDIT_STARTUP_URL_EVENT, function(event) { this.startupUrlDialogModel_ = event.detail; - this.openDialog_(); + this.showStartupUrlDialog_ = true; event.stopPropagation(); }.bind(this)); }, /** @private */ onAddPageTap_: function() { - this.openDialog_(); + this.showStartupUrlDialog_ = true; }, - /** - * Opens the dialog and registers a listener for removing the dialog from the - * DOM once is closed. The listener is destroyed when the dialog is removed - * (because of 'restamp'). - * @private - */ - openDialog_: function() { - this.showStartupUrlDialog_ = true; - this.async(function() { - var dialog = this.$$('settings-startup-url-dialog'); - dialog.addEventListener('close', function() { - this.showStartupUrlDialog_ = false; - this.startupUrlDialogModel_ = null; - }.bind(this)); - }.bind(this)); + /** @private */ + destroyUrlDialog_: function() { + this.showStartupUrlDialog_ = false; + this.startupUrlDialogModel_ = null; }, /** @private */ diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/address_edit_dialog.html b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/address_edit_dialog.html index faf5828d186..442b1c7f739 100644 --- a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/address_edit_dialog.html +++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/address_edit_dialog.html @@ -1,11 +1,12 @@ <link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.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/md_select_css.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-textarea.html"> -<link rel="import" href="/md_select_css.html"> <link rel="import" href="/settings_shared_css.html"> +<link rel="import" href="/settings_vars_css.html"> <dom-module id="settings-address-edit-dialog"> <template> diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html index d4d3f6a4003..847c03fbe2f 100644 --- a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html +++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.html @@ -1,7 +1,8 @@ -<link rel="import" href="chrome://resources/cr_elements/cr_shared_menu/cr_shared_menu.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html"> <link rel="import" href="chrome://resources/html/action_link.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> +<link rel="import" href="/i18n_setup.html"> <link rel="import" href="/passwords_and_forms_page/address_edit_dialog.html"> <link rel="import" href="/passwords_and_forms_page/credit_card_edit_dialog.html"> <link rel="import" href="/passwords_and_forms_page/passwords_shared_css.html"> @@ -11,10 +12,6 @@ <link rel="import" type="css" href="chrome://resources/css/action_link.css"> <template> <style include="settings-shared passwords-shared"> - .menu-item { - @apply(--settings-actionable); - } - .type-column { align-items: center; flex: 2; @@ -63,15 +60,16 @@ <a is="action-link" on-tap="onAddAddressTap_">$i18n{addAddress}</a> </div> </div> - <cr-shared-menu id="addressSharedMenu"> - <button id="menuEditAddress" class="list-item menu-item" + <dialog is="cr-action-menu" id="addressSharedMenu"> + <button id="menuEditAddress" class="dropdown-item" on-tap="onMenuEditAddressTap_">$i18n{editAddress}</button> - <button id="menuRemoveAddress" class="list-item menu-item" + <button id="menuRemoveAddress" class="dropdown-item" + hidden$="[[!activeAddress.metadata.isLocal]]" on-tap="onMenuRemoveAddressTap_">$i18n{removeAddress}</button> - </cr-shared-menu> - <template is="dom-if" if="[[activeAddress]]" restamp> + </dialog> + <template is="dom-if" if="[[showAddressDialog_]]" restamp> <settings-address-edit-dialog address="[[activeAddress]]" - on-close="unstampAddressEditDialog_"> + on-close="onAddressDialogClosed_"> </settings-address-edit-dialog> </template> <div class="settings-box first"> @@ -118,17 +116,21 @@ </a> </div> </div> - <cr-shared-menu id="creditCardSharedMenu"> - <button id="menuEditCreditCard" class="list-item menu-item" + <dialog is="cr-action-menu" id="creditCardSharedMenu"> + <button id="menuEditCreditCard" class="dropdown-item" on-tap="onMenuEditCreditCardTap_">$i18n{editCreditCard}</button> - <button id="menuRemoveCreditCard" class="list-item menu-item" + <button id="menuRemoveCreditCard" class="dropdown-item" + hidden$="[[!activeCreditCard.metadata.isLocal]]" on-tap="onMenuRemoveCreditCardTap_">$i18n{removeCreditCard}</button> - <button id="menuClearCreditCard" class="list-item menu-item" - on-tap="onMenuClearCreditCardTap_">$i18n{clearCreditCard}</button> - </cr-shared-menu> - <template is="dom-if" if="[[activeCreditCard]]" restamp> + <button id="menuClearCreditCard" class="dropdown-item" + on-tap="onMenuClearCreditCardTap_" + hidden$="[[!activeCreditCard.metadata.isCached]]"> + $i18n{clearCreditCard} + </button> + </dialog> + <template is="dom-if" if="[[showCreditCardDialog_]]" restamp> <settings-credit-card-edit-dialog credit-card="[[activeCreditCard]]" - on-close="unstampCreditCardEditDialog_"> + on-close="onCreditCardDialogClosed_"> </settings-credit-card-edit-dialog> </template> </template> diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js index 9fa0edf19b4..8e243d3a257 100644 --- a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js +++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/autofill_section.js @@ -22,11 +22,14 @@ addresses: Array, /** - * Assigning a non-null value triggers the add/edit dialog. + * The model for any address related action menus or dialogs. * @private {?chrome.autofillPrivate.AddressEntry} */ activeAddress: Object, + /** @private */ + showAddressDialog_: Boolean, + /** * An array of saved addresses. * @type {!Array<!chrome.autofillPrivate.CreditCardEntry>} @@ -34,15 +37,13 @@ creditCards: Array, /** - * Assigning a non-null value triggers the add/edit dialog. + * The model for any credit card related action menus or dialogs. * @private {?chrome.autofillPrivate.CreditCardEntry} */ activeCreditCard: Object, - }, - listeners: { - 'addressList.scroll': 'closeMenu_', - 'creditCardList.scroll': 'closeMenu_', + /** @private */ + showCreditCardDialog_: Boolean, }, /** @@ -64,30 +65,32 @@ }, /** - * Toggles the address overflow menu. + * Open the address action menu. * @param {!Event} e The polymer event. * @private */ onAddressMenuTap_: function(e) { - // Close the other menu. - this.$.creditCardSharedMenu.closeMenu(); - var menuEvent = /** @type {!{model: !{item: !Object}}} */(e); - var address = /** @type {!chrome.autofillPrivate.AddressEntry} */( + this.activeAddress = /** @type {!chrome.autofillPrivate.AddressEntry} */( menuEvent.model.item); - this.$.menuRemoveAddress.hidden = !address.metadata.isLocal; - this.$.addressSharedMenu.toggleMenu(Polymer.dom(e).localTarget, address); - e.stopPropagation(); // Prevent the tap event from closing the menu. + + var dotsButton = /** @type {!HTMLElement} */ (Polymer.dom(e).localTarget); + /** @type {!CrActionMenuElement} */ ( + this.$.addressSharedMenu).showAt(dotsButton); }, /** * Handles tapping on the "Add address" button. - * @param {!Event} e * @private */ - onAddAddressTap_: function(e) { - e.preventDefault(); + onAddAddressTap_: function() { this.activeAddress = {}; + this.showAddressDialog_ = true; + }, + + /** @private */ + onAddressDialogClosed_: function() { + this.showAddressDialog_ = false; }, /** @@ -95,21 +98,12 @@ * @private */ onMenuEditAddressTap_: function() { - var menu = this.$.addressSharedMenu; - /** @type {chrome.autofillPrivate.AddressEntry} */ - var address = menu.itemData; - - if (address.metadata.isLocal) - this.activeAddress = address; + if (this.activeAddress.metadata.isLocal) + this.showAddressDialog_ = true; else window.open(this.i18n('manageAddressesUrl')); - menu.closeMenu(); - }, - - /** @private */ - unstampAddressEditDialog_: function(e) { - this.activeAddress = null; + this.$.addressSharedMenu.close(); }, /** @@ -117,28 +111,24 @@ * @private */ onMenuRemoveAddressTap_: function() { - var menu = this.$.addressSharedMenu; - this.fire('remove-address', menu.itemData); - menu.closeMenu(); + this.fire('remove-address', this.activeAddress); + this.$.addressSharedMenu.close(); }, /** - * Toggles the credit card overflow menu. + * Opens the credit card action menu. * @param {!Event} e The polymer event. * @private */ onCreditCardMenuTap_: function(e) { - // Close the other menu. - this.$.addressSharedMenu.closeMenu(); - var menuEvent = /** @type {!{model: !{item: !Object}}} */(e); - var creditCard = /** @type {!chrome.autofillPrivate.CreditCardEntry} */( - menuEvent.model.item); - this.$.menuRemoveCreditCard.hidden = !creditCard.metadata.isLocal; - this.$.menuClearCreditCard.hidden = !creditCard.metadata.isCached; - this.$.creditCardSharedMenu.toggleMenu( - Polymer.dom(e).localTarget, creditCard); - e.stopPropagation(); // Prevent the tap event from closing the menu. + this.activeCreditCard = + /** @type {!chrome.autofillPrivate.CreditCardEntry} */( + menuEvent.model.item); + + var dotsButton = /** @type {!HTMLElement} */ (Polymer.dom(e).localTarget); + /** @type {!CrActionMenuElement} */ ( + this.$.creditCardSharedMenu).showAt(dotsButton); }, /** @@ -153,7 +143,12 @@ expirationMonth: expirationMonth.toString(), expirationYear: date.getFullYear().toString(), }; - e.preventDefault(); + this.showCreditCardDialog_ = true; + }, + + /** @private */ + onCreditCardDialogClosed_: function() { + this.showCreditCardDialog_ = false; }, /** @@ -161,31 +156,22 @@ * @private */ onMenuEditCreditCardTap_: function() { - var menu = this.$.creditCardSharedMenu; - /** @type {chrome.autofillPrivate.CreditCardEntry} */ - var creditCard = menu.itemData; - - if (creditCard.metadata.isLocal) - this.activeCreditCard = creditCard; + if (this.activeCreditCard.metadata.isLocal) + this.showCreditCardDialog_ = true; else window.open(this.i18n('manageCreditCardsUrl')); - menu.closeMenu(); + this.$.creditCardSharedMenu.close(); }, - /** @private */ - unstampCreditCardEditDialog_: function(e) { - this.activeCreditCard = null; - }, /** * Handles tapping on the "Remove" credit card button. * @private */ onMenuRemoveCreditCardTap_: function() { - var menu = this.$.creditCardSharedMenu; - this.fire('remove-credit-card', menu.itemData); - menu.closeMenu(); + this.fire('remove-credit-card', this.activeCreditCard); + this.$.creditCardSharedMenu.close(); }, /** @@ -193,18 +179,8 @@ * @private */ onMenuClearCreditCardTap_: function() { - var menu = this.$.creditCardSharedMenu; - this.fire('clear-credit-card', menu.itemData); - menu.closeMenu(); - }, - - /** - * Closes the overflow menus. - * @private - */ - closeMenu_: function() { - this.$.addressSharedMenu.closeMenu(); - this.$.creditCardSharedMenu.closeMenu(); + this.fire('clear-credit-card', this.activeCreditCard); + this.$.creditCardSharedMenu.close(); }, /** diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/compiled_resources2.gyp index 26eeb69bde8..3341d4a5022 100644 --- a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/compiled_resources2.gyp @@ -21,7 +21,7 @@ { 'target_name': 'autofill_section', 'dependencies': [ - '<(DEPTH)/ui/webui/resources/cr_elements/cr_shared_menu/compiled_resources2.gyp:cr_shared_menu', + '<(DEPTH)/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp:cr_action_menu', '<(EXTERNS_GYP):autofill_private', 'address_edit_dialog', 'credit_card_edit_dialog', @@ -48,8 +48,8 @@ { 'target_name': 'passwords_section', 'dependencies': [ - '<(DEPTH)/ui/webui/resources/cr_elements/compiled_resources2.gyp:cr_scrollable_behavior', - '<(DEPTH)/ui/webui/resources/cr_elements/cr_shared_menu/compiled_resources2.gyp:cr_shared_menu', + '../compiled_resources2.gyp:global_scroll_target_behavior', + '<(DEPTH)/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp:cr_action_menu', '<(EXTERNS_GYP):passwords_private', 'password_edit_dialog', ], diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/credit_card_edit_dialog.html b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/credit_card_edit_dialog.html index a31c7968e4a..93d232e0e95 100644 --- a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/credit_card_edit_dialog.html +++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/credit_card_edit_dialog.html @@ -1,9 +1,10 @@ <link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/html/i18n_behavior.html"> +<link rel="import" href="chrome://resources/html/md_select_css.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html"> -<link rel="import" href="/md_select_css.html"> +<link rel="import" href="/settings_vars_css.html"> <link rel="import" href="/settings_shared_css.html"> <dom-module id="settings-credit-card-edit-dialog"> @@ -16,6 +17,16 @@ -webkit-margin-start: 16px; } + #expired { + align-items: center; + background-color: var(--paper-red-50); + color: var(--settings-error-color); + display: flex; + height: 40px; + margin-top: 12px; + padding: 0 0 0 8px; + } + #month { width: 70px; } @@ -58,6 +69,9 @@ </select> <span class="md-select-underline"></span> </span> + <span id="expired" hidden="[[!checkIfCardExpired_(expirationMonth_, expirationYear_)]]"> + $i18n{creditCardExpired} + </span> </div> <div class="button-container"> <paper-button id="cancelButton" class="cancel-button" diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/credit_card_edit_dialog.js b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/credit_card_edit_dialog.js index b3ff3fb37ce..32a7dd3fe91 100644 --- a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/credit_card_edit_dialog.js +++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/credit_card_edit_dialog.js @@ -55,6 +55,17 @@ Polymer({ I18nBehavior, ], + /** + * @return {boolean} True iff the provided expiration date is passed. + * @private + */ + checkIfCardExpired_: function(expirationMonth_, expirationYear_) { + var now = new Date(); + return (expirationYear_ < now.getFullYear() || + (expirationYear_ == now.getFullYear() && + expirationMonth_ <= now.getMonth())); + }, + /** @override */ attached: function() { this.title_ = this.i18n( @@ -108,10 +119,15 @@ Polymer({ * @private */ onSaveButtonTap_: function() { - this.creditCard.expirationYear = this.expirationYear_; - this.creditCard.expirationMonth = this.expirationMonth_; - this.fire('save-credit-card', this.creditCard); - this.close(); + // If the card is expired, reflect the error to the user. + // Otherwise, update the card, save and close the dialog. + if (!this.checkIfCardExpired_(this.expirationMonth_, + this.expirationYear_)) { + this.creditCard.expirationYear = this.expirationYear_; + this.creditCard.expirationMonth = this.expirationMonth_; + this.fire('save-credit-card', this.creditCard); + this.close(); + } }, /** @private */ diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.html b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.html index 301cf0f28ed..065a12af2cf 100644 --- a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.html +++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.html @@ -26,8 +26,7 @@ <div>$i18n{autofill}</div> <div class="secondary">$i18n{autofillDetail}</div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"> - </button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="secondary-action"> <paper-toggle-button id="autofillToggle" @@ -43,8 +42,7 @@ <div>$i18n{passwords}</div> <div class="secondary">$i18n{passwordsDetail}</div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"> - </button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="secondary-action"> <paper-toggle-button id="passwordToggle" @@ -62,7 +60,7 @@ </settings-autofill-section> </settings-subpage> </template> - <template is="dom-if" route-path="/managePasswords"> + <template is="dom-if" route-path="/passwords"> <settings-subpage associated-control="[[$$('#passwordManagerButton')]]" page-title="$i18n{passwords}" diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.js b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.js index 4093e996eda..fd81d8f1ee3 100644 --- a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.js +++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_and_forms_page.js @@ -302,17 +302,9 @@ AutofillManagerImpl.prototype = { Polymer({ is: 'settings-passwords-and-forms-page', - behaviors: [ - PrefsBehavior, - ], + behaviors: [PrefsBehavior], properties: { - /** Preferences state. */ - prefs: { - type: Object, - notify: true, - }, - /** * An array of passwords to display. * @type {!Array<!PasswordManager.PasswordUiEntry>} @@ -328,7 +320,7 @@ Polymer({ /** @private Filter applied to passwords and password exceptions. */ passwordFilter_: String, - /** + /** * An array of saved addresses. * @type {!Array<!AutofillManager.AddressEntry>} */ @@ -339,7 +331,7 @@ Polymer({ * @type {!Array<!AutofillManager.CreditCardEntry>} */ creditCards: Array, - }, + }, listeners: { 'clear-credit-card': 'clearCreditCard_', diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html index ad630969921..0fe8c28c439 100644 --- a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html +++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.html @@ -1,10 +1,10 @@ +<link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/html/action_link.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> -<link rel="import" href="chrome://resources/cr_elements/cr_scrollable_behavior.html"> -<link rel="import" href="chrome://resources/cr_elements/cr_shared_menu/cr_shared_menu.html"> +<link rel="import" href="/global_scroll_target_behavior.html"> <link rel="import" href="/passwords_and_forms_page/password_edit_dialog.html"> <link rel="import" href="/passwords_and_forms_page/passwords_shared_css.html"> <link rel="import" href="/prefs/prefs.html"> @@ -42,10 +42,6 @@ .selectable { -webkit-user-select: text; } - - .menu-item { - @apply(--settings-actionable); - } </style> <div class="settings-box first two-line"> <settings-checkbox id="autosigninCheckbox" @@ -61,7 +57,7 @@ <div class="settings-box first"> <h2>$i18n{savedPasswordsHeading}</h2> </div> - <div class="list-frame" scrollable> + <div class="list-frame"> <div id="savedPasswordsHeading" class="list-item column-header" hidden$="[[!hasSome_(savedPasswords)]]"> <div class="website-column">$i18n{editPasswordWebsiteLabel}</div> @@ -74,7 +70,8 @@ </div> <iron-list id="passwordList" items="[[getFilteredPasswords_(savedPasswords, filter)]]" - class="vertical-list list-with-header"> + class="vertical-list list-with-header" + scroll-target="[[scrollTarget]]"> <template> <div class="list-item"> <div class="website-column"> @@ -101,15 +98,15 @@ $i18n{noPasswordsFound} </div> </div> - <cr-shared-menu id="menu"> - <button id="menuEditPassword" class="list-item menu-item" + <dialog is="cr-action-menu" id="menu"> + <button id="menuEditPassword" class="dropdown-item" on-tap="onMenuEditPasswordTap_" hidden$="[[!showPasswords]]">$i18n{passwordViewDetails}</button> - <button id="menuRemovePassword" class="list-item menu-item" + <button id="menuRemovePassword" class="dropdown-item" on-tap="onMenuRemovePasswordTap_">$i18n{removePassword}</button> - </cr-shared-menu> - <template is="dom-if" if="[[activePassword]]" restamp> - <password-edit-dialog on-close="unstampPasswordEditDialog_" + </dialog> + <template is="dom-if" if="[[showPasswordEditDialog_]]" restamp> + <password-edit-dialog on-close="onPasswordEditDialogClosed_" item="[[activePassword]]"> </password-edit-dialog> </template> diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js index 721d5eeec69..66e5a042713 100644 --- a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js +++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_section.js @@ -20,7 +20,7 @@ var ExceptionPairEntryEvent; Polymer({ is: 'passwords-section', - behaviors: [CrScrollableBehavior], + behaviors: [settings.GlobalScrollTargetBehavior], properties: { /** Preferences state. */ @@ -57,11 +57,14 @@ Polymer({ /** - * Assigning a non-null value triggers the add/edit dialog. + * The model for any password related action menus or dialogs. * @private {?chrome.passwordsPrivate.PasswordUiEntry} */ activePassword: Object, + /** @private */ + showPasswordEditDialog_: Boolean, + /** Filter on the saved passwords and exceptions. */ filter: { type: String, @@ -69,20 +72,6 @@ Polymer({ }, }, - listeners: { - 'passwordList.scroll': 'closeMenu_', - }, - - observers: ['passwordListChanged_(savedPasswords, filter)'], - - /** - * Updates the scrollable contents when the list of passwords has changed. - * @private - */ - passwordListChanged_: function() { - this.updateScrollableContents(); - }, - /** * Sets the password in the current password dialog if the loginPair matches. * @param {!chrome.passwordsPrivate.LoginPair} loginPair @@ -101,15 +90,13 @@ Polymer({ * @private */ onMenuEditPasswordTap_: function() { - var menu = /** @type {CrSharedMenuElement} */(this.$.menu); - this.activePassword = - /** @type {chrome.passwordsPrivate.PasswordUiEntry} */(menu.itemData); - menu.closeMenu(); + /** @type {CrActionMenuElement} */(this.$.menu).close(); + this.showPasswordEditDialog_ = true; }, /** @private */ - unstampPasswordEditDialog_: function(e) { - this.activePassword = null; + onPasswordEditDialogClosed_: function() { + this.showPasswordEditDialog_ = false; }, /** @@ -144,11 +131,8 @@ Polymer({ * @private */ onMenuRemovePasswordTap_: function() { - var menu = /** @type {CrSharedMenuElement} */(this.$.menu); - var data = - /** @type {chrome.passwordsPrivate.PasswordUiEntry} */(menu.itemData); - this.fire('remove-saved-password', data.loginPair); - menu.closeMenu(); + this.fire('remove-saved-password', this.activePassword.loginPair); + /** @type {CrActionMenuElement} */(this.$.menu).close(); }, /** @@ -169,25 +153,18 @@ Polymer({ getEmptyPassword_: function(length) { return ' '.repeat(length); }, /** - * Toggles the overflow menu. - * @param {!Event} e The polymer event. + * Opens the password action menu. * @private */ onPasswordMenuTap_: function(e) { - var menu = /** @type {CrSharedMenuElement} */(this.$.menu); + var menu = /** @type {!CrActionMenuElement} */(this.$.menu); var target = /** @type {!Element} */(Polymer.dom(e).localTarget); var passwordUiEntryEvent = /** @type {!PasswordUiEntryEvent} */(e); - menu.toggleMenu(target, passwordUiEntryEvent.model.item); - e.stopPropagation(); // Prevent the tap event from closing the menu. - }, - - /** - * Closes the overflow menu. - * @private - */ - closeMenu_: function() { - /** @type {CrSharedMenuElement} */(this.$.menu).closeMenu(); + this.activePassword = + /** @type {!chrome.passwordsPrivate.PasswordUiEntry} */ ( + passwordUiEntryEvent.model.item); + menu.showAt(target); }, /** diff --git a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_shared_css.html b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_shared_css.html index 738ed42c470..d7afeb6dd97 100644 --- a/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_shared_css.html +++ b/chromium/chrome/browser/resources/settings/passwords_and_forms_page/passwords_shared_css.html @@ -24,15 +24,6 @@ .list-with-header > div:first-of-type { border-top: var(--settings-separator-line); } - - /* TODO(hcarmona): Grow menu width by 64px if content is wider */ - .menu-item { - -webkit-padding-start: 24px; - background-color: white; - border: none; - font: inherit; - width: 104px; - } </style> </template> </dom-module> diff --git a/chromium/chrome/browser/resources/settings/people_page/change_picture.html b/chromium/chrome/browser/resources/settings/people_page/change_picture.html index f0460f60329..396e51654b2 100644 --- a/chromium/chrome/browser/resources/settings/people_page/change_picture.html +++ b/chromium/chrome/browser/resources/settings/people_page/change_picture.html @@ -21,6 +21,10 @@ padding-top: 16px; } + #availableIcons { + margin: -8px; + } + #availableIcons img, #availableIcons iron-icon { border-radius: 4px; @@ -35,6 +39,9 @@ } #availableIcons iron-icon { + --iron-icon-fill-color: var(--google-grey-500); + --iron-icon-height: 32px; + --iron-icon-width: 32px; border: 1px solid var(--google-grey-500); padding: 17px; } @@ -92,21 +99,21 @@ selected-item="{{selectedItem_}}"> <iron-icon id="cameraImage" data-type$="[[selectionTypesEnum_.CAMERA]]" - icon="settings:camera-alt" alt="$i18n{takePhoto}" + icon="settings:camera-alt" title="$i18n{takePhoto}" hidden="[[!cameraPresent_]]"> </iron-icon> <iron-icon data-type$="[[selectionTypesEnum_.FILE]]" - icon="settings:folder" alt="$i18n{chooseFile}"> + icon="settings:folder" title="$i18n{chooseFile}"> </iron-icon> <img id="profileImage" data-type$="[[selectionTypesEnum_.PROFILE]]" - src="[[profileImageUrl_]]" alt="$i18n{profilePhotoLoading}"> + src="[[profileImageUrl_]]" title="$i18n{profilePhotoLoading}"> <img id="oldImage" data-type$="[[selectionTypesEnum_.OLD]]" src="[[oldImageUrl_]]" hidden="[[!oldImageUrl_]]"> <template is="dom-repeat" items="[[defaultImages_]]"> <img data-type$="[[selectionTypesEnum_.DEFAULT]]" data-default-image-index$="[[index]]" src="[[item.url]]" - alt="[[item.title]]"> + title="[[item.title]]"> </template> </iron-selector> <template is="dom-if" if="[[isAuthorCreditShown_(selectedItem_)]]"> diff --git a/chromium/chrome/browser/resources/settings/people_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/people_page/compiled_resources2.gyp index 76a8bdaff7a..2c4ceac02ea 100644 --- a/chromium/chrome/browser/resources/settings/people_page/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/settings/people_page/compiled_resources2.gyp @@ -50,6 +50,13 @@ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, { + 'target_name': 'import_data_browser_proxy', + 'dependencies': [ + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', + ], + 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + { 'target_name': 'manage_profile', 'dependencies': [ '../compiled_resources2.gyp:route', @@ -152,6 +159,7 @@ { 'target_name': 'user_list', 'dependencies': [ + '../compiled_resources2.gyp:route', '<(EXTERNS_GYP):settings_private', '<(EXTERNS_GYP):users_private', ], @@ -173,5 +181,15 @@ ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, + { + 'target_name': 'import_data_dialog', + 'dependencies': [ + '../prefs/compiled_resources2.gyp:prefs_behavior', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:i18n_behavior', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior', + 'import_data_browser_proxy', + ], + 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], + }, ], } diff --git a/chromium/chrome/browser/resources/settings/people_page/import_data_browser_proxy.html b/chromium/chrome/browser/resources/settings/people_page/import_data_browser_proxy.html new file mode 100644 index 00000000000..32b91905943 --- /dev/null +++ b/chromium/chrome/browser/resources/settings/people_page/import_data_browser_proxy.html @@ -0,0 +1 @@ +<script src="/people_page/import_data_browser_proxy.js"></script> diff --git a/chromium/chrome/browser/resources/settings/people_page/import_data_browser_proxy.js b/chromium/chrome/browser/resources/settings/people_page/import_data_browser_proxy.js new file mode 100644 index 00000000000..24c108ec339 --- /dev/null +++ b/chromium/chrome/browser/resources/settings/people_page/import_data_browser_proxy.js @@ -0,0 +1,91 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview A helper object used from the the Import Data dialog to allow + * users to import data (like bookmarks) from other web browsers. + */ +cr.exportPath('settings'); + +/** + * An object describing a source browser profile that may be imported. + * The structure of this data must be kept in sync with C++ ImportDataHandler. + * @typedef {{ + * name: string, + * index: number, + * history: boolean, + * favorites: boolean, + * passwords: boolean, + * search: boolean, + * autofillFormData: boolean, + * }} + */ +settings.BrowserProfile; + +/** + * @enum {string} + * These string values must be kept in sync with the C++ ImportDataHandler. + */ +settings.ImportDataStatus = { + INITIAL: 'initial', + IN_PROGRESS: 'inProgress', + SUCCEEDED: 'succeeded', + FAILED: 'failed', +}; + +cr.define('settings', function() { + /** @interface */ + function ImportDataBrowserProxy() {} + + ImportDataBrowserProxy.prototype = { + /** + * Returns the source profiles available for importing from other browsers. + * @return {!Promise<!Array<!settings.BrowserProfile>>} + */ + initializeImportDialog: function() {}, + + /** + * Starts importing data for the specificed source browser profile. The C++ + * responds with the 'import-data-status-changed' WebUIListener event. + * @param {number} sourceBrowserProfileIndex + */ + importData: function(sourceBrowserProfileIndex) {}, + + /** + * Prompts the user to choose a bookmarks file to import bookmarks from. + */ + importFromBookmarksFile: function() {}, + }; + + /** + * @constructor + * @implements {settings.ImportDataBrowserProxy} + */ + function ImportDataBrowserProxyImpl() {} + // The singleton instance_ is replaced with a test version of this wrapper + // during testing. + cr.addSingletonGetter(ImportDataBrowserProxyImpl); + + ImportDataBrowserProxyImpl.prototype = { + /** @override */ + initializeImportDialog: function() { + return cr.sendWithPromise('initializeImportDialog'); + }, + + /** @override */ + importData: function(sourceBrowserProfileIndex) { + chrome.send('importData', [sourceBrowserProfileIndex]); + }, + + /** @override */ + importFromBookmarksFile: function() { + chrome.send('importFromBookmarksFile'); + }, + }; + + return { + ImportDataBrowserProxy: ImportDataBrowserProxy, + ImportDataBrowserProxyImpl: ImportDataBrowserProxyImpl, + }; +}); diff --git a/chromium/chrome/browser/resources/settings/people_page/import_data_dialog.html b/chromium/chrome/browser/resources/settings/people_page/import_data_dialog.html new file mode 100644 index 00000000000..b3a04205b6b --- /dev/null +++ b/chromium/chrome/browser/resources/settings/people_page/import_data_dialog.html @@ -0,0 +1,124 @@ +<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html"> +<link rel="import" href="chrome://resources/html/i18n_behavior.html"> +<link rel="import" href="chrome://resources/html/md_select_css.html"> +<link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.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-button/paper-button.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner.html"> +<link rel="import" href="/controls/settings_checkbox.html"> +<link rel="import" href="/controls/settings_toggle_button.html"> +<link rel="import" href="/i18n_setup.html"> +<link rel="import" href="/icons.html"> +<link rel="import" href="/people_page/import_data_browser_proxy.html"> +<link rel="import" href="/prefs/prefs_behavior.html"> +<link rel="import" href="/settings_vars_css.html"> + +<dom-module id="settings-import-data-dialog"> + <template> + <style include="settings-shared md-select"> + .description { + align-items: center; + display: flex; + min-height: var(--settings-row-min-height); + } + + paper-spinner { + margin: 0 8px; + } + + #successIcon { + fill: var(--paper-blue-600); + height: 80px; + margin: auto; + width: 100%; + } + </style> + <dialog is="cr-dialog" id="dialog"> + <div class="title">$i18n{importTitle}</div> + <div class="body"> + <div hidden$="[[!hasImportStatus_( + importStatusEnum_.SUCCEEDED, importStatus_)]]"> + <iron-icon id="successIcon" icon="settings:check-circle"> + </iron-icon> + <div hidden$="[[!prefs.import_bookmarks.value]]"> + <div class="description">$i18n{importSuccess}</div> + <settings-toggle-button class="start" + label="$i18n{showBookmarksBar}" + pref="{{prefs.bookmark_bar.show_on_all_tabs}}"> + </settings-toggle-button> + </div> + </div> + + <div hidden$="[[hasImportStatus_( + importStatusEnum_.SUCCEEDED, importStatus_)]]"> + <span class="md-select-wrapper"> + <select id="browserSelect" class="md-select" + on-change="onBrowserProfileSelectionChange_"> + <template is="dom-repeat" items="[[browserProfiles_]]"> + <option value="[[item.index]]">[[item.name]]</option> + </template> + </select> + <span class="md-select-underline"></span> + </span> + <div class="description">$i18n{importDescription}</div> + <settings-checkbox + hidden="[[!selected_.history]]" + pref="{{prefs.import_history}}" + label="$i18n{importHistory}"> + </settings-checkbox> + <settings-checkbox + hidden="[[!selected_.favorites]]" + pref="{{prefs.import_bookmarks}}" + label="$i18n{importFavorites}"> + </settings-checkbox> + <settings-checkbox + hidden="[[!selected_.passwords]]" + pref="{{prefs.import_saved_passwords}}" + label="$i18n{importPasswords}"> + </settings-checkbox> + <settings-checkbox + hidden="[[!selected_.search]]" + pref="{{prefs.import_search_engine}}" + label="$i18n{importSearch}"> + </settings-checkbox> + <settings-checkbox + hidden="[[!selected_.autofillFormData]]" + pref="{{prefs.import_autofill_form_data}}" + label="$i18n{importAutofillFormData}"> + </settings-checkbox> + </div> + </div> + <div class="button-container"> + <paper-spinner + active="[[hasImportStatus_( + importStatusEnum_.IN_PROGRESS, importStatus_)]]" + hidden="[[hasImportStatus_( + importStatusEnum_.SUCCEEDED, importStatus_)]]"> + </paper-spinner> + <paper-button id="cancel" class="cancel-button" + hidden="[[hasImportStatus_( + importStatusEnum_.SUCCEEDED, importStatus_)]]" + disabled="[[hasImportStatus_( + importStatusEnum_.IN_PROGRESS, importStatus_)]]" + on-tap="closeDialog_"> + $i18n{cancel} + </paper-button> + <paper-button id="import" class="action-button" + hidden="[[hasImportStatus_( + importStatusEnum_.SUCCEEDED, importStatus_)]]" + disabled="[[shouldDisableImport_( + importStatus_, noImportDataTypeSelected_)]]" + on-tap="onActionButtonTap_"> + [[getActionButtonText_(selected_)]] + </paper-button> + + <paper-button id="done" class="action-button" + hidden$="[[!hasImportStatus_( + importStatusEnum_.SUCCEEDED, importStatus_)]]" + on-tap="closeDialog_">$i18n{done}</paper-button> + </div> + </dialog> + </template> + <script src="import_data_dialog.js"></script> +</dom-module> diff --git a/chromium/chrome/browser/resources/settings/people_page/import_data_dialog.js b/chromium/chrome/browser/resources/settings/people_page/import_data_dialog.js new file mode 100644 index 00000000000..e035c281577 --- /dev/null +++ b/chromium/chrome/browser/resources/settings/people_page/import_data_dialog.js @@ -0,0 +1,139 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview 'settings-import-data-dialog' is a component for importing + * bookmarks and other data from other sources. + */ +Polymer({ + is: 'settings-import-data-dialog', + + behaviors: [I18nBehavior, WebUIListenerBehavior, PrefsBehavior], + + properties: { + /** @private {!Array<!settings.BrowserProfile>} */ + browserProfiles_: Array, + + /** @private {!settings.BrowserProfile} */ + selected_: Object, + + /** + * Whether none of the import data categories is selected. + * @private + */ + noImportDataTypeSelected_: { + type: Boolean, + value: false, + }, + + /** @private */ + importStatus_: { + type: String, + value: settings.ImportDataStatus.INITIAL, + }, + + /** + * Mirroring the enum so that it can be used from HTML bindings. + * @private + */ + importStatusEnum_: { + type: Object, + value: settings.ImportDataStatus, + }, + }, + + observers: [ + 'prefsChanged_(selected_, prefs.*)', + ], + + /** @private {?settings.ImportDataBrowserProxy} */ + browserProxy_: null, + + /** @override */ + attached: function() { + this.browserProxy_ = settings.ImportDataBrowserProxyImpl.getInstance(); + this.browserProxy_.initializeImportDialog().then( + /** @param {!Array<!settings.BrowserProfile>} data */ + function(data) { + this.browserProfiles_ = data; + this.selected_ = this.browserProfiles_[0]; + }.bind(this)); + + this.addWebUIListener( + 'import-data-status-changed', + /** @param {settings.ImportDataStatus} importStatus */ + function(importStatus) { + this.importStatus_ = importStatus; + if (this.hasImportStatus_(settings.ImportDataStatus.FAILED)) + this.closeDialog_(); + }.bind(this)); + + this.$.dialog.showModal(); + }, + + /** @private */ + prefsChanged_() { + this.noImportDataTypeSelected_ = + !(this.getPref('import_history').value && this.selected_.history) && + !(this.getPref('import_bookmarks').value && this.selected_.favorites) && + !(this.getPref('import_saved_passwords').value && + this.selected_.passwords) && + !(this.getPref('import_search_engine').value && + this.selected_.search) && + !(this.getPref('import_autofill_form_data').value && + this.selected_.autofillFormData); + }, + + /** + * @param {!settings.ImportDataStatus} status + * @return {boolean} Whether |status| is the current status. + * @private + */ + hasImportStatus_: function(status) { + return this.importStatus_ == status; + }, + + /** @private */ + isImportFromFileSelected_: function() { + // The last entry in |browserProfiles_| always refers to dummy profile for + // importing from a bookmarks file. + return this.selected_.index == this.browserProfiles_.length - 1; + }, + + /** + * @return {string} + * @private + */ + getActionButtonText_: function() { + return this.i18n(this.isImportFromFileSelected_() ? + 'importChooseFile' : 'importCommit'); + }, + + /** @private */ + onBrowserProfileSelectionChange_: function() { + this.selected_ = this.browserProfiles_[this.$.browserSelect.selectedIndex]; + }, + + /** @private */ + onActionButtonTap_: function() { + if (this.isImportFromFileSelected_()) + this.browserProxy_.importFromBookmarksFile(); + else + this.browserProxy_.importData(this.$.browserSelect.selectedIndex); + }, + + /** @private */ + closeDialog_: function() { + this.$.dialog.close(); + }, + + /** + * @return {boolean} Whether the import button should be disabled. + * @private + */ + shouldDisableImport_: function() { + return this.hasImportStatus_(settings.ImportDataStatus.IN_PROGRESS) || + this.noImportDataTypeSelected_; + }, +}); diff --git a/chromium/chrome/browser/resources/settings/people_page/manage_profile.html b/chromium/chrome/browser/resources/settings/people_page/manage_profile.html index a4745d557f5..5ad3795fab7 100644 --- a/chromium/chrome/browser/resources/settings/people_page/manage_profile.html +++ b/chromium/chrome/browser/resources/settings/people_page/manage_profile.html @@ -3,6 +3,8 @@ <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/shadow.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html"> +<link rel="import" href="/i18n_setup.html"> <link rel="import" href="/people_page/manage_profile_browser_proxy.html"> <link rel="import" href="/route.html"> <link rel="import" href="/settings_shared_css.html"> @@ -20,6 +22,15 @@ disabled="[[isProfileNameDisabled_(syncStatus)]]"> </paper-input> </div> + <template is="dom-if" if="[[isProfileShortcutsEnabled_]]"> + <div class="settings-box first"> + <div class="flex">$i18n{showShortcutLabel}</div> + <paper-toggle-button id="hasShortcutToggle" + checked="{{hasProfileShortcut_}}" + on-change="onHasProfileShortcutChange_"> + </paper-toggle-button> + </div> + </template> <cr-profile-avatar-selector id="selector" avatars="[[availableIcons]]" selected-avatar-url="{{profileIconUrl}}" on-iron-activate="onIconActivate_"> diff --git a/chromium/chrome/browser/resources/settings/people_page/manage_profile.js b/chromium/chrome/browser/resources/settings/people_page/manage_profile.js index 740d4b3eeae..898085276ba 100644 --- a/chromium/chrome/browser/resources/settings/people_page/manage_profile.js +++ b/chromium/chrome/browser/resources/settings/people_page/manage_profile.js @@ -24,6 +24,11 @@ Polymer({ profileName: String, /** + * True if the current profile has a shortcut. + */ + hasProfileShortcut_: Boolean, + + /** * The available icons for selection. * @type {!Array<string>} */ @@ -47,6 +52,18 @@ Polymer({ return settings.ManageProfileBrowserProxyImpl.getInstance(); }, }, + + /** + * True if the profile shortcuts feature is enabled. + * @private + */ + isProfileShortcutsEnabled_: { + type: Boolean, + value: function() { + return loadTimeData.getBoolean('profileShortcutsEnabled'); + }, + readOnly: true, + }, }, /** @override */ @@ -61,8 +78,16 @@ Polymer({ /** @protected */ currentRouteChanged: function() { - if (settings.getCurrentRoute() == settings.Route.MANAGE_PROFILE) + if (settings.getCurrentRoute() == settings.Route.MANAGE_PROFILE) { this.$.name.value = this.profileName; + + if (this.isProfileShortcutsEnabled_) { + var setHasProfileShortcut = function(hasProfileShortcut) { + this.hasProfileShortcut_ = hasProfileShortcut; + }.bind(this); + this.browserProxy_.getHasProfileShortcut().then(setHasProfileShortcut); + } + } }, /** @@ -96,4 +121,17 @@ Polymer({ isProfileNameDisabled_: function(syncStatus) { return !!syncStatus.supervisedUser && !syncStatus.childUser; }, + + /** + * Handler for when the profile shortcut toggle is changed. + * @param {!Event} event + * @private + */ + onHasProfileShortcutChange_: function(event) { + if (this.hasProfileShortcut_) { + this.browserProxy_.addProfileShortcut(); + } else { + this.browserProxy_.removeProfileShortcut(); + } + } }); diff --git a/chromium/chrome/browser/resources/settings/people_page/manage_profile_browser_proxy.js b/chromium/chrome/browser/resources/settings/people_page/manage_profile_browser_proxy.js index e1b8a4368f6..0a96f0ec36c 100644 --- a/chromium/chrome/browser/resources/settings/people_page/manage_profile_browser_proxy.js +++ b/chromium/chrome/browser/resources/settings/people_page/manage_profile_browser_proxy.js @@ -23,6 +23,22 @@ cr.define('settings', function() { * @param {!string} name The new profile name. */ setProfileIconAndName: function(iconUrl, name) {}, + + /** + * Returns whether the current profile has a shortcut. + * @return {!Promise<boolean>} + */ + getHasProfileShortcut: function() {}, + + /** + * Adds a shortcut for the current profile. + */ + addProfileShortcut: function() {}, + + /** + * Removes the shortcut of the current profile. + */ + removeProfileShortcut: function() {}, }; /** @@ -44,6 +60,21 @@ cr.define('settings', function() { setProfileIconAndName: function(iconUrl, name) { chrome.send('setProfileIconAndName', [iconUrl, name]); }, + + /** @override */ + getHasProfileShortcut: function() { + return cr.sendWithPromise('requestHasProfileShortcuts'); + }, + + /** @override */ + addProfileShortcut: function() { + chrome.send('addProfileShortcut'); + }, + + /** @override */ + removeProfileShortcut: function() { + chrome.send('removeProfileShortcut'); + }, }; return { diff --git a/chromium/chrome/browser/resources/settings/people_page/password_prompt_dialog.html b/chromium/chrome/browser/resources/settings/people_page/password_prompt_dialog.html index 5f893f8ea0b..235d3877d12 100644 --- a/chromium/chrome/browser/resources/settings/people_page/password_prompt_dialog.html +++ b/chromium/chrome/browser/resources/settings/people_page/password_prompt_dialog.html @@ -17,7 +17,8 @@ } </style> - <dialog is="cr-dialog" id="dialog" on-close="onClose_"> + <dialog is="cr-dialog" id="dialog" on-close="onClose_" + close-text="$i18n{close}"> <div class="title">$i18n{passwordPromptTitle}</div> <div class="body"> diff --git a/chromium/chrome/browser/resources/settings/people_page/people_page.html b/chromium/chrome/browser/resources/settings/people_page/people_page.html index 8bbda0c3125..029e9d79402 100644 --- a/chromium/chrome/browser/resources/settings/people_page/people_page.html +++ b/chromium/chrome/browser/resources/settings/people_page/people_page.html @@ -26,6 +26,7 @@ <link rel="import" href="/people_page/users_page.html"> </if> <if expr="not chromeos"> +<link rel="import" href="/people_page/import_data_dialog.html"> <link rel="import" href="/people_page/manage_profile.html"> </if> @@ -55,14 +56,23 @@ --iron-icon-fill-color: var(--google-green-700); } - iron-icon[icon='settings:sync-problem'] { + #sync-status[actionable] iron-icon[icon='settings:sync-problem'] { --iron-icon-fill-color: var(--settings-error-color); } - .settings-box .sync-error { + #sync-status:not([actionable]) .subpage-arrow { + display: none; + } + + .settings-box[actionable] .sync-error { color: var(--settings-error-color); } + #easy-unlock .start { + /* Use padding to ensure taller content looks correct. */ + padding: 11px 0; + } + .icon-container { display: flex; flex-shrink: 0; @@ -84,40 +94,45 @@ <settings-animated-pages id="pages" section="people"> <neon-animatable route-path="default"> <div id="picture-subpage-trigger" class="settings-box first two-line"> - <div id="profile-icon" on-tap="onPictureTap_" actionable - style="background-image: [[getIconImageset_(profileIconUrl_)]]"> - </div> + <template is="dom-if" if="[[syncStatus]]"> + <div id="profile-icon" on-tap="onPictureTap_" actionable + style="background-image: [[getIconImageset_(profileIconUrl_)]]"> + </div> <if expr="not chromeos"> - <div class="middle two-line" on-tap="onProfileNameTap_" actionable> + <div class="middle two-line" on-tap="onProfileNameTap_" actionable> </if> <if expr="chromeos"> - <div class="middle two-line" on-tap="onPictureTap_" actionable> + <div class="middle two-line" on-tap="onPictureTap_" actionable> </if> - <span class="flex" id="profile-name"> - [[profileName_]] - </span> - <button class="icon-arrow-right" is="paper-icon-button-light"> - </button> - </div> + <div class="flex"> + <span id="profile-name">[[profileName_]]</span> + <div class="secondary" hidden="[[!syncStatus.signedIn]]"> + [[syncStatus.signedInUsername]] + </div> + </div> + <button class="subpage-arrow" is="paper-icon-button-light"> + </button> + </div> <if expr="not chromeos"> - <template is="dom-if" if="[[showSignin_(syncStatus)]]"> - <span class="secondary-action"> - <paper-button class="primary-button" on-tap="onSigninTap_" - disabled="[[syncStatus.setupInProgress]]"> - $i18n{syncSignin} - </paper-button> - </span> - </template> - <template is="dom-if" if="[[syncStatus.signedIn]]"> - <span class="secondary-action"> - <paper-button id="disconnectButton" class="secondary-button" - on-tap="onDisconnectTap_" - disabled="[[syncStatus.setupInProgress]]"> - $i18n{syncDisconnect} - </paper-button> - </span> - </template> + <template is="dom-if" if="[[showSignin_(syncStatus)]]"> + <span class="secondary-action"> + <paper-button class="primary-button" on-tap="onSigninTap_" + disabled="[[syncStatus.setupInProgress]]"> + $i18n{syncSignin} + </paper-button> + </span> + </template> + <template is="dom-if" if="[[syncStatus.signedIn]]"> + <span class="secondary-action"> + <paper-button id="disconnectButton" class="secondary-button" + on-tap="onDisconnectTap_" + disabled="[[syncStatus.setupInProgress]]"> + $i18n{syncDisconnect} + </paper-button> + </span> + </template> </if> + </template> </div> <div class="settings-box two-line" hidden="[[!showSignin_(syncStatus)]]"> @@ -145,23 +160,19 @@ <template is="dom-if" if="[[isAdvancedSyncSettingsVisible_(syncStatus)]]"> <div class="settings-box two-line" on-tap="onSyncTap_" - id="customize-sync" actionable$="[[!syncStatus.managed]]"> + id="sync-status" actionable$="[[isSyncStatusActionable_( + syncStatus)]]"> <div class="icon-container"> <iron-icon id="sync-icon" icon$="[[getSyncIcon_(syncStatus)]]"> </iron-icon> </div> <div class="middle"> <div>$i18n{sync}</div> - <div class="secondary" hidden="[[syncStatus.hasError]]"> - [[syncStatus.statusText]] - </div> - <div class="secondary sync-error" - hidden="[[!syncStatus.hasError]]"> + <div class$="secondary [[getSyncStatusTextClass_(syncStatus)]]"> [[syncStatus.statusText]] </div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"> - </button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> </template> @@ -190,19 +201,20 @@ <template is="dom-if" if="[[quickUnlockEnabled_]]"> <div class="settings-box two-line" actionable on-tap="onConfigureLockTap_"> - <div class="middle"> - <div>$i18n{lockScreenTitle}</div> + <div class="start"> + $i18n{lockScreenTitle} <div class="secondary"> [[getPasswordState_(hasPin, prefs.settings.enable_screen_lock.value)]] </div> </div> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> </template> <template is="dom-if" if="[[easyUnlockAllowed_]]"> - <div class="settings-box"> - <div class="middle"> + <div id="easy-unlock" class="settings-box two-line"> + <div class="start"> <div>$i18n{easyUnlockSectionTitle}</div> <div class="secondary"> <template is="dom-if" if="[[!easyUnlockEnabled_]]"> @@ -211,7 +223,7 @@ <template is="dom-if" if="[[easyUnlockEnabled_]]"> $i18n{easyUnlockDescription} </template> - <a target="_blank" href$="$i18n{easyUnlockLearnMoreURL}"> + <a target="_blank" href="$i18n{easyUnlockLearnMoreURL}"> $i18n{learnMore} </a> <template is="dom-if" if="[[easyUnlockEnabled_]]"> @@ -244,15 +256,18 @@ </if> <div id="manage-other-people-subpage-trigger" - class="settings-box two-line" on-tap="onManageOtherPeople_" - actionable> - <div class="start"> - $i18n{manageOtherPeople} - <div class="secondary">$i18n{manageOtherPeopleDescription}</div> - </div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> + class="settings-box" on-tap="onManageOtherPeople_" actionable> + <div class="start">$i18n{manageOtherPeople}</div> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> +<if expr="not chromeos"> + <div class="settings-box" on-tap="onImportDataTap_" actionable> + <div class="start">$i18n{importTitle}</div> + <button class="subpage-arrow" is="paper-icon-button-light"></button> + </div> +</if> + <template is="dom-if" if=[[profileManagesSupervisedUsers_]]> <div id="manageSupervisedUsersContainer" class="settings-box two-line" on-tap="onManageSupervisedUsers_" actionable> @@ -269,7 +284,7 @@ <template is="dom-if" route-path="/syncSetup" no-search$="[[!isAdvancedSyncSettingsVisible_(syncStatus)]]"> <settings-subpage - associated-control="[[$$('#customize-sync')]]" + associated-control="[[$$('#sync-status')]]" page-title="$i18n{syncPageTitle}" no-search$="[[!isAdvancedSyncSettingsVisible_(syncStatus)]]"> <settings-sync-page></settings-sync-page> @@ -313,7 +328,8 @@ </if> </settings-animated-pages> - <dialog is="cr-dialog" id="disconnectDialog" on-close="onDisconnectClosed_"> + <dialog is="cr-dialog" id="disconnectDialog" on-close="onDisconnectClosed_" + ignore-popstate> <div class="title">$i18n{syncDisconnectTitle}</div> <div class="body"> <div inner-h-t-m-l="[[getDisconnectExplanationHtml_(syncStatus.domain)]]"> @@ -339,6 +355,12 @@ </div> </dialog> + <template is="dom-if" if="[[showImportDataDialog_]]" restamp> + <settings-import-data-dialog prefs="{{prefs}}" + on-close="onImportDataDialogClosed_"> + </settings-import-data-dialog> + </template> + <if expr="chromeos"> <template is="dom-if" if="[[easyUnlockEnabled_]]"> <easy-unlock-turn-off-dialog id="easyUnlockTurnOffDialog"> diff --git a/chromium/chrome/browser/resources/settings/people_page/people_page.js b/chromium/chrome/browser/resources/settings/people_page/people_page.js index 400bb0f1f90..9bea085c763 100644 --- a/chromium/chrome/browser/resources/settings/people_page/people_page.js +++ b/chromium/chrome/browser/resources/settings/people_page/people_page.js @@ -48,6 +48,14 @@ Polymer({ */ profileManagesSupervisedUsers_: Boolean, +<if expr="not chromeos"> + /** @private */ + showImportDataDialog_: { + type: Boolean, + value: false, + }, +</if> + /** @private {!settings.SyncBrowserProxy} */ syncBrowserProxy_: { type: Object, @@ -64,7 +72,7 @@ Polymer({ quickUnlockEnabled_: { type: Boolean, value: function() { - return loadTimeData.getBoolean('quickUnlockEnabled'); + return loadTimeData.getBoolean('pinUnlockEnabled'); }, readOnly: true, }, @@ -142,10 +150,20 @@ Polymer({ /** @protected */ currentRouteChanged: function() { - if (settings.getCurrentRoute() == settings.Route.SIGN_OUT) - this.$.disconnectDialog.showModal(); - else if (this.$.disconnectDialog.open) + this.showImportDataDialog_ = + settings.getCurrentRoute() == settings.Route.IMPORT_DATA; + + if (settings.getCurrentRoute() == settings.Route.SIGN_OUT) { + // If the sync status has not been fetched yet, optimistically display + // the disconnect dialog. There is another check when the sync status is + // fetched. The dialog will be closed then the user is not signed in. + if (this.syncStatus && !this.syncStatus.signedIn) + settings.navigateToPreviousRoute(); + else + this.$.disconnectDialog.showModal(); + } else if (this.$.disconnectDialog.open) { this.$.disconnectDialog.close(); + } }, <if expr="chromeos"> @@ -184,9 +202,12 @@ Polymer({ * @private */ handleSyncStatus_: function(syncStatus) { - if (!this.syncStatus && syncStatus && !syncStatus.signedIn) { + if (!this.syncStatus && syncStatus && !syncStatus.signedIn) chrome.metricsPrivate.recordUserAction('Signin_Impression_FromSettings'); - } + + if (!syncStatus.signedIn && this.$.disconnectDialog.open) + this.$.disconnectDialog.close(); + this.syncStatus = syncStatus; }, @@ -231,6 +252,7 @@ Polymer({ onDisconnectClosed_: function() { if (settings.getCurrentRoute() == settings.Route.SIGN_OUT) settings.navigateToPreviousRoute(); + this.fire('signout-dialog-closed'); }, /** @private */ @@ -247,7 +269,15 @@ Polymer({ onDisconnectConfirm_: function() { var deleteProfile = !!this.syncStatus.domain || (this.$.deleteProfile && this.$.deleteProfile.checked); - this.syncBrowserProxy_.signOut(deleteProfile); + // Trigger the sign out event after the navigateToPreviousRoute(). + // So that the navigation to the setting page could be finished before the + // sign out if navigateToPreviousRoute() returns synchronously even the + // browser is closed after the sign out. Otherwise, the navigation will be + // finshed during session restore if the browser is closed before the async + // callback executed. + listenOnce(this, 'signout-dialog-closed', function() { + this.syncBrowserProxy_.signOut(deleteProfile); + }.bind(this)); this.$.disconnectDialog.close(); }, @@ -257,10 +287,36 @@ Polymer({ assert(this.syncStatus.signedIn); assert(this.syncStatus.syncSystemEnabled); - if (this.syncStatus.managed) + if (!this.isSyncStatusActionable_(this.syncStatus)) return; - settings.navigateTo(settings.Route.SYNC); + switch (this.syncStatus.statusAction) { + case settings.StatusAction.REAUTHENTICATE: + this.syncBrowserProxy_.startSignIn(); + break; + case settings.StatusAction.SIGNOUT_AND_SIGNIN: +<if expr="chromeos"> + this.syncBrowserProxy_.attemptUserExit(); +</if> +<if expr="not chromeos"> + if (this.syncStatus.domain) + settings.navigateTo(settings.Route.SIGN_OUT); + else { + // Silently sign the user out without deleting their profile and + // prompt them to sign back in. + this.syncBrowserProxy_.signOut(false); + this.syncBrowserProxy_.startSignIn(); + } +</if> + break; + case settings.StatusAction.UPGRADE_CLIENT: + settings.navigateTo(settings.Route.ABOUT); + break; + case settings.StatusAction.ENTER_PASSPHRASE: + case settings.StatusAction.NO_ACTION: + default: + settings.navigateTo(settings.Route.SYNC); + } }, <if expr="chromeos"> @@ -306,6 +362,16 @@ Polymer({ '<span id="managed-by-domain-name">' + domain + '</span>'; return loadTimeData.getStringF('domainManagedProfile', innerSpan); }, + + /** @private */ + onImportDataTap_: function() { + settings.navigateTo(settings.Route.IMPORT_DATA); + }, + + /** @private */ + onImportDataDialogClosed_: function() { + settings.navigateToPreviousRoute(); + }, </if> /** @@ -337,17 +403,43 @@ Polymer({ /** * @private * @param {?settings.SyncStatus} syncStatus + * @return {boolean} Whether an action can be taken with the sync status. sync + * status is actionable if sync is not managed and if there is a sync + * error, there is an action associated with it. + */ + isSyncStatusActionable_: function(syncStatus) { + return !!syncStatus && !syncStatus.managed && (!syncStatus.hasError || + syncStatus.statusAction != settings.StatusAction.NO_ACTION); + }, + + /** + * @private + * @param {?settings.SyncStatus} syncStatus * @return {string} */ getSyncIcon_: function(syncStatus) { if (!syncStatus) return ''; + + var syncIcon = 'settings:sync'; + if (syncStatus.hasError) - return 'settings:sync-problem'; + syncIcon = 'settings:sync-problem'; + + // Override the icon to the disabled icon if sync is managed. if (syncStatus.managed) - return 'settings:sync-disabled'; + syncIcon = 'settings:sync-disabled'; + + return syncIcon; + }, - return 'settings:sync'; + /** + * @private + * @param {?settings.SyncStatus} syncStatus + * @return {string} The class name for the sync status text. + */ + getSyncStatusTextClass_: function(syncStatus) { + return (!!syncStatus && syncStatus.hasError) ? 'sync-error' : ''; }, /** @@ -360,6 +452,7 @@ Polymer({ }, /** + * @param {!settings.SyncStatus} syncStatus * @return {boolean} Whether to show the "Sign in to Chrome" button. * @private */ diff --git a/chromium/chrome/browser/resources/settings/people_page/setup_pin_dialog.html b/chromium/chrome/browser/resources/settings/people_page/setup_pin_dialog.html index 3f222420dd6..91beddf2fa6 100644 --- a/chromium/chrome/browser/resources/settings/people_page/setup_pin_dialog.html +++ b/chromium/chrome/browser/resources/settings/people_page/setup_pin_dialog.html @@ -10,11 +10,11 @@ <style include="settings-shared"></style> <style> .warning { - color: var(--paper-grey-500); + color: var(--paper-grey-700); } .warning > iron-icon { - --iron-icon-fill-color: var(--paper-grey-500); + --iron-icon-fill-color: var(--paper-grey-700); } .error { diff --git a/chromium/chrome/browser/resources/settings/people_page/setup_pin_dialog.js b/chromium/chrome/browser/resources/settings/people_page/setup_pin_dialog.js index 72b68c82911..14da74e9200 100644 --- a/chromium/chrome/browser/resources/settings/people_page/setup_pin_dialog.js +++ b/chromium/chrome/browser/resources/settings/people_page/setup_pin_dialog.js @@ -141,11 +141,12 @@ Polymer({ }, /** - * Returns true if the PIN is ready to be changed to a new value. + * Returns true if the currently entered PIN is the same as the initially + * submitted PIN. * @private * @return {boolean} */ - canSubmit_: function() { + isPinConfirmed_: function() { return this.isPinLongEnough_(this.pinKeyboardValue_) && this.initialPin_ == this.pinKeyboardValue_; }, @@ -157,10 +158,17 @@ Polymer({ * @param {string} problemClass */ showProblem_: function(messageId, problemClass) { + var previousMessage = this.problemMessage_; + + // Update problem info. this.problemMessage_ = this.i18n(messageId); this.problemClass_ = problemClass; this.updateStyles(); - }, + + // If the problem message has changed, fire an alert. + if (previousMessage != this.problemMessage_) + this.$.problemDiv.setAttribute('role', 'alert'); + }, /** @private */ hideProblem_: function() { @@ -174,8 +182,8 @@ Polymer({ var isPinLongEnough = this.isPinLongEnough_(this.pinKeyboardValue_); var isWeak = isPinLongEnough && this.isPinWeak_(this.pinKeyboardValue_); - if (!isPinLongEnough && this.pinKeyboardValue_) - this.showProblem_('configurePinTooShort', 'error'); + if (!isPinLongEnough) + this.showProblem_('configurePinTooShort', 'warning'); else if (isWeak) this.showProblem_('configurePinWeakPin', 'warning'); else @@ -184,14 +192,12 @@ Polymer({ this.enableSubmit_ = isPinLongEnough; } else { - var canSubmit = this.canSubmit_(); - - if (!canSubmit && this.pinKeyboardValue_) - this.showProblem_('configurePinMismatched', 'error'); - else + if (this.isPinConfirmed_()) this.hideProblem_(); + else + this.showProblem_('configurePinMismatched', 'warning'); - this.enableSubmit_ = canSubmit; + this.enableSubmit_ = true; } }, @@ -208,8 +214,10 @@ Polymer({ } else { // onPinSubmit_ gets called if the user hits enter on the PIN keyboard. // The PIN is not guaranteed to be valid in that case. - if (!this.canSubmit_()) + if (!this.isPinConfirmed_()) { + this.showProblem_('configurePinMismatched', 'error'); return; + } function onSetModesCompleted(didSet) { if (!didSet) { diff --git a/chromium/chrome/browser/resources/settings/people_page/sync_browser_proxy.js b/chromium/chrome/browser/resources/settings/people_page/sync_browser_proxy.js index fd98d0661ca..be5c2b6d985 100644 --- a/chromium/chrome/browser/resources/settings/people_page/sync_browser_proxy.js +++ b/chromium/chrome/browser/resources/settings/people_page/sync_browser_proxy.js @@ -10,8 +10,7 @@ cr.exportPath('settings'); /** - * @typedef {{actionLinkText: (string|undefined), - * childUser: (boolean|undefined), + * @typedef {{childUser: (boolean|undefined), * domain: (string|undefined), * hasError: (boolean|undefined), * hasUnrecoverableError: (boolean|undefined), @@ -19,7 +18,9 @@ cr.exportPath('settings'); * setupCompleted: (boolean|undefined), * setupInProgress: (boolean|undefined), * signedIn: (boolean|undefined), + * signedInUsername: (string|undefined), * signinAllowed: (boolean|undefined), + * statusAction: (!settings.StatusAction), * statusText: (string|undefined), * supervisedUser: (boolean|undefined), * syncSystemEnabled: (boolean|undefined)}} @@ -27,6 +28,20 @@ cr.exportPath('settings'); */ settings.SyncStatus; + +/** + * Must be kept in sync with the return values of getSyncErrorAction in + * chrome/browser/ui/webui/settings/people_handler.cc + * @enum {string} + */ +settings.StatusAction = { + NO_ACTION: 'noAction', // No action to take. + REAUTHENTICATE: 'reauthenticate', // User needs to reauthenticate. + SIGNOUT_AND_SIGNIN: 'signOutAndSignIn', // User needs to sign out and sign in. + UPGRADE_CLIENT: 'upgradeClient', // User needs to upgrade the client. + ENTER_PASSPHRASE: 'enterPassphrase', // User needs to enter passphrase. +}; + /** * The state of sync. This is the data structure sent back and forth between * C++ and JS. Its naming and structure is not optimal, but changing it would @@ -109,6 +124,13 @@ cr.define('settings', function() { manageOtherPeople: function() {}, </if> +<if expr="chromeos"> + /** + * Signs the user out. + */ + attemptUserExit: function() {}, +</if> + /** * Gets the current sync status. * @return {!Promise<!settings.SyncStatus>} @@ -159,10 +181,7 @@ cr.define('settings', function() { <if expr="not chromeos"> /** @override */ startSignIn: function() { - // TODO(tommycli): Currently this is always false, but this will become - // a parameter once supervised users are implemented in MD Settings. - var creatingSupervisedUser = false; - chrome.send('SyncSetupStartSignIn', [creatingSupervisedUser]); + chrome.send('SyncSetupStartSignIn'); }, /** @override */ @@ -175,6 +194,12 @@ cr.define('settings', function() { chrome.send('SyncSetupManageOtherPeople'); }, </if> +<if expr="chromeos"> + /** @override */ + attemptUserExit: function() { + return chrome.send('AttemptUserExit'); + }, +</if> /** @override */ getSyncStatus: function() { diff --git a/chromium/chrome/browser/resources/settings/people_page/sync_page.html b/chromium/chrome/browser/resources/settings/people_page/sync_page.html index 0e329a7c76d..429271ea129 100644 --- a/chromium/chrome/browser/resources/settings/people_page/sync_page.html +++ b/chromium/chrome/browser/resources/settings/people_page/sync_page.html @@ -6,7 +6,6 @@ <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-button/paper-radio-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-radio-group/paper-radio-group.html"> -<link rel="import" href="/controls/settings_checkbox.html"> <link rel="import" href="/people_page/sync_browser_proxy.html"> <link rel="import" href="/route.html"> <link rel="import" href="/settings_shared_css.html"> @@ -14,19 +13,36 @@ <dom-module id="settings-sync-page"> <template> <style include="settings-shared"> - #create-password-box { - /* The password fields line up with the encryption radio box text. */ + #create-password-box, + #reset-sync-message-box { + /* In order to line up with the encryption radio box text. */ -webkit-margin-start: 36px; } paper-input { width: var(--paper-input-max-width); + --paper-input-container-focus-color: var(--google-blue-500); + --paper-input-container-input: { + font-size: inherit; + }; + } + + #saveNewPassphrase { + margin-top: 20px; + } + + #existingPassphraseContainer, + #passphraseRecoverHint { + align-items: flex-end; } #existingPassphraseInput { /* The submit button for the existing passphrase is on the same line. */ -webkit-margin-end: 16px; display: inline-block; + --paper-input-container: { + padding: 0; + }; } </style> <div id="[[pages.SPINNER]]" class="settings-box first" @@ -154,27 +170,40 @@ </paper-radio-button> <paper-radio-button name="encrypt-with-passphrase" class="list-item" disabled="[[syncPrefs.encryptAllData]]"> - <span> - [[encryptWithPassphraseBody_(syncPrefs.fullEncryptionBody)]] - </span> + <template is="dom-if" if="[[syncPrefs.fullEncryptionBody]]"> + <span>[[syncPrefs.fullEncryptionBody]]</span> + </template> + <template is="dom-if" if="[[!syncPrefs.fullEncryptionBody]]"> + <span>$i18nRaw{encryptWithSyncPassphraseLabel}</span> + </template> </paper-radio-button> </paper-radio-group> + <div id="reset-sync-message-box" class="list-item" + hidden="[[!syncPrefs.encryptAllData]]"> + <span>$i18nRaw{passphraseResetHint}</span> + </div> </div> <template is="dom-if" if="[[creatingNewPassphrase_]]"> <div class="list-frame"> <div id="create-password-box"> - <div>$i18n{passphraseExplanationText}</div> + <div class="list-item"> + <span>$i18nRaw{passphraseExplanationText}</span> + </div> <paper-input id="passphraseInput" type="password" + value="{{passphrase_}}" placeholder="$i18n{passphrasePlaceholder}" error-message="$i18n{emptyPassphraseError}"> </paper-input> <paper-input id="passphraseConfirmationInput" type="password" + value="{{confirmation_}}" placeholder="$i18n{passphraseConfirmationPlaceholder}" error-message="$i18n{mismatchedPassphraseError}"> </paper-input> <paper-button id="saveNewPassphrase" - on-tap="onSaveNewPassphraseTap_" class="action-button"> + on-tap="onSaveNewPassphraseTap_" class="action-button" + disabled="[[!isSaveNewPassphraseEnabled_(passphrase_, + confirmation_)]]"> $i18n{save} </paper-button> </div> @@ -183,25 +212,27 @@ <template is="dom-if" if="[[syncPrefs.passphraseRequired]]"> <div class="list-frame"> - <div id="askCustomPassphraseMessage" class="list-item" - hidden$="[[!syncPrefs.passphraseTypeIsCustom]]"> - [[syncPrefs.enterPassphraseBody]] - </div> - <div id="askOldGooglePassphraseMessage" class="list-item" - hidden$="[[syncPrefs.passphraseTypeIsCustom]]"> - [[syncPrefs.enterGooglePassphraseBody]] - </div> <div class="list-item"> + <span> + [[enterPassphrasePrompt_(syncPrefs.passphraseTypeIsCustom)]] + <a href="$i18nRaw{syncErrorHelpUrl}" target="_blank"> + $i18n{learnMore} + </a> + </span> + </div> + <div id="existingPassphraseContainer" class="list-item"> <paper-input id="existingPassphraseInput" type="password" + value="{{existingPassphrase_}}" placeholder="$i18n{passphrasePlaceholder}" error-message="$i18n{incorrectPassphraseError}"> </paper-input> <paper-button id="submitExistingPassphrase" - on-tap="onSubmitExistingPassphraseTap_" class="action-button"> + on-tap="onSubmitExistingPassphraseTap_" class="action-button" + disabled="[[!existingPassphrase_]]"> $i18n{submitPassphraseButton} </paper-button> </div> - <div class="list-item"> + <div id="passphraseRecoverHint" class="list-item"> <span>$i18nRaw{passphraseRecover}</span> </div> </div> diff --git a/chromium/chrome/browser/resources/settings/people_page/sync_page.js b/chromium/chrome/browser/resources/settings/people_page/sync_page.js index 0d9a738b414..7ac0f0db0e0 100644 --- a/chromium/chrome/browser/resources/settings/people_page/sync_page.js +++ b/chromium/chrome/browser/resources/settings/people_page/sync_page.js @@ -5,7 +5,7 @@ (function() { /** - * Names of the radio buttons which allow the user to choose his encryption + * Names of the radio buttons which allow the user to choose their encryption * mechanism. * @enum {string} */ @@ -91,7 +91,7 @@ Polymer({ /** * Whether the "create passphrase" inputs should be shown. These inputs * give the user the opportunity to use a custom passphrase instead of - * authenticating with his Google credentials. + * authenticating with their Google credentials. * @private */ creatingNewPassphrase_: { @@ -99,6 +99,33 @@ Polymer({ value: false, }, + /** + * The passphrase input field value. + * @private + */ + passphrase_: { + type: String, + value: '', + }, + + /** + * The passphrase confirmation input field value. + * @private + */ + confirmation_: { + type: String, + value: '', + }, + + /** + * The existing passphrase input field value. + * @private + */ + existingPassphrase_: { + type: String, + value: '', + }, + /** @private {!settings.SyncBrowserProxy} */ browserProxy_: { type: Object, @@ -138,9 +165,6 @@ Polymer({ /** @protected */ currentRouteChanged: function() { - if (!this.isAttached) - return; - if (settings.getCurrentRoute() == settings.Route.SYNC) this.onNavigateToPage_(); else @@ -158,8 +182,6 @@ Polymer({ /** @private */ onNavigateToPage_: function() { - // The element is not ready for C++ interaction until it is attached. - assert(this.isAttached); assert(settings.getCurrentRoute() == settings.Route.SYNC); if (this.unloadCallback_) @@ -260,6 +282,16 @@ Polymer({ }, /** + * @param {string} passphrase The passphrase input field value + * @param {string} confirmation The passphrase confirmation input field value. + * @return {boolean} Whether the passphrase save button should be enabled. + * @private + */ + isSaveNewPassphraseEnabled_: function(passphrase, confirmation) { + return passphrase !== '' && confirmation !== ''; + }, + + /** * Sends the newly created custom sync passphrase to the browser. * @private */ @@ -273,7 +305,7 @@ Polymer({ this.syncPrefs.encryptAllData = true; this.syncPrefs.setNewPassphrase = true; - this.syncPrefs.passphrase = this.$$('#passphraseInput').value; + this.syncPrefs.passphrase = this.passphrase_; this.browserProxy_.setSyncEncryption(this.syncPrefs).then( this.handlePageStatusChanged_.bind(this)); @@ -288,9 +320,8 @@ Polymer({ this.syncPrefs.setNewPassphrase = false; - var existingPassphraseInput = this.$$('#existingPassphraseInput'); - this.syncPrefs.passphrase = existingPassphraseInput.value; - existingPassphraseInput.value = ''; + this.syncPrefs.passphrase = this.existingPassphrase_; + this.existingPassphrase_ = ''; this.browserProxy_.setSyncEncryption(this.syncPrefs).then( this.handlePageStatusChanged_.bind(this)); @@ -343,14 +374,14 @@ Polymer({ }, /** - * Computed binding returning the encryption text body. + * Computed binding returning text of the prompt for entering the passphrase. * @private */ - encryptWithPassphraseBody_: function() { - if (this.syncPrefs && this.syncPrefs.fullEncryptionBody) - return this.syncPrefs.fullEncryptionBody; + enterPassphrasePrompt_: function() { + if (this.syncPrefs && this.syncPrefs.passphraseTypeIsCustom) + return this.syncPrefs.enterPassphraseBody; - return this.i18n('encryptWithSyncPassphraseLabel'); + return this.syncPrefs.enterGooglePassphraseBody; }, /** @@ -374,24 +405,17 @@ Polymer({ /** * Checks the supplied passphrases to ensure that they are not empty and that - * they match each other. Additionally, displays error UI if they are - * invalid. + * they match each other. Additionally, displays error UI if they are invalid. * @return {boolean} Whether the check was successful (i.e., that the * passphrases were valid). * @private */ validateCreatedPassphrases_: function() { - var passphraseInput = this.$$('#passphraseInput'); - var passphraseConfirmationInput = this.$$('#passphraseConfirmationInput'); - - var passphrase = passphraseInput.value; - var confirmation = passphraseConfirmationInput.value; - - var emptyPassphrase = !passphrase; - var mismatchedPassphrase = passphrase != confirmation; + var emptyPassphrase = !this.passphrase_; + var mismatchedPassphrase = this.passphrase_ != this.confirmation_; - passphraseInput.invalid = emptyPassphrase; - passphraseConfirmationInput.invalid = + this.$$('#passphraseInput').invalid = emptyPassphrase; + this.$$('#passphraseConfirmationInput').invalid = !emptyPassphrase && mismatchedPassphrase; return !emptyPassphrase && !mismatchedPassphrase; diff --git a/chromium/chrome/browser/resources/settings/people_page/user_list.html b/chromium/chrome/browser/resources/settings/people_page/user_list.html index 265be7813da..4ce38d2b555 100644 --- a/chromium/chrome/browser/resources/settings/people_page/user_list.html +++ b/chromium/chrome/browser/resources/settings/people_page/user_list.html @@ -2,40 +2,51 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> +<link rel="import" href="/route.html"> <link rel="import" href="/settings_shared_css.html"> <dom-module id="settings-user-list"> <template> <style include="settings-shared"> - .soft-border { - border: 1px solid #c4c4c4; - border-radius: 2px; + .user-list { + /* 4 users (the extra 1px is to account for the border-bottom) */ + max-height: calc(4 * (var(--settings-row-two-line-min-height) + 1px)); + overflow-y: auto; } .user { - -webkit-padding-end: 8px; - -webkit-padding-start: 20px; - font-size: 0.75em; - height: 34px; + border-bottom: var(--settings-separator-line); } - .user-list { - border: 1px solid gray; - height: 160px; - overflow-y: auto; - padding: 10px 0; + .user-icon { + background-position: center; + background-repeat: no-repeat; + background-size: cover; + border-radius: 20px; + flex-shrink: 0; + height: 40px; + width: 40px; + } + + .user-info { + -webkit-padding-start: 16px; } </style> - <div class="user-list soft-border"> - <template is="dom-repeat" items="[[users]]"> - <div class="user layout horizontal justified"> - <div class="layout vertical center-justified">[[item.name]]</div> - <div class="close-button" - hidden$="[[shouldHideCloseButton_(disabled, item.isOwner)]]"> - <paper-icon-button icon="cr:clear" class="clear-icon" - on-tap="removeUser_"> - </paper-icon-button> + <div class="user-list"> + <template is="dom-repeat" items="[[users_]]"> + <div class="user layout horizontal center two-line"> + <img class="user-icon" src="[[getProfilePictureUrl_(item.name)]]"> + <div class="flex user-info"> + <div> + [[item.name]] + <span hidden="[[!item.isOwner]]">$i18n{deviceOwnerLabel}</span> + </div> + <div class="secondary">[[item.email]]</div> </div> + <paper-icon-button icon="cr:clear" class="clear-icon" + on-tap="removeUser_" + hidden="[[shouldHideCloseButton_(disabled, item.isOwner)]]"> + </paper-icon-button> </div> </template> </div> diff --git a/chromium/chrome/browser/resources/settings/people_page/user_list.js b/chromium/chrome/browser/resources/settings/people_page/user_list.js index 3fd8ce1c7a9..21f3b530596 100644 --- a/chromium/chrome/browser/resources/settings/people_page/user_list.js +++ b/chromium/chrome/browser/resources/settings/people_page/user_list.js @@ -15,12 +15,16 @@ Polymer({ is: 'settings-user-list', + behaviors: [ + settings.RouteObserverBehavior, + ], + properties: { /** * Current list of whitelisted users. - * @type {!Array<!chrome.usersPrivate.User>} + * @private {!Array<!chrome.usersPrivate.User>} */ - users: { + users_: { type: Array, value: function() { return []; }, notify: true @@ -43,15 +47,34 @@ Polymer({ prefs.forEach(function(pref) { if (pref.key == 'cros.accounts.users') { chrome.usersPrivate.getWhitelistedUsers(function(users) { - this.users = users; + this.setUsers_(users); }.bind(this)); } }, this); }.bind(this)); + }, - chrome.usersPrivate.getWhitelistedUsers(function(users) { - this.users = users; - }.bind(this)); + /** @protected */ + currentRouteChanged: function() { + if (settings.getCurrentRoute() == settings.Route.ACCOUNTS) { + chrome.usersPrivate.getWhitelistedUsers(function(users) { + this.setUsers_(users); + }.bind(this)); + } + }, + + /** + * Helper function that sorts and sets the given list of whitelisted users. + * @param {!Array<!chrome.usersPrivate.User>} users List of whitelisted users. + */ + setUsers_: function(users) { + this.users_ = users; + this.users_.sort(function(a, b) { + if (a.isOwner != b.isOwner) + return b.isOwner ? 1 : -1; + else + return -1; + }); }, /** @@ -66,5 +89,10 @@ Polymer({ /** @private */ shouldHideCloseButton_: function(disabled, isUserOwner) { return disabled || isUserOwner; + }, + + /** @private */ + getProfilePictureUrl_: function(username) { + return 'chrome://userimage/' + username + '?id=' + Date.now(); } }); diff --git a/chromium/chrome/browser/resources/settings/people_page/users_add_user_dialog.html b/chromium/chrome/browser/resources/settings/people_page/users_add_user_dialog.html index cf1a4e581a8..cc2180c3f44 100644 --- a/chromium/chrome/browser/resources/settings/people_page/users_add_user_dialog.html +++ b/chromium/chrome/browser/resources/settings/people_page/users_add_user_dialog.html @@ -7,7 +7,15 @@ <dom-module id="settings-users-add-user-dialog"> <template> - <style include="settings-shared"></style> + <style include="settings-shared"> + paper-input { + width: var(--paper-input-max-width); + --paper-input-container-focus-color: var(--google-blue-500); + --paper-input-container-input: { + font-size: inherit; + }; + } + </style> <dialog is="cr-dialog" id="dialog"> <div class="title">$i18n{addUsers}</div> <div class="body"> diff --git a/chromium/chrome/browser/resources/settings/people_page/users_page.html b/chromium/chrome/browser/resources/settings/people_page/users_page.html index 9e4ed47512e..ba9e09c8e70 100644 --- a/chromium/chrome/browser/resources/settings/people_page/users_page.html +++ b/chromium/chrome/browser/resources/settings/people_page/users_page.html @@ -1,9 +1,7 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html"> <link rel="import" href="/controls/settings_checkbox.html"> -<link rel="import" href="/settings_page/settings_section.html"> <link rel="import" href="/settings_shared_css.html"> <link rel="import" href="user_list.html"> <link rel="import" href="users_add_user_dialog.html"> @@ -15,14 +13,24 @@ /* The users box must line up with the checkbox text. */ -webkit-margin-start: 36px; } + + .settings-box:first-of-type { + border-top: none; + } + + #add-user-button { + /* Add user button must be lined up with the start of users' names. */ + -webkit-margin-start: 56px; + } </style> - <div class="settings-box" - hidden$="[[isOwnerLabelHidden_(isOwner_, isWhitelistManaged_)]]"> - $i18n{usersModifiedByOwnerLabel} - </div> - <div class="settings-box" hidden$="[[!isWhitelistManaged_]]"> - $i18n{settingsManagedLabel} - </div> + <template is="dom-if" if="[[isWhitelistManaged_]]"> + <div class="settings-box">$i18n{settingsManagedLabel}</div> + </template> + <template is="dom-if" if="[[!isWhitelistManaged_]]"> + <template is="dom-if" if="[[!isOwner_]]"> + <div class="settings-box">$i18n{usersModifiedByOwnerLabel}</div> + </template> + </template> <div class="settings-box block"> <settings-checkbox pref="{{prefs.cros.accounts.allowBWSI}}" @@ -48,12 +56,15 @@ </settings-checkbox> <div class="users"> <settings-user-list prefs="[[prefs]]" - disabled="[[isEditingUsersDisabled_(isOwner_, isWhitelistManaged_, prefs.cros.accounts.allowGuest.value)]]"> + disabled="[[isEditingUsersDisabled_(isOwner_, isWhitelistManaged_, + prefs.cros.accounts.allowGuest.value)]]"> </settings-user-list> - <paper-button on-tap="openAddUserDialog_" - disabled="[[isEditingUsersDisabled_(isOwner_, isWhitelistManaged_, prefs.cros.accounts.allowGuest.value)]]"> + <div id="add-user-button" class="list-item list-button" + on-tap="openAddUserDialog_" + hidden="[[isEditingUsersDisabled_(isOwner_, isWhitelistManaged_, + prefs.cros.accounts.allowGuest.value)]]"> $i18n{addUsers} - </paper-button> + </div> </div> </div> <settings-users-add-user-dialog id="addUserDialog"> diff --git a/chromium/chrome/browser/resources/settings/people_page/users_page.js b/chromium/chrome/browser/resources/settings/people_page/users_page.js index 44bfe426ad7..0a78794cf73 100644 --- a/chromium/chrome/browser/resources/settings/people_page/users_page.js +++ b/chromium/chrome/browser/resources/settings/people_page/users_page.js @@ -66,16 +66,6 @@ Polymer({ * @private * @return {boolean} */ - isOwnerLabelHidden_: function(isOwner, isWhitelistManaged) { - return isOwner || isWhitelistManaged; - }, - - /** - * @param {boolean} isOwner - * @param {boolean} isWhitelistManaged - * @private - * @return {boolean} - */ isEditingDisabled_: function(isOwner, isWhitelistManaged) { return !isOwner || isWhitelistManaged; }, diff --git a/chromium/chrome/browser/resources/settings/prefs/prefs.js b/chromium/chrome/browser/resources/settings/prefs/prefs.js index dd09816eb61..446c222964e 100644 --- a/chromium/chrome/browser/resources/settings/prefs/prefs.js +++ b/chromium/chrome/browser/resources/settings/prefs/prefs.js @@ -227,11 +227,16 @@ * @private */ setPrefCallback_: function(key, success) { - if (success) - return; + if (!success) + this.refresh(key); + }, - // Get the current pref value from chrome.settingsPrivate to ensure the - // UI stays up to date. + /** + * Get the current pref value from chrome.settingsPrivate to ensure the UI + * stays up to date. + * @param {string} key + */ + refresh: function(key) { this.settingsApi_.getPref(key, function(pref) { this.updatePrefs_([pref]); }.bind(this)); diff --git a/chromium/chrome/browser/resources/settings/prefs/prefs_behavior.js b/chromium/chrome/browser/resources/settings/prefs/prefs_behavior.js index 8c9446000ef..76a4399c2ea 100644 --- a/chromium/chrome/browser/resources/settings/prefs/prefs_behavior.js +++ b/chromium/chrome/browser/resources/settings/prefs/prefs_behavior.js @@ -8,6 +8,14 @@ /** @polymerBehavior */ var PrefsBehavior = { + properties: { + /** Preferences state. */ + prefs: { + type: Object, + notify: true, + }, + }, + /** * Gets the pref at the given prefPath. Throws if the pref is not found. * @param {string} prefPath diff --git a/chromium/chrome/browser/resources/settings/printing_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/printing_page/compiled_resources2.gyp index 4929165f20f..f1b675acb80 100644 --- a/chromium/chrome/browser/resources/settings/printing_page/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/settings/printing_page/compiled_resources2.gyp @@ -41,6 +41,7 @@ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior', 'cups_printers_browser_proxy', + '<(EXTERNS_GYP):networking_private', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, @@ -54,6 +55,7 @@ { 'target_name': 'cups_printers_list', 'dependencies': [ + '<(DEPTH)/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp:cr_action_menu', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:icon', 'cups_printers_browser_proxy', @@ -63,6 +65,7 @@ { 'target_name': 'printing_page', 'dependencies': [ + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', '../compiled_resources2.gyp:route', '../settings_page/compiled_resources2.gyp:settings_animated_pages', diff --git a/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html b/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html index f594c188c29..8dc379280e1 100644 --- a/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html +++ b/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.html @@ -1,12 +1,13 @@ +<link rel="import" href="chrome://resources/html/md_select_css.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-dropdown-menu/paper-dropdown-menu-light.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-input/paper-input.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-spinner/paper-spinner.html"> <link rel="import" href="/i18n_setup.html"> <link rel="import" href="/printing_page/cups_add_printer_dialog_util.html"> <link rel="import" href="/printing_page/cups_printers_browser_proxy.html"> <link rel="import" href="/settings_shared_css.html"> +<link rel="import" href="/settings_vars_css.html"> <dom-module id="add-printer-discovery-dialog"> <template> @@ -44,6 +45,7 @@ } </style> <add-printer-dialog> + <div class="dialog-title">$i18n{addPrintersNearbyTitle}</div> <div class="dialog-body"> <add-printer-list printers="[[discoveredPrinters]]" selected-printer="{{selectedPrinter}}"> @@ -75,7 +77,7 @@ <dom-module id="add-printer-maually-dialog"> <template> - <style include="settings-shared"> + <style include="settings-shared md-select"> #discoverPrintersButton { -webkit-margin-end: 153px; } @@ -132,6 +134,7 @@ } </style> <add-printer-dialog> + <div class="dialog-title">$i18n{addPrintersManuallyTitle}</div> <div class="dialog-body"> <div class="settings-box first two-line"> <div class="start"> @@ -158,29 +161,21 @@ <div class="start"> <div class="label">$i18n{printerProtocol}</div> <div class="secondary"> - <paper-dropdown-menu-light no-label-float> - <paper-listbox class="dropdown-content" - selected="{{newPrinter.printerProtocol}}" - attr-for-selected="value"> - <paper-item value="ipp"> - $i18n{printerProtocolIpp} - </paper-item> - <paper-item value="ipps"> - $i18n{printerProtocolIpps} - </paper-item> - <paper-item value="http"> - $i18n{printerProtocolHttp} - </paper-item> - <paper-item value="https"> - $i18n{printerProtocolHttps} - </paper-item> - <paper-item value="socket"> - $i18n{printerProtocolAppSocket} - </paper-item> - <paper-item value="lpd">$i18n{printerProtocolLpd}</paper-item> - <paper-item value="usb">$i18n{printerProtocolUsb}</paper-item> - </paper-listbox> - </paper-dropdown-menu-light> + <div class="md-select-wrapper"> + <select class="md-select" + value="[[newPrinter.printerProtocol]]" + on-change="onProtocolChange_"> + <option value="ipp">$i18n{printerProtocolIpp}</option> + <option value="ipps">$i18n{printerProtocolIpps}</option> + <option value="http">$i18n{printerProtocolHttp}</option> + <option value="https">$i18n{printerProtocolHttps}</option> + <option value="socket">$i18n{printerProtocolAppSocket} + </option> + <option value="lpd">$i18n{printerProtocolLpd}</option> + <option value="usb">$i18n{printerProtocolUsb}</option> + </select> + <span class="md-select-underline"></span> + </div> </div> </div> </div> @@ -206,10 +201,6 @@ </div> </div> <div class="dialog-buttons"> - <paper-button id="discoverPrintersButton" - on-tap="switchToDiscoveryDialog_"> - $i18n{discoverPrintersButtonText} - </paper-button> <paper-button class="cancel-button" on-tap="onCancelTap_"> $i18n{cancelButtonText} </paper-button> @@ -270,6 +261,7 @@ } </style> <add-printer-dialog> + <div class="dialog-title">$i18n{addPrintersManuallyTitle}</div> <div class="dialog-body"> <div class="settings-box first"> $i18n{selectManufacturerModelMessage} @@ -336,6 +328,7 @@ } </style> <add-printer-dialog> + <div class="dialog-title">[[dialogTitle]]</div> <div class="dialog-body"> <paper-spinner active></paper-spinner> <div id="configuringMessage">$i18n{printerConfiguringMessage}</div> @@ -368,7 +361,8 @@ <!-- Configuring Printer Dialog --> <template is="dom-if" if="[[showConfiguringDialog_]]" restamp> <add-printer-configuring-dialog - printer-name="[[getConfiguringPrinterName_()]]"> + printer-name="[[getConfiguringPrinterName_()]]" + dialog-title="[[configuringDialogTitle]]"> </add-printer-configuring-dialog> </template> diff --git a/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js b/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js index 43c2dee03bc..1eebf826293 100644 --- a/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js +++ b/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog.js @@ -165,6 +165,14 @@ Polymer({ // corresponding message after the API is ready. // The format of address is: ip-address-or-hostname:port-number. }, + + /** + * @param {!Event} event + * @private + */ + onProtocolChange_: function(event) { + this.newPrinter.printerProtocol = event.target.value; + }, }); Polymer({ @@ -177,12 +185,12 @@ Polymer({ notify: true, }, - /** @type {!Array<string>} */ + /** @type {?Array<string>} */ manufacturerList: { type: Array, }, - /** @type {!Array<string>} */ + /** @type {?Array<string>} */ modelList: { type: Array, }, @@ -199,13 +207,16 @@ Polymer({ /** @override */ ready: function() { - // TODO(xdai): Get available manufacturerList after the API is ready. + settings.CupsPrintersBrowserProxyImpl.getInstance(). + getCupsPrinterManufacturersList().then( + this.manufacturerListChanged_.bind(this)); }, /** @private */ - selectedManufacturerChanged_: function() { - // TODO(xdai): Get available modelList for a selected manufacturer after - // the API is ready. + selectedManufacturerChanged_: function(manufacturer) { + settings.CupsPrintersBrowserProxyImpl.getInstance(). + getCupsPrinterModelsList(manufacturer).then( + this.modelListChanged_.bind(this)); }, /** @private */ @@ -223,6 +234,24 @@ Polymer({ this.$$('paper-input').value = this.getBaseName_(path); }, + /** + * @param {!ManufacturersInfo} manufacturersInfo + * @private + */ + manufacturerListChanged_: function(manufacturersInfo) { + if (manufacturersInfo.success) + this.manufacturerList = manufacturersInfo.manufacturers; + }, + + /** + * @param {!ModelsInfo} modelsInfo + * @private + */ + modelListChanged_: function(modelsInfo) { + if (modelsInfo.success) + this.modelList = modelsInfo.models; + }, + /** @private */ switchToManualAddDialog_: function() { this.$$('add-printer-dialog').close(); @@ -255,6 +284,7 @@ Polymer({ properties: { printerName: String, + dialogTitle: String, }, /** @override */ @@ -296,6 +326,8 @@ Polymer({ value: false, }, + configuringDialogTitle: String, + /** @private {string} */ previousDialog_: String, @@ -331,7 +363,8 @@ Polymer({ /** Opens the Add printer discovery dialog. */ open: function() { this.resetData_(); - this.switchDialog_('', AddPrinterDialogs.DISCOVERY, 'showDiscoveryDialog_'); + this.switchDialog_( + '', AddPrinterDialogs.MANUALLY, 'showManuallyAddDialog_'); }, /** @@ -382,10 +415,14 @@ Polymer({ this.switchDialog_(this.currentDialog_, AddPrinterDialogs.CONFIGURING, 'showConfiguringDialog_'); if (this.previousDialog_ == AddPrinterDialogs.DISCOVERY) { + this.configuringDialogTitle = + loadTimeData.getString('addPrintersNearbyTitle'); settings.CupsPrintersBrowserProxyImpl.getInstance(). addCupsPrinter(this.selectedPrinter); } else if (this.previousDialog_ == AddPrinterDialogs.MANUALLY || this.previousDialog_ == AddPrinterDialogs.MANUFACTURER) { + this.configuringDialogTitle = + loadTimeData.getString('addPrintersManuallyTitle'); settings.CupsPrintersBrowserProxyImpl.getInstance(). addCupsPrinter(this.newPrinter); } @@ -399,10 +436,7 @@ Polymer({ /** @private */ configuringDialogClosed_: function() { - if (this.previousDialog_ == AddPrinterDialogs.DISCOVERY) { - this.switchDialog_( - this.currentDialog_, this.previousDialog_, 'showDiscoveryDialog_'); - } else if (this.previousDialog_ == AddPrinterDialogs.MANUALLY) { + if (this.previousDialog_ == AddPrinterDialogs.MANUALLY) { this.switchDialog_( this.currentDialog_, this.previousDialog_, 'showManuallyAddDialog_'); } else if (this.previousDialog_ == AddPrinterDialogs.MANUFACTURER) { diff --git a/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog_util.html b/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog_util.html index b9c3d6bcc2b..f7f458ae66d 100644 --- a/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog_util.html +++ b/chromium/chrome/browser/resources/settings/printing_page/cups_add_printer_dialog_util.html @@ -77,6 +77,10 @@ <dom-module id="add-printer-dialog"> <template> <style include="settings-shared"> + #dialog { + width: 525px; + } + #dialog .body { -webkit-padding-end: 0; -webkit-padding-start: 0; @@ -96,7 +100,9 @@ </style> <dialog is="cr-dialog" id="dialog"> - <div class="title">$i18n{addPrinterTitle}</div> + <div class="title"> + <content select=".dialog-title"></content> + </div> <div class="body"> <content select=".dialog-body"></content> </div> diff --git a/chromium/chrome/browser/resources/settings/printing_page/cups_printers.html b/chromium/chrome/browser/resources/settings/printing_page/cups_printers.html index e0708b2ff66..957f239fcc7 100644 --- a/chromium/chrome/browser/resources/settings/printing_page/cups_printers.html +++ b/chromium/chrome/browser/resources/settings/printing_page/cups_printers.html @@ -16,6 +16,15 @@ text-decoration: underline; } + .settings-box .start { + color: var(--paper-grey-500); + } + + .settings-box .start .secondary { + color: var(--paper-grey-800); + font-size: 12px; + } + #message { display: flex; justify-content: center; @@ -45,9 +54,16 @@ </style> <div class="settings-box first"> - <a is="action-link" on-tap="onAddPrinterTap_" actionable> + <a is="action-link" on-tap="onAddPrinterTap_" actionable + hidden="[[!canAddPrinter_]]"> $i18n{addCupsPrinter} </a> + <div class="start" hidden="[[canAddPrinter_]]"> + <span>$i18n{addCupsPrinter}</span> + <div class="secondary"> + $i18n{requireNetworkMessage} + </div> + </div> </div> <settings-cups-add-printer-dialog id="addPrinterDialog"> diff --git a/chromium/chrome/browser/resources/settings/printing_page/cups_printers.js b/chromium/chrome/browser/resources/settings/printing_page/cups_printers.js index 103bbb9d830..94f9bc8fd79 100644 --- a/chromium/chrome/browser/resources/settings/printing_page/cups_printers.js +++ b/chromium/chrome/browser/resources/settings/printing_page/cups_printers.js @@ -24,12 +24,59 @@ Polymer({ searchTerm: { type: String, }, + + /** @private */ + canAddPrinter_: Boolean, }, + /** + * @type {function()} + * @private + */ + networksChangedListener_: function() {}, + /** @override */ ready: function() { this.updateCupsPrintersList_(); + this.refreshNetworks_(); + }, + + /** @override */ + attached: function() { this.addWebUIListener('on-add-cups-printer', this.onAddPrinter_.bind(this)); + this.networksChangedListener_ = this.refreshNetworks_.bind(this); + chrome.networkingPrivate.onNetworksChanged.addListener( + this.networksChangedListener_); + }, + + /** @override */ + detached: function() { + chrome.networkingPrivate.onNetworksChanged.removeListener( + this.networksChangedListener_); + }, + + /** + * Callback function when networks change. + * @private + */ + refreshNetworks_: function() { + chrome.networkingPrivate.getNetworks( + {'networkType': chrome.networkingPrivate.NetworkType.ALL, + 'configured': true}, + this.onNetworksReceived_.bind(this)); + }, + + /** + * Callback function when configured networks are received. + * @param {!Array<!chrome.networkingPrivate.NetworkStateProperties>} states + * A list of network state information for each network. + * @private + */ + onNetworksReceived_: function(states) { + this.canAddPrinter_ = states.some(function(entry) { + return entry.hasOwnProperty('ConnectionState') && + entry.ConnectionState == 'Connected'; + }); }, /** diff --git a/chromium/chrome/browser/resources/settings/printing_page/cups_printers_browser_proxy.js b/chromium/chrome/browser/resources/settings/printing_page/cups_printers_browser_proxy.js index d9dd97ad594..c02a562f92b 100644 --- a/chromium/chrome/browser/resources/settings/printing_page/cups_printers_browser_proxy.js +++ b/chromium/chrome/browser/resources/settings/printing_page/cups_printers_browser_proxy.js @@ -30,6 +30,22 @@ var CupsPrinterInfo; */ var CupsPrintersList; +/** + * @typedef {{ + * success: boolean, + * manufacturers: Array<string> + * }} + */ +var ManufacturersInfo; + +/** + * @typedef {{ + * success: boolean, + * models: Array<string> + * }} + */ +var ModelsInfo; + cr.define('settings', function() { /** @interface */ function CupsPrintersBrowserProxy() {} @@ -66,6 +82,17 @@ cr.define('settings', function() { startDiscoveringPrinters: function() {}, stopDiscoveringPrinters: function() {}, + + /** + * @return {!Promise<!ManufacturersInfo>} + */ + getCupsPrinterManufacturersList: function() {}, + + /** + * @param {string} manufacturer + * @return {!Promise<!ModelsInfo>} + */ + getCupsPrinterModelsList: function(manufacturer) {}, }; /** @@ -110,6 +137,16 @@ cr.define('settings', function() { stopDiscoveringPrinters: function() { chrome.send('stopDiscoveringPrinters'); }, + + /** @override */ + getCupsPrinterManufacturersList: function() { + return cr.sendWithPromise('getCupsPrinterManufacturersList'); + }, + + /** @override */ + getCupsPrinterModelsList: function(manufacturer) { + return cr.sendWithPromise('getCupsPrinterModelsList', manufacturer); + }, }; return { diff --git a/chromium/chrome/browser/resources/settings/printing_page/cups_printers_list.html b/chromium/chrome/browser/resources/settings/printing_page/cups_printers_list.html index 077a0f47ec4..1193820a7b9 100644 --- a/chromium/chrome/browser/resources/settings/printing_page/cups_printers_list.html +++ b/chromium/chrome/browser/resources/settings/printing_page/cups_printers_list.html @@ -1,8 +1,7 @@ +<link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/html/polymer.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-dropdown/iron-dropdown.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html"> <link rel="import" href="/printing_page/cups_printers_browser_proxy.html"> <link rel="import" href="/settings_shared_css.html"> @@ -23,33 +22,25 @@ .list-item { min-height: 20px; } - - iron-dropdown { - width: 120px; - } </style> - <template is="dom-repeat" items="{{printers}}" + <dialog is="cr-action-menu"> + <button class="dropdown-item" role="option" on-tap="onDetailsTap_"> + $i18n{cupsPrinterDetails} + </button> + <button class="dropdown-item" role="option" on-tap="onRemoveTap_"> + $i18n{removePrinter} + </button> + </dialog> + <template is="dom-repeat" items="[[printers]]" filter="[[filterPrinter_(searchTerm)]]"> <div id="container" class="list-item"> <div class="name-column"> <span class="name" id="printer-name">[[item.printerName]]</span> <!--TODO(xdai): Add icon for enterprise CUPS printer. --> </div> - <paper-icon-button icon="cr:more-vert" toggles - active="{{item.menuOpened}}"> + <paper-icon-button icon="cr:more-vert" on-tap="onOpenActionMenuTap_"> </paper-icon-button> - <iron-dropdown opened="{{item.menuOpened}}" horizontal-align="right" - vertical-align="top" horizontal-offset="15" vertical-offset="5"> - <div class="dropdown-content"> - <paper-item on-tap="onDetailsTap_"> - $i18n{cupsPrinterDetails} - </paper-item> - <paper-item on-tap="onRemoveTap_"> - $i18n{removePrinter} - </paper-item> - <div> - </iron-dropdown> </div> </template> </template> diff --git a/chromium/chrome/browser/resources/settings/printing_page/cups_printers_list.js b/chromium/chrome/browser/resources/settings/printing_page/cups_printers_list.js index 6364807697e..7ce3f04513e 100644 --- a/chromium/chrome/browser/resources/settings/printing_page/cups_printers_list.js +++ b/chromium/chrome/browser/resources/settings/printing_page/cups_printers_list.js @@ -19,6 +19,12 @@ Polymer({ searchTerm: { type: String, }, + + /** + * The model for the printer action menu. + * @private {?CupsPrinterInfo} + */ + activePrinter_: Object, }, /** @private {settings.CupsPrintersBrowserProxy} */ @@ -30,14 +36,25 @@ Polymer({ }, /** + * @param {!{model: !{item: !CupsPrinterInfo}}} e + * @private + */ + onOpenActionMenuTap_: function(e) { + this.activePrinter_ = e.model.item; + var menu = /** @type {!CrActionMenuElement} */ ( + this.$$('dialog[is=cr-action-menu]')); + menu.showAt(/** @type {!Element} */ ( + Polymer.dom(/** @type {!Event} */ (e)).localTarget)); + }, + + /** * @param {{model:Object}} event * @private */ onDetailsTap_: function(event) { - this.closeDropdownMenu_(); - // Event is caught by 'settings-printing-page'. - this.fire('show-cups-printer-details', event.model.item); + this.fire('show-cups-printer-details', this.activePrinter_); + this.closeDropdownMenu_(); }, /** @@ -45,17 +62,19 @@ Polymer({ * @private */ onRemoveTap_: function(event) { - this.closeDropdownMenu_(); - - var index = this.printers.indexOf(event.model.item); + var index = this.printers.indexOf(assert(this.activePrinter_)); this.splice('printers', index, 1); - this.browserProxy_.removeCupsPrinter(event.model.item.printerId, - event.model.item.printerName); + this.browserProxy_.removeCupsPrinter(this.activePrinter_.printerId, + this.activePrinter_.printerName); + this.closeDropdownMenu_(); }, /** @private */ closeDropdownMenu_: function() { - this.$$('iron-dropdown').close(); + this.activePrinter_ = null; + var menu = /** @type {!CrActionMenuElement} */ ( + this.$$('dialog[is=cr-action-menu]')); + menu.close(); }, /** diff --git a/chromium/chrome/browser/resources/settings/printing_page/printing_page.html b/chromium/chrome/browser/resources/settings/printing_page/printing_page.html index 8d2afd76f9c..0bf5a8b61af 100644 --- a/chromium/chrome/browser/resources/settings/printing_page/printing_page.html +++ b/chromium/chrome/browser/resources/settings/printing_page/printing_page.html @@ -1,8 +1,6 @@ <link rel="import" href="chrome://resources/html/polymer.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html"> -<link rel="import" href="/icons.html"> <link rel="import" href="/printing_page/cloud_printers.html"> <link rel="import" href="/route.html"> <link rel="import" href="/settings_page/settings_animated_pages.html"> @@ -25,20 +23,20 @@ <template is="dom-if" if="[[showCupsPrintingFeatures_]]"> <div id="cupsPrinters" class="settings-box first" on-tap="onTapCupsPrinters_" actionable> - <iron-icon icon="cr:print"></iron-icon> - <div class="middle">$i18n{cupsPrintersTitle}</div> + <div class="start"> + $i18n{cupsPrintersTitle} + </div> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> </template> </if> <div id="cloudPrinters" class="settings-box two-line" on-tap="onTapCloudPrinters_" actionable> - <iron-icon icon="settings:cloud-printing"></iron-icon> - <div class="middle"> + <div class="start"> $i18n{cloudPrintersTitle} <div class="secondary">$i18n{cloudPrintersTitleDescription}</div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"> - </button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> </neon-animatable> <if expr="chromeos"> diff --git a/chromium/chrome/browser/resources/settings/privacy_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/privacy_page/compiled_resources2.gyp index c2b4372f15f..c394c9ecb4f 100644 --- a/chromium/chrome/browser/resources/settings/privacy_page/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/settings/privacy_page/compiled_resources2.gyp @@ -7,6 +7,7 @@ 'target_name': 'privacy_page_browser_proxy', 'dependencies': [ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', + '../compiled_resources2.gyp:lifetime_browser_proxy', '<(EXTERNS_GYP):chrome_send', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], @@ -19,6 +20,7 @@ '../settings_page/compiled_resources2.gyp:settings_animated_pages', '../settings_ui/compiled_resources2.gyp:settings_ui_types', '../site_settings/compiled_resources2.gyp:constants', + '../site_settings/compiled_resources2.gyp:site_data_details_subpage', 'privacy_page_browser_proxy', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], diff --git a/chromium/chrome/browser/resources/settings/privacy_page/privacy_page.html b/chromium/chrome/browser/resources/settings/privacy_page/privacy_page.html index 717ff905cf2..7d920afc81a 100644 --- a/chromium/chrome/browser/resources/settings/privacy_page/privacy_page.html +++ b/chromium/chrome/browser/resources/settings/privacy_page/privacy_page.html @@ -7,6 +7,8 @@ <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html"> <link rel="import" href="/clear_browsing_data_dialog/clear_browsing_data_dialog.html"> <link rel="import" href="/controls/settings_checkbox.html"> +<link rel="import" href="/controls/settings_toggle_button.html"> +<link rel="import" href="/lifetime_browser_proxy.html"> <link rel="import" href="/route.html"> <link rel="import" href="/settings_page/settings_animated_pages.html"> <link rel="import" href="/settings_page/settings_subpage.html"> @@ -14,7 +16,10 @@ <link rel="import" href="/site_settings/all_sites.html"> <link rel="import" href="/site_settings/constants.html"> <link rel="import" href="/site_settings/media_picker.html"> +<link rel="import" href="/site_settings/pdf_documents.html"> <link rel="import" href="/site_settings/protocol_handlers.html"> +<link rel="import" href="/site_settings/site_data_details_subpage.html"> +<link rel="import" href="/site_settings/site_settings_category.html"> <link rel="import" href="/site_settings/usb_devices.html"> <link rel="import" href="/site_settings/site_data.html"> <link rel="import" href="/site_settings/zoom_levels.html"> @@ -28,15 +33,21 @@ <dom-module id="settings-privacy-page"> <template> <style include="settings-shared"> + button[is='paper-icon-button-light'].icon-help { + background-image: url(../images/help_outline.svg); + } + /* TODO(dbeam): this is similar to a 1 line checkbox. Worth somehow * combining? */ - #metricsReporting { + #metricsReporting, + #safeBrowsingExtendedReporting { align-items: center; display: flex; - min-height: var(--settings-row-min-height); + min-height: var(--settings-row-min-height); } - #metricsReportingCheckbox { + #metricsReportingCheckbox, + #safeBrowsingExtendedReportingCheckbox { display: inline-block; } @@ -47,6 +58,11 @@ #indicator { -webkit-margin-start: var(--checkbox-spacing); } + + #restart { + flex: 1; + text-align: end; + } </style> <template is="dom-if" if="[[showClearBrowsingDataDialog_]]" restamp> <settings-clear-browsing-data-dialog prefs="{{prefs}}" @@ -73,18 +89,17 @@ label="$i18n{networkPredictionEnabled}" hidden="[[!pageVisibility.networkPrediction]]"> </settings-checkbox> - <settings-checkbox - pref="{{prefs.safebrowsing.extended_reporting_enabled}}" - label="$i18n{safeBrowsingEnableExtendedReporting}"> - </settings-checkbox> + <div id="safeBrowsingExtendedReporting"> + <paper-checkbox id="safeBrowsingExtendedReportingCheckbox" + on-tap="onSafeBrowsingExtendedReportingCheckboxTap_" + checked="[[safeBrowsingExtendedReportingEnabled_]]"> + $i18n{safeBrowsingEnableExtendedReporting} + </paper-checkbox> + </div> <settings-checkbox pref="{{prefs.safebrowsing.enabled}}" label="$i18n{safeBrowsingEnableProtection}"> </settings-checkbox> <if expr="_google_chrome"> - <settings-checkbox - pref="{{prefs.spellcheck.use_spelling_service}}" - label="$i18n{spellingPref}"> - </settings-checkbox> <if expr="chromeos"> <settings-checkbox pref="{{prefs.cros.metrics.reportingEnabled}}" @@ -106,6 +121,13 @@ $i18n{controlledSettingPolicy} </paper-tooltip> </template> + <template is="dom-if" if="[[showRestart_]]" restamp> + <div id="restart"> + <paper-button on-tap="onRestartTap_"> + $i18n{restart} + </paper-button> + </div> + </template> </div> </if><!-- not chromeos --> </if><!-- _google_chrome --> @@ -123,6 +145,17 @@ </settings-checkbox> </if> </div> +<if expr="_google_chrome"> + <div class="settings-box two-line" actionable + on-tap="onUseSpellingServiceTap_"> + <div class="start"> + $i18n{spellingPref} + <div class="secondary">$i18n{spellingDescription}</div> + </div> + <paper-toggle-button id="spellingServiceToggleButton"> + </paper-toggle-button> + </div> +</if> <if expr="use_nss_certs or is_win or is_macosx"> <div id="manageCertificates" class="settings-box two-line" actionable on-tap="onManageCertificatesTap_"> @@ -130,19 +163,17 @@ <div>$i18n{manageCertificates}</div> <div class="secondary">$i18n{manageCertificatesDescription}</div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"> - </button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> </if> <div id="site-settings-subpage-trigger" class="settings-box two-line" actionable on-tap="onSiteSettingsTap_"> <div class="start"> - <div>$i18n{siteSettings}</div> + <div>[[siteSettingsPageTitle_()]]</div> <div class="secondary">$i18n{siteSettingsDescription}</div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"> - </button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="settings-box two-line" id="clearBrowsingData" on-tap="onClearBrowsingDataTap_" actionable> @@ -150,8 +181,7 @@ $i18n{clearBrowsingData} <div class="secondary">$i18n{clearBrowsingDataDescription}</div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"> - </button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> </neon-animatable> <if expr="use_nss_certs"> @@ -164,41 +194,46 @@ </settings-subpage> </template> </if> - <template is="dom-if" route-path="/siteSettings"> + <template is="dom-if" route-path="/content"> <settings-subpage associated-control="[[$$('#site-settings-subpage-trigger')]]" id="site-settings" - page-title="$i18n{siteSettings}"> + page-title="[[siteSettingsPageTitle_()]]"> <settings-site-settings-page category-selected="{{categorySelected}}"> </settings-site-settings-page> </settings-subpage> </template> - <template is="dom-if" route-path="/siteSettings/all" no-search> + <template is="dom-if" route-path="/content/all" no-search> <settings-subpage page-title="$i18n{siteSettingsCategoryAllSites}"> <all-sites selected-site="{{selectedSite}}"></all-sites> </settings-subpage> </template> - <template is="dom-if" route-path="/siteSettings/automaticDownloads" no-search> - no-search> + <template is="dom-if" route-path="/content/automaticDownloads" no-search> <settings-subpage page-title="$i18n{siteSettingsAutomaticDownloads}"> + <button class="icon-help subpage-title-extra" + is="paper-icon-button-light" on-tap="onHelpTap_"></button> <site-settings-category selected-site="{{selectedSite}}" category="{{ContentSettingsTypes.AUTOMATIC_DOWNLOADS}}"> </site-settings-category> </settings-subpage> </template> - <template is="dom-if" route-path="/siteSettings/backgroundSync" no-search> + <template is="dom-if" route-path="/content/backgroundSync" no-search> no-search> <settings-subpage page-title="$i18n{siteSettingsBackgroundSync}"> + <button class="icon-help subpage-title-extra" + is="paper-icon-button-light" on-tap="onHelpTap_"></button> <site-settings-category selected-site="{{selectedSite}}" category="{{ContentSettingsTypes.BACKGROUND_SYNC}}"> </site-settings-category> </settings-subpage> </template> - <template is="dom-if" route-path="/siteSettings/camera" no-search> + <template is="dom-if" route-path="/content/camera" no-search> <settings-subpage page-title="$i18n{siteSettingsCategoryCamera}"> + <button class="icon-help subpage-title-extra" + is="paper-icon-button-light" on-tap="onHelpTap_"></button> <site-settings-category selected-site="{{selectedSite}}" category="{{ContentSettingsTypes.CAMERA}}"> @@ -206,66 +241,83 @@ </site-settings-category> </settings-subpage> </template> - <template is="dom-if" route-path="/siteSettings/cookies" no-search> + <template is="dom-if" route-path="/content/cookies" no-search> <settings-subpage page-title="$i18n{siteSettingsCategoryCookies}"> + <button class="icon-help subpage-title-extra" + is="paper-icon-button-light" on-tap="onHelpTap_"></button> <site-settings-category selected-site="{{selectedSite}}" category="{{ContentSettingsTypes.COOKIES}}"> <div class="settings-box cookie-controls"> - <settings-checkbox class="start" + <settings-toggle-button class="start" label="$i18n{thirdPartyCookie}" sub-label="$i18n{thirdPartyCookieSublabel}" pref="{{prefs.profile.block_third_party_cookies}}"> - </settings-checkbox> + </settings-toggle-button> </div> <site-data class="site-data"></site-data> </site-settings-category> </settings-subpage> </template> - <template is="dom-if" route-path="/siteSettings/images" no-search> + <template is="dom-if" route-path="/content/images" no-search> <settings-subpage page-title="$i18n{siteSettingsCategoryImages}"> + <button class="icon-help subpage-title-extra" + is="paper-icon-button-light" on-tap="onHelpTap_"></button> <site-settings-category selected-site="{{selectedSite}}" category="{{ContentSettingsTypes.IMAGES}}"> </site-settings-category> </settings-subpage> </template> - <template is="dom-if" route-path="/siteSettings/location" no-search> + <template is="dom-if" route-path="/content/location" no-search> <settings-subpage page-title="$i18n{siteSettingsCategoryLocation}"> + <button class="icon-help subpage-title-extra" + is="paper-icon-button-light" on-tap="onHelpTap_"></button> <site-settings-category selected-site="{{selectedSite}}" category="{{ContentSettingsTypes.GEOLOCATION}}"> </site-settings-category> </settings-subpage> </template> - <template is="dom-if" route-path="/siteSettings/handlers" no-search> + <template is="dom-if" route-path="/handlers" no-search> <settings-subpage page-title="$i18n{siteSettingsCategoryHandlers}"> <protocol-handlers></protocol-handlers> </settings-subpage> </template> - <template is="dom-if" route-path="/siteSettings/zoomLevels" no-search> + <template is="dom-if" route-path="/content/zoomLevels" no-search> <settings-subpage page-title="$i18n{siteSettingsCategoryZoomLevels}"> <zoom-levels></zoom-levels> </settings-subpage> </template> - <template is="dom-if" route-path="/siteSettings/javascript" no-search> + <template is="dom-if" route-path="/content/pdfDocuments" no-search> + <settings-subpage page-title="$i18n{siteSettingsPdfDocuments}"> + <settings-pdf-documents prefs="{{prefs}}"></settings-pdf-documents> + </settings-subpage> + </template> + <template is="dom-if" route-path="/content/javascript" no-search> <settings-subpage page-title="$i18n{siteSettingsCategoryJavascript}"> + <button class="icon-help subpage-title-extra" + is="paper-icon-button-light" on-tap="onHelpTap_"></button> <site-settings-category selected-site="{{selectedSite}}" category="{{ContentSettingsTypes.JAVASCRIPT}}"> </site-settings-category> </settings-subpage> </template> - <template is="dom-if" route-path="/siteSettings/keygen" no-search> + <template is="dom-if" route-path="/content/keygen" no-search> <settings-subpage page-title="$i18n{siteSettingsKeygen}"> + <button class="icon-help subpage-title-extra" + is="paper-icon-button-light" on-tap="onHelpTap_"></button> <site-settings-category selected-site="{{selectedSite}}" category="{{ContentSettingsTypes.KEYGEN}}"> </site-settings-category> </settings-subpage> </template> - <template is="dom-if" route-path="/siteSettings/microphone" no-search> + <template is="dom-if" route-path="/content/microphone" no-search> <settings-subpage page-title="$i18n{siteSettingsCategoryMicrophone}"> + <button class="icon-help subpage-title-extra" + is="paper-icon-button-light" on-tap="onHelpTap_"></button> <site-settings-category selected-site="{{selectedSite}}" category="{{ContentSettingsTypes.MIC}}"> @@ -273,49 +325,68 @@ </site-settings-category> </settings-subpage> </template> - <template is="dom-if" route-path="/siteSettings/notifications" no-search> + <template is="dom-if" route-path="/content/notifications" no-search> <settings-subpage page-title="$i18n{siteSettingsCategoryNotifications}"> + <button class="icon-help subpage-title-extra" + is="paper-icon-button-light" on-tap="onHelpTap_"></button> <site-settings-category selected-site="{{selectedSite}}" category="{{ContentSettingsTypes.NOTIFICATIONS}}"> </site-settings-category> </settings-subpage> </template> - <template is="dom-if" route-path="/siteSettings/flash" no-search> + <template is="dom-if" route-path="/content/flash" no-search> <settings-subpage page-title="$i18n{siteSettingsFlash}"> + <button class="icon-help subpage-title-extra" + is="paper-icon-button-light" on-tap="onHelpTap_"></button> <site-settings-category selected-site="{{selectedSite}}" category="{{ContentSettingsTypes.PLUGINS}}"> </site-settings-category> </settings-subpage> </template> - <template is="dom-if" route-path="/siteSettings/popups" no-search> + <template is="dom-if" route-path="/content/popups" no-search> <settings-subpage page-title="$i18n{siteSettingsCategoryPopups}"> + <button class="icon-help subpage-title-extra" + is="paper-icon-button-light" on-tap="onHelpTap_"></button> <site-settings-category selected-site="{{selectedSite}}" category="{{ContentSettingsTypes.POPUPS}}"> </site-settings-category> </settings-subpage> </template> - <template is="dom-if" route-path="/siteSettings/unsandboxedPlugins" no-search> + <template is="dom-if" route-path="/content/unsandboxedPlugins" no-search> <settings-subpage page-title="$i18n{siteSettingsUnsandboxedPlugins}"> + <button class="icon-help subpage-title-extra" + is="paper-icon-button-light" on-tap="onHelpTap_"></button> <site-settings-category selected-site="{{selectedSite}}" category="{{ContentSettingsTypes.UNSANDBOXED_PLUGINS}}"> </site-settings-category> </settings-subpage> </template> - <template is="dom-if" route-path="/siteSettings/usbDevices" no-search> + <template is="dom-if" route-path="/content/usbDevices" no-search> <settings-subpage page-title="$i18n{siteSettingsUsbDevices}"> <usb-devices></usb-devices> </settings-subpage> </template> - <template is="dom-if" route-path="/siteSettings/siteDetails" no-search> + <template is="dom-if" route-path="/content/siteDetails" no-search> <settings-subpage page-title="$i18n{siteSettingsSiteDetails}"> <site-details site="[[selectedSite]]"></site-details> </settings-subpage> </template> + <template is="dom-if" route-path="/cookies/detail" + no-search> + <settings-subpage page-title="[[pageTitle]]"> + <paper-button class="subpage-title-extra" + on-tap="onRemoveAllCookiesFromSite_"> + $i18n{siteSettingsCookieRemoveAll} + </paper-button> + <site-data-details-subpage page-title="{{pageTitle}}"> + </site-data-details-subpage> + </settings-subpage> + </template> </settings-animated-pages> </template> <script src="privacy_page.js"></script> -</dom-module> +</dom-module>
\ No newline at end of file diff --git a/chromium/chrome/browser/resources/settings/privacy_page/privacy_page.js b/chromium/chrome/browser/resources/settings/privacy_page/privacy_page.js index ebcbff77a4d..72dc80d4cd6 100644 --- a/chromium/chrome/browser/resources/settings/privacy_page/privacy_page.js +++ b/chromium/chrome/browser/resources/settings/privacy_page/privacy_page.js @@ -12,9 +12,7 @@ Polymer({ behaviors: [ settings.RouteObserverBehavior, -<if expr="_google_chrome and not chromeos"> WebUIListenerBehavior, -</if> ], properties: { @@ -35,15 +33,30 @@ Polymer({ <if expr="_google_chrome and not chromeos"> /** @type {MetricsReporting} */ metricsReporting_: Object, + + showRestart_: Boolean, </if> /** @private */ + safeBrowsingExtendedReportingEnabled_: Boolean, + + /** @private */ showClearBrowsingDataDialog_: Boolean, }, +<if expr="_google_chrome"> + observers: [ + 'updateSpellingService_(prefs.spellcheck.use_spelling_service.value)', + ], +</if> + ready: function() { this.ContentSettingsTypes = settings.ContentSettingsTypes; +<if expr="_google_chrome"> + this.updateSpellingService_(); +</if> + <if expr="_google_chrome and not chromeos"> var boundSetMetricsReporting = this.setMetricsReporting_.bind(this); this.addWebUIListener('metrics-reporting-change', boundSetMetricsReporting); @@ -51,6 +64,12 @@ Polymer({ var browserProxy = settings.PrivacyPageBrowserProxyImpl.getInstance(); browserProxy.getMetricsReporting().then(boundSetMetricsReporting); </if> + + var boundSetSber = this.setSafeBrowsingExtendedReporting_.bind(this); + this.addWebUIListener('safe-browsing-extended-reporting-change', + boundSetSber); + settings.PrivacyPageBrowserProxyImpl.getInstance() + .getSafeBrowsingExtendedReporting().then(boundSetSber); }, /** @protected */ @@ -70,6 +89,17 @@ Polymer({ </if> }, + /** + * This is a workaround to connect the remove all button to the subpage. + * @private + */ + onRemoveAllCookiesFromSite_: function() { + var node = /** @type {?SiteDataDetailsSubpageElement} */(this.$$( + 'site-data-details-subpage')); + if (node) + node.removeAll(); + }, + /** @private */ onSiteSettingsTap_: function() { settings.navigateTo(settings.Route.SITE_SETTINGS); @@ -85,6 +115,12 @@ Polymer({ settings.navigateToPreviousRoute(); }, + /** @private */ + onHelpTap_: function() { + window.open( + 'https://support.google.com/chrome/?p=settings_manage_exceptions'); + }, + <if expr="_google_chrome and not chromeos"> /** @private */ onMetricsReportingCheckboxTap_: function() { @@ -98,7 +134,59 @@ Polymer({ * @private */ setMetricsReporting_: function(metricsReporting) { + // TODO(dbeam): remember whether metrics reporting was enabled when Chrome + // started. + if (metricsReporting.managed) { + this.showRestart_ = false; + } else if (this.metricsReporting_ && + metricsReporting.enabled != this.metricsReporting_.enabled) { + this.showRestart_ = true; + } this.metricsReporting_ = metricsReporting; }, + + /** @private */ + onRestartTap_: function() { + settings.LifetimeBrowserProxyImpl.getInstance().restart(); + }, +</if> + + /** @private */ + onSafeBrowsingExtendedReportingCheckboxTap_: function() { + var browserProxy = settings.PrivacyPageBrowserProxyImpl.getInstance(); + var enabled = this.$.safeBrowsingExtendedReportingCheckbox.checked; + browserProxy.setSafeBrowsingExtendedReportingEnabled(enabled); + }, + + /** @param {boolean} enabled Whether reporting is enabled or not. + * @private + */ + setSafeBrowsingExtendedReporting_: function(enabled) { + this.safeBrowsingExtendedReportingEnabled_ = enabled; + }, + +<if expr="_google_chrome"> + /** @private */ + updateSpellingService_: function() { + this.$.spellingServiceToggleButton.checked = + this.get('prefs.spellcheck.use_spelling_service.value'); + }, + + /** @private */ + onUseSpellingServiceTap_: function() { + this.set('prefs.spellcheck.use_spelling_service.value', + this.$.spellingServiceToggleButton.checked); + }, </if> + + /** + * The sub-page title for the site or content settings. + * @return {string} + * @private + */ + siteSettingsPageTitle_: function() { + return loadTimeData.getBoolean('enableSiteSettings') ? + loadTimeData.getString('siteSettings') : + loadTimeData.getString('contentSettings'); + }, }); diff --git a/chromium/chrome/browser/resources/settings/privacy_page/privacy_page_browser_proxy.js b/chromium/chrome/browser/resources/settings/privacy_page/privacy_page_browser_proxy.js index 54975912315..a630f7423b1 100644 --- a/chromium/chrome/browser/resources/settings/privacy_page/privacy_page_browser_proxy.js +++ b/chromium/chrome/browser/resources/settings/privacy_page/privacy_page_browser_proxy.js @@ -24,6 +24,12 @@ cr.define('settings', function() { /** Invokes the native certificate manager (used by win and mac). */ showManageSSLCertificates: function() {}, </if> + + /** @return {!Promise<boolean>} */ + getSafeBrowsingExtendedReporting: assertNotReached, + + /** @param {boolean} enabled */ + setSafeBrowsingExtendedReportingEnabled: assertNotReached, }; /** @@ -46,6 +52,16 @@ cr.define('settings', function() { }, </if> + /** @override */ + getSafeBrowsingExtendedReporting: function() { + return cr.sendWithPromise('getSafeBrowsingExtendedReporting'); + }, + + /** @override */ + setSafeBrowsingExtendedReportingEnabled: function(enabled) { + chrome.send('setSafeBrowsingExtendedReportingEnabled', [enabled]); + }, + <if expr="is_win or is_macosx"> /** @override */ showManageSSLCertificates: function() { diff --git a/chromium/chrome/browser/resources/settings/reset_page/powerwash_dialog.html b/chromium/chrome/browser/resources/settings/reset_page/powerwash_dialog.html index 5f9ed425de7..633807f48ad 100644 --- a/chromium/chrome/browser/resources/settings/reset_page/powerwash_dialog.html +++ b/chromium/chrome/browser/resources/settings/reset_page/powerwash_dialog.html @@ -2,7 +2,6 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/classes/iron-flex-layout.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html"> <link rel="import" href="/lifetime_browser_proxy.html"> <link rel="import" href="/reset_page/reset_browser_proxy.html"> <link rel="import" href="/settings_shared_css.html"> diff --git a/chromium/chrome/browser/resources/settings/reset_page/reset_browser_proxy.js b/chromium/chrome/browser/resources/settings/reset_page/reset_browser_proxy.js index 6c81d8bb301..96817a8f483 100644 --- a/chromium/chrome/browser/resources/settings/reset_page/reset_browser_proxy.js +++ b/chromium/chrome/browser/resources/settings/reset_page/reset_browser_proxy.js @@ -10,9 +10,10 @@ cr.define('settings', function() { /** * @param {boolean} sendSettings Whether the user gave consent to upload * broken settings to Google for analysis. + * @param {string} requestOrigin The origin of the reset request. * @return {!Promise} A promise firing once resetting has completed. */ - performResetProfileSettings: function(sendSettings) {}, + performResetProfileSettings: function(sendSettings, requestOrigin) {}, /** * A method to be called when the reset profile dialog is hidden. @@ -35,6 +36,13 @@ cr.define('settings', function() { */ showReportedSettings: function() {}, + /** + * Retrieves the triggered reset tool name. + * @return {!Promise<string>} A promise firing with the tool name, once it + * has been retrieved. + */ + getTriggeredResetToolName: function() {}, + <if expr="chromeos"> /** * A method to be called when the reset powerwash dialog is shown. @@ -57,8 +65,9 @@ cr.define('settings', function() { ResetBrowserProxyImpl.prototype = { /** @override */ - performResetProfileSettings: function(sendSettings) { - return cr.sendWithPromise('performResetProfileSettings', sendSettings); + performResetProfileSettings: function(sendSettings, requestOrigin) { + return cr.sendWithPromise('performResetProfileSettings', + sendSettings, requestOrigin); }, /** @override */ @@ -90,6 +99,11 @@ cr.define('settings', function() { }); }, + /** @override */ + getTriggeredResetToolName: function() { + return cr.sendWithPromise('getTriggeredResetToolName'); + }, + <if expr="chromeos"> /** @override */ onPowerwashDialogShow: function() { diff --git a/chromium/chrome/browser/resources/settings/reset_page/reset_page.html b/chromium/chrome/browser/resources/settings/reset_page/reset_page.html index ccf84b5384e..2333b124110 100644 --- a/chromium/chrome/browser/resources/settings/reset_page/reset_page.html +++ b/chromium/chrome/browser/resources/settings/reset_page/reset_page.html @@ -19,9 +19,9 @@ <div>$i18n{resetPageTitle}</div> <div class="secondary">$i18n{resetPageDescription}</div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> - <template is="cr-lazy-render" id="resetProfileDialog"> + <template is="dom-if" if="[[showResetProfileDialog_]]" restamp> <settings-reset-profile-dialog on-close="onResetProfileDialogClose_"> </settings-reset-profile-dialog> </template> @@ -32,7 +32,7 @@ <div>$i18n{powerwashTitle}</div> <div class="secondary">$i18n{powerwashDescription}</div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <template is="dom-if" if="[[showPowerwashDialog_]]" restamp> <settings-powerwash-dialog on-close="onPowerwashDialogClose_"> diff --git a/chromium/chrome/browser/resources/settings/reset_page/reset_page.js b/chromium/chrome/browser/resources/settings/reset_page/reset_page.js index a33fe549942..dc69d704721 100644 --- a/chromium/chrome/browser/resources/settings/reset_page/reset_page.js +++ b/chromium/chrome/browser/resources/settings/reset_page/reset_page.js @@ -31,18 +31,29 @@ Polymer({ type: Boolean, value: cr.isChromeOS ? loadTimeData.getBoolean('allowPowerwash') : false }, + + /** @private */ + showResetProfileDialog_: { + type: Boolean, + value: false, + }, }, - /** @protected */ - currentRouteChanged: function() { - if (settings.getCurrentRoute() == settings.Route.RESET_DIALOG) { - this.$.resetProfileDialog.get().open(); - } + /** + * settings.RouteObserverBehavior + * @param {!settings.Route} route + * @protected + */ + currentRouteChanged: function(route) { + this.showResetProfileDialog_ = + route == settings.Route.TRIGGERED_RESET_DIALOG || + route == settings.Route.RESET_DIALOG; }, /** @private */ onShowResetProfileDialog_: function() { - settings.navigateTo(settings.Route.RESET_DIALOG); + settings.navigateTo(settings.Route.RESET_DIALOG, + new URLSearchParams('origin=userclick')); }, /** @private */ diff --git a/chromium/chrome/browser/resources/settings/reset_page/reset_profile_banner.html b/chromium/chrome/browser/resources/settings/reset_page/reset_profile_banner.html index a42aa4f9d98..75ea93c2bff 100644 --- a/chromium/chrome/browser/resources/settings/reset_page/reset_profile_banner.html +++ b/chromium/chrome/browser/resources/settings/reset_page/reset_profile_banner.html @@ -64,8 +64,8 @@ </paper-button> </div> </div> - <template is="dom-if" if="[[showResetProfileDialog_]]"> - <settings-reset-profile-dialog on-reset-done="onResetDone_"> + <template is="dom-if" if="[[showResetProfileDialog_]]" restamp> + <settings-reset-profile-dialog on-close="onDialogClose_"> </settings-reset-profile-dialog> </template> </template> diff --git a/chromium/chrome/browser/resources/settings/reset_page/reset_profile_banner.js b/chromium/chrome/browser/resources/settings/reset_page/reset_profile_banner.js index 4c5aa929d08..4ce02ea192b 100644 --- a/chromium/chrome/browser/resources/settings/reset_page/reset_profile_banner.js +++ b/chromium/chrome/browser/resources/settings/reset_page/reset_profile_banner.js @@ -24,18 +24,15 @@ Polymer({ }, /** - * Creates and shows a <settings-reset-profile-dialog>. + * Shows a <settings-reset-profile-dialog>. * @private */ - showDialog_: function(dialogName) { + showDialog_: function() { this.showResetProfileDialog_ = true; - this.async(function() { - var dialog = this.$$('settings-reset-profile-dialog'); - dialog.open(); - }.bind(this)); }, - onResetDone_: function() { + /** @private */ + onDialogClose_: function() { this.showResetProfileDialog_ = false; }, }); diff --git a/chromium/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html b/chromium/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html index 79b5fdc552f..bb3e049d952 100644 --- a/chromium/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html +++ b/chromium/chrome/browser/resources/settings/reset_page/reset_profile_dialog.html @@ -23,11 +23,13 @@ margin: 0 8px; } </style> - <dialog is="cr-dialog" id="dialog"> - <div class="title">$i18n{resetPageTitle}</div> + <dialog is="cr-dialog" id="dialog" ignore-popstate> + <div class="title"> + [[getPageTitle_(isTriggered_, triggeredResetToolName_)]] + </div> <div class="body"> <span> - $i18n{resetPageExplanation} + [[getExplanationText_(isTriggered_, triggeredResetToolName_)]] <a href="$i18nRaw{resetPageLearnMoreUrl}" target="_blank"> $i18n{learnMore} </a> diff --git a/chromium/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js b/chromium/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js index b82b347793f..5e89ad531d5 100644 --- a/chromium/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js +++ b/chromium/chrome/browser/resources/settings/reset_page/reset_profile_dialog.js @@ -4,8 +4,11 @@ /** * @fileoverview + * * 'settings-reset-profile-dialog' is the dialog shown for clearing profile - * settings. + * settings. A triggered variant of this dialog can be shown under certain + * circumstances. See triggered_profile_resetter.h for when the triggered + * variant will be used. */ Polymer({ is: 'settings-reset-profile-dialog', @@ -15,6 +18,22 @@ Polymer({ properties: { // TODO(dpapad): Evaluate whether this needs to be synced across different // settings tabs. + + /** @private */ + isTriggered_: { + type: Boolean, + value: false, + }, + + /** @private */ + triggeredResetToolName_: { + type: String, + value: '', + }, + + /** @private */ + resetRequestOrigin_: String, + /** @private */ clearingInProgress_: { type: Boolean, @@ -25,6 +44,30 @@ Polymer({ /** @private {!settings.ResetBrowserProxy} */ browserProxy_: null, + /** + * @private + * @return {string} + */ + getExplanationText_: function() { + if (this.isTriggered_) { + return loadTimeData.getStringF('triggeredResetPageExplanation', + this.triggeredResetToolName_); + } + return loadTimeData.getStringF('resetPageExplanation'); + }, + + /** + * @private + * @return {string} + */ + getPageTitle_: function() { + if (this.isTriggered_) { + return loadTimeData.getStringF('triggeredResetPageTitle', + this.triggeredResetToolName_); + } + return loadTimeData.getStringF('resetPageTitle'); + }, + /** @override */ ready: function() { this.browserProxy_ = settings.ResetBrowserProxyImpl.getInstance(); @@ -34,11 +77,33 @@ Polymer({ }.bind(this)); }, - open: function() { + /** @private */ + showDialog_: function() { this.$.dialog.showModal(); this.browserProxy_.onShowResetProfileDialog(); }, + /** @override */ + attached: function() { + this.isTriggered_ = + settings.getCurrentRoute() == settings.Route.TRIGGERED_RESET_DIALOG; + if (this.isTriggered_) { + this.browserProxy_.getTriggeredResetToolName().then(function(name) { + this.resetRequestOrigin_ = 'triggeredreset'; + this.triggeredResetToolName_ = name; + this.showDialog_(); + }.bind(this)); + } else { + // For the non-triggered reset dialog, a '#cct' hash indicates that the + // reset request came from the Chrome Cleanup Tool by launching Chrome + // with the startup URL chrome://settings/resetProfileSettings#cct. + var origin = window.location.hash.slice(1).toLowerCase() == 'cct' ? + 'cct' : settings.getQueryParameters().get('origin'); + this.resetRequestOrigin_ = origin || ''; + this.showDialog_(); + } + }, + /** @private */ onCancelTap_: function() { this.$.dialog.cancel(); @@ -48,7 +113,7 @@ Polymer({ onResetTap_: function() { this.clearingInProgress_ = true; this.browserProxy_.performResetProfileSettings( - this.$.sendSettings.checked).then(function() { + this.$.sendSettings.checked, this.resetRequestOrigin_).then(function() { this.clearingInProgress_ = false; if (this.$.dialog.open) this.$.dialog.close(); diff --git a/chromium/chrome/browser/resources/settings/route.js b/chromium/chrome/browser/resources/settings/route.js index e5e1b39887d..082a46d3015 100644 --- a/chromium/chrome/browser/resources/settings/route.js +++ b/chromium/chrome/browser/resources/settings/route.js @@ -93,9 +93,12 @@ cr.define('settings', function() { // Navigable dialogs. These are the only non-section children of root pages. // These are disfavored. If we add anymore, we should add explicit support. + r.IMPORT_DATA = r.BASIC.createChild('/importData'); r.SIGN_OUT = r.BASIC.createChild('/signOut'); r.CLEAR_BROWSER_DATA = r.ADVANCED.createChild('/clearBrowserData'); r.RESET_DIALOG = r.ADVANCED.createChild('/resetProfileSettings'); + r.TRIGGERED_RESET_DIALOG = + r.ADVANCED.createChild('/triggeredResetProfileSettings'); <if expr="chromeos"> r.INTERNET = r.BASIC.createSection('/internet', 'internet'); @@ -135,12 +138,12 @@ cr.define('settings', function() { r.PRIVACY = r.ADVANCED.createSection('/privacy', 'privacy'); r.CERTIFICATES = r.PRIVACY.createChild('/certificates'); - r.SITE_SETTINGS = r.PRIVACY.createChild('/siteSettings'); + r.SITE_SETTINGS = r.PRIVACY.createChild('/content'); r.SITE_SETTINGS_ALL = r.SITE_SETTINGS.createChild('all'); r.SITE_SETTINGS_SITE_DETAILS = - r.SITE_SETTINGS_ALL.createChild('/siteSettings/siteDetails'); + r.SITE_SETTINGS_ALL.createChild('/content/siteDetails'); - r.SITE_SETTINGS_HANDLERS = r.SITE_SETTINGS.createChild('handlers'); + r.SITE_SETTINGS_HANDLERS = r.SITE_SETTINGS.createChild('/handlers'); // TODO(tommycli): Find a way to refactor these repetitive category routes. r.SITE_SETTINGS_AUTOMATIC_DOWNLOADS = @@ -149,6 +152,8 @@ cr.define('settings', function() { r.SITE_SETTINGS.createChild('backgroundSync'); r.SITE_SETTINGS_CAMERA = r.SITE_SETTINGS.createChild('camera'); r.SITE_SETTINGS_COOKIES = r.SITE_SETTINGS.createChild('cookies'); + r.SITE_SETTINGS_DATA_DETAILS = + r.SITE_SETTINGS_COOKIES.createChild('/cookies/detail'); r.SITE_SETTINGS_IMAGES = r.SITE_SETTINGS.createChild('images'); r.SITE_SETTINGS_JAVASCRIPT = r.SITE_SETTINGS.createChild('javascript'); r.SITE_SETTINGS_KEYGEN = r.SITE_SETTINGS.createChild('keygen'); @@ -161,22 +166,19 @@ cr.define('settings', function() { r.SITE_SETTINGS.createChild('unsandboxedPlugins'); r.SITE_SETTINGS_USB_DEVICES = r.SITE_SETTINGS.createChild('usbDevices'); r.SITE_SETTINGS_ZOOM_LEVELS = r.SITE_SETTINGS.createChild('zoomLevels'); + r.SITE_SETTINGS_PDF_DOCUMENTS = r.SITE_SETTINGS.createChild('pdfDocuments'); <if expr="chromeos"> r.DATETIME = r.ADVANCED.createSection('/dateTime', 'dateTime'); - r.BLUETOOTH = r.ADVANCED.createSection('/bluetooth', 'bluetooth'); - r.BLUETOOTH_ADD_DEVICE = r.BLUETOOTH.createChild('/bluetoothAddDevice'); - r.BLUETOOTH_PAIR_DEVICE = - r.BLUETOOTH_ADD_DEVICE.createChild('bluetoothPairDevice'); </if> - r.PASSWORDS = r.ADVANCED.createSection('/passwords', 'passwordsAndForms'); + r.PASSWORDS = + r.ADVANCED.createSection('/passwordsAndForms', 'passwordsAndForms'); r.AUTOFILL = r.PASSWORDS.createChild('/autofill'); - r.MANAGE_PASSWORDS = r.PASSWORDS.createChild('/managePasswords'); + r.MANAGE_PASSWORDS = r.PASSWORDS.createChild('/passwords'); r.LANGUAGES = r.ADVANCED.createSection('/languages', 'languages'); - r.LANGUAGES_DETAIL = r.LANGUAGES.createChild('edit'); <if expr="chromeos"> r.INPUT_METHODS = r.LANGUAGES.createChild('/inputMethods'); </if> @@ -184,7 +186,7 @@ cr.define('settings', function() { r.EDIT_DICTIONARY = r.LANGUAGES.createChild('/editDictionary'); </if> - r.DOWNLOADS = r.ADVANCED.createSection('/downloadsDirectory', 'downloads'); + r.DOWNLOADS = r.ADVANCED.createSection('/downloads', 'downloads'); r.PRINTING = r.ADVANCED.createSection('/printing', 'printing'); r.CLOUD_PRINTERS = r.PRINTING.createChild('/cloudPrinters'); @@ -225,8 +227,14 @@ cr.define('settings', function() { assert(routeObservers_.delete(this)); }, - /** @abstract */ - currentRouteChanged: assertNotReached, + /** + * @param {!settings.Route|undefined} opt_newRoute + * @param {!settings.Route|undefined} opt_oldRoute + * @abstract + */ + currentRouteChanged: function(opt_newRoute, opt_oldRoute) { + assertNotReached(); + }, }; /** @@ -312,17 +320,24 @@ cr.define('settings', function() { * Navigates to a canonical route and pushes a new history entry. * @param {!settings.Route} route * @param {URLSearchParams=} opt_dynamicParameters Navigations to the same - * search parameters in a different order will still push to history. + * URL parameters in a different order will still push to history. + * @param {boolean=} opt_removeSearch Whether to strip the 'search' URL + * parameter during navigation. Defaults to false. */ - var navigateTo = function(route, opt_dynamicParameters) { + var navigateTo = function(route, opt_dynamicParameters, opt_removeSearch) { var params = opt_dynamicParameters || new URLSearchParams(); + var removeSearch = !!opt_removeSearch; + + var oldSearchParam = getQueryParameters().get('search') || ''; + var newSearchParam = params.get('search') || ''; + + if (!removeSearch && oldSearchParam && !newSearchParam) + params.append('search', oldSearchParam); var url = route.path; - if (opt_dynamicParameters) { - var queryString = opt_dynamicParameters.toString(); - if (queryString) - url += '?' + queryString; - } + var queryString = params.toString(); + if (queryString) + url += '?' + queryString; // History serializes the state, so we don't push the actual route object. window.history.pushState(currentRoute_.path, '', url); diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/search_engines_page/compiled_resources2.gyp index cf9a8e5d120..dc139913e64 100644 --- a/chromium/chrome/browser/resources/settings/search_engines_page/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/settings/search_engines_page/compiled_resources2.gyp @@ -15,6 +15,8 @@ { 'target_name': 'search_engine_entry', 'dependencies': [ + '<(DEPTH)/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp:cr_action_menu', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:icon', 'search_engines_browser_proxy', @@ -22,6 +24,18 @@ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, { + 'target_name': 'omnibox_extension_entry', + 'dependencies': [ + '<(DEPTH)/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp:cr_action_menu', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:icon', + '../compiled_resources2.gyp:extension_control_browser_proxy', + 'search_engines_browser_proxy', + ], + 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + { 'target_name': 'search_engines_browser_proxy', 'dependencies': [ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', @@ -32,7 +46,7 @@ { 'target_name': 'search_engines_list', 'dependencies': [ - '<(DEPTH)/ui/webui/resources/cr_elements/compiled_resources2.gyp:cr_scrollable_behavior', + '../compiled_resources2.gyp:global_scroll_target_behavior', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', 'search_engines_browser_proxy', ], diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.html b/chromium/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.html index 0a08f0c58fc..939da76668f 100644 --- a/chromium/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.html +++ b/chromium/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.html @@ -1,15 +1,15 @@ +<link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/html/icon.html"> -<link rel="import" href="/search_engines_page/search_engines_browser_proxy.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-dropdown/iron-dropdown.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> +<link rel="import" href="/extension_control_browser_proxy.html"> +<link rel="import" href="/search_engines_page/search_engine_entry_css.html"> <link rel="import" href="/settings_shared_css.html"> <dom-module id="settings-omnibox-extension-entry"> - <link rel="import" type="css" href="/search_engines_page/search_engine_entry.css"> <template> - <style include="settings-shared"> + <style include="settings-shared search-engine-entry"> .name-column { flex: 3; } @@ -25,22 +25,19 @@ <span class="name">[[engine.displayName]]</span> </div> <div class="keyword-column">[[engine.keyword]]</div> - <paper-icon-button icon="cr:more-vert" toggles tabindex$="[[tabindex]]" - active="{{editMenuOpened}}"> + <paper-icon-button icon="cr:more-vert" tabindex$="[[tabindex]]" + on-tap="onDotsTap_"> </paper-icon-button> - <iron-dropdown opened="{{editMenuOpened}}" horizontal-align="right" - vertical-align="auto"> - <div class="dropdown-content"> - <button class="dropdown-item" role="option" on-tap="onManageTap_" - id="manage"> - $i18n{searchEnginesManageExtension} - </button> - <button class="dropdown-item" role="option" on-tap="onDisableTap_" - id="disable"> - $i18n{disable} - </button> - <div> - </iron-dropdown> + <dialog is="cr-action-menu"> + <button class="dropdown-item" role="option" on-tap="onManageTap_" + id="manage"> + $i18n{searchEnginesManageExtension} + </button> + <button class="dropdown-item" role="option" on-tap="onDisableTap_" + id="disable"> + $i18n{disable} + </button> + </dialog> </div> </template> <script src="omnibox_extension_entry.js"></script> diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.js b/chromium/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.js index 0ed0c9f5cd1..30600fd9666 100644 --- a/chromium/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.js +++ b/chromium/chrome/browser/resources/settings/search_engines_page/omnibox_extension_entry.js @@ -13,13 +13,14 @@ Polymer({ /** @type {!SearchEngine} */ engine: Object, - /** @private {!settings.SearchEnginesBrowserProxy} */ + /** @private {!settings.ExtensionControlBrowserProxy} */ browserProxy_: Object, }, /** @override */ created: function() { - this.browserProxy_ = settings.SearchEnginesBrowserProxyImpl.getInstance(); + this.browserProxy_ = + settings.ExtensionControlBrowserProxyImpl.getInstance(); }, /** @private */ @@ -36,7 +37,7 @@ Polymer({ /** @private */ closePopupMenu_: function() { - this.$$('iron-dropdown').close(); + this.$$('dialog[is=cr-action-menu]').close(); }, /** @@ -47,4 +48,11 @@ Polymer({ getIconSet_: function(url) { return cr.icon.getFavicon(url); }, + + /** @private */ + onDotsTap_: function() { + /** @type {!CrActionMenuElement} */ ( + this.$$('dialog[is=cr-action-menu]')).showAt( + assert(this.$$('paper-icon-button'))); + }, }); diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_entry.css b/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_entry.css deleted file mode 100644 index 06a8d0c5238..00000000000 --- a/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_entry.css +++ /dev/null @@ -1,26 +0,0 @@ -/* Copyright (c) 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. */ - -.favicon-image { - -webkit-margin-end: 8px; - background-repeat: no-repeat; - background-size: contain; - display: inline-block; - height: 20px; - vertical-align: middle; - width: 20px; -} - -.name { - margin: auto; -} - -.dropdown-content { - background: white; - box-shadow: 0 2px 6px grey; -} - -paper-icon-button { - -webkit-padding-end: 0; -} diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html b/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html index e467d92a89a..81130ec9cf3 100644 --- a/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html +++ b/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_entry.html @@ -1,17 +1,16 @@ +<link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/html/icon.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-dropdown/iron-dropdown.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> <link rel="import" href="/search_engines_page/search_engine_dialog.html"> +<link rel="import" href="/search_engines_page/search_engine_entry_css.html"> <link rel="import" href="/search_engines_page/search_engines_browser_proxy.html"> <link rel="import" href="/settings_shared_css.html"> <dom-module id="settings-search-engine-entry"> - <link rel="import" type="css" href="/search_engines_page/search_engine_entry.css"> <template> - <style include="settings-shared"></style> - <style> + <style include="settings-shared search-engine-entry"> :host([is-default]) { font-weight: 500; } @@ -41,24 +40,21 @@ </div> <div class="keyword-column">[[engine.keyword]]</div> <div class="url-column">[[engine.url]]</div> - <paper-icon-button icon="cr:more-vert" toggles tabindex$="[[tabindex]]" - active="{{editMenuOpened}}"> + <paper-icon-button icon="cr:more-vert" tabindex$="[[tabindex]]" + on-tap="onDotsTap_"> </paper-icon-button> - <iron-dropdown opened="{{editMenuOpened}}" horizontal-align="right" - vertical-align="auto"> - <div class="dropdown-content"> - <button class="dropdown-item" role="option" on-tap="onMakeDefaultTap_" - hidden$="[[!engine.canBeDefault]]" id="makeDefault"> - $i18n{searchEnginesMakeDefault} - </button> - <button class="dropdown-item" role="option" on-tap="onEditTap_" - hidden$="[[!engine.canBeEdited]]" - id="edit">$i18n{searchEnginesEdit}</button> - <button class="dropdown-item" role="option" on-tap="onDeleteTap_" - hidden$="[[!engine.canBeRemoved]]" - id="delete">$i18n{searchEnginesRemoveFromList}</button> - <div> - </iron-dropdown> + <dialog is="cr-action-menu"> + <button class="dropdown-item" role="option" on-tap="onMakeDefaultTap_" + hidden$="[[!engine.canBeDefault]]" id="makeDefault"> + $i18n{searchEnginesMakeDefault} + </button> + <button class="dropdown-item" role="option" on-tap="onEditTap_" + hidden$="[[!engine.canBeEdited]]" + id="edit">$i18n{searchEnginesEdit}</button> + <button class="dropdown-item" role="option" on-tap="onDeleteTap_" + hidden$="[[!engine.canBeRemoved]]" + id="delete">$i18n{searchEnginesRemoveFromList}</button> + </dialog> </div> </template> <script src="search_engine_entry.js"></script> diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_entry.js b/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_entry.js index 5a33a8757e3..12f7d82c85e 100644 --- a/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_entry.js +++ b/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_entry.js @@ -43,6 +43,7 @@ Polymer({ /** @private */ onDeleteTap_: function() { this.browserProxy_.removeSearchEngine(this.engine.modelIndex); + this.closePopupMenu_(); }, /** @private */ @@ -69,7 +70,7 @@ Polymer({ /** @private */ closePopupMenu_: function() { - this.$$('iron-dropdown').close(); + this.$$('dialog[is=cr-action-menu]').close(); }, /** @@ -81,4 +82,11 @@ Polymer({ // Force default icon, if no |engine.iconURL| is available. return cr.icon.getFavicon(url || ''); }, + + /** @private */ + onDotsTap_: function() { + /** @type {!CrActionMenuElement} */ ( + this.$$('dialog[is=cr-action-menu]')).showAt( + assert(this.$$('paper-icon-button'))); + }, }); diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_entry_css.html b/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_entry_css.html new file mode 100644 index 00000000000..70ad7660430 --- /dev/null +++ b/chromium/chrome/browser/resources/settings/search_engines_page/search_engine_entry_css.html @@ -0,0 +1,24 @@ +<dom-module id="search-engine-entry"> + <template> + <style> + .favicon-image { + -webkit-margin-end: 8px; + background-repeat: no-repeat; + background-size: contain; + display: inline-block; + height: 20px; + vertical-align: middle; + width: 20px; + } + + .name { + margin: auto; + } + + .dropdown-content { + background: white; + box-shadow: 0 2px 6px grey; + } + </style> + </template> +</dom-module> diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.js b/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.js index b70692a6090..1590c1f608a 100644 --- a/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.js +++ b/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_browser_proxy.js @@ -68,12 +68,6 @@ cr.define('settings', function() { * @return {!Promise<boolean>} */ validateSearchEngineInput: function(fieldName, fieldValue) {}, - - /** @param {string} extensionId */ - disableExtension: function(extensionId) {}, - - /** @param {string} extensionId */ - manageExtension: function(extensionId) {}, }; /** @@ -123,16 +117,6 @@ cr.define('settings', function() { return cr.sendWithPromise( 'validateSearchEngineInput', fieldName, fieldValue); }, - - /** @override */ - disableExtension: function(extensionId) { - chrome.send('disableExtension', [extensionId]); - }, - - /** @override */ - manageExtension: function(extensionId) { - window.open('chrome://extensions?id=' + extensionId); - }, }; return { diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_list.html b/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_list.html index a1c3ea5462a..469207deaa2 100644 --- a/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_list.html +++ b/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_list.html @@ -1,7 +1,7 @@ -<link rel="import" href="chrome://resources/cr_elements/cr_scrollable_behavior.html"> <link rel="import" href="chrome://resources/cr_elements/shared_style_css.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-list/iron-list.html"> +<link rel="import" href="/global_scroll_target_behavior.html"> <link rel="import" href="/search_engines_page/search_engine_entry.html"> <dom-module id="settings-search-engines-list"> @@ -35,8 +35,8 @@ </style> <div id="outer"> <content></content> - <div id="container" class="scroll-container" scrollable> - <iron-list items="[[engines]]" scroll-target="container"> + <div id="container" class="scroll-container"> + <iron-list items="[[engines]]" scroll-target="[[scrollTarget]]"> <template> <settings-search-engine-entry engine="[[item]]" tabindex$="[[tabIndex]]"> diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_list.js b/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_list.js index 2bb7f3bd50c..741164fd33c 100644 --- a/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_list.js +++ b/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_list.js @@ -9,21 +9,10 @@ Polymer({ is: 'settings-search-engines-list', - behaviors: [CrScrollableBehavior], + behaviors: [settings.GlobalScrollTargetBehavior], properties: { /** @type {!Array<!SearchEngine>} */ - engines: { - type: Array, - value: function() { - return []; - }, - observer: 'enginesChanged_', - } - }, - - /** @private */ - enginesChanged_: function() { - this.updateScrollableContents(); + engines: Array, }, }); diff --git a/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_page.html b/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_page.html index 0cd7c510880..35a512fc788 100644 --- a/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_page.html +++ b/chromium/chrome/browser/resources/settings/search_engines_page/search_engines_page.html @@ -1,8 +1,6 @@ <link rel="import" href="chrome://resources/html/action_link.html"> <link rel="import" href="chrome://resources/html/cr.html"> <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/polymer/v1_0/iron-collapse/iron-collapse.html"> <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="/search_engines_page/search_engines_browser_proxy.html"> <link rel="import" href="/search_engines_page/search_engine_dialog.html"> diff --git a/chromium/chrome/browser/resources/settings/search_page/search_page.html b/chromium/chrome/browser/resources/settings/search_page/search_page.html index 546967e0c9f..3caa43a6066 100644 --- a/chromium/chrome/browser/resources/settings/search_page/search_page.html +++ b/chromium/chrome/browser/resources/settings/search_page/search_page.html @@ -1,14 +1,14 @@ +<link rel="import" href="chrome://resources/html/md_select_css.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/neon-animation/neon-animatable.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html"> -<link rel="import" href="/md_select_css.html"> <link rel="import" href="/route.html"> <link rel="import" href="/search_engines_page/search_engines_page.html"> <link rel="import" href="/search_engines_page/search_engines_browser_proxy.html"> <link rel="import" href="/settings_page/settings_animated_pages.html"> <link rel="import" href="/settings_page/settings_subpage.html"> <link rel="import" href="/settings_shared_css.html"> +<link rel="import" href="/settings_vars_css.html"> <dom-module id="settings-search-page"> <template> @@ -34,8 +34,7 @@ $i18n{searchEnginesManageDescription} </div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"> - </button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> </neon-animatable> <template is="dom-if" route-path="/searchEngines"> diff --git a/chromium/chrome/browser/resources/settings/search_settings.js b/chromium/chrome/browser/resources/settings/search_settings.js index 0a74ff014be..d349f9223bb 100644 --- a/chromium/chrome/browser/resources/settings/search_settings.js +++ b/chromium/chrome/browser/resources/settings/search_settings.js @@ -149,7 +149,13 @@ cr.define('settings', function() { if (request.regExp.test(textContent)) { foundMatches = true; revealParentSection_(node, request.rawQuery_); - highlight_(node, textContent.split(request.regExp)); + + // Don't highlight <select> nodes, yellow rectangles can't be + // displayed within an <option>. + // TODO(dpapad): highlight <select> controls with a search bubble + // instead. + if (node.parentNode.nodeName != 'OPTION') + highlight_(node, textContent.split(request.regExp)); } // Returning early since TEXT_NODE nodes never have children. return; diff --git a/chromium/chrome/browser/resources/settings/settings_main/settings_main.html b/chromium/chrome/browser/resources/settings/settings_main/settings_main.html index ba150265bbf..97c3c7a713d 100644 --- a/chromium/chrome/browser/resources/settings/settings_main/settings_main.html +++ b/chromium/chrome/browser/resources/settings/settings_main/settings_main.html @@ -68,8 +68,7 @@ showPages_.basic, inSearchMode_, hasExpandedSection_)]]"> <settings-basic-page prefs="{{prefs}}" page-visibility="[[pageVisibility]]" - on-subpage-expand="onSubpageExpand_" - on-freeze-scroll="onFreezeScroll_"> + on-subpage-expand="onSubpageExpand_"> </settings-basic-page> </template> <template is="dom-if" @@ -78,9 +77,10 @@ showPages_.basic, hasExpandedSection_, inSearchMode_)]]"> <div id="toggleSpacer"></div> <h2 id="toggleContainer"> - <paper-button id="advancedToggle" on-tap="toggleAdvancedPage_"> + <paper-button id="advancedToggle" active="{{advancedToggleExpanded}}" + aria-active-attribute="aria-expanded" toggles> <span>$i18n{advancedPageTitle}</span> - <iron-icon icon="[[arrowState_(advancedToggleExpanded_)]]"> + <iron-icon icon="[[arrowState_(advancedToggleExpanded)]]"> </iron-icon> </paper-button> </h2> @@ -89,8 +89,7 @@ showPages_.advanced, inSearchMode_, hasExpandedSection_)]]"> <settings-advanced-page prefs="{{prefs}}" page-visibility="[[pageVisibility]]" - on-subpage-expand="onSubpageExpand_" - on-freeze-scroll="onFreezeScroll_"> + on-subpage-expand="onSubpageExpand_"> </settings-advanced-page> </template> </template> diff --git a/chromium/chrome/browser/resources/settings/settings_main/settings_main.js b/chromium/chrome/browser/resources/settings/settings_main/settings_main.js index f931e6f0d5a..5d9dd81c119 100644 --- a/chromium/chrome/browser/resources/settings/settings_main/settings_main.js +++ b/chromium/chrome/browser/resources/settings/settings_main/settings_main.js @@ -25,10 +25,10 @@ Polymer({ notify: true, }, - /** @private */ - advancedToggleExpanded_: { + advancedToggleExpanded: { type: Boolean, - value: false, + notify: true, + observer: 'updatePagesShown_', }, /** @@ -90,15 +90,16 @@ Polymer({ /** @override */ attached: function() { - document.addEventListener('toggle-advanced-page', function(e) { - this.advancedToggleExpanded_ = e.detail; - this.updatePagesShown_(); - }.bind(this)); - + this.listen(this, 'freeze-scroll', 'onFreezeScroll_'); var currentRoute = settings.getCurrentRoute(); this.hasExpandedSection_ = currentRoute && currentRoute.isSubpage(); }, + /** @override */ + detached: function() { + this.unlisten(this, 'freeze-scroll', 'onFreezeScroll_'); + }, + /** @private */ overscrollChanged_: function() { if (!this.overscroll_ && this.boundScroll_) { @@ -138,12 +139,11 @@ Polymer({ * Enables or disables user scrolling, via overscroll: hidden. Room for the * hidden scrollbar is added to prevent the page width from changing back and * forth. Also freezes the overscroll height. - * @param {!Event} e - * @param {boolean} detail True to freeze, false to unfreeze. + * @param {!Event} e |e.detail| is true to freeze, false to unfreeze. * @private */ - onFreezeScroll_: function(e, detail) { - if (detail) { + onFreezeScroll_: function(e) { + if (e.detail) { // Update the overscroll and ignore scroll events. this.setOverscroll_(this.overscrollHeight_()); this.ignoreScroll_ = true; @@ -206,7 +206,7 @@ Polymer({ this.hasExpandedSection_ = false; if (settings.Route.ADVANCED.contains(newRoute)) - this.advancedToggleExpanded_ = true; + this.advancedToggleExpanded = true; this.updatePagesShown_(); }, @@ -235,7 +235,7 @@ Polymer({ !this.hasExpandedSection_, advanced: this.hasExpandedSection_ ? settings.Route.ADVANCED.contains(currentRoute) : - this.advancedToggleExpanded_, + this.advancedToggleExpanded, }; } @@ -292,7 +292,7 @@ Polymer({ /** @private */ toggleAdvancedPage_: function() { - this.fire('toggle-advanced-page', !this.advancedToggleExpanded_); + this.advancedToggleExpanded = !this.advancedToggleExpanded; }, /** @@ -318,32 +318,23 @@ Polymer({ }, /** - * Navigates to the default search page (if necessary). - * @private - */ - ensureInDefaultSearchPage_: function() { - if (settings.getCurrentRoute() != settings.Route.BASIC) - settings.navigateTo(settings.Route.BASIC); - }, - - /** * @param {string} query * @return {!Promise} A promise indicating that searching finished. */ searchContents: function(query) { // Trigger rendering of the basic and advanced pages and search once ready. this.inSearchMode_ = true; - this.ensureInDefaultSearchPage_(); this.toolbarSpinnerActive = true; return new Promise(function(resolve, reject) { setTimeout(function() { var whenSearchDone = settings.getSearchManager().search( query, assert(this.getPage_(settings.Route.BASIC))); - assert( - whenSearchDone === - settings.getSearchManager().search( - query, assert(this.getPage_(settings.Route.ADVANCED)))); + + if (this.pageVisibility.advancedSettings !== false) { + assert(whenSearchDone === settings.getSearchManager().search( + query, assert(this.getPage_(settings.Route.ADVANCED)))); + } whenSearchDone.then(function(request) { resolve(); diff --git a/chromium/chrome/browser/resources/settings/settings_menu/settings_menu.html b/chromium/chrome/browser/resources/settings/settings_menu/settings_menu.html index abd0493712b..912bbd35186 100644 --- a/chromium/chrome/browser/resources/settings/settings_menu/settings_menu.html +++ b/chromium/chrome/browser/resources/settings/settings_menu/settings_menu.html @@ -101,7 +101,7 @@ $i18n{internetPageTitle} </div> </if> - <div data-path="/people" on-tap="openPage_" + <div id="people" data-path="/people" on-tap="openPage_" hidden="[[!pageVisibility.people]]"> <iron-icon icon="settings:people"></iron-icon> $i18n{peoplePageTitle} @@ -136,11 +136,11 @@ </paper-menu> </div> <paper-submenu class="page-menu" id="advancedPage" actionable - opened="{{advancedOpened_}}" + opened="{{advancedOpened}}" hidden="[[!pageVisibility.advancedSettings]]"> <div class="menu-trigger"> <span>$i18n{advancedPageTitle}</span> - <iron-icon icon="[[arrowState_(advancedOpened_)]]"></iron-icon> + <iron-icon icon="[[arrowState_(advancedOpened)]]"></iron-icon> <paper-ripple></paper-ripple> </div> <paper-menu attr-for-selected="data-path" class="menu-content" @@ -161,7 +161,7 @@ $i18n{bluetoothPageTitle} </div> </if> - <div data-path="/passwords" on-tap="openPage_" + <div data-path="/passwordsAndForms" on-tap="openPage_" hidden="[[!pageVisibility.passwordsAndForms]]"> <iron-icon icon="settings:assignment"></iron-icon> $i18n{passwordsAndAutofillPageTitle} @@ -170,7 +170,7 @@ <iron-icon icon="settings:language"></iron-icon> $i18n{languagesPageTitle} </div> - <div data-path="/downloadsDirectory" on-tap="openPage_"> + <div data-path="/downloads" on-tap="openPage_"> <iron-icon icon="cr:file-download"></iron-icon> $i18n{downloadsPageTitle} </div> diff --git a/chromium/chrome/browser/resources/settings/settings_menu/settings_menu.js b/chromium/chrome/browser/resources/settings/settings_menu/settings_menu.js index a5ea67415c7..d40439842da 100644 --- a/chromium/chrome/browser/resources/settings/settings_menu/settings_menu.js +++ b/chromium/chrome/browser/resources/settings/settings_menu/settings_menu.js @@ -12,6 +12,11 @@ Polymer({ behaviors: [settings.RouteObserverBehavior], properties: { + advancedOpened: { + type: Boolean, + notify: true, + }, + /** @private */ aboutSelected_: Boolean, @@ -24,24 +29,21 @@ Polymer({ }, }, - attached: function() { - document.addEventListener('toggle-advanced-page', function(e) { - if (e.detail) - this.$.advancedPage.open(); - else - this.$.advancedPage.close(); - }.bind(this)); - - this.$.advancedPage.addEventListener('paper-submenu-open', function() { - this.fire('toggle-advanced-page', true); - }.bind(this)); - - this.$.advancedPage.addEventListener('paper-submenu-close', function() { - this.fire('toggle-advanced-page', false); - }.bind(this)); - - this.fire('toggle-advanced-page', - settings.Route.ADVANCED.contains(settings.getCurrentRoute())); + ready: function() { + // When a <paper-submenu> is created with the [opened] attribute as true, + // its _active member isn't correctly initialized. See this bug for more + // info: https://github.com/PolymerElements/paper-menu/issues/88. This means + // the first tap to close an opened Advanced section does nothing (because + // it calls .open() on an opened menu instead of .close(). This is a fix for + // that bug without changing that code through its public API. + // + // TODO(dbeam): we're currently deciding whether <paper-{,sub}menu> are + // right for our needs (there have been minor a11y problems). If we decide + // to keep <paper-{,sub}menu>, fix this bug with a local Chrome CL (ex: + // https://codereview.chromium.org/2412343004) or a Polymer PR (ex: + // https://github.com/PolymerElements/paper-menu/pull/107). + if (this.advancedOpened) + this.$.advancedPage.open(); }, /** @@ -73,7 +75,8 @@ Polymer({ openPage_: function(event) { var route = settings.getRouteForPath(event.currentTarget.dataset.path); assert(route, 'settings-menu has an an entry with an invalid path'); - settings.navigateTo(route); + settings.navigateTo( + route, /* dynamicParams */ null, /* removeSearch */ true); }, /** diff --git a/chromium/chrome/browser/resources/settings/settings_page/main_page_behavior.js b/chromium/chrome/browser/resources/settings/settings_page/main_page_behavior.js index ebf7979202f..904b12fa399 100644 --- a/chromium/chrome/browser/resources/settings/settings_page/main_page_behavior.js +++ b/chromium/chrome/browser/resources/settings/settings_page/main_page_behavior.js @@ -25,14 +25,26 @@ var MainPageBehaviorImpl = { * @param {settings.Route} oldRoute */ currentRouteChanged: function(newRoute, oldRoute) { - // If this is the first route, or the page was hidden, allow the page to - // render before expanding the section. - if (!oldRoute && newRoute.contains(settings.getCurrentRoute()) || - this.scrollHeight == 0) { - setTimeout(this.tryTransitionToSection_.bind(this)); - } else { - this.tryTransitionToSection_(); + // Scroll to the section except for back/forward. Also scroll for any + // back/forward navigations that are in-page. + var oldRouteWasSection = + !!oldRoute && !!oldRoute.parent && !!oldRoute.section && + oldRoute.parent.section != oldRoute.section; + + if (oldRouteWasSection && newRoute == settings.Route.BASIC) { + this.scroller.scrollTop = 0; + return; } + + var scrollToSection = + !settings.lastRouteChangeWasPopstate() || oldRouteWasSection; + + // For previously uncreated pages (including on first load), allow the page + // to render before scrolling to or expanding the section. + if (!oldRoute || this.scrollHeight == 0) + setTimeout(this.tryTransitionToSection_.bind(this, scrollToSection)); + else + this.tryTransitionToSection_(scrollToSection); }, /** @@ -41,9 +53,10 @@ var MainPageBehaviorImpl = { * that one, then schedules this function again. This ensures the current * section is quickly shown, without getting the page into a broken state -- * if currentRoute changes in between calls, just transition to the new route. + * @param {boolean} scrollToSection * @private */ - tryTransitionToSection_: function() { + tryTransitionToSection_: function(scrollToSection) { var currentRoute = settings.getCurrentRoute(); var currentSection = this.getSection(currentRoute.section); @@ -63,7 +76,7 @@ var MainPageBehaviorImpl = { if (!currentRoute.isSubpage() || expandedSection != currentSection) { promise = this.collapseSection_(expandedSection); // Scroll to the collapsed section. - if (currentSection && !settings.lastRouteChangeWasPopstate()) + if (currentSection && scrollToSection) currentSection.scrollIntoView(); } else { // Scroll to top while sliding to another subpage. @@ -73,14 +86,14 @@ var MainPageBehaviorImpl = { // Expand the section into a subpage or scroll to it on the main page. if (currentRoute.isSubpage()) promise = this.expandSection_(currentSection); - else if (!settings.lastRouteChangeWasPopstate()) + else if (scrollToSection) currentSection.scrollIntoView(); } // When this animation ends, another may be necessary. Call this function // again after the promise resolves. if (promise) - promise.then(this.tryTransitionToSection_.bind(this)); + promise.then(this.tryTransitionToSection_.bind(this, scrollToSection)); }, /** diff --git a/chromium/chrome/browser/resources/settings/settings_page/settings_section.html b/chromium/chrome/browser/resources/settings/settings_page/settings_section.html index 6ceb1653807..38ff819691c 100644 --- a/chromium/chrome/browser/resources/settings/settings_page/settings_section.html +++ b/chromium/chrome/browser/resources/settings/settings_page/settings_section.html @@ -31,7 +31,6 @@ background-color: white; border-radius: 2px; flex: 1; - overflow: hidden; } :host(.expanded) #card { @@ -42,6 +41,7 @@ :host(.collapsing) #card, :host(.expanded) #card { @apply(--shadow-elevation-4dp); + overflow: hidden; /* A stacking context constrains sliding sub-pages to the card. */ z-index: 0; } diff --git a/chromium/chrome/browser/resources/settings/settings_page/settings_subpage.html b/chromium/chrome/browser/resources/settings/settings_page/settings_subpage.html index 0a4c36fd0fe..af7d0c3b2df 100644 --- a/chromium/chrome/browser/resources/settings/settings_page/settings_subpage.html +++ b/chromium/chrome/browser/resources/settings/settings_page/settings_subpage.html @@ -32,7 +32,8 @@ h1 { color: var(--settings-nav-grey); - font-size: 107.6923%; /* go to 14px from 13px */ + flex: 1; /* Push other items to the end. */ + font-size: 107.6923%; /* Go to 14px from 13px */ font-weight: 500; } @@ -41,7 +42,8 @@ } </style> <div class="settings-box first"> - <paper-icon-button icon="settings:arrow-back" on-tap="onTapBack_"> + <paper-icon-button icon="settings:arrow-back" on-tap="onTapBack_" + aria-label="$i18n{back}"> </paper-icon-button> <h1>[[pageTitle]]</h1> <template is="dom-if" if="[[searchLabel]]"> @@ -49,6 +51,7 @@ on-search-changed="onSearchChanged_"> </settings-subpage-search> </template> + <content select=".subpage-title-extra"></content> </div> <content></content> </template> diff --git a/chromium/chrome/browser/resources/settings/settings_resources.grd b/chromium/chrome/browser/resources/settings/settings_resources.grd index 1c629e0815c..4f04c098d9e 100644 --- a/chromium/chrome/browser/resources/settings/settings_resources.grd +++ b/chromium/chrome/browser/resources/settings/settings_resources.grd @@ -129,6 +129,12 @@ type="chrome_html" flattenhtml="true" allowexternalscript="true" /> + <structure name="IDR_SETTINGS_EXTENSION_CONTROL_BROWSER_PROXY_JS" + file="extension_control_browser_proxy.js" + type="chrome_html" /> + <structure name="IDR_SETTINGS_EXTENSION_CONTROL_BROWSER_PROXY_HTML" + file="extension_control_browser_proxy.html" + type="chrome_html" /> <structure name="IDR_SETTINGS_FONTS_BROWSER_PROXY_HTML" file="appearance_page/fonts_browser_proxy.html" type="chrome_html" /> @@ -142,6 +148,12 @@ file="lifetime_browser_proxy.js" type="chrome_html" flattenhtml="true" /> + <structure name="IDR_SETTINGS_ON_STARTUP_BROWSER_PROXY_HTML" + file="on_startup_page/on_startup_browser_proxy.html" + type="chrome_html" /> + <structure name="IDR_SETTINGS_ON_STARTUP_BROWSER_PROXY_JS" + file="on_startup_page/on_startup_browser_proxy.js" + type="chrome_html" /> <structure name="IDR_SETTINGS_ON_STARTUP_PAGE_HTML" file="on_startup_page/on_startup_page.html" type="chrome_html" /> @@ -233,10 +245,6 @@ file="settings_shared_css.html" type="chrome_html" flattenhtml="true" /> - <structure name="IDR_SETTINGS_MD_SELECT_CSS_HTML" - file="md_select_css.html" - type="chrome_html" - flattenhtml="true" /> <structure name="IDR_SETTINGS_CR_SETTINGS_UI_HTML" file="settings_ui/settings_ui.html" type="chrome_html" /> @@ -244,6 +252,12 @@ file="settings_ui/settings_ui.js" type="chrome_html" flattenhtml="true" /> + <structure name="IDR_SETTINGS_GLOBAL_SCROLL_TARGET_BEHAVIOR_HTML" + file="global_scroll_target_behavior.html" + type="chrome_html" /> + <structure name="IDR_SETTINGS_GLOBAL_SCROLL_TARGET_BEHAVIOR_JS" + file="global_scroll_target_behavior.js" + type="chrome_html" /> <if expr="use_nss_certs"> <structure name="IDR_SETTINGS_CERTIFICATE_MANAGER_PAGE_HTML" file="certificate_manager_page/certificate_manager_page.html" @@ -330,6 +344,12 @@ <structure name="IDR_SETTINGS_HISTORY_DELETION_DIALOG_JS" file="clear_browsing_data_dialog/history_deletion_dialog.js" type="chrome_html" /> + <structure name="IDR_SETTINGS_CONTROLS_BOOLEAN_CONTROL_BEHAVIOR_HTML" + file="controls/settings_boolean_control_behavior.html" + type="chrome_html" /> + <structure name="IDR_SETTINGS_CONTROLS_BOOLEAN_CONTROL_BEHAVIOR_JS" + file="controls/settings_boolean_control_behavior.js" + type="chrome_html" /> <structure name="IDR_SETTINGS_CONTROLS_CONTROLLED_BUTTON_JS" file="controls/controlled_button.js" type="chrome_html" /> @@ -342,6 +362,12 @@ <structure name="IDR_SETTINGS_CONTROLS_CONTROLLED_RADIO_BUTTON_HTML" file="controls/controlled_radio_button.html" type="chrome_html" /> + <structure name="IDR_SETTINGS_CONTROLS_EXTENSION_CONTROLLED_INDICATOR_JS" + file="controls/extension_controlled_indicator.js" + type="chrome_html" /> + <structure name="IDR_SETTINGS_CONTROLS_EXTENSION_CONTROLLED_INDICATOR_HTML" + file="controls/extension_controlled_indicator.html" + type="chrome_html" /> <structure name="IDR_SETTINGS_CONTROLS_CHECKBOX_HTML" file="controls/settings_checkbox.html" type="chrome_html" /> @@ -372,6 +398,12 @@ <structure name="IDR_SETTINGS_CONTROLS_RADIO_GROUP_JS" file="controls/settings_radio_group.js" type="chrome_html" /> + <structure name="IDR_SETTINGS_CONTROLS_TOGGLE_BUTTON_HTML" + file="controls/settings_toggle_button.html" + type="chrome_html" /> + <structure name="IDR_SETTINGS_CONTROLS_TOGGLE_BUTTON_JS" + file="controls/settings_toggle_button.js" + type="chrome_html" /> <structure name="IDR_SETTINGS_COOKIE_INFO_JS" file="site_settings/cookie_info.js" type="chrome_html" /> @@ -618,6 +650,18 @@ flattenhtml="true" allowexternalscript="true" /> <if expr="not chromeos"> + <structure name="IDR_SETTINGS_PEOPLE_PAGE_IMPORT_DATA_DIALOG_HTML" + file="people_page/import_data_dialog.html" + type="chrome_html" /> + <structure name="IDR_SETTINGS_PEOPLE_PAGE_IMPORT_DATA_DIALOG_JS" + file="people_page/import_data_dialog.js" + type="chrome_html" /> + <structure name="IDR_SETTINGS_PEOPLE_PAGE_IMPORT_DATA_BROWSER_PROXY_HTML" + file="people_page/import_data_browser_proxy.html" + type="chrome_html" /> + <structure name="IDR_SETTINGS_PEOPLE_PAGE_IMPORT_DATA_BROWSER_PROXY_JS" + file="people_page/import_data_browser_proxy.js" + type="chrome_html" /> <structure name="IDR_SETTINGS_PEOPLE_PAGE_MANAGE_PROFILE_HTML" file="people_page/manage_profile.html" type="chrome_html" @@ -724,6 +768,12 @@ <structure name="IDR_SETTINGS_CLOUD_PRINTING_PAGE_JS" file="printing_page/cloud_printers.js" type="chrome_html" /> + <structure name="IDR_SETTINGS_PDF_DOCUMENTS_HTML" + file="site_settings/pdf_documents.html" + type="chrome_html" /> + <structure name="IDR_SETTINGS_PDF_DOCUMENTS_JS" + file="site_settings/pdf_documents.js" + type="chrome_html" /> <structure name="IDR_SETTINGS_PRIVACY_PAGE_HTML" file="privacy_page/privacy_page.html" type="chrome_html" @@ -753,17 +803,23 @@ file="route.js" type="chrome_html" preprocess="true" /> + <structure name="IDR_SETTINGS_COOKIE_TREE_BEHAVIOR_HTML" + file="site_settings/cookie_tree_behavior.html" + type="chrome_html" /> + <structure name="IDR_SETTINGS_COOKIE_TREE_BEHAVIOR_JS" + file="site_settings/cookie_tree_behavior.js" + type="chrome_html" /> <structure name="IDR_SETTINGS_SITE_DATA_HTML" file="site_settings/site_data.html" type="chrome_html" /> <structure name="IDR_SETTINGS_SITE_DATA_JS" file="site_settings/site_data.js" type="chrome_html" /> - <structure name="IDR_SETTINGS_SITE_DATA_DETAILS_DIALOG_HTML" - file="site_settings/site_data_details_dialog.html" + <structure name="IDR_SETTINGS_SITE_DATA_DETAILS_SUBPAGE_HTML" + file="site_settings/site_data_details_subpage.html" type="chrome_html" /> - <structure name="IDR_SETTINGS_SITE_DATA_DETAILS_DIALOG_JS" - file="site_settings/site_data_details_dialog.js" + <structure name="IDR_SETTINGS_SITE_DATA_DETAILS_SUBPAGE_JS" + file="site_settings/site_data_details_subpage.js" type="chrome_html" /> <structure name="IDR_SETTINGS_SITE_LIST_HTML" file="site_settings/site_list.html" @@ -830,8 +886,8 @@ type="chrome_html" flattenhtml="true" allowexternalscript="true" /> - <structure name="IDR_SETTINGS_SEARCH_ENGINES_PAGE_SEARCH_ENGINE_ENTRY_CSS" - file="search_engines_page/search_engine_entry.css" + <structure name="IDR_SETTINGS_SEARCH_ENGINES_PAGE_SEARCH_ENGINE_ENTRY_CSS_HTML" + file="search_engines_page/search_engine_entry_css.html" type="chrome_html" /> <structure name="IDR_SETTINGS_SEARCH_ENGINES_PAGE_OMNIBOX_EXTENSION_ENTRY_JS" file="search_engines_page/omnibox_extension_entry.js" diff --git a/chromium/chrome/browser/resources/settings/settings_shared_css.html b/chromium/chrome/browser/resources/settings/settings_shared_css.html index 65939c12ac8..0f852d067ed 100644 --- a/chromium/chrome/browser/resources/settings/settings_shared_css.html +++ b/chromium/chrome/browser/resources/settings/settings_shared_css.html @@ -5,26 +5,32 @@ <dom-module id="settings-shared"> <template> <style include="cr-shared-style"> + /* Included here so we don't have to include "iron-positioning" in every + * stylesheet. See crbug.com/498405. */ + [hidden] { + display: none !important; + } + button[is='paper-icon-button-light'] { - --paper-icon-button-light-ripple: { - /* Center the ripple on the icon button. */ - height: 36px; - left: -8px; - top: -8px; - width: 36px; - }; + -webkit-margin-end: -8px; /* Allow ripple to overlap the end. */ -webkit-margin-start: 16px; - background-size: cover; + background-position: center; + background-repeat: no-repeat; + background-size: var(--settings-icon-size); flex-shrink: 0; - height: 20px; - width: 20px; + height: var(--settings-icon-ripple-size); + width: var(--settings-icon-ripple-size); } - [actionable] button[is="paper-icon-button-light"].icon-arrow-right { + :host-context([dir=rtl]) button[is='paper-icon-button-light'] { + transform: scaleX(-1); /* Flip on the X axis (aka mirror). */ + } + + [actionable] button[is='paper-icon-button-light'].subpage-arrow { background-image: url(images/arrow_right.svg); } - [actionable] button[is="paper-icon-button-light"].icon-external { + [actionable] button[is='paper-icon-button-light'].icon-external { background-image: url(images/open_in_new.svg); } @@ -163,8 +169,9 @@ .secondary-button { --paper-button: { color: var(--paper-grey-600); - text-decoration: none; font-weight: 500; + min-width: 1em; /* A tighter fit than 5.14em for short buttons. */ + text-decoration: none; }; --paper-button-flat-keyboard-focus: { background: rgba(0, 0, 0, .12); @@ -229,11 +236,6 @@ display: block; } - .list-frame .secondary, - .list-item .secondary { - @apply(--settings-secondary); - } - /* A list-item is intended to be contained within a list-frame. The list * frame will setup the initial start margin. */ .list-item { @@ -252,10 +254,6 @@ font-weight: 500; } - .list-item select { - -webkit-margin-start: 4px; - } - /* The middle part (horizontally) of a list item. */ .list-item .middle { flex: 1; @@ -283,16 +281,26 @@ font-weight: 500; } + /* A row with two lines of text. Often the lower line will be .secondary. + */ + .two-line { + min-height: var(--settings-row-two-line-min-height); + } + /* A settings-box is a horizontal row of text or controls within a * setting section (page or subpage). */ .settings-box { align-items: center; border-top: var(--settings-separator-line); display: flex; - min-height: var(--settings-row-min-height); + min-height: var(--settings-box-min-height); padding: 0 var(--settings-box-row-padding); } + .settings-box.two-line { + min-height: var(--settings-box-two-line-min-height); + } + /* We use an explicit tag to remove the top border, rather than a * :first-of-type modifier. This is a conscious choice, please consult * with dbeam@ or dschuyler@ prior to changing it. */ @@ -305,27 +313,32 @@ display: block; } - /* A row with two lines of text. Often the lower line will be .secondary. - */ - .settings-box.two-line { - min-height: var(--settings-row-two-line-min-height); - } - - /* - * A settings box with a single start-aligned column, generally but not - * necessarily used in combination with two-line. - */ - .settings-box.single-column { + /* A start-aligned column. */ + .single-column { align-items: flex-start; flex-direction: column; justify-content: center; } - /* The lower line of text in a .settings-box.two-line. */ - .settings-box .secondary { + /* A settings-box with no height other than the separator line. */ + .settings-box.line-only { + min-height: 0; + } + + /* The lower line of text in a two-line row. */ + .secondary { @apply(--settings-secondary); } + /* The |:empty| CSS selector only works when there is no whitespace. + * E.g. <div>[[foo]]</div> will be |:empty| when foo == ""; and + * <div> [[foo]] </div> will not be |:empty| when foo == "". Ensure there + * is no extra whitespace when the contents of .secondary may be "". + */ + .secondary:empty { + margin: 0; + } + /* The middle part (horizontally) of a row. */ .settings-box .middle { -webkit-padding-start: 16px; @@ -333,9 +346,9 @@ flex: auto; } - .settings-box .middle.two-line { + .settings-box .middle.two-line, + .settings-box .start.two-line { display: flex; - min-height: var(--settings-row-two-line-min-height); } /* The start (left in LTR) part (horizontally) of a row. */ @@ -344,11 +357,6 @@ flex: auto; } - .settings-box .start.two-line { - display: flex; - min-height: var(--settings-row-two-line-min-height); - } - /* The secondary-action wraps a clickable sub-area of a .settings-box. * An example is the |sign out| button on the People settings. * Here is an example with and without a secondary action box: @@ -423,6 +431,7 @@ position: absolute; top: -5px; width: 10px; + z-index: -1; } /* Turns the arrow direction downwards, when the bubble is placed above diff --git a/chromium/chrome/browser/resources/settings/settings_ui/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/settings_ui/compiled_resources2.gyp index d5f6fac6d4a..d78d202d2cd 100644 --- a/chromium/chrome/browser/resources/settings/settings_ui/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/settings/settings_ui/compiled_resources2.gyp @@ -7,7 +7,11 @@ 'target_name': 'settings_ui', 'dependencies': [ '<(DEPTH)/third_party/polymer/v1_0/components-chromium/app-layout/app-drawer/compiled_resources2.gyp:app-drawer-extracted', + '<(DEPTH)/ui/webui/resources/cr_elements/cr_toolbar/compiled_resources2.gyp:cr_toolbar', + '<(DEPTH)/ui/webui/resources/cr_elements/cr_toolbar/compiled_resources2.gyp:cr_toolbar_search_field', '../compiled_resources2.gyp:direction_delegate', + '../compiled_resources2.gyp:global_scroll_target_behavior', + '../prefs/compiled_resources2.gyp:prefs', '../settings_main/compiled_resources2.gyp:settings_main', 'settings_ui_types', ], diff --git a/chromium/chrome/browser/resources/settings/settings_ui/settings_ui.html b/chromium/chrome/browser/resources/settings/settings_ui/settings_ui.html index 5cea906f0fe..7f24d2f4c1c 100644 --- a/chromium/chrome/browser/resources/settings/settings_ui/settings_ui.html +++ b/chromium/chrome/browser/resources/settings/settings_ui/settings_ui.html @@ -5,6 +5,7 @@ <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-header-panel/paper-header-panel.html"> <link rel="import" href="/direction_delegate.html"> +<link rel="import" href="/global_scroll_target_behavior.html"> <link rel="import" href="/i18n_setup.html"> <link rel="import" href="/icons.html"> <link rel="import" href="/settings_main/settings_main.html"> @@ -85,25 +86,31 @@ } </style> <settings-prefs id="prefs" prefs="{{prefs}}"></settings-prefs> - <cr-toolbar page-name="$i18n{settings}" clear-label="$i18n{clearSearch}" - search-prompt="$i18n{searchPrompt}" on-cr-menu-tap="onMenuButtonTap_" - spinner-active="[[toolbarSpinnerActive_]]" show-menu - menu-label="$i18n{menuButtonLabel}"> + <cr-toolbar page-name="$i18n{settings}" + clear-label="$i18n{clearSearch}" + search-prompt="$i18n{searchPrompt}" + on-cr-toolbar-menu-tap="onMenuButtonTap_" + spinner-active="[[toolbarSpinnerActive_]]" + menu-label="$i18n{menuButtonLabel}" + on-search-changed="onSearchChanged_" + show-menu> </cr-toolbar> <app-drawer swipe-open> <div class="drawer-header">$i18n{settings}</div> <div class="drawer-content"> <template is="dom-if" id="drawerTemplate"> <settings-menu page-visibility="[[pageVisibility_]]" - on-iron-activate="onIronActivate_"> + on-iron-activate="onIronActivate_" + advanced-opened="{{advancedOpened_}}"> </settings-menu> </template> </div> </app-drawer> - <paper-header-panel mode="waterfall"> - <settings-main prefs="{{prefs}}" + <paper-header-panel id="headerPanel" mode="waterfall"> + <settings-main id="main" prefs="{{prefs}}" toolbar-spinner-active="{{toolbarSpinnerActive_}}" - page-visibility="[[pageVisibility_]]"> + page-visibility="[[pageVisibility_]]" + advanced-toggle-expanded="{{advancedOpened_}}"> </settings-main> </paper-header-panel> </template> diff --git a/chromium/chrome/browser/resources/settings/settings_ui/settings_ui.js b/chromium/chrome/browser/resources/settings/settings_ui/settings_ui.js index 59d21d3c325..c035dfbae88 100644 --- a/chromium/chrome/browser/resources/settings/settings_ui/settings_ui.js +++ b/chromium/chrome/browser/resources/settings/settings_ui/settings_ui.js @@ -19,6 +19,8 @@ settings.defaultResourceLoaded = true; Polymer({ is: 'settings-ui', + behaviors: [settings.RouteObserverBehavior], + properties: { /** * Preferences state. @@ -32,6 +34,13 @@ Polymer({ value: new settings.DirectionDelegateImpl(), }, + /** @private */ + advancedOpened_: { + type: Boolean, + value: false, + notify: true, + }, + /** @private {boolean} */ toolbarSpinnerActive_: { type: Boolean, @@ -43,6 +52,16 @@ Polymer({ * @private {!GuestModePageVisibility} */ pageVisibility_: Object, + + /** @private */ + lastSearchQuery_: { + type: String, + value: '', + } + }, + + listeners: { + 'refresh-pref': 'onRefreshPref_', }, /** @override */ @@ -56,10 +75,6 @@ Polymer({ * strict mode. */ ready: function() { - this.$$('cr-toolbar').addEventListener('search-changed', function(e) { - this.$$('settings-main').searchContents(e.detail); - }.bind(this)); - // Lazy-create the drawer the first time it is opened or swiped into view. var drawer = assert(this.$$('app-drawer')); listenOnce(drawer, 'track opened-changed', function() { @@ -106,6 +121,59 @@ Polymer({ attached: function() { // Preload bold Roboto so it doesn't load and flicker the first time used. document.fonts.load('bold 12px Roboto'); + settings.setGlobalScrollTarget(this.$.headerPanel.scroller); + }, + + /** @param {!settings.Route} route */ + currentRouteChanged: function(route) { + var urlSearchQuery = settings.getQueryParameters().get('search') || ''; + if (urlSearchQuery == this.lastSearchQuery_) + return; + + this.lastSearchQuery_ = urlSearchQuery; + + var toolbar = /** @type {!CrToolbarElement} */ (this.$$('cr-toolbar')); + var searchField = /** @type {CrToolbarSearchFieldElement} */ ( + toolbar.getSearchField()); + + // If the search was initiated by directly entering a search URL, need to + // sync the URL parameter to the textbox. + if (urlSearchQuery != searchField.getValue()) { + // Setting the search box value without triggering a 'search-changed' + // event, to prevent an unnecessary duplicate entry in |window.history|. + searchField.setValue(urlSearchQuery, true /* noEvent */); + } + + this.$.main.searchContents(urlSearchQuery); + }, + + /** + * @param {!CustomEvent} e + * @private + */ + onRefreshPref_: function(e) { + var prefName = /** @type {string} */(e.detail); + return /** @type {SettingsPrefsElement} */(this.$.prefs).refresh(prefName); + }, + + /** + * Handles the 'search-changed' event fired from the toolbar. + * @param {!Event} e + * @private + */ + onSearchChanged_: function(e) { + // Trim leading whitespace only, to prevent searching for empty string. This + // still allows the user to search for 'foo bar', while taking a long pause + // after typing 'foo '. + var query = e.detail.replace(/^\s+/, ''); + // Prevent duplicate history entries. + if (query == this.lastSearchQuery_) + return; + + settings.navigateTo( + settings.Route.BASIC, + query.length > 0 ? new URLSearchParams(`search=${query}`) : undefined, + /* removeSearch */ true); }, /** diff --git a/chromium/chrome/browser/resources/settings/settings_vars_css.html b/chromium/chrome/browser/resources/settings/settings_vars_css.html index 9ec492364f3..39e7a6320aa 100644 --- a/chromium/chrome/browser/resources/settings/settings_vars_css.html +++ b/chromium/chrome/browser/resources/settings/settings_vars_css.html @@ -19,6 +19,9 @@ --settings-disabled-opacity: .65; --settings-error-color: var(--paper-red-700); + --settings-icon-ripple-size: 36px; + --settings-icon-size: 20px; + --settings-list-frame-padding: { -webkit-padding-end: var(--settings-box-row-padding); -webkit-padding-start: 56px; @@ -30,8 +33,16 @@ --settings-page-vertical-margin: 21px; + /* These are used for row items such as radio buttons, check boxes, list + * items etc. */ --settings-row-min-height: 44px; --settings-row-two-line-min-height: 56px; + + /* These are used for the settings-box containers, which may contain one or + * more "row items". */ + --settings-box-min-height: 48px; + --settings-box-two-line-min-height: 60px; + --settings-secondary: { color: var(--paper-grey-600); font-weight: 400; @@ -54,20 +65,25 @@ width: 16px; }; --settings-toggle-color: var(--google-blue-500); - } - :root { --checkbox-margin-start: 2px; --checkbox-size: 16px; --checkbox-spacing: 18px; --iron-icon-fill-color: var(--paper-grey-600); - --iron-icon-height: 20px; - --iron-icon-width: 20px; + --iron-icon-height: var(--settings-icon-size); + --iron-icon-width: var(--settings-icon-size); --paper-checkbox-label-color: inherit; --paper-dialog-color: inherit; --paper-icon-button: { - height: 36px; - width: 36px; + height: var(--settings-icon-ripple-size); + width: var(--settings-icon-ripple-size); + }; + --paper-input-container-focus-color: var(--google-blue-500); + --paper-input-container-input: { + color: inherit; + font-size: inherit; + font-weight: inherit; + vertical-align: baseline; }; --paper-input-max-width: 264px; --paper-item: { diff --git a/chromium/chrome/browser/resources/settings/site_settings/add_site_dialog.js b/chromium/chrome/browser/resources/settings/site_settings/add_site_dialog.js index 6c09138011a..48fca0f1950 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/add_site_dialog.js +++ b/chromium/chrome/browser/resources/settings/site_settings/add_site_dialog.js @@ -14,15 +14,28 @@ Polymer({ properties: { /** + * What kind of setting, e.g. Location, Camera, Cookies, and so on. + * @type {settings.ContentSettingsTypes} + */ + category: String, + + /** + * Whether this is about an Allow, Block, SessionOnly, or other. + * @type {settings.PermissionValues} + */ + contentSetting: String, + + /** * The site to add an exception for. * @private */ site_: String, + }, - /** - * Whether this is an allow exception this dialog is adding. - */ - allowException: Boolean, + /** @override */ + attached: function() { + assert(this.category); + assert(this.contentSetting); }, /** @@ -33,7 +46,6 @@ Polymer({ open: function(type) { this.addWebUIListener('onIncognitoStatusChanged', this.onIncognitoStatusChanged_.bind(this)); - this.allowException = type == settings.PermissionValues.ALLOW; this.browserProxy.updateIncognitoStatus(); this.$.dialog.showModal(); }, @@ -76,8 +88,7 @@ Polymer({ return; // Can happen when Enter is pressed. var pattern = this.addPatternWildcard(this.site_); this.browserProxy.setCategoryPermissionForOrigin( - pattern, pattern, this.category, this.allowException ? - settings.PermissionValues.ALLOW : settings.PermissionValues.BLOCK, + pattern, pattern, this.category, this.contentSetting, this.$.incognito.checked); this.$.dialog.close(); }, diff --git a/chromium/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp b/chromium/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp index 0c54600f9e9..fd7cab24c18 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp +++ b/chromium/chrome/browser/resources/settings/site_settings/compiled_resources2.gyp @@ -7,6 +7,7 @@ 'target_name': 'add_site_dialog', 'dependencies': [ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior', + 'constants', 'site_settings_behavior', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], @@ -39,21 +40,35 @@ 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, { - 'target_name': 'cookie_tree_node', + 'target_name': 'cookie_info', + 'dependencies': [ + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', + ], + 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], + }, + { + 'target_name': 'cookie_tree_behavior', 'dependencies': [ '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', 'cookie_info', + 'site_settings_behavior', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, { - 'target_name': 'cookie_info', + 'target_name': 'cookie_tree_node', + 'dependencies': [ + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:load_time_data', + 'cookie_info', + ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, { 'target_name': 'protocol_handlers', 'dependencies': [ + '<(DEPTH)/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp:cr_action_menu', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior', 'site_settings_behavior', ], @@ -62,6 +77,7 @@ { 'target_name': 'usb_devices', 'dependencies': [ + '<(DEPTH)/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp:cr_action_menu', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior', 'site_settings_behavior', ], @@ -70,19 +86,19 @@ { 'target_name': 'site_data', 'dependencies': [ - '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior', + '../settings_page/compiled_resources2.gyp:settings_subpage_search', + 'cookie_tree_behavior', 'cookie_tree_node', - 'site_settings_behavior', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, { - 'target_name': 'site_data_details_dialog', + 'target_name': 'site_data_details_subpage', 'dependencies': [ - '<(DEPTH)/ui/webui/resources/cr_elements/cr_dialog/compiled_resources2.gyp:cr_dialog', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior', - 'cookie_tree_node', - 'site_settings_behavior', + '../compiled_resources2.gyp:route', + 'site_settings_prefs_browser_proxy', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], }, @@ -120,10 +136,12 @@ 'target_name': 'site_list', 'dependencies': [ '../compiled_resources2.gyp:route', + '<(DEPTH)/ui/webui/resources/cr_elements/cr_action_menu/compiled_resources2.gyp:cr_action_menu', + 'constants', + '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:assert', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:cr', '<(DEPTH)/ui/webui/resources/js/compiled_resources2.gyp:web_ui_listener_behavior', '<(EXTERNS_GYP):settings_private', - 'constants', 'site_settings_behavior', ], 'includes': ['../../../../../third_party/closure_compiler/compile_js2.gypi'], diff --git a/chromium/chrome/browser/resources/settings/site_settings/constants.js b/chromium/chrome/browser/resources/settings/site_settings/constants.js index e3961103a0f..61948c00535 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/constants.js +++ b/chromium/chrome/browser/resources/settings/site_settings/constants.js @@ -2,64 +2,59 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -cr.define('settings', function() { - /** - * All possible contentSettingsTypes that we currently support configuring in - * the UI. Both top-level categories and content settings that represent - * individual permissions under Site Details should appear here. This is a - * subset of the constants found in site_settings_helper.cc and the values - * should be kept in sync. - * @enum {string} - */ - var ContentSettingsTypes = { - COOKIES: 'cookies', - IMAGES: 'images', - JAVASCRIPT: 'javascript', - PLUGINS: 'plugins', - POPUPS: 'popups', - GEOLOCATION: 'location', - NOTIFICATIONS: 'notifications', - FULLSCREEN: 'fullscreen', - MIC: 'media-stream-mic', - CAMERA: 'media-stream-camera', - PROTOCOL_HANDLERS: 'register-protocol-handler', - UNSANDBOXED_PLUGINS: 'ppapi-broker', - AUTOMATIC_DOWNLOADS: 'multiple-automatic-downloads', - KEYGEN: 'keygen', - BACKGROUND_SYNC: 'background-sync', - USB_DEVICES: 'usb-chooser-data', - ZOOM_LEVELS: 'zoom-levels', - }; +cr.exportPath('settings'); - /** - * Contains the possible string values for a given contentSettingsType. - * @enum {string} - */ - var PermissionValues = { - DEFAULT: 'default', - ALLOW: 'allow', - BLOCK: 'block', - ASK: 'ask', - SESSION_ONLY: 'session_only', - IMPORTANT_CONTENT: 'detect_important_content', - }; +/** + * All possible contentSettingsTypes that we currently support configuring in + * the UI. Both top-level categories and content settings that represent + * individual permissions under Site Details should appear here. This is a + * subset of the constants found in site_settings_helper.cc and the values + * should be kept in sync. + * @enum {string} + */ +settings.ContentSettingsTypes = { + COOKIES: 'cookies', + IMAGES: 'images', + JAVASCRIPT: 'javascript', + PLUGINS: 'plugins', + POPUPS: 'popups', + GEOLOCATION: 'location', + NOTIFICATIONS: 'notifications', + MIC: 'media-stream-mic', + CAMERA: 'media-stream-camera', + PROTOCOL_HANDLERS: 'register-protocol-handler', + UNSANDBOXED_PLUGINS: 'ppapi-broker', + AUTOMATIC_DOWNLOADS: 'multiple-automatic-downloads', + KEYGEN: 'keygen', + BACKGROUND_SYNC: 'background-sync', + USB_DEVICES: 'usb-chooser-data', + ZOOM_LEVELS: 'zoom-levels', +}; - /** - * A category value to use for the All Sites list. - * @const {string} - */ - var ALL_SITES = 'all-sites'; +/** + * Contains the possible string values for a given contentSettingsType. + * @enum {string} + * + * TODO(dschuyler): This should be rename as ContentSetting to maintain + * nomenclature with C++. + */ +settings.PermissionValues = { + DEFAULT: 'default', + ALLOW: 'allow', + BLOCK: 'block', + ASK: 'ask', + SESSION_ONLY: 'session_only', + IMPORTANT_CONTENT: 'detect_important_content', +}; - /** - * An invalid subtype value. - * @const {string} - */ - var INVALID_CATEGORY_SUBTYPE = ''; +/** + * A category value to use for the All Sites list. + * @const {string} + */ +settings.ALL_SITES = 'all-sites'; - return { - ContentSettingsTypes: ContentSettingsTypes, - PermissionValues: PermissionValues, - ALL_SITES: ALL_SITES, - INVALID_CATEGORY_SUBTYPE: INVALID_CATEGORY_SUBTYPE, - }; -}); +/** + * An invalid subtype value. + * @const {string} + */ +settings.INVALID_CATEGORY_SUBTYPE = ''; diff --git a/chromium/chrome/browser/resources/settings/site_settings/cookie_info.js b/chromium/chrome/browser/resources/settings/site_settings/cookie_info.js index 3b912a351ed..dae2096f447 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/cookie_info.js +++ b/chromium/chrome/browser/resources/settings/site_settings/cookie_info.js @@ -2,6 +2,22 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +/** + * @typedef {{hasChildren: boolean, + * id: string, + * idPath: string, + * title: string, + * totalUsage: string, + * type: string}} + */ +var CookieDetails; + +/** + * @typedef {{content: string, + * label: string}} + */ +var CookieDataForDisplay; + // This structure maps the various cookie type names from C++ (hence the // underscores) to arrays of the different types of data each has, along with // the i18n name for the description of that data type. @@ -45,4 +61,32 @@ ['size', 'cacheStorageSize'], ['modified', 'cacheStorageLastModified']], 'flash_lso': [['domain', 'cookieDomain']], + 'media_license': [['origin', 'mediaLicenseOrigin'], + ['size', 'mediaLicenseSize'], + ['modified', 'mediaLicenseLastModified']], +}; + +/** + * Get cookie data for a given HTML node. + * @param {CookieDetails} data The contents of the cookie. + * @return {!Array<CookieDataForDisplay>} + */ +var getCookieData = function(data) { + /** @type {!Array<CookieDataForDisplay>} */ + var out = []; + var fields = cookieInfo[data.type]; + for (var field of fields) { + // Iterate through the keys found in |cookieInfo| for the given |type| + // and see if those keys are present in the data. If so, display them + // (in the order determined by |cookieInfo|). + var key = field[0]; + if (data[key].length > 0) { + var entry = /** @type {CookieDataForDisplay} */({ + label: loadTimeData.getString(field[1]), + content: data[key], + }); + out.push(entry); + } + } + return out; }; diff --git a/chromium/chrome/browser/resources/settings/site_settings/cookie_tree_behavior.html b/chromium/chrome/browser/resources/settings/site_settings/cookie_tree_behavior.html new file mode 100644 index 00000000000..f013afafd23 --- /dev/null +++ b/chromium/chrome/browser/resources/settings/site_settings/cookie_tree_behavior.html @@ -0,0 +1,3 @@ +<link rel="import" href="/site_settings/site_settings_behavior.html"> +<link rel="import" href="/site_settings/site_settings_prefs_browser_proxy.html"> +<script src="cookie_tree_behavior.js"></script> diff --git a/chromium/chrome/browser/resources/settings/site_settings/cookie_tree_behavior.js b/chromium/chrome/browser/resources/settings/site_settings/cookie_tree_behavior.js new file mode 100644 index 00000000000..9f090f7bec2 --- /dev/null +++ b/chromium/chrome/browser/resources/settings/site_settings/cookie_tree_behavior.js @@ -0,0 +1,99 @@ +// 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. + +/** + * @fileoverview A behavior for managing a tree of cookies. + */ + +/** @polymerBehavior */ +var CookieTreeBehaviorImpl = { + properties: { + /** + * A summary list of all sites and how many entities each contain. + * @type {!Array<!CookieDataSummaryItem>} + */ + sites: Array, + + /** + * The cookie tree with the details needed to display individual sites and + * their contained data. + * @type {!settings.CookieTreeNode} + * @protected + */ + rootCookieNode: Object, + }, + + /** @override */ + ready: function() { + cr.addWebUIListener('onTreeItemRemoved', + this.onTreeItemRemoved_.bind(this)); + this.rootCookieNode = new settings.CookieTreeNode(null); + }, + + /** + * Called when the cookie list is ready to be shown. + * @param {!CookieList} list The cookie list to show. + * @return {Promise} + * @private + */ + loadChildren_: function(list) { + var loadChildrenRecurse = function(childList) { + var parentId = childList.id; + var children = childList.children; + var prefix = ''; + if (parentId !== null) { + this.rootCookieNode.populateChildNodes(parentId, + this.rootCookieNode, children); + prefix = parentId + ', '; + } + var promises = []; + for (let child of children) { + if (child.hasChildren) { + promises.push(this.browserProxy.loadCookieChildren( + prefix + child.id).then(loadChildrenRecurse.bind(this))); + } + } + return Promise.all(promises); + }.bind(this); + + // New root being added, clear the list and add the nodes. + this.sites = []; + this.rootCookieNode.addChildNodes(this.rootCookieNode, list.children); + return loadChildrenRecurse(list).then(function() { + this.sites = this.rootCookieNode.getSummaryList(); + return Promise.resolve(); + }.bind(this)); + }, + + /** + * Loads (or reloads) the whole cookie list. + * @return {Promise} + */ + loadCookies: function() { + return this.browserProxy.reloadCookies().then( + this.loadChildren_.bind(this)); + }, + + /** + * Called when a single item has been removed (not during delete all). + * @param {!CookieRemovePacket} args The details about what to remove. + * @private + */ + onTreeItemRemoved_: function(args) { + this.rootCookieNode.removeByParentId(args.id, args.start, args.count); + this.sites = this.rootCookieNode.getSummaryList(); + }, + + /** + * Deletes site data for multiple sites. + * @return {Promise} + */ + removeAllCookies: function() { + return this.browserProxy.removeAllCookies().then( + this.loadChildren_.bind(this)); + }, +}; + +/** @polymerBehavior */ +var CookieTreeBehavior = [SiteSettingsBehavior, CookieTreeBehaviorImpl]; diff --git a/chromium/chrome/browser/resources/settings/site_settings/cookie_tree_node.js b/chromium/chrome/browser/resources/settings/site_settings/cookie_tree_node.js index 0763e803229..f6c1cbc5d98 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/cookie_tree_node.js +++ b/chromium/chrome/browser/resources/settings/site_settings/cookie_tree_node.js @@ -3,15 +3,6 @@ // found in the LICENSE file. /** - * @typedef {{hasChildren: boolean, - * id: string, - * title: string, - * totalUsage: string, - * type: string}} - */ -var CookieDetails; - -/** * @typedef {{title: string, * id: string, * data: CookieDetails}} @@ -34,8 +25,8 @@ var CookieList; /** * @typedef {{id: string, - * start: !number, - * count: !number}} + * start: number, + * count: number}} */ var CookieRemovePacket; @@ -50,6 +41,7 @@ var categoryLabels = { 'indexed_db': loadTimeData.getString('cookieDatabaseStorage'), 'local_storage': loadTimeData.getString('cookieLocalStorage'), 'service_worker': loadTimeData.getString('cookieServiceWorker'), + 'media_license': loadTimeData.getString('cookieMediaLicense'), }; /** @@ -73,9 +65,9 @@ cr.define('settings', function() { function CookieTreeNode(data) { /** * The data for this cookie node. - * @private {CookieDetails} + * @type {CookieDetails} */ - this.data_ = data; + this.data = data; /** * The child cookie nodes. @@ -111,7 +103,7 @@ cr.define('settings', function() { */ populateChildNodes: function(parentId, startingNode, newNodes) { for (var i = 0; i < startingNode.children_.length; ++i) { - if (startingNode.children_[i].data_.id == parentId) { + if (startingNode.children_[i].data.id == parentId) { this.addChildNodes(startingNode.children_[i], newNodes); return true; } @@ -142,12 +134,11 @@ cr.define('settings', function() { */ getCookieList: function() { var list = []; - - for (var group of this.children_) { - for (var cookie of group.children_) { - list.push({title: cookie.data_.title, - id: cookie.data_.id, - data: cookie.data_}); + for (var child of this.children_) { + for (var cookie of child.children_) { + list.push({title: cookie.data.title, + id: cookie.data.id, + data: cookie.data}); } } @@ -162,10 +153,13 @@ cr.define('settings', function() { var list = []; for (var i = 0; i < this.children_.length; ++i) { var siteEntry = this.children_[i]; - var title = siteEntry.data_.title; - var id = siteEntry.data_.id; + var title = siteEntry.data.title; + var id = siteEntry.data.id; var description = ''; + if (siteEntry.children_.length == 0) + continue; + for (var j = 0; j < siteEntry.children_.length; ++j) { var descriptionNode = siteEntry.children_[j]; if (j > 0) @@ -173,12 +167,12 @@ cr.define('settings', function() { // Some types, like quota, have no description nodes. var dataType = ''; - if (descriptionNode.data_.type != undefined) { - dataType = descriptionNode.data_.type; + if (descriptionNode.data.type != undefined) { + dataType = descriptionNode.data.type; } else { // A description node might not have children when it's deleted. if (descriptionNode.children_.length > 0) - dataType = descriptionNode.children_[0].data_.type; + dataType = descriptionNode.children_[0].data.type; } var count = @@ -187,9 +181,8 @@ cr.define('settings', function() { description += loadTimeData.getStringF('cookiePlural', count); } else { description += getCookieDataCategoryText( - dataType, descriptionNode.data_.totalUsage); + dataType, descriptionNode.data.totalUsage); } - } list.push({ site: title, id: id, localData: description }); } @@ -209,7 +202,7 @@ cr.define('settings', function() { for (var i = 0; i < this.children_.length; ++i) { if (this.children_[i] == null) return null; - if (this.children_[i].data_.id == id) + if (this.children_[i].data.id == id) return this.children_[i]; if (recursive) { var node = this.children_[i].fetchNodeById(id, true); @@ -221,28 +214,16 @@ cr.define('settings', function() { }, /** - * Add cookie data to a given HTML node. - * @param {HTMLElement} root The node to add the data to. - * @param {!settings.CookieTreeNode} item The data to add. + * Fetch a CookieTreeNode by site. + * @param {string} site The web site to look up. + * @return {?settings.CookieTreeNode} The node found, if any. */ - addCookieData: function(root, item) { - var fields = cookieInfo[item.data_.type]; - for (var field of fields) { - // Iterate through the keys found in |cookieInfo| for the given |type| - // and see if those keys are present in the data. If so, display them - // (in the order determined by |cookieInfo|). - var key = field[0]; - if (item.data_[key].length > 0) { - var label = loadTimeData.getString(field[1]); - - var header = document.createElement('div'); - header.appendChild(document.createTextNode(label)); - var content = document.createElement('div'); - content.appendChild(document.createTextNode(item.data_[key])); - root.appendChild(header); - root.appendChild(content); - } + fetchNodeBySite: function(site) { + for (var i = 0; i < this.children_.length; ++i) { + if (this.children_[i].data.title == site) + return this.children_[i]; } + return null; }, }; diff --git a/chromium/chrome/browser/resources/settings/site_settings/media_picker.html b/chromium/chrome/browser/resources/settings/site_settings/media_picker.html index 9839b5eea2f..97407eaf17a 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/media_picker.html +++ b/chromium/chrome/browser/resources/settings/site_settings/media_picker.html @@ -1,6 +1,7 @@ +<link rel="import" href="chrome://resources/html/md_select_css.html"> <link rel="import" href="chrome://resources/html/polymer.html"> -<link rel="import" href="/md_select_css.html"> <link rel="import" href="/settings_shared_css.html"> +<link rel="import" href="/settings_vars_css.html"> <dom-module id="media-picker"> <template> diff --git a/chromium/chrome/browser/resources/settings/site_settings/pdf_documents.html b/chromium/chrome/browser/resources/settings/site_settings/pdf_documents.html new file mode 100644 index 00000000000..98c0c18ac08 --- /dev/null +++ b/chromium/chrome/browser/resources/settings/site_settings/pdf_documents.html @@ -0,0 +1,23 @@ +<link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="/controls/settings_toggle_button.html"> +<link rel="import" href="/settings_shared_css.html"> + +<dom-module id="settings-pdf-documents"> + <template> + <style include="settings-shared"> + .secondary { + margin-top: 0; /* Cancel separation between main and secondary text. */ + } + </style> + <div class="settings-box first two-line"> + <div class="start secondary"> + $i18n{siteSettingsPdfDifferentApplication} + </div> + <settings-toggle-button id="toggle" checked="{{categoryEnabled}}" + on-change="onToggleChange_" + pref="{{prefs.plugins.always_open_pdf_externally}}"> + </settings-toggle-button> + </div> + </template> + <script src="pdf_documents.js"></script> +</dom-module> diff --git a/chromium/chrome/browser/resources/settings/site_settings/pdf_documents.js b/chromium/chrome/browser/resources/settings/site_settings/pdf_documents.js new file mode 100644 index 00000000000..66f61a6db59 --- /dev/null +++ b/chromium/chrome/browser/resources/settings/site_settings/pdf_documents.js @@ -0,0 +1,20 @@ +// Copyright 2016 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +/** + * @fileoverview + * 'settings-pdf-documents' is the polymer element for showing the + * settings for viewing PDF documents under Site Settings. + */ + +Polymer({ + is: 'settings-pdf-documents', + + properties: { + prefs: { + type: Object, + notify: true, + }, + }, +}); diff --git a/chromium/chrome/browser/resources/settings/site_settings/protocol_handlers.html b/chromium/chrome/browser/resources/settings/site_settings/protocol_handlers.html index ab78ee849ff..265b2f10738 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/protocol_handlers.html +++ b/chromium/chrome/browser/resources/settings/site_settings/protocol_handlers.html @@ -1,10 +1,9 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-menu/paper-menu.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-menu-button/paper-menu-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html"> + <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="/i18n_setup.html"> <link rel="import" href="/settings_shared_css.html"> @@ -42,35 +41,33 @@ <div class="favicon-image" style$="[[computeSiteIcon(item.host)]]"> </div> <div class="middle" > - <div>[[item.host]]</div> - <div class="secondary" + <div class="protocol-host">[[item.host]]</div> + <div class="secondary protocol-default" hidden$="[[!isDefault_(index, protocol.default_handler)]]"> $i18n{handlerIsDefault} </div> </div> - <paper-menu-button> - <paper-icon-button icon="cr:more-vert" - class="dropdown-trigger"> - </paper-icon-button> - <paper-menu id="actionMenu" class="dropdown-content" actionable - on-iron-activate="onActionMenuIronActivate_" - attr-for-selected="menu-value"> - <paper-item menu-value$="[[menuActions_.SET_DEFAULT]]" - hidden$="[[isDefault_(index, protocol.default_handler)]]" - actionable> - $i18n{handlerSetDefault} - </paper-item> - <paper-item menu-value$="[[menuActions_.REMOVE]]" actionable> - $i18n{handlerRemove} - </paper-item> - </paper-menu> - </paper-menu-button> + <paper-icon-button icon="cr:more-vert" on-tap="showMenu_" + class="dropdown-trigger"> + </paper-icon-button> </div> </template> </div> </template> + + <dialog is="cr-action-menu"> + <button class="dropdown-item" role="option" on-tap="onDefaultTap_" + hidden$="[[isModelDefault_(actionMenuModel_)]]" + id="defaultButton"> + $i18n{handlerSetDefault} + </button> + <button class="dropdown-item" role="option" on-tap="onRemoveTap_" + id="removeButton"> + $i18n{handlerRemove} + </button> + </dialog> </template> <script src="protocol_handlers.js"></script> </dom-module> diff --git a/chromium/chrome/browser/resources/settings/site_settings/protocol_handlers.js b/chromium/chrome/browser/resources/settings/site_settings/protocol_handlers.js index 404d3df1dae..b175e83ed82 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/protocol_handlers.js +++ b/chromium/chrome/browser/resources/settings/site_settings/protocol_handlers.js @@ -51,14 +51,10 @@ Polymer({ protocols: Array, /** - * The possible menu actions. - * @type {MenuActions} + * The targetted object for menu operations. + * @private {?Object} */ - menuActions_: { - type: Object, - value: MenuActions, - readOnly: true, - }, + actionMenuModel_: Object }, ready: function() { @@ -133,18 +129,50 @@ Polymer({ }, /** - * A handler when an action is selected in the action menu. - * @param {!{model: !{item: ProtocolHandlerEntry}, - * detail: !{selected: string}}} event + * The handler for when "Set Default" is selected in the action menu. * @private */ - onActionMenuIronActivate_: function(event) { - var protocol = event.model.item.protocol; - var url = event.model.item.spec; - if (event.detail.selected == MenuActions.SET_DEFAULT) { - this.browserProxy.setProtocolDefault(protocol, url); - } else if (event.detail.selected == MenuActions.REMOVE) { - this.browserProxy.removeProtocolHandler(protocol, url); - } + onDefaultTap_: function() { + var item = this.actionMenuModel_.item; + + this.$$('dialog[is=cr-action-menu]').close(); + this.actionMenuModel_ = null; + this.browserProxy.setProtocolDefault(item.protocol, item.spec); + }, + + /** + * The handler for when "Remove" is selected in the action menu. + * @private + */ + onRemoveTap_: function() { + var item = this.actionMenuModel_.item; + + this.$$('dialog[is=cr-action-menu]').close(); + this.actionMenuModel_ = null; + this.browserProxy.removeProtocolHandler(item.protocol, item.spec); }, + + /** + * Checks whether or not the selected actionMenuModel is the default handler + * for its protocol. + * @return {boolean} if actionMenuModel_ is default handler of its protocol. + */ + isModelDefault_: function() { + return !!this.actionMenuModel_ && (this.actionMenuModel_.index == + this.actionMenuModel_.protocol.default_handler); + }, + + /** + * A handler to show the action menu next to the clicked menu button. + * @param {!{model: !{protocol: HandlerEntry, item: ProtocolEntry, + * index: number}}} event + * @private + */ + showMenu_: function(event) { + this.actionMenuModel_ = event.model; + /** @type {!CrActionMenuElement} */ ( + this.$$('dialog[is=cr-action-menu]')).showAt( + /** @type {!Element} */ ( + Polymer.dom(/** @type {!Event} */ (event)).localTarget)); + } }); diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_data.html b/chromium/chrome/browser/resources/settings/site_settings/site_data.html index 2d95ea9c9c1..be45b89145e 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/site_data.html +++ b/chromium/chrome/browser/resources/settings/site_settings/site_data.html @@ -1,68 +1,67 @@ <link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> -<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout-classes.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button-light.html"> <link rel="import" href="/settings_page/settings_subpage_search.html"> <link rel="import" href="/settings_shared_css.html"> -<link rel="import" href="/site_settings/site_data_details_dialog.html"> +<link rel="import" href="/site_settings/cookie_tree_behavior.html"> <link rel="import" href="/site_settings/site_settings_behavior.html"> <dom-module id="site-data"> <template> <style include="settings-shared"> - :host { - display: block; - margin-top: 18px; - width: 100%; + paper-button#removeButton { + -webkit-margin-start: auto; } - .list-frame { - -webkit-margin-end: -29px; - -webkit-padding-start: 36px; - margin-top: 10px; - } - - .site-header { - margin-top: 10px; - } - - .site { - margin-top: 7px; - } - - #filter { - margin-top: -4px; + .subtitle-row { + margin-top: 9px; /* With 15px in sub-items == 24px total margin. */ } </style> - <div class="layout horizontal"> - <div class="flex site-header">$i18n{siteSettingsCookieHeader}</div> - <div class="secondary-action" - hidden$="[[!isRemoveButtonVisible_(sites, renderedItemCount)]]"> - <paper-button on-tap="onDeleteMultipleSites_" class="secondary-button"> - [[computeRemoveLabel_(filterString_)]] - </paper-button> + <div class="settings-box first subtitle-row"> + <div class="start"> + <div>$i18n{siteSettingsCookieHeader}</div> </div> <settings-subpage-search id="filter" on-search-changed="onSearchChanged_" label="$i18n{siteSettingsCookieSearch}"> </settings-subpage-search> </div> - + <div class="settings-box continuation"> + <paper-button class="secondary-button" id="removeButton" + on-tap="onConfirmDeleteMultipleSites_" + hidden$="[[!isRemoveButtonVisible_(sites, renderedItemCount)]]"> + [[computeRemoveLabel_(filterString_)]] + </paper-button> + </div> <div class="list-frame vertical-list"> <template is="dom-repeat" id="list" items="[[sites]]" filter="showItem_" rendered-item-count="{{renderedItemCount}}"> - <div class="list-item layout horizontal"> - <div class="layout horizontal flex" on-tap="onSiteTap_" actionable> - <div class="favicon-image site" - style$="[[computeSiteIcon(item.site)]]"> - </div> - <div class="flex middle">[[item.site]]</div> - <div class="site">[[item.localData]]</div> + <div class="list-item two-line" on-tap="onSiteTap_" actionable> + <div class="favicon-image" style$="[[computeSiteIcon(item.site)]]"> + </div> + <div class="middle"> + [[item.site]] + <div class="secondary">[[item.localData]]</div> </div> - <paper-icon-button on-tap="onDeleteSite_" - icon="cr:delete"></paper-icon-button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> </template> </div> + + <!-- Confirm Delete dialog --> + <dialog is="cr-dialog" id="confirmDeleteDialog"> + <div class="title">$i18n{siteSettingsCookieRemoveDialogTitle}</div> + <div class="body">[[confirmationDeleteMsg_]]</div> + <div class="button-container"> + <paper-button class="cancel-button" on-tap="onCloseDialog_"> + $i18n{cancel} + </paper-button> + <paper-button class="action-button" on-tap="onConfirmDelete_"> + $i18n{siteSettingsCookiesClearAll} + </paper-button> + </div> + </dialog> </template> <script src="cookie_info.js"></script> <script src="cookie_tree_node.js"></script> diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_data.js b/chromium/chrome/browser/resources/settings/site_settings/site_data.js index b8657741880..c5df0d69c51 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/site_data.js +++ b/chromium/chrome/browser/resources/settings/site_settings/site_data.js @@ -10,58 +10,34 @@ Polymer({ is: 'site-data', - behaviors: [SiteSettingsBehavior, WebUIListenerBehavior], + behaviors: [CookieTreeBehavior], properties: { /** - * A summary list of all sites and how many entities each contain. - * @type {Array<CookieDataSummaryItem>} - */ - sites: Array, - - /** - * The cookie tree with the details needed to display individual sites and - * their contained data. - * @type {!settings.CookieTreeNode} - */ - treeNodes_: Object, - - /** - * Keeps track of how many outstanding requests for more data there are. - */ - requests_: Number, - - /** * The current filter applied to the cookie data list. + * @private */ filterString_: { type: String, value: '', - } - }, + }, - ready: function() { - this.addWebUIListener('onTreeItemRemoved', - this.onTreeItemRemoved_.bind(this)); - this.treeNodes_ = new settings.CookieTreeNode(null); - // Start the initial request. - this.reloadCookies_(); + /** @private */ + confirmationDeleteMsg_: String, + + /** @private */ + idToDelete_: String, }, - /** - * Reloads the whole cookie list. - * @private - */ - reloadCookies_: function() { - this.browserProxy.reloadCookies().then(function(list) { - this.loadChildren_(list); - }.bind(this)); + /** @override */ + ready: function() { + this.loadCookies(); }, /** * A filter function for the list. * @param {!CookieDataSummaryItem} item The item to possibly filter out. - * @return {!boolean} Whether to show the item. + * @return {boolean} Whether to show the item. * @private */ showItem_: function(item) { @@ -83,7 +59,7 @@ Polymer({ /** * Returns the string to use for the Remove label. - * @return {!string} filterString The current filter string. + * @return {string} filterString The current filter string. * @private */ computeRemoveLabel_: function(filterString) { @@ -92,61 +68,40 @@ Polymer({ return loadTimeData.getString('siteSettingsCookieRemoveAllShown'); }, + /** @private */ + onCloseDialog_: function() { + this.$.confirmDeleteDialog.close(); + }, + /** - * Called when the cookie list is ready to be shown. - * @param {!CookieList} list The cookie list to show. + * Shows a dialog to confirm the deletion of multiple sites. * @private */ - loadChildren_: function(list) { - var parentId = list.id; - var data = list.children; - - if (parentId == null) { - // New root being added, clear the list and add the nodes. - this.sites = []; - this.requests_ = 0; - this.treeNodes_.addChildNodes(this.treeNodes_, data); - } else { - this.treeNodes_.populateChildNodes(parentId, this.treeNodes_, data); - } - - for (var i = 0; i < data.length; ++i) { - var prefix = parentId == null ? '' : parentId + ', '; - if (data[i].hasChildren) { - ++this.requests_; - this.browserProxy.loadCookieChildren( - prefix + data[i].id).then(function(list) { - --this.requests_; - this.loadChildren_(list); - }.bind(this)); - } - } - - if (this.requests_ == 0) - this.sites = this.treeNodes_.getSummaryList(); - - // If this reaches below zero then we're forgetting to increase the - // outstanding request count and the summary list won't be updated at the - // end. - assert(this.requests_ >= 0); + onConfirmDeleteMultipleSites_: function() { + this.idToDelete_ = ''; // Delete all. + this.confirmationDeleteMsg_ = loadTimeData.getString( + 'siteSettingsCookieRemoveMultipleConfirmation'); + this.$.confirmDeleteDialog.showModal(); }, /** - * Called when a single item has been removed (not during delete all). - * @param {!CookieRemovePacket} args The details about what to remove. + * Called when deletion for a single/multiple sites has been confirmed. + * @private */ - onTreeItemRemoved_: function(args) { - this.treeNodes_.removeByParentId(args.id, args.start, args.count); - this.sites = this.treeNodes_.getSummaryList(); + onConfirmDelete_: function() { + if (this.idToDelete_ != '') + this.onDeleteSite_(); + else + this.onDeleteMultipleSites_(); + this.$.confirmDeleteDialog.close(); }, /** * Deletes all site data for a given site. - * @param {!{model: !{item: CookieDataSummaryItem}}} event * @private */ - onDeleteSite_: function(event) { - this.browserProxy.removeCookie(event.model.item.id); + onDeleteSite_: function() { + this.browserProxy.removeCookie(this.idToDelete_); }, /** @@ -155,15 +110,15 @@ Polymer({ */ onDeleteMultipleSites_: function() { if (this.filterString_.length == 0) { - this.browserProxy.removeAllCookies().then(function(list) { - this.loadChildren_(list); - }.bind(this)); + this.removeAllCookies(); } else { var items = this.$.list.items; for (var i = 0; i < items.length; ++i) { if (this.showItem_(items[i])) this.browserProxy.removeCookie(items[i].id); } + // We just deleted all items found by the filter, let's reset the filter. + /** @type {SettingsSubpageSearchElement} */(this.$.filter).setValue(''); } }, @@ -172,15 +127,7 @@ Polymer({ * @private */ onSiteTap_: function(event) { - var dialog = document.createElement('site-data-details-dialog'); - dialog.category = this.category; - this.shadowRoot.appendChild(dialog); - - var node = this.treeNodes_.fetchNodeById(event.model.item.id, false); - dialog.open(node); - - dialog.addEventListener('close', function(event) { - dialog.remove(); - }); + settings.navigateTo(settings.Route.SITE_SETTINGS_DATA_DETAILS, + new URLSearchParams('site=' + event.model.item.site)); }, }); diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_data_details_dialog.html b/chromium/chrome/browser/resources/settings/site_settings/site_data_details_dialog.html deleted file mode 100644 index 1779516a989..00000000000 --- a/chromium/chrome/browser/resources/settings/site_settings/site_data_details_dialog.html +++ /dev/null @@ -1,59 +0,0 @@ -<link rel="import" href="chrome://resources/html/polymer.html"> -<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html"> -<link rel="import" href="/i18n_setup.html"> -<link rel="import" href="/md_select_css.html"> -<link rel="import" href="/settings_shared_css.html"> - -<dom-module id="site-data-details-dialog"> - <template> - <style include="settings-shared md-select"> - .picker-container { - flex: 1; - margin: auto; - } - - .remove-button { - margin: 0; - } - </style> - <dialog is="cr-dialog" id="dialog"> - <div class="title">[[title_]]</div> - <div class="body"> - <div class="layout horizontal" id="container"> - <div class="picker-container"> - <div class="md-select-wrapper"> - <select id="picker" class="md-select" on-change="onItemSelected_"> - <template is="dom-repeat" items="[[entries_]]"> - <option value$="[[item.id]]"> - [[getEntryDescription(item)]] - </option> - </template> - </select> - <span class="md-select-underline"></span> - </div> - </div> - <div class="button-container"> - <paper-button on-tap="onRemove_" - class="cancel-button remove-button"> - $i18n{siteSettingsCookieRemove} - </paper-button> - </div> - </div> - - <div id="content"></div> - - <div class="button-container"> - <paper-button class="cancel-button" on-tap="onCancelTap_"> - $i18n{cancel} - </paper-button> - <paper-button class="action-button" id="clear" on-tap="onRemoveAll_"> - $i18n{siteSettingsCookieRemoveAll} - </paper-button> - </div> - </div> - </dialog> - </template> - <script src="cookie_info.js"></script> - <script src="cookie_tree_node.js"></script> - <script src="site_data_details_dialog.js"></script> -</dom-module> diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_data_details_dialog.js b/chromium/chrome/browser/resources/settings/site_settings/site_data_details_dialog.js deleted file mode 100644 index 94b9e910704..00000000000 --- a/chromium/chrome/browser/resources/settings/site_settings/site_data_details_dialog.js +++ /dev/null @@ -1,203 +0,0 @@ -// Copyright 2016 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview - * 'site-data-details-dialog' provides a dialog to show details of site data - * stored by a given site. - */ -Polymer({ - is: 'site-data-details-dialog', - - behaviors: [SiteSettingsBehavior], - - properties: { - /** - * The title of the dialog. - */ - title_: String, - - /** - * The site to show details for. - * @type {!settings.CookieTreeNode} - * @private - */ - site_: Object, - - /** - * The cookie entries for the given site. - * @type {!Array<!CookieDataItem>} - * @private - */ - entries_: Array, - - /** - * The index of the last selected item. - */ - lastSelectedIndex_: Number, - - /** - * Our WebUI listener. - * @type {?WebUIListener} - */ - listener_: Object, - }, - - /** - * Opens the dialog. - * @param {!settings.CookieTreeNode} site The site to show data for. - */ - open: function(site) { - this.site_ = site; - this.populateDialog_(); - this.listener_ = cr.addWebUIListener( - 'onTreeItemRemoved', this.onTreeItemRemoved_.bind(this)); - this.$.dialog.showModal(); - }, - - /** - * Closes the dialog, if open. - */ - close: function() { - var dialog = /** @type {!CrDialogElement} */(this.$.dialog); - if (dialog.open) - dialog.close(); - }, - - /** - * Populates the dialog with the data about the site. - * @private - */ - populateDialog_: function() { - this.title_ = loadTimeData.getStringF('siteSettingsCookieDialog', - this.site_.data_.title); - - this.entries_ = this.site_.getCookieList(); - if (this.entries_.length < 2) { - // When there's only one item to show, hide the picker and change the - // 'Remove All' button to read 'Remove' instead. - this.$.container.hidden = true; - this.$.clear.textContent = - loadTimeData.getString('siteSettingsCookieRemove'); - } else { - this.$.picker.value = this.entries_[0].id; - this.lastSelectedIndex_ = 0; - } - - this.populateItem_(this.entries_[0].id, this.site_); - }, - - /** - * Recursively look up a node path for a leaf node with a given id. - * @param {!settings.CookieTreeNode} node The node to start with. - * @param {string} currentPath The path constructed so far. - * @param {string} targetId The id of the target leaf node to look for. - * @return {string} The path of the node returned (or blank if not found). - * @private - */ - nodePath_: function(node, currentPath, targetId) { - if (node.data_.id == targetId) - return currentPath; - - for (var i = 0; i < node.children_.length; ++i) { - var child = node.children_[i]; - var path = this.nodePath_( - child, currentPath + ',' + child.data_.id, targetId); - if (path.length > 0) - return path; - } - - return ''; - }, - - /** - * Add the cookie data to the content section of this dialog. - * @param {string} id The id of the cookie node to display. - * @param {!settings.CookieTreeNode} site The current site. - * @private - */ - populateItem_: function(id, site) { - // Out with the old... - var root = this.$.content; - while (root.lastChild) { - root.removeChild(root.lastChild); - } - - // In with the new... - var node = site.fetchNodeById(id, true); - if (node) - site.addCookieData(root, node); - }, - - /** - * Called when a single item has been removed. - * @param {!CookieRemovePacket} args The details about what to remove. - * @private - */ - onTreeItemRemoved_: function(args) { - this.entries_ = this.site_.getCookieList(); - if (this.site_.children_.length == 0 || this.entries_.length == 0) { - this.close(); - return; - } - - if (this.entries_.length <= this.lastSelectedIndex_) - this.lastSelectedIndex_ = this.entries_.length - 1; - var selectedId = this.entries_[this.lastSelectedIndex_].id; - this.$.picker.value = selectedId; - this.populateItem_(selectedId, this.site_); - }, - - /** - * A handler for when the user changes the dropdown box (switches cookies). - * @private - */ - onItemSelected_: function() { - var selectedItem = this.$.picker.value; - this.populateItem_(selectedItem, this.site_); - - // Store the index of what was selected so we can re-select the next value - // when things get deleted. - for (var i = 0; i < this.entries_.length; ++i) { - if (this.entries_[i].data.id == selectedItem) { - this.lastSelectedIndex_ = i; - break; - } - } - }, - - getEntryDescription: function(item) { - // Frequently there are multiple cookies per site. To avoid showing a list - // of '1 cookie', '1 cookie', ... etc, it is better to show the title of the - // cookie to differentiate them. - if (item.data.type == 'cookie') - return item.title; - - return getCookieDataCategoryText(item.data.type, item.data.totalUsage); - }, - - /** - * A handler for when the user opts to remove a single cookie. - * @private - */ - onRemove_: function(event) { - this.browserProxy.removeCookie(this.nodePath_( - this.site_, this.site_.data_.id, this.$.picker.value)); - }, - - /** - * A handler for when the user opts to remove all cookies. - * @private - */ - onRemoveAll_: function(event) { - cr.removeWebUIListener(this.listener_); - this.browserProxy.removeCookie(this.site_.data_.id); - this.close(); - }, - - /** @private */ - onCancelTap_: function() { - this.$.dialog.cancel(); - }, -}); diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_data_details_subpage.html b/chromium/chrome/browser/resources/settings/site_settings/site_data_details_subpage.html new file mode 100644 index 00000000000..ece1b3ea69f --- /dev/null +++ b/chromium/chrome/browser/resources/settings/site_settings/site_data_details_subpage.html @@ -0,0 +1,49 @@ +<link rel="import" href="chrome://resources/cr_elements/cr_expand_button/cr_expand_button.html"> +<link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/iron-collapse/iron-collapse.html"> +<link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> +<link rel="import" href="/route.html"> +<link rel="import" href="/settings_shared_css.html"> +<link rel="import" href="/site_settings/site_settings_prefs_browser_proxy.html"> + +<dom-module id="site-data-details-subpage"> + <template> + <style include="settings-shared md-select"> + [first] { + border-top: none; + } + + .secondary, + .start { + -webkit-user-select: text; + max-width: 100%; + word-wrap: break-word; + } + </style> + <template is="dom-repeat" items="[[entries_]]"> + <div class="settings-box" first$="[[!index]]"> + <div class="start">[[getEntryDescription_(item)]]</div> + <cr-expand-button expanded="{{item.expanded_}}"> + </cr-expand-button> + <paper-icon-button data-id-path$="[[item.idPath]]" icon="cr:close" + on-tap="onRemove_"> + </paper-icon-button> + </div> + <iron-collapse class="list-frame vertical-list" + opened="[[item.expanded_]]"> + <template is="dom-repeat" items="[[getCookieNodes_(item)]]"> + <div class="list-item two-line"> + <div class="start"> + [[item.label]] + <div class="secondary">[[item.content]]</div> + </div> + </div> + </template> + </iron-collapse> + </template> + </template> + <script src="cookie_info.js"></script> + <script src="cookie_tree_node.js"></script> + <script src="site_data_details_subpage.js"></script> +</dom-module> diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_data_details_subpage.js b/chromium/chrome/browser/resources/settings/site_settings/site_data_details_subpage.js new file mode 100644 index 00000000000..d7ea49bb4b9 --- /dev/null +++ b/chromium/chrome/browser/resources/settings/site_settings/site_data_details_subpage.js @@ -0,0 +1,139 @@ +// 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. + +(function() { + 'use strict'; + +/** + * 'site-data-details-subpage' Display cookie contents. + */ +Polymer({ + is: 'site-data-details-subpage', + + behaviors: [settings.RouteObserverBehavior, WebUIListenerBehavior], + + properties: { + /** + * The browser proxy used to retrieve and change cookies. + * @type {settings.SiteSettingsPrefsBrowserProxy} + */ + browserProxy: Object, + + /** + * The cookie entries for the given site. + * @type {!Array<!CookieDataItem>} + * @private + */ + entries_: Array, + + /** Set the page title on the settings-subpage parent. */ + pageTitle: { + type: String, + notify: true, + }, + + /** @private */ + site_: String, + + /** @private */ + siteId_: String, + }, + + /** @override */ + ready: function() { + this.browserProxy = + settings.SiteSettingsPrefsBrowserProxyImpl.getInstance(); + + this.addWebUIListener('onTreeItemRemoved', + this.getCookieDetails_.bind(this)); + }, + + /** + * settings.RouteObserverBehavior + * @param {!settings.Route} route + * @protected + */ + currentRouteChanged: function(route) { + if (settings.getCurrentRoute() != settings.Route.SITE_SETTINGS_DATA_DETAILS) + return; + var site = settings.getQueryParameters().get('site'); + if (!site || site == this.site_) + return; + this.site_ = site; + this.pageTitle = loadTimeData.getStringF('siteSettingsCookieSubpage', site); + this.getCookieDetails_(); + }, + + /** @private */ + getCookieDetails_: function() { + if (!this.site_) + return; + this.browserProxy.getCookieDetails(this.site_).then( + this.onCookiesLoaded_.bind(this), + this.onCookiesLoadFailed_.bind(this)); + }, + + /** + * @return {!Array<!CookieDataForDisplay>} + * @private + */ + getCookieNodes_: function(node) { + return getCookieData(node); + }, + + /** + * @param {!CookieDataSummaryItem} cookies + * @private + */ + onCookiesLoaded_: function(cookies) { + this.siteId_ = cookies.id; + this.entries_ = cookies.children; + // Set up flag for expanding cookie details. + this.entries_.map(function(e) { return e.expanded_ = false; }); + }, + + /** + * The site was not found. E.g. The site data may have been deleted or the + * site URL parameter may be mistyped. + * @private + */ + onCookiesLoadFailed_: function() { + this.siteId_ = ''; + this.entries_ = []; + }, + + /** + * A handler for when the user opts to remove a single cookie. + * @param {!CookieDetails} item + * @return {string} + * @private + */ + getEntryDescription_: function(item) { + // Frequently there are multiple cookies per site. To avoid showing a list + // of '1 cookie', '1 cookie', ... etc, it is better to show the title of the + // cookie to differentiate them. + if (item.type == 'cookie') + return item.title; + return getCookieDataCategoryText(item.type, item.totalUsage); + }, + + /** + * A handler for when the user opts to remove a single cookie. + * @param {!Event} event + * @private + */ + onRemove_: function(event) { + this.browserProxy.removeCookie( + /** @type {!CookieDetails} */(event.currentTarget.dataset).idPath); + }, + + /** + * A handler for when the user opts to remove all cookies. + */ + removeAll: function() { + this.browserProxy.removeCookie(this.siteId_); + }, +}); + +})(); diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_details.html b/chromium/chrome/browser/resources/settings/site_settings/site_details.html index cca0a6e8c53..9a93225392e 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/site_details.html +++ b/chromium/chrome/browser/resources/settings/site_settings/site_details.html @@ -1,7 +1,7 @@ <link rel="import" href="chrome://resources/html/polymer.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_dialog/cr_dialog.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-flex-layout/iron-flex-layout.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> <link rel="import" href="/route.html"> <link rel="import" href="/settings_shared_css.html"> @@ -21,6 +21,20 @@ -webkit-padding-end: 0; } </style> + <!-- Confirm Delete dialog --> + <dialog is="cr-dialog" id="confirmDeleteDialog"> + <div class="title">$i18n{siteSettingsSiteRemoveDialogTitle}</div> + <div class="body">[[confirmationDeleteMsg_]]</div> + <div class="button-container"> + <paper-button class="cancel-button" on-tap="onCloseDialog_"> + $i18n{cancel} + </paper-button> + <paper-button class="action-button" on-tap="onClearStorage_"> + $i18n{siteSettingsSiteClearAll} + </paper-button> + </div> + </dialog> + <div class="settings-box first"> <div class="favicon-image" style$="[[computeSiteIcon(site.originForDisplay)]]"> @@ -35,7 +49,7 @@ <paper-item id="storage" hidden$="[[!storedData_]]"> <div class="flex">[[storedData_]]</div> <paper-icon-button icon="cr:delete" - on-tap="onClearStorage_" + on-tap="onConfirmClearStorage_" alt="$i18n{siteSettingsDelete}"></paper-icon-button> </paper-item> </div> @@ -44,44 +58,56 @@ <h2>$i18n{siteSettingsPermissions}</h2> </div> <div class="list-frame"> - <site-details-permission site="[[site]]" id="cookies" - category="{{ContentSettingsTypes.COOKIES}}"> - </site-details-permission> - <site-details-permission site="[[site]]" id="geolocation" - category="{{ContentSettingsTypes.GEOLOCATION}}"> + <site-details-permission category="{{ContentSettingsTypes.COOKIES}}" + icon="settings:cookie" id="cookies" label="$i18n{siteSettingsCookies}" + site="[[site]]"> </site-details-permission> - <site-details-permission site="[[site]]" id="camera" - category="{{ContentSettingsTypes.CAMERA}}"> + <site-details-permission category="{{ContentSettingsTypes.GEOLOCATION}}" + icon="settings:location-on" id="geolocation" + label="$i18n{siteSettingsLocation}" site="[[site]]"> </site-details-permission> - <site-details-permission site="[[site]]" id="mic" - category="{{ContentSettingsTypes.MIC}}"> + <site-details-permission category="{{ContentSettingsTypes.CAMERA}}" + icon="settings:videocam" id="camera" + label="$i18n{siteSettingsCamera}" site="[[site]]"> </site-details-permission> - <site-details-permission site="[[site]]" id="notification" - category="{{ContentSettingsTypes.NOTIFICATIONS}}"> + <site-details-permission category="{{ContentSettingsTypes.MIC}}" + icon="settings:mic" id="mic" + label="$i18n{siteSettingsMic}" site="[[site]]"> </site-details-permission> - <site-details-permission site="[[site]]" id="javascript" - category="{{ContentSettingsTypes.JAVASCRIPT}}"> + <site-details-permission category="{{ContentSettingsTypes.NOTIFICATIONS}}" + icon="settings:notifications" id="notification" + label="$i18n{siteSettingsNotifications}" site="[[site]]"> </site-details-permission> - <site-details-permission site="[[site]]" id="plugins" - category="{{ContentSettingsTypes.PLUGINS}}"> + <site-details-permission category="{{ContentSettingsTypes.JAVASCRIPT}}" + icon="settings:input" id="javascript" + label="$i18n{siteSettingsJavascript}" site="[[site]]"> </site-details-permission> - <site-details-permission site="[[site]]" id="popups" - category="{{ContentSettingsTypes.POPUPS}}"> + <site-details-permission category="{{ContentSettingsTypes.PLUGINS}}" + icon="cr:extension" id="plugins" label="$i18n{siteSettingsFlash}" + site="[[site]]"> </site-details-permission> - <site-details-permission site="[[site]]" id="backgroundSync" - category="{{ContentSettingsTypes.BACKGROUND_SYNC}}"> + <site-details-permission category="{{ContentSettingsTypes.POPUPS}}" + icon="cr:open-in-new" id="popups" label="$i18n{siteSettingsPopups}" + site="[[site]]"> </site-details-permission> - <site-details-permission site="[[site]]" id="keygen" - category="{{ContentSettingsTypes.KEYGEN}}"> + <site-details-permission + category="{{ContentSettingsTypes.BACKGROUND_SYNC}}" + icon="settings:sync" id="backgroundSync" + label="$i18n{siteSettingsBackgroundSync}" site="[[site]]"> </site-details-permission> - <site-details-permission site="[[site]]" id="automaticDownloads" - category="{{ContentSettingsTypes.AUTOMATIC_DOWNLOADS}}"> + <site-details-permission category="{{ContentSettingsTypes.KEYGEN}}" + icon="settings:code" id="keygen"label="$i18n{siteSettingsKeygen}" + site="[[site]]"> </site-details-permission> - <site-details-permission site="[[site]]" id="unsandboxedPlugins" - category="{{ContentSettingsTypes.UNSANDBOXED_PLUGINS}}"> + <site-details-permission + category="{{ContentSettingsTypes.AUTOMATIC_DOWNLOADS}}" + icon="cr:file-download" id="automaticDownloads" + label="$i18n{siteSettingsAutomaticDownloads}" site="[[site]]"> </site-details-permission> - <site-details-permission site="[[site]]" id="fullscreen" - category="{{ContentSettingsTypes.FULLSCREEN}}"> + <site-details-permission + category="{{ContentSettingsTypes.UNSANDBOXED_PLUGINS}}" + icon="cr:extension" id="unsandboxedPlugins" + label="$i18n{siteSettingsUnsandboxedPlugins}" site="[[site]]"> </site-details-permission> <div on-tap="onClearAndReset_" raised class="list-item list-button"> diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_details.js b/chromium/chrome/browser/resources/settings/site_settings/site_details.js index 125e163823c..f60a905c010 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/site_details.js +++ b/chromium/chrome/browser/resources/settings/site_settings/site_details.js @@ -24,6 +24,7 @@ Polymer({ /** * The amount of data stored for the origin. + * @private */ storedData_: { type: String, @@ -32,14 +33,19 @@ Polymer({ /** * The type of storage for the origin. + * @private */ storageType_: Number, + + /** @private */ + confirmationDeleteMsg_: String, }, listeners: { - 'usage-deleted': 'onUsageDeleted', + 'usage-deleted': 'onUsageDeleted_', }, + /** @override */ ready: function() { this.ContentSettingsTypes = settings.ContentSettingsTypes; }, @@ -60,19 +66,35 @@ Polymer({ /** * Handler for when the origin changes. + * @private */ onSiteChanged_: function() { - // originForDisplay may be initially undefined if the user follows a direct + // origin may be initially undefined if the user follows a direct // link (URL) to this page. - if (this.site.originForDisplay !== undefined) { - // Using originForDisplay avoids the [*.] prefix that some exceptions use. - var url = new URL(this.ensureUrlHasScheme(this.site.originForDisplay)); - this.$.usageApi.fetchUsageTotal(url.hostname); - } + var origin = this.site.origin; + if (origin !== undefined) + this.$.usageApi.fetchUsageTotal(this.toUrl(origin).hostname); + }, + + /** @private */ + onCloseDialog_: function() { + this.$.confirmDeleteDialog.close(); + }, + + /** + * Confirms the deletion of storage for a site. + * @private + */ + onConfirmClearStorage_: function() { + this.confirmationDeleteMsg_ = loadTimeData.getStringF( + 'siteSettingsSiteRemoveConfirmation', + this.toUrl(this.site.origin).href); + this.$.confirmDeleteDialog.showModal(); }, /** * Clears all data stored for the current origin. + * @private */ onClearStorage_: function() { this.$.usageApi.clearUsage( @@ -81,8 +103,10 @@ Polymer({ /** * Called when usage has been deleted for an origin. + * @param {!{detail: !{origin: string}}} event + * @private */ - onUsageDeleted: function(event) { + onUsageDeleted_: function(event) { if (event.detail.origin == this.toUrl(this.site.origin).href) { this.storedData_ = ''; this.navigateBackIfNoData_(); @@ -91,6 +115,7 @@ Polymer({ /** * Resets all permissions and clears all data stored for the current origin. + * @private */ onClearAndReset_: function() { Array.prototype.forEach.call( @@ -105,6 +130,7 @@ Polymer({ /** * Navigate back if the UI is empty (everything been cleared). + * @private */ navigateBackIfNoData_: function() { if (this.storedData_ == '' && !this.permissionShowing_()) @@ -113,6 +139,7 @@ Polymer({ /** * Returns true if one or more permission is showing. + * @private */ permissionShowing_: function() { return Array.prototype.some.call( diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_details_permission.html b/chromium/chrome/browser/resources/settings/site_settings/site_details_permission.html index a2ac435fa0e..c34ae3f01d7 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/site_details_permission.html +++ b/chromium/chrome/browser/resources/settings/site_settings/site_details_permission.html @@ -1,8 +1,9 @@ +<link rel="import" href="chrome://resources/html/md_select_css.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/iron-icon/iron-icon.html"> <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> -<link rel="import" href="/md_select_css.html"> <link rel="import" href="/settings_shared_css.html"> +<link rel="import" href="/settings_vars_css.html"> <link rel="import" href="/site_settings/constants.html"> <link rel="import" href="/site_settings/site_settings_behavior.html"> <link rel="import" href="/site_settings/site_settings_prefs_browser_proxy.html"> @@ -13,12 +14,10 @@ <div id="details" hidden> <div class="list-item underbar"> <div> - <iron-icon icon="[[computeIconForContentCategory(category)]]"> + <iron-icon icon="[[icon]]"> </iron-icon> </div> - <div class="middle" id="permissionHeader"> - [[computeTitleForContentCategory(category)]] - </div> + <div class="middle" id="permissionHeader">[[label]]</div> <div class="md-select-wrapper"> <select id="permission" class="md-select" on-change="onPermissionSelectionChange_"> diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_list.html b/chromium/chrome/browser/resources/settings/site_settings/site_list.html index 58a8bbb062e..d3e83dc04b0 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/site_list.html +++ b/chromium/chrome/browser/resources/settings/site_settings/site_list.html @@ -1,11 +1,9 @@ +<link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html"> <link rel="import" href="chrome://resources/cr_elements/icons.html"> <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/iron-dropdown/iron-dropdown.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-button/paper-button.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-menu/paper-submenu.html"> <link rel="import" href="/i18n_setup.html"> <link rel="import" href="/icons.html"> <link rel="import" href="/route.html"> @@ -18,6 +16,10 @@ <dom-module id="site-list"> <template> <style include="settings-shared"> + paper-button { + margin-top: 12px; /* Align with <h2>. */ + } + paper-icon-button { left: 8px; right: 8px; @@ -27,28 +29,51 @@ -webkit-user-select: text; } </style> - <paper-submenu id="category" hidden - on-paper-submenu-open="onToggle_" on-paper-submenu-close="onToggle_"> - <div class="menu-trigger settings-box" hidden$="[[allSites]]" actionable> - <div class="flex" id="header"> - [[computeSiteListHeader_(sites, categoryEnabled)]] - </div> - <iron-icon id="icon" icon="cr:expand-more"></iron-icon> + <div id="category"> + <div class="settings-box first" hidden$="[[allSites]]"> + <h2 class="start">[[categoryHeader]]</h2> + <paper-button class="secondary-button" id="icon" on-tap="onAddSiteTap_"> + $i18n{add} + </paper-button> </div> + <dialog is="cr-action-menu"> + <button class="dropdown-item" role="option" id="allow" + on-tap="onAllowTap_" hidden$="[[!showAllowAction_]]"> + $i18n{siteSettingsActionAllow} + </button> + <button class="dropdown-item" role="option" id="block" + on-tap="onBlockTap_" hidden$="[[!showBlockAction_]]"> + $i18n{siteSettingsActionBlock} + </button> + <button class="dropdown-item" role="option" id="sessionOnly" + on-tap="onSessionOnlyTap_" + hidden$="[[!showSessionOnlyActionForSite_(actionMenuSite_)]]"> + $i18n{siteSettingsActionSessionOnly} + </button> + <button class="dropdown-item" role="option" id="reset" + on-tap="onResetTap_"> + $i18n{siteSettingsActionReset} + </button> + </dialog> + + <div class="list-frame" hidden$="[[hasSites_(sites)]]"> + <div class="list-item secondary">$i18n{noSitesAdded}</div> + </div> <div class="list-frame menu-content vertical-list" id="listContainer"> <template is="dom-repeat" items="[[sites]]"> <div class="list-item"> <div class="start layout horizontal center" on-tap="onOriginTap_" - actionable> + actionable$="[[enableSiteSettings_]]"> <div class="favicon-image" style$="[[computeSiteIcon(item.originForDisplay)]]"> </div> <div class="middle"> <div class="selectable">[[item.originForDisplay]]</div> - <div class="selectable secondary"> - [[computeSiteDescription_(item)]] - </div> + + <!-- This div must not contain extra whitespace. --> + <div class="selectable secondary" + >[[computeSiteDescription_(item)]]</div> </div> </div> @@ -56,44 +81,20 @@ <iron-icon icon="[[computeIconControlledBy_(item)]]"></iron-icon> </template> - <paper-icon-button id="dots" icon="cr:more-vert" toggles - active="{{item.menuOpened}}" - hidden="[[isExceptionControlled_(item.source)]]"> + <paper-icon-button id="dots" icon="cr:more-vert" + hidden="[[isExceptionControlled_(item.source)]]" + on-tap="onShowActionMenuTap_"> </paper-icon-button> - <template is="dom-if" if="[[item.menuOpened]]"> - <iron-dropdown vertical-align="auto" horizontal-align="right" - opened="{{item.menuOpened}}"> - <div class="dropdown-content"> - <button class="dropdown-item" role="option" id="allow" - on-tap="onAllowTap_" hidden$="[[!showAllowAction_]]"> - $i18n{siteSettingsActionAllow} - </button> - <button class="dropdown-item" role="option" id="block" - on-tap="onBlockTap_" hidden$="[[!showBlockAction_]]"> - $i18n{siteSettingsActionBlock} - </button> - <button class="dropdown-item" role="option" id="sessionOnly" - on-tap="onSessionOnlyTap_" - hidden$="[[!showSessionOnlyActionForSite_(item)]]"> - $i18n{siteSettingsActionSessionOnly} - </button> - <button class="dropdown-item" role="option" id="reset" - on-tap="onResetTap_"> - $i18n{siteSettingsActionReset} - </button> - </div> - </iron-dropdown> + <template is="dom-if" if="[[enableSiteSettings_]]"> + <div on-tap="onOriginTap_" actionable> + <button class="subpage-arrow" is="paper-icon-button-light"> + </button> + </div> </template> </div> </template> - - <template is="dom-if" if="[[!allSites]]"> - <div class="list-item list-button" on-tap="onAddSiteTap_"> - $i18n{addSiteLink} - </div> - </template> </div> - </paper-submenu> + </div> </template> <script src="site_list.js"></script> </dom-module> diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_list.js b/chromium/chrome/browser/resources/settings/site_settings/site_list.js index f2fcb7c1602..449fd4ea226 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/site_list.js +++ b/chromium/chrome/browser/resources/settings/site_settings/site_list.js @@ -26,6 +26,14 @@ Polymer({ behaviors: [SiteSettingsBehavior, WebUIListenerBehavior], properties: { + /** @private */ + enableSiteSettings_: { + type: Boolean, + value: function() { + return loadTimeData.getBoolean('enableSiteSettings'); + }, + }, + /** * The site that was selected by the user in the dropdown list. * @type {SiteException} @@ -36,6 +44,12 @@ Polymer({ }, /** + * The site serving as the model for the currently open action menu. + * @private {?SiteException} + */ + actionMenuSite_: Object, + + /** * Array of sites to display in the widget. * @type {!Array<SiteException>} */ @@ -113,7 +127,7 @@ Polymer({ }, observers: [ - 'configureWidget_(category, categorySubtype, categoryEnabled, allSites)' + 'configureWidget_(category, categorySubtype)' ], ready: function() { @@ -161,39 +175,12 @@ Polymer({ } this.setUpActionMenu_(); - this.ensureOpened_(); this.populateList_(); - }, - /** - * Ensures the widget is |opened| when needed when displayed initially. - * @private - */ - ensureOpened_: function() { - // Allowed list and Clear on Exit lists are always shown opened by default - // and All Sites is presented all in one list (nothing closed by default). - if (this.allSites || - this.categorySubtype == settings.PermissionValues.ALLOW || - this.categorySubtype == settings.PermissionValues.SESSION_ONLY) { - this.$.category.opened = true; - return; - } - - // Block list should only be shown opened if there is nothing to show in - // the other lists. - if (this.category != settings.INVALID_CATEGORY_SUBTYPE) { - this.browserProxy_.getExceptionList(this.category).then( - function(exceptionList) { - var othersExists = exceptionList.some(function(exception) { - return exception.setting == settings.PermissionValues.ALLOW || - exception.setting == settings.PermissionValues.SESSION_ONLY; - }); - if (othersExists) - return; - this.$.category.opened = true; - }.bind(this)); - } else { - this.$.category.opened = true; + // The Session permissions are only for cookies. + if (this.categorySubtype == settings.PermissionValues.SESSION_ONLY) { + this.$.category.hidden = + this.category != settings.ContentSettingsTypes.COOKIES; } }, @@ -211,21 +198,21 @@ Polymer({ }, /** - * @param {string} source Where the setting came from. + * Whether there are any site exceptions added for this content setting. * @return {boolean} * @private */ - shouldShowMenu_: function(source) { - return !(this.isExceptionControlled_(source) || this.allSites); + hasSites_: function() { + return !!this.sites.length; }, /** - * Makes sure the visibility is correct for this widget. + * @param {string} source Where the setting came from. + * @return {boolean} * @private */ - updateCategoryVisibility_: function() { - this.$.category.hidden = - !this.showSiteList_(this.sites, this.categoryEnabled); + shouldShowMenu_: function(source) { + return !(this.isExceptionControlled_(source) || this.allSites); }, /** @@ -235,6 +222,7 @@ Polymer({ onAddSiteTap_: function() { var dialog = document.createElement('add-site-dialog'); dialog.category = this.category; + dialog.contentSetting = this.categorySubtype; this.shadowRoot.appendChild(dialog); dialog.open(this.categorySubtype); @@ -245,17 +233,6 @@ Polymer({ }, /** - * Handles the expanding and collapsing of the sites list. - * @private - */ - onToggle_: function(e) { - if (this.$.category.opened) - this.$.icon.icon = 'cr:expand-less'; - else - this.$.icon.icon = 'cr:expand-more'; - }, - - /** * Populate the sites list for display. * @private */ @@ -283,7 +260,6 @@ Polymer({ for (var i = 0; i < data.length; ++i) sites = this.appendSiteList_(sites, data[i]); this.sites = this.toSiteArray_(sites); - this.updateCategoryVisibility_(); }, /** @@ -385,7 +361,7 @@ Polymer({ }, /** - * Setup the values to use for the action menu. + * Set up the values to use for the action menu. * @private */ setUpActionMenu_: function() { @@ -399,15 +375,15 @@ Polymer({ }, /** - * Whether to show the Session Only menu item for a given site. - * @param {SiteException} site The site in question. - * @return {boolean} Whether to show the menu item. + * @return {boolean} Whether to show the "Session Only" menu item for the + * currently active site. + * @private */ - showSessionOnlyActionForSite_: function(site) { + showSessionOnlyActionForSite_: function() { // It makes no sense to show "clear on exit" for exceptions that only apply // to incognito. It gives the impression that they might under some // circumstances not be cleared on exit, which isn't true. - if (site.incognito) + if (!this.actionMenuSite_ || this.actionMenuSite_.incognito) return false; return this.showSessionOnlyAction_; @@ -415,9 +391,12 @@ Polymer({ /** * A handler for selecting a site (by clicking on the origin). + * @param {!{model: !{item: !SiteException}}} event * @private */ onOriginTap_: function(event) { + if (!this.enableSiteSettings_) + return; this.selectedSite = event.model.item; settings.navigateTo(settings.Route.SITE_SETTINGS_SITE_DETAILS, new URLSearchParams('site=' + this.selectedSite.origin)); @@ -425,15 +404,14 @@ Polymer({ /** * A handler for activating one of the menu action items. - * @param {!{model: !{item: !{origin: string}}}} event * @param {string} action The permission to set (Allow, Block, SessionOnly, * etc). * @private */ - onActionMenuActivate_: function(event, action) { - var origin = event.model.item.origin; - var incognito = event.model.item.incognito; - var embeddingOrigin = event.model.item.embeddingOrigin; + onActionMenuActivate_: function(action) { + var origin = this.actionMenuSite_.origin; + var incognito = this.actionMenuSite_.incognito; + var embeddingOrigin = this.actionMenuSite_.embeddingOrigin; if (action == settings.PermissionValues.DEFAULT) { this.browserProxy.resetCategoryPermissionForOrigin( origin, embeddingOrigin, this.category, incognito); @@ -444,46 +422,27 @@ Polymer({ }, /** @private */ - onAllowTap_: function(event) { - this.onActionMenuActivate_(event, settings.PermissionValues.ALLOW); + onAllowTap_: function() { + this.onActionMenuActivate_(settings.PermissionValues.ALLOW); + this.closeActionMenu_(); }, /** @private */ - onBlockTap_: function(event) { - this.onActionMenuActivate_(event, settings.PermissionValues.BLOCK); + onBlockTap_: function() { + this.onActionMenuActivate_(settings.PermissionValues.BLOCK); + this.closeActionMenu_(); }, /** @private */ - onSessionOnlyTap_: function(event) { - this.onActionMenuActivate_(event, settings.PermissionValues.SESSION_ONLY); + onSessionOnlyTap_: function() { + this.onActionMenuActivate_(settings.PermissionValues.SESSION_ONLY); + this.closeActionMenu_(); }, /** @private */ - onResetTap_: function(event) { - this.onActionMenuActivate_(event, settings.PermissionValues.DEFAULT); - }, - - /** - * Returns the appropriate header value for display. - * @param {Array<string>} siteList The list of all sites to display for this - * category subtype. - * @param {boolean} toggleState The state of the global toggle for this - * category. - * @private - */ - computeSiteListHeader_: function(siteList, toggleState) { - var title = ''; - if (this.categorySubtype == settings.PermissionValues.ALLOW) { - title = loadTimeData.getString( - toggleState ? 'siteSettingsAllow' : 'siteSettingsExceptions'); - } else if (this.categorySubtype == settings.PermissionValues.BLOCK) { - title = loadTimeData.getString('siteSettingsBlock'); - } else if (this.categorySubtype == settings.PermissionValues.SESSION_ONLY) { - title = loadTimeData.getString('siteSettingsSessionOnly'); - } else { - return title; - } - return loadTimeData.getStringF('titleAndCount', title, siteList.length); + onResetTap_: function() { + this.onActionMenuActivate_(settings.PermissionValues.DEFAULT); + this.closeActionMenu_(); }, /** @@ -505,38 +464,21 @@ Polymer({ }, /** - * Returns true if this widget is showing the Allow list. - * @private - */ - isAllowList_: function() { - return this.categorySubtype == settings.PermissionValues.ALLOW; - }, - - /** - * Returns true if this widget is showing the Session Only list. + * @param {!{model: !{item: !SiteException}}} e * @private */ - isSessionOnlyList_: function() { - return this.categorySubtype == settings.PermissionValues.SESSION_ONLY; + onShowActionMenuTap_: function(e) { + this.actionMenuSite_ = e.model.item; + /** @type {!CrActionMenuElement} */ ( + this.$$('dialog[is=cr-action-menu]')).showAt( + /** @type {!Element} */ ( + Polymer.dom(/** @type {!Event} */ (e)).localTarget)); }, - /** - * Returns whether to show the site list. - * @param {Array} siteList The list of all sites to display for this category - * subtype. - * @param {boolean} toggleState The state of the global toggle for this - * category. - * @private - */ - showSiteList_: function(siteList, toggleState) { - // The Block list is only shown when the category is set to Allow since it - // is redundant to also list all the sites that are blocked. - if (this.isAllowList_()) - return true; - - if (this.isSessionOnlyList_()) - return siteList.length > 0; - - return toggleState; + /** @private */ + closeActionMenu_: function() { + this.actionMenuSite_ = null; + /** @type {!CrActionMenuElement} */ ( + this.$$('dialog[is=cr-action-menu]')).close(); }, }); diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_settings_behavior.js b/chromium/chrome/browser/resources/settings/site_settings/site_settings_behavior.js index c3043c93bf9..9aefbb26aae 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/site_settings_behavior.js +++ b/chromium/chrome/browser/resources/settings/site_settings/site_settings_behavior.js @@ -33,196 +33,6 @@ var SiteSettingsBehaviorImpl = { }, /** - * A utility function to lookup a category name from its enum. Note: The - * category name is visible to the user as part of the URL. - * @param {string} category The category ID to look up. - * @return {string} The category found or blank string if not found. - * @protected - */ - computeCategoryTextId: function(category) { - switch (category) { - case settings.ContentSettingsTypes.AUTOMATIC_DOWNLOADS: - return 'automatic-downloads'; - case settings.ContentSettingsTypes.BACKGROUND_SYNC: - return 'background-sync'; - case settings.ContentSettingsTypes.CAMERA: - return 'camera'; - case settings.ContentSettingsTypes.COOKIES: - return 'cookies'; - case settings.ContentSettingsTypes.GEOLOCATION: - return 'location'; - case settings.ContentSettingsTypes.IMAGES: - return 'images'; - case settings.ContentSettingsTypes.JAVASCRIPT: - return 'javascript'; - case settings.ContentSettingsTypes.KEYGEN: - return 'keygen'; - case settings.ContentSettingsTypes.MIC: - return 'microphone'; - case settings.ContentSettingsTypes.NOTIFICATIONS: - return 'notifications'; - case settings.ContentSettingsTypes.PLUGINS: - return 'plugins'; - case settings.ContentSettingsTypes.POPUPS: - return 'popups'; - case settings.ContentSettingsTypes.PROTOCOL_HANDLERS: - return 'handlers'; - case settings.ContentSettingsTypes.UNSANDBOXED_PLUGINS: - return 'unsandboxed-plugins'; - case settings.ContentSettingsTypes.USB_DEVICES: - return 'usb-devices'; - case settings.ContentSettingsTypes.ZOOM_LEVELS: - return 'zoom-levels'; - default: - return ''; - } - }, - - /** - * A utility function to lookup the route for a category name. - * @param {string} category The category ID to look up. - * @return {!settings.Route} - * @protected - */ - computeCategoryRoute: function(category) { - switch (category) { - case settings.ContentSettingsTypes.AUTOMATIC_DOWNLOADS: - return settings.Route.SITE_SETTINGS_AUTOMATIC_DOWNLOADS; - case settings.ContentSettingsTypes.BACKGROUND_SYNC: - return settings.Route.SITE_SETTINGS_BACKGROUND_SYNC; - case settings.ContentSettingsTypes.CAMERA: - return settings.Route.SITE_SETTINGS_CAMERA; - case settings.ContentSettingsTypes.COOKIES: - return settings.Route.SITE_SETTINGS_COOKIES; - case settings.ContentSettingsTypes.GEOLOCATION: - return settings.Route.SITE_SETTINGS_LOCATION; - case settings.ContentSettingsTypes.IMAGES: - return settings.Route.SITE_SETTINGS_IMAGES; - case settings.ContentSettingsTypes.JAVASCRIPT: - return settings.Route.SITE_SETTINGS_JAVASCRIPT; - case settings.ContentSettingsTypes.KEYGEN: - return settings.Route.SITE_SETTINGS_KEYGEN; - case settings.ContentSettingsTypes.MIC: - return settings.Route.SITE_SETTINGS_MICROPHONE; - case settings.ContentSettingsTypes.NOTIFICATIONS: - return settings.Route.SITE_SETTINGS_NOTIFICATIONS; - case settings.ContentSettingsTypes.PLUGINS: - return settings.Route.SITE_SETTINGS_FLASH; - case settings.ContentSettingsTypes.POPUPS: - return settings.Route.SITE_SETTINGS_POPUPS; - case settings.ContentSettingsTypes.PROTOCOL_HANDLERS: - return settings.Route.SITE_SETTINGS_HANDLERS; - case settings.ContentSettingsTypes.UNSANDBOXED_PLUGINS: - return settings.Route.SITE_SETTINGS_UNSANDBOXED_PLUGINS; - case settings.ContentSettingsTypes.USB_DEVICES: - return settings.Route.SITE_SETTINGS_USB_DEVICES; - case settings.ContentSettingsTypes.ZOOM_LEVELS: - return settings.Route.SITE_SETTINGS_ZOOM_LEVELS; - } - assertNotReached(); - }, - - /** - * A utility function to compute the icon to use for the category, both for - * the overall category as well as the individual permission in the details - * for a site. - * @param {string} category The category to show the icon for. - * @return {string} The id of the icon for the given category. - * @protected - */ - computeIconForContentCategory: function(category) { - switch (category) { - case settings.ContentSettingsTypes.AUTOMATIC_DOWNLOADS: - return 'cr:file-download'; - case settings.ContentSettingsTypes.BACKGROUND_SYNC: - return 'settings:sync'; - case settings.ContentSettingsTypes.CAMERA: - return 'settings:videocam'; - case settings.ContentSettingsTypes.COOKIES: - return 'settings:cookie'; - case settings.ContentSettingsTypes.FULLSCREEN: - return 'cr:fullscreen'; - case settings.ContentSettingsTypes.GEOLOCATION: - return 'settings:location-on'; - case settings.ContentSettingsTypes.IMAGES: - return 'settings:photo'; - case settings.ContentSettingsTypes.JAVASCRIPT: - return 'settings:input'; - case settings.ContentSettingsTypes.KEYGEN: - return 'settings:code'; - case settings.ContentSettingsTypes.MIC: - return 'settings:mic'; - case settings.ContentSettingsTypes.NOTIFICATIONS: - return 'settings:notifications'; - case settings.ContentSettingsTypes.PLUGINS: - return 'cr:extension'; - case settings.ContentSettingsTypes.POPUPS: - return 'cr:open-in-new'; - case settings.ContentSettingsTypes.PROTOCOL_HANDLERS: - return 'settings:protocol-handler'; - case settings.ContentSettingsTypes.UNSANDBOXED_PLUGINS: - return 'cr:extension'; - case settings.ContentSettingsTypes.USB_DEVICES: - return 'settings:usb'; - case settings.ContentSettingsTypes.ZOOM_LEVELS: - return 'settings:zoom-in'; - default: - assertNotReached('Invalid category: ' + category); - return ''; - } - }, - - /** - * A utility function to compute the title of the category, both for - * the overall category as well as the individual permission in the details - * for a site. - * @param {string} category The category to show the title for. - * @return {string} The title for the given category. - * @protected - */ - computeTitleForContentCategory: function(category) { - switch (category) { - case settings.ContentSettingsTypes.AUTOMATIC_DOWNLOADS: - return loadTimeData.getString('siteSettingsAutomaticDownloads'); - case settings.ContentSettingsTypes.BACKGROUND_SYNC: - return loadTimeData.getString('siteSettingsBackgroundSync'); - case settings.ContentSettingsTypes.CAMERA: - return loadTimeData.getString('siteSettingsCamera'); - case settings.ContentSettingsTypes.COOKIES: - return loadTimeData.getString('siteSettingsCookies'); - case settings.ContentSettingsTypes.FULLSCREEN: - return loadTimeData.getString('siteSettingsFullscreen'); - case settings.ContentSettingsTypes.GEOLOCATION: - return loadTimeData.getString('siteSettingsLocation'); - case settings.ContentSettingsTypes.IMAGES: - return loadTimeData.getString('siteSettingsImages'); - case settings.ContentSettingsTypes.JAVASCRIPT: - return loadTimeData.getString('siteSettingsJavascript'); - case settings.ContentSettingsTypes.KEYGEN: - return loadTimeData.getString('siteSettingsKeygen'); - case settings.ContentSettingsTypes.MIC: - return loadTimeData.getString('siteSettingsMic'); - case settings.ContentSettingsTypes.NOTIFICATIONS: - return loadTimeData.getString('siteSettingsNotifications'); - case settings.ContentSettingsTypes.PLUGINS: - return loadTimeData.getString('siteSettingsFlash'); - case settings.ContentSettingsTypes.POPUPS: - return loadTimeData.getString('siteSettingsPopups'); - case settings.ContentSettingsTypes.PROTOCOL_HANDLERS: - return loadTimeData.getString('siteSettingsHandlers'); - case settings.ContentSettingsTypes.UNSANDBOXED_PLUGINS: - return loadTimeData.getString('siteSettingsUnsandboxedPlugins'); - case settings.ContentSettingsTypes.USB_DEVICES: - return loadTimeData.getString('siteSettingsUsbDevices'); - case settings.ContentSettingsTypes.ZOOM_LEVELS: - return loadTimeData.getString('siteSettingsZoomLevels'); - default: - assertNotReached('Invalid category: ' + category); - return ''; - } - }, - - /** * A utility function to compute the description for the category. * @param {string} category The category to show the description for. * @param {string} setting The string value of the setting. @@ -232,7 +42,7 @@ var SiteSettingsBehaviorImpl = { * @protected */ computeCategoryDesc: function(category, setting, showRecommendation) { - var categoryEnabled = this.computeIsSettingEnabled(category, setting); + var categoryEnabled = this.computeIsSettingEnabled(setting); switch (category) { case settings.ContentSettingsTypes.JAVASCRIPT: // "Allowed (recommended)" vs "Blocked". @@ -443,16 +253,12 @@ var SiteSettingsBehaviorImpl = { /** * Returns true if the passed content setting is considered 'enabled'. - * @param {string} category * @param {string} setting * @return {boolean} * @private */ - computeIsSettingEnabled: function(category, setting) { - // FullScreen is Allow vs. Ask. - return category == settings.ContentSettingsTypes.FULLSCREEN ? - setting != settings.PermissionValues.ASK : - setting != settings.PermissionValues.BLOCK; + computeIsSettingEnabled: function(setting) { + return setting != settings.PermissionValues.BLOCK; }, /** @@ -483,8 +289,10 @@ var SiteSettingsBehaviorImpl = { */ expandSiteException: function(exception) { var origin = exception.origin; - var url = this.toUrl(origin); - var originForDisplay = url ? this.sanitizePort(url.origin) : origin; + // TODO(dschuyler): If orginForDisplay becomes different from origin in the + // site settings, that filtering would happen here. If that doesn't happen + // then originForDisplay should be removed (it's redundant with origin). + // e.g. var originForDisplay = someFilter(origin); var embeddingOrigin = exception.embeddingOrigin; var embeddingOriginForDisplay = ''; @@ -495,7 +303,7 @@ var SiteSettingsBehaviorImpl = { return { origin: origin, - originForDisplay: originForDisplay, + originForDisplay: origin, embeddingOrigin: embeddingOrigin, embeddingOriginForDisplay: embeddingOriginForDisplay, incognito: exception.incognito, diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_settings_category.html b/chromium/chrome/browser/resources/settings/site_settings/site_settings_category.html index 1144a51746f..2bfd9000cb9 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/site_settings_category.html +++ b/chromium/chrome/browser/resources/settings/site_settings/site_settings_category.html @@ -1,7 +1,4 @@ <link rel="import" href="chrome://resources/html/polymer.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-checkbox/paper-checkbox.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-icon-item.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item-body.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-toggle-button/paper-toggle-button.html"> <link rel="import" href="chrome://resources/html/web_ui_listener_behavior.html"> <link rel="import" href="/settings_shared_css.html"> @@ -14,18 +11,6 @@ <dom-module id="site-settings-category"> <template> <style include="settings-shared"> - :host { - display: block; - } - - .toggle-icon { - -webkit-margin-start: 4px; - } - - .toggle-text { - -webkit-margin-start: -11px; - } - site-list { border-bottom: 1px solid var(--paper-grey-300); } @@ -48,63 +33,63 @@ <template is="dom-if" if="[[isCookiesCategory_(category)]]"> <div class="settings-box"> - <paper-checkbox id="sessionOnlyCheckbox" disabled="[[!categoryEnabled]]" - checked="{{cookiesSessionOnly_}}" + <div class="start">$i18n{deleteDataPostSession}</div> + <paper-toggle-button checked="{{cookiesSessionOnly_}}" + disabled="[[!categoryEnabled]]" id="sessionOnlyCheckbox" on-change="onChangePermissionControl_"> - <div>$i18n{deleteDataPostSession}</div> - </paper-checkbox> + </paper-toggle-button> </div> </template> <template is="dom-if" if="[[isFlashCategory_(category)]]"> <div class="settings-box two-line"> - <paper-checkbox id="flashAskCheckbox" checked="{{flashAskFirst_}}" - on-change="onChangePermissionControl_" - disabled="[[!categoryEnabled]]"> - <div>$i18n{siteSettingsFlashAskBefore}</div> + <div class="start"> + $i18n{siteSettingsFlashAskBefore} <div class="secondary">$i18n{siteSettingsFlashAskBeforeSubtitle}</div> - </paper-checkbox> + </div> + <paper-toggle-button checked="{{flashAskFirst_}}" + disabled="[[!categoryEnabled]]" id="flashAskCheckbox" + on-change="onChangePermissionControl_"> + </paper-toggle-button> </div> </template> <content select=".cookie-controls"></content> - <div class="settings-box layout horizontal"> <if expr="chromeos"> + <div class="settings-box layout horizontal"> <div class="flex" hidden$="[[!isPluginCategory_(category)]]"> <div class="list-item list-button" on-tap="onAdobeFlashStorageClicked_"> $i18n{adobeFlashStorage} </div> </div> -</if> - <div class="list-item list-button" on-tap="onLearnMoreClicked_"> - $i18n{learnMore} - </div> </div> +</if> <site-list category="[[category]]" category-subtype="[[PermissionValues.BLOCK]]" category-enabled="[[categoryEnabled]]" + category-header="$i18n{siteSettingsBlock}" selected-site="{{selectedSite}}"> </site-list> <site-list category="[[category]]" - category-subtype="[[PermissionValues.ALLOW]]" + category-subtype="[[PermissionValues.SESSION_ONLY]]" category-enabled="[[categoryEnabled]]" + category-header="$i18n{siteSettingsSessionOnly}" selected-site="{{selectedSite}}"> </site-list> <site-list category="[[category]]" - category-subtype="[[PermissionValues.SESSION_ONLY]]" + category-subtype="[[PermissionValues.ALLOW]]" category-enabled="[[categoryEnabled]]" + category-header="$i18n{siteSettingsAllow}" selected-site="{{selectedSite}}"> </site-list> - <div class="settings-box"> - <content select=".site-data"></content> - </div> + <content select=".site-data"></content> </template> <script src="site_settings_category.js"></script> </dom-module> diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_settings_category.js b/chromium/chrome/browser/resources/settings/site_settings/site_settings_category.js index b2553e3d24a..63cc5ace2c5 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/site_settings_category.js +++ b/chromium/chrome/browser/resources/settings/site_settings/site_settings_category.js @@ -140,8 +140,7 @@ Polymer({ settings.SiteSettingsPrefsBrowserProxyImpl.getInstance() .getDefaultValueForContentType( this.category).then(function(setting) { - this.categoryEnabled = - this.computeIsSettingEnabled(this.category, setting); + this.categoryEnabled = this.computeIsSettingEnabled(setting); // Flash only shows ALLOW or BLOCK descriptions on the slider. var sliderSetting = setting; @@ -194,12 +193,6 @@ Polymer({ }, /** @private */ - onLearnMoreClicked_: function() { - window.open( - 'https://support.google.com/chrome/?p=settings_manage_exceptions'); - }, - - /** @private */ onAdobeFlashStorageClicked_: function() { window.open('https://www.macromedia.com/support/' + 'documentation/en/flashplayer/help/settings_manager07.html'); diff --git a/chromium/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js b/chromium/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js index 10e158411c7..02b9ca2212b 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js +++ b/chromium/chrome/browser/resources/settings/site_settings/site_settings_prefs_browser_proxy.js @@ -87,23 +87,30 @@ cr.define('settings', function() { setDefaultValueForContentType: function(contentType, defaultValue) {}, /** + * Gets the cookie details for a particular site. + * @param {string} site The name of the site. + * @return {!Promise<!CookieDataSummaryItem>} + */ + getCookieDetails: function(site) {}, + + /** * Gets the default value for a site settings category. * @param {string} contentType The name of the category to query. - * @return {Promise<string>} The string value of the default setting. + * @return {!Promise<string>} The string value of the default setting. */ getDefaultValueForContentType: function(contentType) {}, /** * Gets the exceptions (site list) for a particular category. * @param {string} contentType The name of the category to query. - * @return {Promise<Array<SiteException>>} + * @return {!Promise<!Array<!SiteException>>} */ getExceptionList: function(contentType) {}, /** * Gets the exception details for a particular site. * @param {string} site The name of the site. - * @return {Promise<SiteException>} + * @return {!Promise<!SiteException>} */ getSiteDetails: function(site) {}, @@ -157,7 +164,7 @@ cr.define('settings', function() { /** * Reloads all cookies. - * @return {!Promise<Array<CookieDataSummaryItem>>} Returns the full cookie + * @return {!Promise<!CookieList>} Returns the full cookie * list. */ reloadCookies: function() {}, @@ -165,7 +172,7 @@ cr.define('settings', function() { /** * Fetches all children of a given cookie. * @param {string} path The path to the parent cookie. - * @return {!Promise<Array<CookieDataSummaryItem>>} Returns a cookie list + * @return {!Promise<!Array<!CookieDataSummaryItem>>} Returns a cookie list * for the given path. */ loadCookieChildren: function(path) {}, @@ -178,7 +185,7 @@ cr.define('settings', function() { /** * Removes all cookies. - * @return {!Promise<Array<CookieDataSummaryItem>>} Returns the up to date + * @return {!Promise<!CookieList>} Returns the up to date * cookie list once deletion is complete (empty list). */ removeAllCookies: function() {}, @@ -212,7 +219,7 @@ cr.define('settings', function() { /** * Fetches a list of all USB devices and the sites permitted to use them. - * @return {!Promise<Array<UsbDeviceEntry>>} The list of USB devices. + * @return {!Promise<!Array<!UsbDeviceEntry>>} The list of USB devices. */ fetchUsbDevices: function() {}, @@ -221,7 +228,7 @@ cr.define('settings', function() { * origin. * @param {string} origin The origin to look up the permission for. * @param {string} embeddingOrigin the embedding origin to look up. - * @param {UsbDeviceDetails} usbDevice The USB device to revoke permission + * @param {!UsbDeviceDetails} usbDevice The USB device to revoke permission * for. */ removeUsbDevice: function(origin, embeddingOrigin, usbDevice) {}, @@ -262,6 +269,11 @@ cr.define('settings', function() { }, /** @override */ + getCookieDetails: function(site) { + return cr.sendWithPromise('getCookieDetails', site); + }, + + /** @override */ getDefaultValueForContentType: function(contentType) { return cr.sendWithPromise('getDefaultValueForContentType', contentType); }, diff --git a/chromium/chrome/browser/resources/settings/site_settings/usb_devices.html b/chromium/chrome/browser/resources/settings/site_settings/usb_devices.html index d168dc5b009..eed92587011 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/usb_devices.html +++ b/chromium/chrome/browser/resources/settings/site_settings/usb_devices.html @@ -1,8 +1,7 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-icon-button/paper-icon-button.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-item/paper-item.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-menu/paper-menu.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-menu-button/paper-menu-button.html"> +<link rel="import" href="chrome://resources/cr_elements/cr_action_menu/cr_action_menu.html"> + <link rel="import" href="/i18n_setup.html"> <link rel="import" href="/settings_shared_css.html"> <link rel="import" href="/site_settings/site_settings_behavior.html"> @@ -22,7 +21,7 @@ } </style> - <template is="dom-repeat" items="[[devices]]"> + <template is="dom-repeat" items="[[devices_]]"> <div class="site-settings-header">[[item.objectName]]</div> <div class="list-frame menu-content vertical-list"> @@ -30,22 +29,20 @@ <div class="favicon-image" style$="[[computeSiteIcon(item.origin)]]"></div> <div class="middle">[[item.origin]]</div> - <paper-menu-button> - <paper-icon-button icon="cr:more-vert" - class="dropdown-trigger"> - </paper-icon-button> - <paper-menu id="actionMenu" class="dropdown-content" actionable - on-iron-activate="onActionMenuIronActivate_" - attr-for-selected="menu-value"> - <paper-item menu-value$="[[menuActions_.REMOVE]]" actionable> - $i18n{handlerRemove} - </paper-item> - </paper-menu> - </paper-menu-button> + + <paper-icon-button icon="cr:more-vert" on-tap="showMenu_" + class="dropdown-trigger"> + </paper-icon-button> </div> </div> </template> + <dialog is="cr-action-menu"> + <button class="dropdown-item" role="option" on-tap="onRemoveTap_" id="removeButton"> + $i18n{handlerRemove} + </button> + </dialog> + </template> <script src="usb_devices.js"></script> </dom-module> diff --git a/chromium/chrome/browser/resources/settings/site_settings/usb_devices.js b/chromium/chrome/browser/resources/settings/site_settings/usb_devices.js index 836bdf66b35..b941e3bea35 100644 --- a/chromium/chrome/browser/resources/settings/site_settings/usb_devices.js +++ b/chromium/chrome/browser/resources/settings/site_settings/usb_devices.js @@ -16,9 +16,15 @@ Polymer({ properties: { /** * A list of all USB devices. - * @type {Array<UsbDeviceEntry>} + * @private {!Array<!UsbDeviceEntry>} */ - devices: Array, + devices_: Array, + + /** + * The targetted object for menu operations. + * @private {?Object} + */ + actionMenuModel_: Object }, ready: function() { @@ -31,19 +37,34 @@ Polymer({ */ fetchUsbDevices_: function() { this.browserProxy.fetchUsbDevices().then(function(deviceList) { - this.devices = deviceList; + this.devices_ = deviceList; }.bind(this)); }, /** * A handler when an action is selected in the action menu. - * @param {!{model: !{item: UsbDeviceEntry}}} event * @private */ - onActionMenuIronActivate_: function(event) { - var item = event.model.item; + onRemoveTap_: function() { + this.$$('dialog[is=cr-action-menu]').close(); + + var item = this.actionMenuModel_; this.browserProxy.removeUsbDevice( item.origin, item.embeddingOrigin, item.object); + this.actionMenuModel_ = null; this.fetchUsbDevices_(); }, + + /** + * A handler to show the action menu next to the clicked menu button. + * @param {!{model: !{item: UsbDeviceEntry}}} event + * @private + */ + showMenu_: function(event) { + this.actionMenuModel_ = event.model.item; + /** @type {!CrActionMenuElement} */ ( + this.$$('dialog[is=cr-action-menu]')).showAt( + /** @type {!Element} */ ( + Polymer.dom(/** @type {!Event} */ (event)).localTarget)); + } }); diff --git a/chromium/chrome/browser/resources/settings/site_settings_page/site_settings_page.html b/chromium/chrome/browser/resources/settings/site_settings_page/site_settings_page.html index 930e5e5c7a5..75f145c762b 100644 --- a/chromium/chrome/browser/resources/settings/site_settings_page/site_settings_page.html +++ b/chromium/chrome/browser/resources/settings/site_settings_page/site_settings_page.html @@ -10,189 +10,182 @@ <dom-module id="settings-site-settings-page"> <template> <style include="settings-shared"></style> - <div class="settings-box first" category$="[[ALL_SITES]]" - on-tap="onTapCategory" actionable> - <iron-icon icon="settings:list"></iron-icon> - <div class="middle">$i18n{siteSettingsCategoryAllSites}</div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> - </div> - <div class="settings-box two-line" - category$="[[ContentSettingsTypes.COOKIES]]" on-tap="onTapCategory" - actionable> - <iron-icon icon="[[computeIconForContentCategory( - ContentSettingsTypes.COOKIES)]]"></iron-icon> - <div class="middle"> - <div> - [[computeTitleForContentCategory(ContentSettingsTypes.COOKIES)]] - </div> + <template is="dom-if" if="[[enableSiteSettings_]]"> + <div class="settings-box first" category$="[[ALL_SITES]]" + data-route="SITE_SETTINGS_ALL" on-tap="onTapNavigate_" actionable> + <iron-icon icon="settings:list"></iron-icon> + <div class="middle">$i18n{siteSettingsCategoryAllSites}</div> + <button class="subpage-arrow" is="paper-icon-button-light"></button> + </div> + <div class="settings-box line-only"> + </div> + </template> + <div class="settings-box two-line first" + category$="[[ContentSettingsTypes.COOKIES]]" + data-route="SITE_SETTINGS_COOKIES" on-tap="onTapNavigate_" actionable> + <iron-icon icon="settings:cookie"></iron-icon> + <div class="middle"> + <div>$i18n{siteSettingsCookies}</div> <div id="cookies" class="secondary"></div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="settings-box two-line" - category$="[[ContentSettingsTypes.GEOLOCATION]]" on-tap="onTapCategory" - actionable> - <iron-icon icon="[[computeIconForContentCategory( - ContentSettingsTypes.GEOLOCATION)]]"></iron-icon> + category$="[[ContentSettingsTypes.GEOLOCATION]]" + data-route="SITE_SETTINGS_LOCATION" on-tap="onTapNavigate_" actionable> + <iron-icon icon="settings:location-on"></iron-icon> <div class="middle"> - [[computeTitleForContentCategory(ContentSettingsTypes.GEOLOCATION)]] + <div>$i18n{siteSettingsLocation}</div> <div id="geolocation" class="secondary"></div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="settings-box two-line" - category$="[[ContentSettingsTypes.CAMERA]]" on-tap="onTapCategory" - actionable> - <iron-icon icon="[[computeIconForContentCategory( - ContentSettingsTypes.CAMERA)]]"></iron-icon> + category$="[[ContentSettingsTypes.CAMERA]]" + data-route="SITE_SETTINGS_CAMERA" + on-tap="onTapNavigate_" actionable> + <iron-icon icon="settings:videocam"></iron-icon> <div class="middle"> - [[computeTitleForContentCategory(ContentSettingsTypes.CAMERA)]] + <div>$i18n{siteSettingsCamera}</div> <div id="camera" class="secondary"></div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="settings-box two-line" category$="[[ContentSettingsTypes.MIC]]" - on-tap="onTapCategory" actionable> - <iron-icon icon="[[computeIconForContentCategory( - ContentSettingsTypes.MIC)]]"></iron-icon> + data-route="SITE_SETTINGS_MICROPHONE" on-tap="onTapNavigate_" + actionable> + <iron-icon icon="settings:mic"></iron-icon> <div class="middle"> - [[computeTitleForContentCategory(ContentSettingsTypes.MIC)]] + $i18n{siteSettingsMic} <div id="mic" class="secondary"></div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="settings-box two-line" category$="[[ContentSettingsTypes.NOTIFICATIONS]]" - on-tap="onTapCategory" actionable> - <iron-icon icon="[[computeIconForContentCategory( - ContentSettingsTypes.NOTIFICATIONS)]]"></iron-icon> + data-route="SITE_SETTINGS_NOTIFICATIONS" on-tap="onTapNavigate_" + actionable> + <iron-icon icon="settings:notifications"></iron-icon> <div class="middle"> - [[computeTitleForContentCategory(ContentSettingsTypes.NOTIFICATIONS)]] + $i18n{siteSettingsNotifications} <div id="notifications" class="secondary"></div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="settings-box two-line" category$="[[ContentSettingsTypes.JAVASCRIPT]]" - on-tap="onTapCategory" actionable> - <iron-icon icon="[[computeIconForContentCategory( - ContentSettingsTypes.JAVASCRIPT)]]"></iron-icon> + data-route="SITE_SETTINGS_JAVASCRIPT" on-tap="onTapNavigate_" + actionable> + <iron-icon icon="settings:input"></iron-icon> <div class="middle"> - [[computeTitleForContentCategory(ContentSettingsTypes.JAVASCRIPT)]] + $i18n{siteSettingsJavascript} <div id="javascript" class="secondary"></div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="settings-box two-line" category$="[[ContentSettingsTypes.PLUGINS]]" - on-tap="onTapCategory" actionable> - <iron-icon icon="[[computeIconForContentCategory( - ContentSettingsTypes.PLUGINS)]]"></iron-icon> + data-route="SITE_SETTINGS_FLASH" on-tap="onTapNavigate_" actionable> + <iron-icon icon="cr:extension"></iron-icon> <div class="middle"> - [[computeTitleForContentCategory(ContentSettingsTypes.PLUGINS)]] + $i18n{siteSettingsFlash} <div id="plugins" class="secondary"></div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="settings-box two-line" - category$="[[ContentSettingsTypes.IMAGES]]" on-tap="onTapCategory" - actionable> - <iron-icon icon="[[computeIconForContentCategory( - ContentSettingsTypes.IMAGES)]]"></iron-icon> + category$="[[ContentSettingsTypes.IMAGES]]" + data-route="SITE_SETTINGS_IMAGES" on-tap="onTapNavigate_" actionable> + <iron-icon icon="settings:photo"></iron-icon> <div class="middle"> - [[computeTitleForContentCategory(ContentSettingsTypes.IMAGES)]] + $i18n{siteSettingsImages} <div id="images" class="secondary"></div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> - <div class="settings-box two-line" - category$="[[ContentSettingsTypes.POPUPS]]" on-tap="onTapCategory" - actionable> - <iron-icon icon="[[computeIconForContentCategory( - ContentSettingsTypes.POPUPS)]]"></iron-icon> + <div category$="[[ContentSettingsTypes.POPUPS]]" + class="settings-box two-line" data-route="SITE_SETTINGS_POPUPS" + on-tap="onTapNavigate_" actionable> + <iron-icon icon="cr:open-in-new"></iron-icon> <div class="middle"> - [[computeTitleForContentCategory(ContentSettingsTypes.POPUPS)]] + $i18n{siteSettingsPopups} <div id="popups" class="secondary"></div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="settings-box two-line" category$="[[ContentSettingsTypes.BACKGROUND_SYNC]]" - on-tap="onTapCategory" actionable> - <iron-icon icon="[[computeIconForContentCategory( - ContentSettingsTypes.BACKGROUND_SYNC)]]"></iron-icon> + data-route="SITE_SETTINGS_BACKGROUND_SYNC" on-tap="onTapNavigate_" + actionable> + <iron-icon icon="settings:sync"></iron-icon> <div class="middle"> - [[computeTitleForContentCategory( - ContentSettingsTypes.BACKGROUND_SYNC)]] + $i18n{siteSettingsBackgroundSync} <div id="backgroundSync" class="secondary"></div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="settings-box two-line" category$="[[ContentSettingsTypes.KEYGEN]]" - on-tap="onTapCategory" actionable> - <iron-icon icon="[[computeIconForContentCategory( - ContentSettingsTypes.KEYGEN)]]"></iron-icon> + data-route="SITE_SETTINGS_KEYGEN" on-tap="onTapNavigate_" actionable> + <iron-icon icon="settings:code"></iron-icon> <div class="middle"> - [[computeTitleForContentCategory( - ContentSettingsTypes.KEYGEN)]] + $i18n{siteSettingsKeygen} <div id="keygen" class="secondary"></div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="settings-box two-line" category$="[[ContentSettingsTypes.AUTOMATIC_DOWNLOADS]]" - on-tap="onTapCategory" actionable> - <iron-icon icon="[[computeIconForContentCategory( - ContentSettingsTypes.AUTOMATIC_DOWNLOADS)]]"></iron-icon> + data-route="SITE_SETTINGS_AUTOMATIC_DOWNLOADS" + on-tap="onTapNavigate_" actionable> + <iron-icon icon="cr:file-download"></iron-icon> <div class="middle"> - [[computeTitleForContentCategory( - ContentSettingsTypes.AUTOMATIC_DOWNLOADS)]] + $i18n{siteSettingsAutomaticDownloads} <div id="automaticDownloads" class="secondary"></div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="settings-box two-line" category$="[[ContentSettingsTypes.UNSANDBOXED_PLUGINS]]" - on-tap="onTapCategory" actionable> - <iron-icon icon="[[computeIconForContentCategory( - ContentSettingsTypes.UNSANDBOXED_PLUGINS)]]"></iron-icon> + data-route="SITE_SETTINGS_UNSANDBOXED_PLUGINS" + on-tap="onTapNavigate_" actionable> + <iron-icon icon="cr:extension"></iron-icon> <div class="middle"> - [[computeTitleForContentCategory( - ContentSettingsTypes.UNSANDBOXED_PLUGINS)]] + $i18n{siteSettingsUnsandboxedPlugins} <div id="unsandboxedPlugins" class="secondary"></div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="settings-box two-line" category$="[[ContentSettingsTypes.PROTOCOL_HANDLERS]]" - on-tap="onTapCategory" actionable> - <iron-icon icon="[[computeIconForContentCategory( - ContentSettingsTypes.PROTOCOL_HANDLERS)]]"></iron-icon> + data-route="SITE_SETTINGS_HANDLERS" + on-tap="onTapNavigate_" actionable> + <iron-icon icon="settings:protocol-handler"></iron-icon> <div class="middle"> - [[computeTitleForContentCategory( - ContentSettingsTypes.PROTOCOL_HANDLERS)]] + $i18n{siteSettingsHandlers} <div id="handlers" class="secondary"></div> </div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="settings-box" category$="[[ContentSettingsTypes.ZOOM_LEVELS]]" - on-tap="onTapCategory" actionable> - <iron-icon icon="[[computeIconForContentCategory( - ContentSettingsTypes.ZOOM_LEVELS)]]"></iron-icon> - <div class="middle"> - [[computeTitleForContentCategory(ContentSettingsTypes.ZOOM_LEVELS)]] - </div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> + data-route="SITE_SETTINGS_ZOOM_LEVELS" + on-tap="onTapNavigate_" actionable> + <iron-icon icon="settings:zoom-in"></iron-icon> + <div class="middle">$i18n{siteSettingsZoomLevels}</div> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> <div class="settings-box" category$="[[ContentSettingsTypes.USB_DEVICES]]" - on-tap="onTapCategory" actionable> - <iron-icon icon="[[computeIconForContentCategory( - ContentSettingsTypes.USB_DEVICES)]]"></iron-icon> - <div class="middle"> - [[computeTitleForContentCategory(ContentSettingsTypes.USB_DEVICES)]] - </div> - <button class="icon-arrow-right" is="paper-icon-button-light"></button> + data-route="SITE_SETTINGS_USB_DEVICES" + on-tap="onTapNavigate_" actionable> + <iron-icon icon="settings:usb"></iron-icon> + <div class="middle">$i18n{siteSettingsUsbDevices}</div> + <button class="subpage-arrow" is="paper-icon-button-light"></button> + </div> + <div class="settings-box" data-route="SITE_SETTINGS_PDF_DOCUMENTS" + on-tap="onTapNavigate_" actionable> + <iron-icon icon="settings:pdf"></iron-icon> + <div class="middle">$i18n{siteSettingsPdfDocuments}</div> + <button class="subpage-arrow" is="paper-icon-button-light"></button> </div> </template> <script src="site_settings_page.js"></script> diff --git a/chromium/chrome/browser/resources/settings/site_settings_page/site_settings_page.js b/chromium/chrome/browser/resources/settings/site_settings_page/site_settings_page.js index 923d5bcf635..19e572795c7 100644 --- a/chromium/chrome/browser/resources/settings/site_settings_page/site_settings_page.js +++ b/chromium/chrome/browser/resources/settings/site_settings_page/site_settings_page.js @@ -13,6 +13,14 @@ Polymer({ behaviors: [SiteSettingsBehavior], properties: { + /** @private */ + enableSiteSettings_: { + type: Boolean, + value: function() { + return loadTimeData.getBoolean('enableSiteSettings'); + }, + }, + /** * The category selected by the user. */ @@ -59,15 +67,12 @@ Polymer({ }, /** - * Handles selection of a single category and navigates to the details for - * that category. + * Navigate to the route specified in the event dataset. * @param {!Event} event The tap event. + * @private */ - onTapCategory: function(event) { - var category = event.currentTarget.getAttribute('category'); - if (category == settings.ALL_SITES) - settings.navigateTo(settings.Route.SITE_SETTINGS_ALL); - else - settings.navigateTo(this.computeCategoryRoute(category)); + onTapNavigate_: function(event) { + var dataSet = /** @type {{route: string}} */(event.currentTarget.dataset); + settings.navigateTo(settings.Route[dataSet.route]); }, }); diff --git a/chromium/chrome/browser/resources/settings/system_page/system_page.html b/chromium/chrome/browser/resources/settings/system_page/system_page.html index 530b7c60927..bbcbd7dab66 100644 --- a/chromium/chrome/browser/resources/settings/system_page/system_page.html +++ b/chromium/chrome/browser/resources/settings/system_page/system_page.html @@ -1,6 +1,7 @@ <link rel="import" href="chrome://resources/html/polymer.html"> <link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> <link rel="import" href="/controls/controlled_button.html"> +<link rel="import" href="/controls/extension_controlled_indicator.html"> <link rel="import" href="/controls/settings_checkbox.html"> <link rel="import" href="/lifetime_browser_proxy.html"> <link rel="import" href="/prefs/prefs.html"> @@ -20,6 +21,16 @@ #hardware-acceleration settings-checkbox { flex: 1; } + + .proxy-wrapper { + align-items: center; + display: flex; + min-height: inherit; + } + + extension-controlled-indicator { + width: 100%; + } </style> <div class="settings-box block first"> <if expr="not is_macosx"> @@ -37,11 +48,23 @@ </template> </div> </div> - <div class="settings-box"> - <controlled-button class="primary-button" pref="[[prefs.proxy]]" - on-tap="onChangeProxySettingsTap_"> - $i18n{changeProxySettings} - </controlled-button> + <div class="settings-box block"> + <div class="proxy-wrapper"> + <controlled-button class="primary-button" pref="[[prefs.proxy]]" + on-tap="onChangeProxySettingsTap_"> + $i18n{changeProxySettings} + </controlled-button> + </div> + <template is="dom-if" if="[[prefs.proxy.extensionId]]"> + <div class="proxy-wrapper"> + <extension-controlled-indicator + extension-id="[[prefs.proxy.extensionId]]" + extension-name="[[prefs.proxy.controlledByName]]" + extension-can-be-disabled="[[prefs.proxy.extensionCanBeDisabled]]" + on-extension-disable="onExtensionDisable_"> + </extension-controlled-indicator> + </div> + </template> </div> </template> <script src="/system_page/system_page.js"></script> diff --git a/chromium/chrome/browser/resources/settings/system_page/system_page.js b/chromium/chrome/browser/resources/settings/system_page/system_page.js index 8656b29abab..d076182bcb8 100644 --- a/chromium/chrome/browser/resources/settings/system_page/system_page.js +++ b/chromium/chrome/browser/resources/settings/system_page/system_page.js @@ -33,6 +33,16 @@ Polymer({ }, /** @private */ + onExtensionDisable_: function() { + // TODO(dbeam): this is a pretty huge bummer. It means there are things + // (inputs) that our prefs system is not observing. And that changes from + // other sources (i.e. disabling/enabling an extension from + // chrome://extensions or from the omnibox directly) will not update + // |this.prefs.proxy| directly (nor the UI). We should fix this eventually. + this.fire('refresh-pref', 'proxy'); + }, + + /** @private */ onRestartTap_: function() { // TODO(dbeam): we should prompt before restarting the browser. settings.LifetimeBrowserProxyImpl.getInstance().restart(); diff --git a/chromium/chrome/browser/resources/signin/signin_error/signin_error.js b/chromium/chrome/browser/resources/signin/signin_error/signin_error.js index 0abdaa28604..749c99bc038 100644 --- a/chromium/chrome/browser/resources/signin/signin_error/signin_error.js +++ b/chromium/chrome/browser/resources/signin/signin_error/signin_error.js @@ -14,7 +14,11 @@ cr.define('signin.error', function() { if (loadTimeData.getBoolean('isSystemProfile')) { $('learnMoreLink').hidden = true; } - chrome.send('initializedWithSize', [document.body.scrollHeight]); + + // Prefer using |document.body.offsetHeight| instead of + // |document.body.scrollHeight| as it returns the correct height of the + // even when the page zoom in Chrome is different than 100%. + chrome.send('initializedWithSize', [document.body.offsetHeight]); } function onKeyDown(e) { diff --git a/chromium/chrome/browser/resources/signin/signin_shared_css.html b/chromium/chrome/browser/resources/signin/signin_shared_css.html index 20eefa87d4e..301b20e9fec 100644 --- a/chromium/chrome/browser/resources/signin/signin_shared_css.html +++ b/chromium/chrome/browser/resources/signin/signin_shared_css.html @@ -10,6 +10,7 @@ body { margin: 0; padding: 0; + zoom: reset; } paper-button { @@ -37,7 +38,6 @@ .container { background-color: white; color: #333; - overflow: hidden; width: 448px; } diff --git a/chromium/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.css b/chromium/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.css index 340a51f83b4..79e5343ae56 100644 --- a/chromium/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.css +++ b/chromium/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.css @@ -80,6 +80,13 @@ -webkit-margin-start: 8px; } +#syncDisabledDetails { + line-height: 20px; + margin-bottom: 8px; + margin-top: 16px; + padding: 0 24px; +} + #illustration { height: 96px; margin: 0 auto; diff --git a/chromium/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.html b/chromium/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.html index d8e1e312dab..32517dc1baf 100644 --- a/chromium/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.html +++ b/chromium/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.html @@ -20,7 +20,7 @@ <body> <div class="container"> <div class="top-title-bar">$i18n{syncConfirmationTitle}</div> - <div class="details"> + <div class="details" id="syncConfirmationDetails"> <div id="picture-container"> <div id="illustration"> <div id="icons"> @@ -73,6 +73,9 @@ </div> </div> </div> + <div class="details" id="syncDisabledDetails"> + <div class="body text">$i18n{syncDisabledConfirmationDetails}</div> + </div> <div class="action-container"> <paper-button class="primary-action" id="confirmButton"> $i18n{syncConfirmationConfirmLabel} diff --git a/chromium/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.js b/chromium/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.js index e22b4ddecc6..1f51ec8fdb4 100644 --- a/chromium/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.js +++ b/chromium/chrome/browser/resources/signin/sync_confirmation/sync_confirmation.js @@ -21,9 +21,18 @@ cr.define('sync.confirmation', function() { document.addEventListener('keydown', onKeyDown); $('confirmButton').addEventListener('click', onConfirm); $('undoButton').addEventListener('click', onUndo); - $('settingsLink').addEventListener('click', onGoToSettings); - $('profile-picture').addEventListener('load', onPictureLoaded); - chrome.send('initializedWithSize', [document.body.scrollHeight]); + if (loadTimeData.getBoolean('isSyncAllowed')) { + $('settingsLink').addEventListener('click', onGoToSettings); + $('profile-picture').addEventListener('load', onPictureLoaded); + $('syncDisabledDetails').hidden = true; + } else { + $('syncConfirmationDetails').hidden = true; + } + + // Prefer using |document.body.offsetHeight| instead of + // |document.body.scrollHeight| as it returns the correct height of the + // even when the page zoom in Chrome is different than 100%. + chrome.send('initializedWithSize', [document.body.offsetHeight]); } function clearFocus() { @@ -31,11 +40,15 @@ cr.define('sync.confirmation', function() { } function setUserImageURL(url) { - $('profile-picture').src = url; + if (loadTimeData.getBoolean('isSyncAllowed')) { + $('profile-picture').src = url; + } } function onPictureLoaded(e) { - $('picture-container').classList.add('loaded'); + if (loadTimeData.getBoolean('isSyncAllowed')) { + $('picture-container').classList.add('loaded'); + } } function onKeyDown(e) { diff --git a/chromium/chrome/browser/resources/snippets_internals.html b/chromium/chrome/browser/resources/snippets_internals.html index 2d70a958633..acfa350f73b 100644 --- a/chromium/chrome/browser/resources/snippets_internals.html +++ b/chromium/chrome/browser/resources/snippets_internals.html @@ -31,8 +31,11 @@ found in the LICENSE file. <td class="name">Recent Tab Suggestions enabled <td id="flag-recent-offline-tab-suggestions" class="value"> <tr> - <td class="name">Download Suggestions enabled - <td id="flag-download-suggestions" class="value"> + <td class="name">Asset Download Suggestions enabled + <td id="flag-asset-download-suggestions" class="value"> + <tr> + <td class="name">Offline Page Download Suggestions enabled + <td id="flag-offline-page-download-suggestions" class="value"> <tr> <td class="name">Bookmark Suggestions enabled <td id="flag-bookmark-suggestions" class="value"> diff --git a/chromium/chrome/browser/resources/task_scheduler_internals/index.css b/chromium/chrome/browser/resources/task_scheduler_internals/index.css new file mode 100644 index 00000000000..56dfe64005d --- /dev/null +++ b/chromium/chrome/browser/resources/task_scheduler_internals/index.css @@ -0,0 +1,15 @@ +/* Copyright 2016 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. */ + +table { + border: 1px solid black; + border-collapse: collapse; +} + +td, +th { + border: 1px solid black; + padding: 5px; + text-align: center; +} diff --git a/chromium/chrome/browser/resources/task_scheduler_internals/index.html b/chromium/chrome/browser/resources/task_scheduler_internals/index.html index 6680b628fb3..8128d32f394 100644 --- a/chromium/chrome/browser/resources/task_scheduler_internals/index.html +++ b/chromium/chrome/browser/resources/task_scheduler_internals/index.html @@ -3,9 +3,16 @@ <head> <title>Task Scheduler Internals</title> <link rel="stylesheet" href="chrome://resources/css/text_defaults.css"> + <link rel="stylesheet" href="index.css"> + <script src="chrome://resources/js/util.js"></script> + <script src="index.js"></script> </head> <body> <h1>Task Scheduler Internals</h1> - Status: $i18n{status} + <div>Status: <span id="status"></span></div> + <div id="details" hidden> + <h2>Histograms</h2> + <div id="histogram-container"></div> + </div> </body> </html> diff --git a/chromium/chrome/browser/resources/task_scheduler_internals/index.js b/chromium/chrome/browser/resources/task_scheduler_internals/index.js new file mode 100644 index 00000000000..87da676411d --- /dev/null +++ b/chromium/chrome/browser/resources/task_scheduler_internals/index.js @@ -0,0 +1,74 @@ +// Copyright 2016 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. + +/** @typedef {{min: number, max: number, count: number}} */ +var Bucket; + +/** @typedef {{name: string, buckets: !Array<Bucket>}} */ +var Histogram; + +var TaskSchedulerInternals = { + /** + * Updates the histograms on the page. + * @param {!Array<!Histogram>} histograms Array of histogram objects. + */ + updateHistograms: function(histograms) { + var histogramContainer = $('histogram-container'); + for (var i in histograms) { + var histogram = histograms[i]; + var title = document.createElement('div'); + title.textContent = histogram.name; + histogramContainer.appendChild(title); + if (histogram.buckets.length > 0) { + histogramContainer.appendChild( + TaskSchedulerInternals.createHistogramTable(histogram.buckets)); + } else { + var unavailable = document.createElement('div'); + unavailable.textContent = 'No Data Recorded'; + histogramContainer.appendChild(unavailable); + } + } + }, + + /** + * Returns a table representation of the histogram buckets. + * @param {Object} buckets The histogram buckets. + * @return {Object} A table element representation of the histogram buckets. + */ + createHistogramTable: function(buckets) { + var table = document.createElement('table'); + var headerRow = document.createElement('tr'); + var dataRow = document.createElement('tr'); + for (var i in buckets) { + var bucket = buckets[i]; + var header = document.createElement('th'); + header.textContent = `${bucket.min}-${bucket.max}`; + headerRow.appendChild(header); + var data = document.createElement('td'); + data.textContent = bucket.count; + dataRow.appendChild(data); + } + table.appendChild(headerRow); + table.appendChild(dataRow); + return table; + }, + + /** + * Handles callback from onGetTaskSchedulerData. + * @param {Object} data Dictionary containing all task scheduler metrics. + */ + onGetTaskSchedulerData: function(data) { + $('status').textContent = + data.instantiated ? 'Instantiated' : 'Not Instantiated'; + $('details').hidden = !data.instantiated; + if (!data.instantiated) + return; + + TaskSchedulerInternals.updateHistograms(data.histograms); + } +}; + +document.addEventListener('DOMContentLoaded', function() { + chrome.send('getTaskSchedulerData'); +}); diff --git a/chromium/chrome/browser/resources/task_scheduler_internals/resources.grd b/chromium/chrome/browser/resources/task_scheduler_internals/resources.grd index 72b992075dc..08419ac7291 100644 --- a/chromium/chrome/browser/resources/task_scheduler_internals/resources.grd +++ b/chromium/chrome/browser/resources/task_scheduler_internals/resources.grd @@ -15,6 +15,12 @@ <include name="IDR_TASK_SCHEDULER_INTERNALS_RESOURCES_INDEX_HTML" file="index.html" type="BINDATA" /> + <include name="IDR_TASK_SCHEDULER_INTERNALS_RESOURCES_INDEX_CSS" + file="index.css" + type="BINDATA" /> + <include name="IDR_TASK_SCHEDULER_INTERNALS_RESOURCES_INDEX_JS" + file="index.js" + type="BINDATA" /> </includes> </release> </grit> diff --git a/chromium/chrome/browser/resources/translate_internals/translate_internals.css b/chromium/chrome/browser/resources/translate_internals/translate_internals.css index 11626b4e851..9d9a7f97b22 100644 --- a/chromium/chrome/browser/resources/translate_internals/translate_internals.css +++ b/chromium/chrome/browser/resources/translate_internals/translate_internals.css @@ -138,3 +138,7 @@ td.detection-logs-content div { .prefs-setting-disabled { display: none; } + +#country-override input { + margin-bottom: 1px; +} diff --git a/chromium/chrome/browser/resources/usb_internals/usb_internals.js b/chromium/chrome/browser/resources/usb_internals/usb_internals.js index 7784ec02f9b..a1c1a28c08b 100644 --- a/chromium/chrome/browser/resources/usb_internals/usb_internals.js +++ b/chromium/chrome/browser/resources/usb_internals/usb_internals.js @@ -59,19 +59,6 @@ event.preventDefault(); } - /** - * Helper to convert callback-based define() API to a promise-based API. - * @param {!Array<string>} moduleNames - * @return {!Promise} - */ - function importModules(moduleNames) { - return new Promise(function(resolve, reject) { - define(moduleNames, function(var_args) { - resolve(Array.prototype.slice.call(arguments, 0)); - }); - }); - } - function initializeProxies() { return importModules([ 'mojo/public/js/connection', diff --git a/chromium/chrome/browser/resources/user_manager/control_bar.css b/chromium/chrome/browser/resources/user_manager/control_bar.css deleted file mode 100644 index 13dfbeafabf..00000000000 --- a/chromium/chrome/browser/resources/user_manager/control_bar.css +++ /dev/null @@ -1,87 +0,0 @@ -/* Copyright 2013 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. */ - -/* Overrides of styles in chrome/browser/resources/chromeos/login/header_bar.js - * that are needed by the desktop user chooser screen. */ -#login-header-bar { - background-color: white; - border-top: 1px solid #e2e2e2; - bottom: 0; - left: 0; - padding-bottom: 16px; - padding-top: 16px; - position: absolute; - right: 0; -} - -.header-bar-item:first-child { - -webkit-padding-start: 16px; -} - -.header-bar-item { - display: inline-block; - font-size: 12px; -} - -html[dir=rtl] .header-bar-item { - background-color: white; - background-position: right center; -} - -html[dir=rtl] #login-header-bar button { - background-position: right center; -} - -#login-header-bar #add-user-button { - background-image: url(../../../../ui/webui/resources/images/add_box.svg); -} - -#login-header-bar #guest-user-button { - background-image: url(../../../../ui/webui/resources/images/account_box.svg); - border-right: 1px solid #e2e2e2; - margin-right: 10px; -} - -html[dir=rtl] #login-header-bar #guest-user-button { - border-left: 1px solid #e2e2e2; - margin-left: 10px; -} - -#login-header-bar button { - -webkit-padding-start: 24px; - background-color: white; - background-position: left center; - background-repeat: no-repeat; - background-size: 18px; - border: none; - border-radius: 0; - box-shadow: none; - cursor: pointer; - opacity: 0.8; -} - -#login-header-bar button:active, -#login-header-bar button:focus, -#login-header-bar button:hover { - opacity: 1; -} - -#login-header-bar button:focus { - text-decoration: underline; -} - -#logo { - content: -webkit-image-set( - url(../../../app/theme/default_100_percent/%DISTRIBUTION%/product_logo_name_48.png) 1x, - url(../../../app/theme/default_200_percent/%DISTRIBUTION%/product_logo_name_48.png) 2x); - height: 18px; - position: absolute; - right: 16px; - top: 20px; -} - -html[dir=rtl] #logo { - left: 16px; - right: auto; -} diff --git a/chromium/chrome/browser/resources/user_manager/control_bar.html b/chromium/chrome/browser/resources/user_manager/control_bar.html deleted file mode 100644 index 727ed6bb0a2..00000000000 --- a/chromium/chrome/browser/resources/user_manager/control_bar.html +++ /dev/null @@ -1,11 +0,0 @@ -<div id="login-header-bar" class="login-header-bar"> - <div id="guest-user-header-bar-item" class="header-bar-item"> - <button id="guest-user-button" i18n-content="browseAsGuest"></button> - </div> - <div id="add-user-header-bar-item" class="header-bar-item"> - <button id="add-user-button" i18n-content="addUser"></button> - </div> - <div class="header-bar-item"> - <div id="logo"></div> - </div> -</div> diff --git a/chromium/chrome/browser/resources/user_manager/control_bar.js b/chromium/chrome/browser/resources/user_manager/control_bar.js deleted file mode 100644 index 5b0b7906976..00000000000 --- a/chromium/chrome/browser/resources/user_manager/control_bar.js +++ /dev/null @@ -1,183 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/** - * @fileoverview Desktop User Chooser UI control bar implementation. - */ - -cr.define('login', function() { - /** - * Creates a header bar element. - * @constructor - * @extends {HTMLDivElement} - */ - var HeaderBar = cr.ui.define('div'); - - HeaderBar.prototype = { - __proto__: HTMLDivElement.prototype, - - // Whether guest button should be shown when header bar is in normal mode. - showGuest_: true, - - // Current UI state of the sign-in screen. - signinUIState_: SIGNIN_UI_STATE.HIDDEN, - - // Whether to show kiosk apps menu. - hasApps_: false, - - /** @override */ - decorate: function() { - $('add-user-button').addEventListener('click', - this.handleAddUserClick_); - $('guest-user-header-bar-item').addEventListener('click', - this.handleGuestClick_); - $('guest-user-button').addEventListener('click', - this.handleGuestClick_); - this.updateUI_(); - }, - - /** - * Tab index value for all button elements. - * @type {number} - */ - set buttonsTabIndex(tabIndex) { - var buttons = this.getElementsByTagName('button'); - for (var i = 0, button; button = buttons[i]; ++i) { - button.tabIndex = tabIndex; - } - }, - - /** - * Disables the header bar and all of its elements. - * @type {boolean} - */ - set disabled(value) { - var buttons = this.getElementsByTagName('button'); - for (var i = 0, button; button = buttons[i]; ++i) - if (!button.classList.contains('button-restricted')) - button.disabled = value; - }, - - /** - * Add user button click handler. - * @private - */ - handleAddUserClick_: function(e) { - chrome.send('addUser'); - // Prevent further propagation of click event. Otherwise, the click event - // handler of document object will set wallpaper to user's wallpaper when - // there is only one existing user. See http://crbug.com/166477 - e.stopPropagation(); - }, - - /** - * Cancel add user button click handler. - * @private - */ - handleCancelAddUserClick_: function(e) { - // Let screen handle cancel itself if that is capable of doing so. - if (Oobe.getInstance().currentScreen && - Oobe.getInstance().currentScreen.cancel) { - Oobe.getInstance().currentScreen.cancel(); - return; - } - - Oobe.showScreen({id: SCREEN_ACCOUNT_PICKER}); - Oobe.resetSigninUI(true); - }, - - /** - * Guest button click handler. - * @private - */ - handleGuestClick_: function(e) { - chrome.send('launchGuest'); - e.stopPropagation(); - }, - - /** - * If true then "Browse as Guest" button is shown. - * @type {boolean} - */ - set showGuestButton(value) { - this.showGuest_ = value; - this.updateUI_(); - }, - - /** - * Update current header bar UI. - * @type {number} state Current state of the sign-in screen - * (see SIGNIN_UI_STATE). - */ - set signinUIState(state) { - this.signinUIState_ = state; - this.updateUI_(); - }, - - get signinUIState() { - return this.signinUIState_; - }, - - /** - * Whether the Cancel button is enabled during Gaia sign-in. - * @type {boolean} - */ - set allowCancel(value) { - this.allowCancel_ = value; - this.updateUI_(); - }, - - /** - * Updates visibility state of action buttons. - * @private - */ - updateUI_: function() { - $('guest-user-header-bar-item').hidden = false; - $('add-user-header-bar-item').hidden = false; - }, - - /** - * Animates Header bar to hide from the screen. - * @param {function()} callback will be called once animation is finished. - */ - animateOut: function(callback) { - var launcher = this; - launcher.addEventListener( - 'webkitTransitionEnd', function f(e) { - launcher.removeEventListener('webkitTransitionEnd', f); - callback(); - }); - this.classList.remove('login-header-bar-animate-slow'); - this.classList.add('login-header-bar-animate-fast'); - this.classList.add('login-header-bar-hidden'); - }, - - /** - * Animates Header bar to slowly appear on the screen. - */ - animateIn: function() { - this.classList.remove('login-header-bar-animate-fast'); - this.classList.add('login-header-bar-animate-slow'); - this.classList.remove('login-header-bar-hidden'); - }, - }; - - /** - * Convenience wrapper of animateOut. - */ - HeaderBar.animateOut = function(callback) { - $('login-header-bar').animateOut(callback); - }; - - /** - * Convenience wrapper of animateIn. - */ - HeaderBar.animateIn = function() { - $('login-header-bar').animateIn(); - }; - - return { - HeaderBar: HeaderBar - }; -}); diff --git a/chromium/chrome/browser/resources/user_manager/user_manager.css b/chromium/chrome/browser/resources/user_manager/user_manager.css deleted file mode 100644 index a9d911c8064..00000000000 --- a/chromium/chrome/browser/resources/user_manager/user_manager.css +++ /dev/null @@ -1,211 +0,0 @@ -/* Copyright 2013 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. */ - -/* Overrides for the desktop user manager screen. */ - -.oobe-display { - background-color: #eee; -} - -#outer-container { - min-height: 0; -} - -.bubble.faded { - opacity: 0; -} - -.pod { - box-shadow: 0 1px 2px rgba(0, 0, 0, 0.1); - height: 226px; - /* On non-retina desktop, the text is blurry if we use the scale3d() - inherited from user_pod_row.js */ - transform: scale(0.9); -} - -podrow[ncolumns='6'] .pod { - transform: scale(0.8); -} - -/* Because of crbug.com/406529, the text in the .name div is janky if there's -both a transform:scale and a transition:opacity applied to a div, so we must -apply the opacity change to the children instead. */ -.pod.faded { - opacity: 1; -} - -.pod.faded .user-image-pane, -.pod.faded .main-pane { - opacity: .4; -} - -.pod.hovered:not(.focused) { - box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2); -} - -.pod.focused { - box-shadow: 0 16px 21px rgba(0, 0, 0, 0.2); - transform: scale(1) !important; -} - -.pod.focused.locked { - box-shadow: 0 12px 21px rgba(0, 0, 0, 0.2); - height: 220px; -} - -.user-image-pane { - border-top-left-radius: 2px; - border-top-right-radius: 2px; - height: 180px; - left: 0; - top: 0; - width: 180px; -} - -html[dir=rtl] .user-image-pane { - right: 0; -} - -.pod .name { - margin-top: 12px; -} - -.pod .user-image { - height: 180px; - width: 180px; -} - -.pod input[type='password'] { - height: 45px; /* 1px shorter as to not overlap the pod's rounded corners */ - top: 1px; -} - -.pod .indicator-container { - background-color: rgba(255, 255, 255, 0.85); - border-radius: 16px; - height: 32px; - left: 8px; - position: absolute; - top: 8px; -} - -html[dir=rtl] .pod .indicators { - left: auto; - right: 8px; -} - -.pod .indicator { - background-position: center; - background-repeat: no-repeat; - background-size: 18px; - display: none; - float: left; - height: 32px; - width: 32px; -} - -/* Using -webkit-mask on the indicators allows us to tweak the color. */ -.pod .indicator-container > div { - -webkit-mask-position: center; - -webkit-mask-repeat: no-repeat; - -webkit-mask-size: 24px; -} - -.pod.locked .locked-indicator { - -webkit-mask-image: url(../../../../ui/webui/resources/images/lock.svg); - background-color: #757575; - display: initial; -} - -.pod.legacy-supervised .legacy-supervised-indicator { - -webkit-mask-image: - url(../../../../ui/webui/resources/images/supervisor_account.svg); - background-color: rgb(66, 133, 244); - display: initial; -} - -.pod.child .child-indicator { - -webkit-mask-image: - url(../../../../ui/webui/resources/images/account_child_invert.svg); - background-color: rgb(66, 133, 244); - display: initial; -} - -.main-pane { - left: 0; - top: 0; -} - -html[dir=rtl] .main-pane { - right: 0; -} - -.name-container, -.pod.focused:not(.multiprofiles-policy-applied) .auth-container { - top: 180px; - width: 180px; -} - -.pod.focused:not(.locked) .name-container { - display: block; -} - -.pod .name { - color: #363636; - font-size: 15px; - margin-top: 11px; -} - -.pod.focused:not(.locked) .auth-container { - display: none; -} - -.pod[auth-type='offlinePassword'].focused.locked .password-entry-container { - display: flex; - flex: auto; -} - -.action-box-area { - background-color: #f5f5f5; - height: 24px; - /* Because of crbug.com/406529, the text in the .name div is janky if there's - an opacity transition in this div. */ - transition: none; - width: 24px; -} - -.action-box-button, -.action-box-button:hover, -.action-box-area.active .action-box-button { - background-image: none; - border-left: 6px solid transparent; - border-right: 6px solid transparent; - border-top: 6px solid #989898; - height: 0; - left: 6px; - margin: 0; - position: absolute; - top: 9px; - width: 0; -} - -.action-box-button:hover, -.action-box-area.active .action-box-button { - border-top: 6px solid #4c4c4c; -} - -.action-box-remove-user-warning .remove-warning-button { - background: rgb(197, 57, 41); - border-radius: 2px; - color: white; - font-weight: 500; - line-height: 32px; - padding: 0 16px; - width: 100%; -} - -.action-box-remove-user-warning .remove-warning-button[focused] { - background: rgb(173, 50, 36); - font-weight: 500; -} diff --git a/chromium/chrome/browser/resources/user_manager/user_manager.html b/chromium/chrome/browser/resources/user_manager/user_manager.html deleted file mode 100644 index 73fa6263b34..00000000000 --- a/chromium/chrome/browser/resources/user_manager/user_manager.html +++ /dev/null @@ -1,62 +0,0 @@ -<!doctype html> -<html i18n-values="dir:textdirection; - screen:screenType; - build:buildType; - lang:language"> -<head> -<meta charset="utf-8"> -<meta name="google" value="notranslate"> -<title i18n-content="title"></title> -<link rel="stylesheet" href="chrome://resources/css/chrome_shared.css"> -<link rel="stylesheet" href="../../../../ui/login/bubble.css"> -<link rel="stylesheet" href="../../../../ui/login/account_picker/screen_account_picker.css"> -<link rel="stylesheet" href="../../../../ui/login/screen_container.css"> -<link rel="stylesheet" href="../../../../ui/login/oobe.css"> -<link rel="stylesheet" href="../../../../ui/login/account_picker/user_pod_row.css"> -<!-- desktop user manager specific overrides --> -<link rel="stylesheet" href="control_bar.css"> -<link rel="stylesheet" href="user_manager.css"> -<link rel="stylesheet" href="user_manager_tutorial.css"> -<!-- Import paper-button to use in user_pod_template.html --> -<link rel="import" href="chrome://resources/html/polymer.html"> -<link rel="import" href="chrome://resources/polymer/v1_0/paper-button/paper-button.html"> -<!-- framework imports --> -<!-- as per chrome/browser/resources/chromeos/login/login_resources.html --> -<script src="chrome://resources/js/action_link.js"></script> -<script src="chrome://resources/js/cr.js"></script> -<script src="chrome://resources/js/event_tracker.js"></script> -<script src="chrome://resources/js/cr/event_target.js"></script> -<script src="chrome://resources/js/cr/ui.js"></script> -<script src="chrome://resources/js/cr/ui/array_data_model.js"></script> -<script src="chrome://resources/js/cr/ui/list_selection_controller.js"></script> -<script src="chrome://resources/js/cr/ui/list_selection_model.js"></script> -<script src="chrome://resources/js/cr/ui/list_single_selection_model.js"></script> -<script src="chrome://resources/js/cr/ui/list.js"></script> -<script src="chrome://resources/js/cr/ui/list_item.js"></script> -<script src="chrome://resources/js/cr/ui/grid.js"></script> -<script src="chrome://resources/js/cr/ui/menu_item.js"></script> -<script src="chrome://resources/js/cr/ui/menu.js"></script> -<script src="chrome://resources/js/cr/ui/menu_button.js"></script> -<script src="chrome://resources/js/load_time_data.js"></script> -<script src="chrome://resources/js/util.js"></script> -<script src="user_manager.js"></script> -<script src="chrome://user-manager/strings.js"></script> -</head> -<body class="oobe-display"> - <div id="outer-container"> - <include src="user_manager_tutorial.html"> - <div id="oobe" class="faded"> - <div id="inner-container"> - <div id="step-logo" hidden> - <div id="header-sections"></div> - </div> - <include src="../../../../ui/login/account_picker/screen_account_picker.html"> - </div> - </div> - </div> - <div id="bubble" class="bubble faded" hidden></div> - <include src="control_bar.html"> - <include src="../../../../ui/login/account_picker/user_pod_template.html"> - <script src="chrome://resources/js/i18n_template.js"></script> -</body> -</html> diff --git a/chromium/chrome/browser/resources/user_manager/user_manager.js b/chromium/chrome/browser/resources/user_manager/user_manager.js deleted file mode 100644 index 9b9faca3bd7..00000000000 --- a/chromium/chrome/browser/resources/user_manager/user_manager.js +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2013 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. -<include src="../../../../ui/login/screen.js"> -<include src="../../../../ui/login/bubble.js"> -<include src="../../../../ui/login/login_ui_tools.js"> -<include src="../../../../ui/login/display_manager.js"> -<include src="control_bar.js"> -<include src="../../../../ui/login/account_picker/screen_account_picker.js"> -<include src="../../../../ui/login/account_picker/user_pod_row.js"> -<include src="../../../../ui/login/resource_loader.js"> -<include src="user_manager_tutorial.js"> - -cr.define('cr.ui', function() { - var DisplayManager = cr.ui.login.DisplayManager; - var UserManagerTutorial = cr.ui.login.UserManagerTutorial; - - /** - * Constructs an Out of box controller. It manages initialization of screens, - * transitions, error messages display. - * @extends {DisplayManager} - * @constructor - */ - function UserManager() { - } - - cr.addSingletonGetter(UserManager); - - UserManager.prototype = { - __proto__: DisplayManager.prototype, - - /** - * Indicates whether the user pods page is visible. - * @type {boolean} - */ - userPodsPageVisible: true - }; - - /** - * Shows the given screen. - * @param {bool} showGuest Whether the 'Browse as Guest' button is displayed. - * @param {bool} showAddPerson Whether the 'Add Person' button is displayed. - */ - UserManager.showUserManagerScreen = function(showGuest, showAddPerson) { - UserManager.getInstance().showScreen({id: 'account-picker', - data: {disableAddUser: false}}); - // The ChromeOS account-picker will hide the AddUser button if a user is - // logged in and the screen is "locked", so we must re-enabled it - $('add-user-header-bar-item').hidden = false; - - // Hide control options if the user does not have the right permissions. - $('guest-user-button').hidden = !showGuest; - $('add-user-button').hidden = !showAddPerson; - $('login-header-bar').hidden = false; - - // Disable the context menu, as the Print/Inspect element items don't - // make sense when displayed as a widget. - document.addEventListener('contextmenu', function(e) {e.preventDefault();}); - - var hash = window.location.hash; - if (hash && hash == '#tutorial') - UserManagerTutorial.startTutorial(); - }; - - /** - * Open a new browser for the given profile. - * @param {string} profilePath The profile's path. - */ - UserManager.launchUser = function(profilePath) { - chrome.send('launchUser', [profilePath]); - }; - - /** - * Disables signin UI. - */ - UserManager.disableSigninUI = function() { - DisplayManager.disableSigninUI(); - }; - - /** - * Shows signin UI. - * @param {string} opt_email An optional email for signin UI. - */ - UserManager.showSigninUI = function(opt_email) { - DisplayManager.showSigninUI(opt_email); - }; - - /** - * Shows sign-in error bubble. - * @param {number} loginAttempts Number of login attemps tried. - * @param {string} message Error message to show. - * @param {string} link Text to use for help link. - * @param {number} helpId Help topic Id associated with help link. - */ - UserManager.showSignInError = function(loginAttempts, message, link, helpId) { - DisplayManager.showSignInError(loginAttempts, message, link, helpId); - }; - - /** - * Clears error bubble as well as optional menus that could be open. - */ - UserManager.clearErrors = function() { - DisplayManager.clearErrors(); - }; - - /** - * Clears password field in user-pod. - */ - UserManager.clearUserPodPassword = function() { - DisplayManager.clearUserPodPassword(); - }; - - /** - * Restores input focus to currently selected pod. - */ - UserManager.refocusCurrentPod = function() { - DisplayManager.refocusCurrentPod(); - }; - - /** - * Show the user manager tutorial - * @param {string} email The user's email, if signed in. - * @param {string} displayName The user's display name. - */ - UserManager.showUserManagerTutorial = function() { - UserManagerTutorial.startTutorial(); - }; - - // Export - return { - UserManager: UserManager - }; -}); - -cr.define('UserManager', function() { - 'use strict'; - - function initialize() { - cr.ui.login.DisplayManager.initialize(); - cr.ui.login.UserManagerTutorial.initialize(); - login.AccountPickerScreen.register(); - cr.ui.Bubble.decorate($('bubble')); - login.HeaderBar.decorate($('login-header-bar')); - - // Hide the header bar until the showUserManagerMethod can apply function - // parameters that affect widget visiblity. - $('login-header-bar').hidden = true; - - chrome.send('userManagerInitialize', [window.location.hash]); - } - - // Return an object with all of the exports. - return { - initialize: initialize - }; -}); - -// Alias to Oobe for use in src/ui/login/account_picker/user_pod_row.js -var Oobe = cr.ui.UserManager; - -// Allow selection events on components with editable text (password field) -// bug (http://code.google.com/p/chromium/issues/detail?id=125863) -disableTextSelectAndDrag(function(e) { - var src = e.target; - return src instanceof HTMLTextAreaElement || - src instanceof HTMLInputElement && - /text|password|search/.test(src.type); -}); - -document.addEventListener('DOMContentLoaded', UserManager.initialize); diff --git a/chromium/chrome/browser/resources/user_manager/user_manager_tutorial.css b/chromium/chrome/browser/resources/user_manager/user_manager_tutorial.css deleted file mode 100644 index 13a1c84c3d2..00000000000 --- a/chromium/chrome/browser/resources/user_manager/user_manager_tutorial.css +++ /dev/null @@ -1,185 +0,0 @@ -/* Copyright 2014 The Chromium Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. */ - -.tutorial-slide { - -webkit-transition: opacity 200ms ease-in-out; - background-color: white; - border-radius: 2px; - bottom: 0; - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25); - height: 408px; - left: 0; - margin: auto; - position: absolute; - right: 0; - top: 0; - width: 320px; - z-index: 100; -} - -.tutorial-slide.single-pod { - margin-left: 30px; -} - -html[dir=rtl] .tutorial-slide.single-pod { - margin-right: 30px; -} - -.hidden { - opacity: 0; - pointer-events: none; -} - -#slide-guests { - bottom: 20px; - left: 20px; - margin: 0; - top: auto; -} - -html[dir=rtl] #slide-guests { - right: 20px; -} - -#slide-friends, -#slide-not-you { - bottom: 20px; - left: 60px; - margin: 0; - top: auto; -} - -html[dir=rtl] #slide-friends, -html[dir=rtl] #slide-not-you { - right: 60px; -} - -#slide-not-you { - height: 100px; - left: 100px; - margin: 0; - width: 240px; -} - -html[dir=rtl] #slide-not-you { - right: 100px; -} - -.slide-contents { - padding: 0 20px; - text-align: center; -} - -.slide-title { - color: black; - font-size: 20px; - line-height: 20px; - margin: 30px 0; -} - -.slide-text { - color: #666; - font-size: 15px; - line-height: 20px; -} - -.slide-buttons { - bottom: 20px; - position: absolute; - text-align: center; - width: 100%; -} - -.slide-buttons [is='action-link'] { - width: 100%; -} - -.slide-buttons button { - bottom: 0; - height: 35px; - padding: 0 15px; - width: 138px; -} - -.slide-buttons button.left { - left: 16px; - position: absolute; -} - -html[dir=rtl] .slide-buttons button.left { - right: 16px; -} - -.slide-buttons button.right { - bottom: 0; - position: absolute; -} - -.arrow-down { - border-left: 15px solid transparent; - border-right: 15px solid transparent; - border-top: 15px solid white; - bottom: -15px; - height: 0; - left: 120px; - position: absolute; - width: 0; -} - -#slide-not-you .arrow-down { - left: 100px; -} - -html[dir=rtl] #slide-not-you .arrow-down { - right: 100px; -} - -#slide-guests .arrow-down { - left: 60px; -} - -html[dir=rtl] #slide-guests .arrow-down { - right: 60px; -} - -.slide-image { - height: 182px; -} - -#slide-your-chrome .slide-image { - background-color: rgb(241, 202, 58); - background-image: - url(chrome://theme/IDR_ICON_USER_MANAGER_TUTORIAL_YOUR_CHROME); -} - -#slide-guests .slide-image { - background-color: rgb(90, 196, 144); - background-image: url(chrome://theme/IDR_ICON_USER_MANAGER_TUTORIAL_GUESTS); -} - -#slide-friends .slide-image { - background-color: rgb(179, 229, 252); - background-image: - url(chrome://theme/IDR_ICON_USER_MANAGER_TUTORIAL_FRIENDS); -} - -#slide-complete .slide-image { - background-color: white; - background-image: - url(chrome://theme/IDR_ICON_USER_MANAGER_TUTORIAL_COMPLETE); -} - -#slide-not-you #dismiss-bubble-button { - background-image: url(chrome://theme/IDR_CLOSE_1); - cursor: pointer; - height: 16px; - position: absolute; - right: 5px; - top: 5px; - width: 16px; -} - -html[dir=rtl] #slide-not-you #dismiss-bubble-button { - left: 5px; -} diff --git a/chromium/chrome/browser/resources/user_manager/user_manager_tutorial.html b/chromium/chrome/browser/resources/user_manager/user_manager_tutorial.html deleted file mode 100644 index 16b9a063c6e..00000000000 --- a/chromium/chrome/browser/resources/user_manager/user_manager_tutorial.html +++ /dev/null @@ -1,58 +0,0 @@ -<div id="user-manager-tutorial" hidden> - <div class="tutorial-slide" id="slide-your-chrome"> - <div class="slide-image"></div> - <div class="slide-contents"> - <div class="slide-title" i18n-content="slideYourChromeTitle"></div> - <div class="slide-text" i18n-content="slideYourChromeText"></div> - </div> - <div class="slide-buttons"> - <button id="slide-your-chrome-next" i18n-content="tutorialNext"></button> - </div> - </div> - - <div class="tutorial-slide hidden" id="slide-guests"> - <div class="slide-image"></div> - <div class="slide-contents"> - <div class="slide-title" i18n-content="slideGuestsTitle"></div> - <div class="slide-text" i18n-content="slideGuestsText"></div> - </div> - <div class="slide-buttons"> - <button id="slide-guests-next" i18n-content="tutorialNext"></button> - </div> - <div class="arrow-down"></div> - </div> - - <div class="tutorial-slide hidden" id="slide-friends"> - <div class="slide-image"></div> - <div class="slide-contents"> - <div class="slide-title" i18n-content="slideFriendsTitle"></div> - <div class="slide-text" i18n-content="slideFriendsText"></div> - </div> - <div class="slide-buttons"> - <button id="slide-friends-next" i18n-content="tutorialNext"></button> - </div> - <div class="arrow-down"></div> - </div> - - <div class="tutorial-slide hidden" id="slide-complete"> - <div class="slide-image"></div> - <div class="slide-contents"> - <div class="slide-title" i18n-content="slideCompleteTitle"></div> - <div class="slide-text" i18n-content="slideCompleteText"></div> - </div> - <div class="slide-buttons"> - <button id="slide-complete-next" i18n-content="tutorialDone"></button> - </div> - </div> - - <div class="tutorial-slide hidden" id="slide-not-you"> - <div id="dismiss-bubble-button"></div> - <div class="slide-buttons"> - <div class="slide-text" i18n-content="slideCompleteUserNotFound"></div> - <br> - <a is="action-link" id="slide-add-user" - i18n-content="slideCompleteAddUser"></a> - </div> - <div class="arrow-down"></div> - </div> -</div> diff --git a/chromium/chrome/browser/resources/user_manager/user_manager_tutorial.js b/chromium/chrome/browser/resources/user_manager/user_manager_tutorial.js deleted file mode 100644 index b0a46c7d80d..00000000000 --- a/chromium/chrome/browser/resources/user_manager/user_manager_tutorial.js +++ /dev/null @@ -1,136 +0,0 @@ -// Copyright 2014 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -cr.define('cr.ui.login', function() { - /** - * Constructs a slide manager for the user manager tutorial. - * - * @constructor - */ - function UserManagerTutorial() { - } - - cr.addSingletonGetter(UserManagerTutorial); - - UserManagerTutorial.prototype = { - /** - * Tutorial slides. - */ - slides_: ['slide-your-chrome', - 'slide-friends', - 'slide-guests', - 'slide-complete', - 'slide-not-you'], - - /** - * Current tutorial step, index in the slides array. - * @type {number} - */ - currentStep_: 0, - - /** - * Switches to the next tutorial step. - * @param {number} nextStepIndex Index of the next step. - */ - toggleStep_: function(nextStepIndex) { - if (nextStepIndex > this.slides_.length) - return; - - var currentStepId = this.slides_[this.currentStep_]; - var nextStepId = this.slides_[nextStepIndex]; - var oldStep = $(currentStepId); - var newStep = $(nextStepId); - - newStep.classList.remove('hidden'); - - if (nextStepIndex != this.currentStep_) - oldStep.classList.add('hidden'); - - this.currentStep_ = nextStepIndex; - - // The last tutorial step is an information bubble that ends the tutorial. - if (this.currentStep_ == this.slides_.length - 1) - this.endTutorial_(); - }, - - next_: function() { - var nextStep = this.currentStep_ + 1; - this.toggleStep_(nextStep); - }, - - skip_: function() { - this.endTutorial_(); - $('user-manager-tutorial').hidden = true; - }, - - /** - * Add user button click handler. - * @private - */ - handleAddUserClick_: function(e) { - chrome.send('addUser'); - $('user-manager-tutorial').hidden = true; - e.stopPropagation(); - }, - - /** - * Add a button click handler to dismiss the last tutorial bubble. - * @private - */ - handleDismissBubbleClick_: function(e) { - $('user-manager-tutorial').hidden = true; - e.stopPropagation(); - }, - - endTutorial_: function(e) { - $('inner-container').classList.remove('disabled'); - }, - - decorate: function() { - // Transitions between the tutorial slides. - for (var i = 0; i < this.slides_.length; ++i) { - var buttonNext = $(this.slides_[i] + '-next'); - var buttonSkip = $(this.slides_[i] + '-skip'); - if (buttonNext) - buttonNext.addEventListener('click', this.next_.bind(this)); - if (buttonSkip) - buttonSkip.addEventListener('click', this.skip_.bind(this)); - } - $('slide-add-user').addEventListener('click', - this.handleAddUserClick_.bind(this)); - $('dismiss-bubble-button').addEventListener('click', - this.handleDismissBubbleClick_.bind(this)); - } - }; - - /** - * Initializes the tutorial manager. - */ - UserManagerTutorial.startTutorial = function() { - $('user-manager-tutorial').hidden = false; - - // If there's only one pod, show the slides to the side of the pod. - // Otherwise, center the slides and disable interacting with the pods - // while the tutorial is showing. - if ($('pod-row').pods.length == 1) { - $('slide-your-chrome').classList.add('single-pod'); - $('slide-complete').classList.add('single-pod'); - } - - $('pod-row').focusPod(); // No focused pods. - $('inner-container').classList.add('disabled'); - }; - - /** - * Initializes the tutorial manager. - */ - UserManagerTutorial.initialize = function() { - UserManagerTutorial.getInstance().decorate(); - }; - - // Export. - return { - UserManagerTutorial: UserManagerTutorial - }; -}); diff --git a/chromium/chrome/browser/resources/vr_shell/vr_shell_ui.css b/chromium/chrome/browser/resources/vr_shell/vr_shell_ui.css index efb90170f8c..b0ad92bbbfc 100644 --- a/chromium/chrome/browser/resources/vr_shell/vr_shell_ui.css +++ b/chromium/chrome/browser/resources/vr_shell/vr_shell_ui.css @@ -3,16 +3,24 @@ * found in the LICENSE file. */ html { - background-color: rgba(255, 255, 255, 0.2); + background-color: rgba(255, 255, 255, 0); } -.ui-button { - background: white; - border-radius: 6px; - overflow: hidden; +#ui { + --scaleFactor: 4; + left: 0; position: absolute; - text-align: center; - vertical-align: middle; + top: 0; + transform: scale(0.25, 0.25); + transform-origin: left top; + width: 400%; +} + +/* This class manages the position of elements on the texture page. + * Each UI element should have a bounding div of this class. */ +.ui-element { + float: left; + margin: 2px; } .webvr-message-box { @@ -20,16 +28,11 @@ html { display: flex; flex-direction: column; justify-content: center; - position: absolute; } -/* Permanent security warning for WebVR. This uses a fixed-size absolutely - * positioned DIV, the rectangle must match kWebVrWarningPermanentRect - * in vr_shell.cc for use as a GL textured quad. */ +/* Permanent security warning for WebVR. */ #webvr-not-secure-permanent { height: 128px; - left: 0; - top: 0; width: 512px; } @@ -65,13 +68,9 @@ html { white-space: nowrap; } -/* Transient security warning for WebVR. This uses a fixed-size absolutely - * positioned DIV, the rectangle must match kWebVrWarningTransientRect - * in vr_shell.cc for use as a GL textured quad. */ +/* Transient security warning for WebVR. */ #webvr-not-secure-transient { height: 256px; - left: 0; - top: 128px; width: 512px; } @@ -90,7 +89,115 @@ html { line-height: 1.4; max-height: 210px; min-height: 160px; + overflow: hidden; padding: 20px; text-align: center; width: 512px; } + +.round-button .button { + background-color: #eee; + background-position: center; + background-repeat: no-repeat; + background-size: contain; + border-radius: 50%; + height: 96px; + margin: auto auto; + opacity: 0.8; + transition: opacity 150ms ease-in-out; + width: 96px; +} + +.round-button .caption { + color: white; + font-size: 24px; + max-width: 192px; + opacity: 0; + overflow: hidden; + text-align: center; + transition: opacity 150ms ease-in-out; + white-space: nowrap; +} + +#back .button { + background-image: url(../../../../ui/webui/resources/images/vr_back.svg); +} + +#reload .button { + background-image: url(../../../../ui/webui/resources/images/vr_reload.svg); +} + +#forward .button { + background-image: url(../../../../ui/webui/resources/images/vr_back.svg); + transform: scaleX(-1); +} + +#reload-ui-button { + background-color: #555; + color: white; + font-size: 24px; + padding: 12px; +} + +#omni-container { + --tranX: 0; + --tranY: -0.65; + --tranZ: -1.2; +} + +#omni { + align-items: center; + background-color: rgba(255, 255, 255, 0.9); + border-radius: 100px; + box-sizing: border-box; + display: flex; + height: 104px; + justify-content: center; + margin-bottom: 60px; + margin-top: 0; + opacity: 1; + transition: opacity 500ms ease, margin-top 500ms ease; + white-space: nowrap; + width: 512px; +} + +#omni-content { + align-items: center; + display: flex; + max-width: 448px; +} + +#omni .connection-security { + height: 50px; + margin-right: 10px; + width: 50px; +} + +#omni #url { + color: #252525; + font-size: 34px; + overflow: hidden; + white-space: nowrap; +} + +#omni #path { + color: #868686; +} + +#omni.hide { + margin-bottom: 0; + margin-top: 60px; + opacity: 0; +} + +#omni.loading { + border: 4px solid rgb(86, 203, 255); +} + +#omni.idle { + background-color: #ececec; +} + +#omni.idle #domain { + color: black; +} diff --git a/chromium/chrome/browser/resources/vr_shell/vr_shell_ui.html b/chromium/chrome/browser/resources/vr_shell/vr_shell_ui.html index 6029112c79e..2d5364dc6c7 100644 --- a/chromium/chrome/browser/resources/vr_shell/vr_shell_ui.html +++ b/chromium/chrome/browser/resources/vr_shell/vr_shell_ui.html @@ -18,18 +18,46 @@ found in the LICENSE file. <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css"> </head> <body> -<div id="webvr-not-secure-permanent" class="webvr-message-box"> - <div class="webvr-box"> - <img class="webvr-not-secure-icon" width="36" height="36" - src="../../../../ui/webui/resources/images/i_circle.svg"> - <div class="webvr-string">$i18n{insecureWebVrContentPermanent}</div> + <div id="ui"> + <div id="webvr-not-secure-permanent" class="webvr-message-box ui-element"> + <div class="webvr-box"> + <img class="webvr-not-secure-icon" width="36" height="36" + src="../../../../ui/webui/resources/images/i_circle.svg"> + <div class="webvr-string">$i18n{insecureWebVrContentPermanent}</div> + </div> + </div> + <div id="webvr-not-secure-transient" class="webvr-message-box ui-element"> + <div> + <div>$i18n{insecureWebVrContentTransient}</div> + </div> + </div> + <div id="omni-container" class="ui-element"> + <div id="omni" class="idle"> + <div id="omni-content"> + <img id="omni-insecure-icon" class="connection-security" + src="../../../../ui/webui/resources/images/i_circle.svg"> + <img id="omni-secure-icon" class="connection-security" + src="../../../../ui/webui/resources/images/lock.svg"> + <div id="url"> + <span id="domain"></span><span id="path"></span> + </div> + </div> + </div> + </div> + <div id="back" class="round-button ui-element"> + <div class="button"></div> + <div class="caption">$i18n{back}</div> + </div> + <div id="reload" class="round-button ui-element"> + <div class="button"></div> + <div class="caption">$i18n{reload}</div> + </div> + <div id="forward" class="round-button ui-element"> + <div class="button"></div> + <div class="caption">$i18n{forward}</div> + </div> + <div id="reload-ui-button" class="ui-element">Reload UI</div> </div> -</div> -<div id="webvr-not-secure-transient" class="webvr-message-box"> - <div> - <div>$i18n{insecureWebVrContentTransient}</div> - </div> -</div> </body> <!-- Run script after creating body, to let it add its own elements. --> diff --git a/chromium/chrome/browser/resources/vr_shell/vr_shell_ui.js b/chromium/chrome/browser/resources/vr_shell/vr_shell_ui.js index c6d730e210a..ee7a3cf0cae 100644 --- a/chromium/chrome/browser/resources/vr_shell/vr_shell_ui.js +++ b/chromium/chrome/browser/resources/vr_shell/vr_shell_ui.js @@ -5,84 +5,423 @@ var vrShellUi = (function() { 'use strict'; - var scene = new ui.Scene(); + let scene = new ui.Scene(); + let sceneManager; - function initialize() { + let uiRootElement = document.querySelector('#ui'); + let uiStyle = window.getComputedStyle(uiRootElement); + let scaleFactor = uiStyle.getPropertyValue('--scaleFactor'); - domLoaded(); + function getStyleFloat(style, property) { + let value = parseFloat(style.getPropertyValue(property)); + return isNaN(value) ? 0 : value; + } - // Change the body background so that the transparency applies. - window.setTimeout(function() { - document.body.parentNode.style.backgroundColor = 'rgba(255,255,255,0)'; - }, 100); + class ContentQuad { + constructor() { + /** @const */ var SCREEN_HEIGHT = 1.6; + /** @const */ var SCREEN_DISTANCE = 2.0; - addControlButtons(); - } + let element = new api.UiElement(0, 0, 0, 0); + element.setIsContentQuad(false); + element.setVisible(false); + element.setSize(SCREEN_HEIGHT * 16 / 9, SCREEN_HEIGHT); + element.setTranslation(0, 0, -SCREEN_DISTANCE); + this.elementId = scene.addElement(element); + } + + setEnabled(enabled) { + let update = new api.UiElementUpdate(); + update.setVisible(enabled); + scene.updateElement(this.elementId, update); + } + + getElementId() { + return this.elementId; + } + }; + + class DomUiElement { + constructor(domId) { + let domElement = document.querySelector(domId); + + // Pull copy rectangle from the position of the element. + let rect = domElement.getBoundingClientRect(); + let pixelX = Math.floor(rect.left); + let pixelY = Math.floor(rect.top); + let pixelWidth = Math.ceil(rect.right) - pixelX; + let pixelHeight = Math.ceil(rect.bottom) - pixelY; + + let element = new api.UiElement(pixelX, pixelY, pixelWidth, pixelHeight); + element.setSize(scaleFactor * pixelWidth / 1000, + scaleFactor * pixelHeight / 1000); + + // Pull additional custom properties from CSS. + let style = window.getComputedStyle(domElement); + element.setTranslation( + getStyleFloat(style, '--tranX'), + getStyleFloat(style, '--tranY'), + getStyleFloat(style, '--tranZ')); + + this.uiElementId = scene.addElement(element); + this.uiAnimationId = -1; + this.domElement = domElement; + } + }; + + class RoundButton extends DomUiElement { + constructor(domId, callback) { + super(domId); + + let button = this.domElement.querySelector('.button'); + button.addEventListener('mouseenter', this.onMouseEnter.bind(this)); + button.addEventListener('mouseleave', this.onMouseLeave.bind(this)); + button.addEventListener('click', callback); + } + + configure(buttonOpacity, captionOpacity, distanceForward) { + let button = this.domElement.querySelector('.button'); + let caption = this.domElement.querySelector('.caption'); + button.style.opacity = buttonOpacity; + caption.style.opacity = captionOpacity; + let anim = new api.Animation(this.uiElementId, 150); + anim.setTranslation(0, 0, distanceForward); + if (this.uiAnimationId >= 0) { + scene.removeAnimation(this.uiAnimationId); + } + this.uiAnimationId = scene.addAnimation(anim); + scene.flush(); + } + + onMouseEnter() { + this.configure(1, 1, 0.015); + } + + onMouseLeave() { + this.configure(0.8, 0, 0); + } + }; + + class Controls { + constructor(contentQuadId) { + this.buttons = []; + let descriptors = [ + ['#back', function() { + api.doAction(api.Action.HISTORY_BACK); + }], + ['#reload', function() { + api.doAction(api.Action.RELOAD); + }], + ['#forward', function() { + api.doAction(api.Action.HISTORY_FORWARD); + }], + ]; + + /** @const */ var BUTTON_SPACING = 0.136; + + let startPosition = -BUTTON_SPACING * (descriptors.length / 2.0 - 0.5); + for (let i = 0; i < descriptors.length; i++) { + // Use an invisible parent to simplify Z-axis movement on hover. + let position = new api.UiElement(0, 0, 0, 0); + position.setVisible(false); + position.setTranslation(startPosition + i * BUTTON_SPACING, -0.68, -1); + let id = scene.addElement(position); + + let domId = descriptors[i][0]; + let callback = descriptors[i][1]; + let element = new RoundButton(domId, callback); + this.buttons.push(element); + + let update = new api.UiElementUpdate(); + update.setParentId(id); + update.setVisible(false); + scene.updateElement(element.uiElementId, update); + } + + this.reloadUiButton = new DomUiElement('#reload-ui-button'); + this.reloadUiButton.domElement.addEventListener('click', function() { + scene.purge(); + api.doAction(api.Action.RELOAD_UI); + }); + + let update = new api.UiElementUpdate(); + update.setParentId(contentQuadId); + update.setVisible(false); + update.setScale(2.2, 2.2, 1); + update.setTranslation(0, -0.6, 0.3); + update.setAnchoring(api.XAnchoring.XNONE, api.YAnchoring.YBOTTOM); + scene.updateElement(this.reloadUiButton.uiElementId, update); + } + + setEnabled(enabled) { + this.enabled = enabled; + this.configure(); + } + + setReloadUiEnabled(enabled) { + this.reloadUiEnabled = enabled; + this.configure(); + } + + configure() { + for (let i = 0; i < this.buttons.length; i++) { + let update = new api.UiElementUpdate(); + update.setVisible(this.enabled); + scene.updateElement(this.buttons[i].uiElementId, update); + } + let update = new api.UiElementUpdate(); + update.setVisible(this.enabled && this.reloadUiEnabled); + scene.updateElement(this.reloadUiButton.uiElementId, update); + } + }; + + class SecureOriginWarnings { + constructor() { + /** @const */ var DISTANCE = 0.7; + /** @const */ var ANGLE_UP = 16.3 * Math.PI / 180.0; + + // Permanent WebVR security warning. This warning is shown near the top of + // the field of view. + this.webVrSecureWarning = new DomUiElement('#webvr-not-secure-permanent'); + let update = new api.UiElementUpdate(); + update.setScale(DISTANCE, DISTANCE, 1); + update.setTranslation(0, DISTANCE * Math.sin(ANGLE_UP), + -DISTANCE * Math.cos(ANGLE_UP)); + update.setRotation(1.0, 0.0, 0.0, ANGLE_UP); + update.setHitTestable(false); + update.setVisible(false); + update.setLockToFieldOfView(true); + scene.updateElement(this.webVrSecureWarning.uiElementId, update); + + // Temporary WebVR security warning. This warning is shown in the center + // of the field of view, for a limited period of time. + this.transientWarning = new DomUiElement( + '#webvr-not-secure-transient'); + update = new api.UiElementUpdate(); + update.setScale(DISTANCE, DISTANCE, 1); + update.setTranslation(0, 0, -DISTANCE); + update.setHitTestable(false); + update.setVisible(false); + update.setLockToFieldOfView(true); + scene.updateElement(this.transientWarning.uiElementId, update); + } + + setEnabled(enabled) { + this.enabled = enabled; + this.updateState(); + } + + setSecureOrigin(secure) { + this.isSecureOrigin = secure; + this.updateState(); + } + + updateState() { + /** @const */ var TRANSIENT_TIMEOUT_MS = 30000; + + let visible = (this.enabled && !this.isSecureOrigin); + if (this.secureOriginTimer) { + clearInterval(this.secureOriginTimer); + this.secureOriginTimer = null; + } + if (visible) { + this.secureOriginTimer = setTimeout( + this.onTransientTimer.bind(this), TRANSIENT_TIMEOUT_MS); + } + this.showOrHideWarnings(visible); + } + + showOrHideWarnings(visible) { + let update = new api.UiElementUpdate(); + update.setVisible(visible); + scene.updateElement(this.webVrSecureWarning.uiElementId, update); + update = new api.UiElementUpdate(); + update.setVisible(visible); + scene.updateElement(this.transientWarning.uiElementId, update); + } + + onTransientTimer() { + let update = new api.UiElementUpdate(); + update.setVisible(false); + scene.updateElement(this.transientWarning.uiElementId, update); + this.secureOriginTimer = null; + scene.flush(); + } + }; + + class Omnibox { + constructor(contentQuadId) { + /** @const */ var VISIBILITY_TIMEOUT_MS = 3000; + + this.domUiElement = new DomUiElement('#omni-container'); + this.enabled = false; + this.secure = false; + this.visibilityTimeout = VISIBILITY_TIMEOUT_MS; + this.visibilityTimer = null; + this.nativeState = {}; + + // Initially invisible. + let update = new api.UiElementUpdate(); + update.setVisible(false); + scene.updateElement(this.domUiElement.uiElementId, update); + this.nativeState.visible = false; - // Build a row of control buttons. - function addControlButtons() { - var buttons = [ - // Button text, UI action passed down to native. - ['<', api.Action.HISTORY_BACK], - ['>', api.Action.HISTORY_FORWARD], - ['R', api.Action.RELOAD], - ['-', api.Action.ZOOM_OUT], - ['+', api.Action.ZOOM_IN] - ]; - - var buttonWidth = 0.3; - var buttonHeight = 0.2; - var buttonSpacing = 0.5; - var buttonStartPosition = -buttonSpacing * (buttons.length / 2.0 - 0.5); - - for (var i = 0; i < buttons.length; i++) { - var b = document.createElement('div'); - b.position = 'absolute'; - b.style.top = '384px'; - b.style.left = 50 * i + 'px'; - b.style.width = '50px'; - b.style.height = '50px'; - b.className = 'ui-button'; - b.textContent = buttons[i][0]; - - // Add click behaviour. - b.addEventListener('click', function(action, e) { - api.doAction(action); - }.bind(undefined, buttons[i][1])); - - document.body.appendChild(b); - - // Add a UI rectangle for the button. - var el = new api.UiElement(50 * i, 384, 50, 50); - el.setParentId(api.getContentElementId()); - el.setAnchoring(api.XAnchoring.XNONE, api.YAnchoring.YBOTTOM); - el.setSize(buttonWidth, buttonHeight); - el.setTranslation(buttonStartPosition + buttonSpacing * i, -0.3, 0.0); - var buttonId = scene.addElement(el); - - // Add transitions when the mouse hovers over (and leaves) the button. - b.addEventListener('mouseenter', function(buttonId, width, height, e) { - var resize = new api.Animation(buttonId, 250); - resize.setSize(width, height); - scene.addAnimation(resize); - scene.flush(); - }.bind(undefined, buttonId, buttonWidth * 1.5, buttonHeight * 1.5)); - b.addEventListener('mouseleave', function(buttonId, width, height) { - var resize = new api.Animation(buttonId, 250); - resize.setSize(width, height); - scene.addAnimation(resize); - scene.flush(); - }.bind(undefined, buttonId, buttonWidth, buttonHeight)); + // Listen to the end of transitions, so that the box can be natively + // hidden after it finishes hiding itself. + document.querySelector('#omni').addEventListener('transitionend', + this.onAnimationDone.bind(this)); } + + setEnabled(enabled) { + this.enabled = enabled; + this.resetVisibilityTimer(); + this.updateState(); + } + + setLoading(loading) { + this.loading = loading; + this.resetVisibilityTimer(); + this.updateState(); + } + + setURL(host, path) { + let omnibox = this.domUiElement.domElement; + omnibox.querySelector('#domain').innerHTML = host; + omnibox.querySelector('#path').innerHTML = path; + this.resetVisibilityTimer(); + this.updateState(); + } + + setSecureOrigin(secure) { + this.secure = secure; + this.resetVisibilityTimer(); + this.updateState(); + } + + setVisibilityTimeout(milliseconds) { + this.visibilityTimeout = milliseconds; + this.resetVisibilityTimer(); + this.updateState(); + } + + resetVisibilityTimer() { + if (this.visibilityTimer) { + clearInterval(this.visibilityTimer); + this.visibilityTimer = null; + } + if (this.enabled && this.visibilityTimeout > 0) { + this.visibilityTimer = setTimeout( + this.onVisibilityTimer.bind(this), this.visibilityTimeout); + } + } + + onVisibilityTimer() { + this.visibilityTimer = null; + this.updateState(); + } + + onAnimationDone(e) { + if (e.propertyName == 'opacity' && !this.visibleAfterTransition) { + this.setNativeVisibility(false); + } + } + + updateState() { + if (!this.enabled) { + this.setNativeVisibility(false); + return; + } + + document.querySelector('#omni-secure-icon').style.display = + (this.secure ? 'block' : 'none'); + document.querySelector('#omni-insecure-icon').style.display = + (this.secure ? 'none' : 'block'); + + let state = 'idle'; + this.visibleAfterTransition = true; + if (this.visibilityTimeout > 0 && !this.visibilityTimer) { + state = 'hide'; + this.visibleAfterTransition = false; + } else if (this.loading) { + state = 'loading'; + } + document.querySelector('#omni').className = state; + + this.setNativeVisibility(true); + } + + setNativeVisibility(visible) { + if (visible == this.nativeState.visible) { + return; + } + this.nativeState.visible = visible; + let update = new api.UiElementUpdate(); + update.setVisible(visible); + scene.updateElement(this.domUiElement.uiElementId, update); + scene.flush(); + } + }; + + class SceneManager { + constructor() { + this.mode = api.Mode.UNKNOWN; + + this.contentQuad = new ContentQuad(); + let contentId = this.contentQuad.getElementId(); + + this.controls = new Controls(contentId); + this.secureOriginWarnings = new SecureOriginWarnings(); + this.omnibox = new Omnibox(contentId); + } + + setMode(mode) { + this.mode = mode; + this.contentQuad.setEnabled(mode == api.Mode.STANDARD); + this.controls.setEnabled(mode == api.Mode.STANDARD); + this.omnibox.setEnabled(mode == api.Mode.STANDARD); + this.secureOriginWarnings.setEnabled(mode == api.Mode.WEB_VR); + } + + setSecureOrigin(secure) { + this.secureOriginWarnings.setSecureOrigin(secure); + this.omnibox.setSecureOrigin(secure); + } + + setReloadUiEnabled(enabled) { + this.controls.setReloadUiEnabled(enabled); + } + }; + + function initialize() { + sceneManager = new SceneManager(); scene.flush(); - } - function domLoaded() { api.domLoaded(); } + function command(dict) { + if ('mode' in dict) { + sceneManager.setMode(dict['mode']); + } + if ('secureOrigin' in dict) { + sceneManager.setSecureOrigin(dict['secureOrigin']); + } + if ('enableReloadUi' in dict) { + sceneManager.setReloadUiEnabled(dict['enableReloadUi']); + } + if ('url' in dict) { + let url = dict['url']; + sceneManager.omnibox.setURL(url['host'], url['path']); + } + if ('loading' in dict) { + sceneManager.omnibox.setLoading(dict['loading']); + } + scene.flush(); + } + return { initialize: initialize, + command: command, }; })(); diff --git a/chromium/chrome/browser/resources/vr_shell/vr_shell_ui_api.js b/chromium/chrome/browser/resources/vr_shell/vr_shell_ui_api.js index a65288c07db..e2313c101ed 100644 --- a/chromium/chrome/browser/resources/vr_shell/vr_shell_ui_api.js +++ b/chromium/chrome/browser/resources/vr_shell/vr_shell_ui_api.js @@ -71,6 +71,18 @@ var api = (function() { 'RELOAD': 2, 'ZOOM_OUT': 3, 'ZOOM_IN': 4, + 'RELOAD_UI': 5, + }); + + /** + * Enumeration of modes that can be specified by the native side. + * @enum {number} + * @const + */ + var Mode = Object.freeze({ + 'UNKNOWN': -1, + 'STANDARD': 0, + 'WEB_VR': 1 }); /** @@ -95,6 +107,10 @@ var api = (function() { */ class UiElementUpdate { + setIsContentQuad() { + this.contentQuad = true; + } + /** * Specify a parent for this element. If set, this element is positioned * relative to its parent element, rather than absolutely. This allows @@ -145,6 +161,28 @@ var api = (function() { this.xAnchoring = x; this.yAnchoring = y; } + + /** + * Visibility controls whether the element is rendered. + */ + setVisible(visible) { + this.visible = !!visible; + } + + /** + * Hit-testable implies that the reticle will hit the element, if visible. + */ + setHitTestable(testable) { + this.hitTestable = !!testable; + } + + /** + * Causes an element to be rendered relative to the field of view, rather + * than the scene. Elements locked in this way should not have a parent. + */ + setLockToFieldOfView(locked) { + this.lockToFov = !!locked; + } }; /** @@ -261,6 +299,7 @@ var api = (function() { Easing: Easing, Command: Command, Action: Action, + Mode: Mode, getContentElementId: getContentElementId, UiElement: UiElement, UiElementUpdate: UiElementUpdate, diff --git a/chromium/chrome/browser/resources/welcome/win10/README.md b/chromium/chrome/browser/resources/welcome/win10/README.md new file mode 100644 index 00000000000..efaee2433ff --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/win10/README.md @@ -0,0 +1,7 @@ +# Windows 10 Welcome page + +There are 2 different styles of the Windows 10 Welcome Page. A/B testing will +be done to find out which one of them is better. + +TODO(pmonette): Experiment with the 2 versions of the Welcome Page and +get rid of one of them. Bug id 658918. diff --git a/chromium/chrome/browser/resources/welcome/win10/inline.css b/chromium/chrome/browser/resources/welcome/win10/inline.css new file mode 100644 index 00000000000..215ded8bd80 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/win10/inline.css @@ -0,0 +1,239 @@ +/* Copyright 2016 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. */ + +body { + box-sizing: border-box; + color: var(--paper-grey-900); + display: flex; + flex-direction: column; + font-size: 100%; + justify-content: center; + margin: 0; + min-height: 100vh; +} + +a { + color: var(--google-blue-500); + text-decoration: none; +} + +ol { + margin: 0; + padding: 0; +} + +strong { + font-weight: 500; +} + +.content { + margin: 0 auto; + padding: 4em 1.5em 1.5em 1.5em; +} + +.header-logo { + content: url(chrome://welcome-win10/logo-large.png); + height: 4em; +} + +.heading { + font-size: 2.125em; + line-height: 1.6em; + margin-bottom: 0.5em; + margin-top: 1.2em; +} + +.sections { + margin-bottom: 2em; +} + +.section.expandable { + border-top: 1px solid var(--google-grey-300); +} + +.section.expandable:last-child { + border-bottom: 1px solid var(--google-grey-300); +} + +.section.expandable .section-heading { + color: var(--google-blue-500); + cursor: pointer; +} + +.section-heading { + align-items: center; + display: flex; + padding: 1.5em 0; +} + +.section-heading-text { + flex: 1; + font-weight: 500; +} + +.section.expandable .section-heading-text { + font-weight: normal; +} + +.section.expandable.expanded .section-heading-text { + font-weight: 500; +} + +.section-heading-expand { + height: 1.25em; + opacity: 0.54; + transition: transform 150ms cubic-bezier(.4, .2, 0, 1) 50ms; + width: 1.25em; +} + +.section.expandable.expanded .section-heading-expand { + transform: rotate(180deg); + transition-delay: 150ms; +} + +.section-steps { + overflow: hidden; +} + +.section-steps li { + -webkit-margin-start: 1.25em; + -webkit-padding-start: 1em; + margin-bottom: 1em; +} + +.section-steps li:last-child { + margin-bottom: 1em; +} + +.section.expandable .section-steps { + max-height: 0; + opacity: 0; + transition: max-height 300ms cubic-bezier(.4, .2, 0, 1) 50ms, opacity 150ms; +} + +.section.expandable.expanded .section-steps { + max-height: 28.75em; + opacity: 1; + transition: max-height 300ms cubic-bezier(.4, .2, 0, 1) 50ms, + opacity 150ms 250ms; +} + +.button { + -webkit-font-smoothing: antialiased; + background: var(--google-blue-500); + border-radius: 2px; + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1); + color: #fff; + display: inline-block; + font-size: .8125em; + font-weight: 500; + line-height: 2.25rem; + padding: 0 1em; + text-align: center; + transition: 300ms cubic-bezier(.4, .2, 0, 1); + will-change: box-shadow; +} + +.button:hover { + background: var(--paper-blue-a400); + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1), 0 1px 2px rgba(0, 0, 0, .24) +} + +.logo-small { + content: url(chrome://welcome-win10/logo-small.png); + display: inline; + height: 1.25em; + vertical-align: top; + width: 1.25em; +} + +.screenshot { + display: block; + height: 440px; + margin: 0 auto; + max-width: 100%; + position: relative; + top: -96px; + width: 720px; +} + +.screenshot-image { + box-shadow: 0 0 0 1px rgba(0, 0, 0, .12), 0 1px 2px rgba(0, 0, 0, .24); + height: 48vw; + margin: 1em 0; + max-height: 300px; + max-width: 400px; + min-height: 150px; + min-width: 200px; + position: relative; + width: 64vw; +} + +#screenshot-image--default { + background: -webkit-image-set( + url(https://www.gstatic.com/chrome/login/win10/default-small.webp) 1x, + url(https://www.gstatic.com/chrome/login/win10/default-small@2x.webp) 2x); + background-repeat: no-repeat; + background-size: cover; +} + +#screenshot-image--taskbar { + background: -webkit-image-set( + url(https://www.gstatic.com/chrome/login/win10/pin-small.webp) 1x, + url(https://www.gstatic.com/chrome/login/win10/pin-small@2x.webp) 2x); + background-repeat: no-repeat; + background-size: cover; +} + +.screenshot-html-overlay { + box-sizing: border-box; + font-size: 6px; + line-height: 0; + position: absolute; +} + +#screenshot-html-overlay--browser { + left: 54.8%; + top: 53%; +} + +#screenshot-html-overlay--edge { + left: 65%; + top: 63.5%; +} + +#screenshot-html-overlay--taskbar { + left: 31%; + top: 73%; +} + +#screenshot-html-overlay--taskbar div { + color: #ccc; + font-family: Tahoma, Verdana, Segoe, sans-serif; + font-weight: 500; +} + +#screenshot-html-overlay--icon { + background-image: url(/logo-small.png); + background-size: cover; + height: 8%; + left: 46%; + top: 90%; + width: 6%; +} + +/* This value is precisely set so that the text over the screenshot starts + * scaling at the same time the image starts scaling too. */ +@media (min-width: 312px) { + .screenshot-html-overlay { + font-size: 1.95vw; + } +} + +/* Font-size used when the screenshot exactly reaches its max size. */ +@media (min-width: 626px) { + .screenshot-html-overlay { + font-size: 12.2px; + } +} diff --git a/chromium/chrome/browser/resources/welcome/win10/inline.html b/chromium/chrome/browser/resources/welcome/win10/inline.html new file mode 100644 index 00000000000..8a5bfa4bb10 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/win10/inline.html @@ -0,0 +1,86 @@ +<!DOCTYPE html> +<html> +<head> + <title>$i18n{headerText}</title> + + <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/html/polymer.html"> + <link rel="import" href="chrome://resources/html/util.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-button/paper-button.html"> + <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html"> + + <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css"> + <link rel="stylesheet" href="/welcome.css"> + + <script src="/welcome.js"></script> +</head> +<body> + <template is="dom-bind" id="inline-app"> + <div class="content"> + <div class="header-logo"></div> + <div class="heading">$i18n{headerText}</div> + <div class="sections"> + <div class$="[[computeClasses(isCombined)]]"> + <div class="section-heading" on-tap="onToggle"> + <div class="section-heading-text"> + $i18n{defaultBrowserSubheaderText} + </div> + <template is="dom-if" if="[[isCombined]]"> + <iron-icon class="section-heading-expand" icon="cr:expand-more"> + </iron-icon> + </template> + </div> + <ol class="section-steps"> + <li> + <a href="#" on-tap="onOpenSettings">$i18n{openSettingsText}</a> + </li> + <li> + <div>$i18nRaw{clickEdgeText}</div> + <div class="screenshot-image" id="screenshot-image--default"> + <div class="screenshot-html-overlay" + id="screenshot-html-overlay--browser"> + <div>$i18n{webBrowserLabel}</div> + </div> + <div class="screenshot-html-overlay" + id="screenshot-html-overlay--edge"> + <div>$i18n{microsoftEdgeLabel}</div> + </div> + </div> + </li> + <li>$i18nRaw{clickSelectChrome}</li> + </ol> + </div> + <template is="dom-if" if="[[isCombined]]"> + <div class="section expandable"> + <div class="section-heading" on-tap="onToggle"> + <div class="section-heading-text">$i18n{pinSubheaderText}</div> + <iron-icon class="section-heading-expand" icon="cr:expand-more"> + </iron-icon> + </div> + <ol class="section-steps"> + <li>$i18nRaw{rightClickText}</li> + <li> + <div>$i18nRaw{pinInstructionText}</div> + <div class="screenshot-image" id="screenshot-image--taskbar"> + <div class="screenshot-html-overlay" + id="screenshot-html-overlay--taskbar"> + <div>$i18n{pinToTaskbarLabel}</div> + </div> + <div class="screenshot-html-overlay" + id="screenshot-html-overlay--icon"> + </div> + </div> + </li> + </ol> + </div> + </template> + </div> + <paper-button class="button" on-tap="onContinue"> + $i18n{continueText} + </paper-button> + </div> + </template> +</body> +</html> diff --git a/chromium/chrome/browser/resources/welcome/win10/inline.js b/chromium/chrome/browser/resources/welcome/win10/inline.js new file mode 100644 index 00000000000..35c09807a19 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/win10/inline.js @@ -0,0 +1,72 @@ +// Copyright 2016 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('inline', function() { + 'use strict'; + + function computeClasses(isCombined) { + if (isCombined) + return 'section expandable expanded'; + return 'section'; + } + + function onContinue() { + chrome.send('handleContinue'); + } + + function onOpenSettings() { + chrome.send('handleSetDefaultBrowser'); + } + + function onToggle(app) { + if (app.isCombined) { + var sections = document.querySelectorAll('.section.expandable'); + sections.forEach(function(section) { + section.classList.toggle('expanded'); + }); + } + } + + function initialize() { + var app = $('inline-app'); + + // Set variables. + // Determines if the combined variant should be displayed. The combined + // variant includes instructions on how to pin Chrome to the taskbar. + app.isCombined = false; + + // Set handlers. + app.computeClasses = computeClasses; + app.onContinue = onContinue; + app.onOpenSettings = onOpenSettings; + app.onToggle = onToggle.bind(this, app); + + // Asynchronously check if Chrome is pinned to the taskbar. + cr.sendWithPromise('getPinnedToTaskbarState').then( + function(isPinnedToTaskbar) { + // Allow overriding of the result via a query parameter. + // TODO(pmonette): Remove these checks when they are no longer needed. + /** @const */ var VARIANT_KEY = 'variant'; + var VariantType = { + DEFAULT_ONLY: 'defaultonly', + COMBINED: 'combined' + }; + var params = new URLSearchParams(location.search.slice(1)); + if (params.has(VARIANT_KEY)) { + if (params.get(VARIANT_KEY) === VariantType.DEFAULT_ONLY) + app.isCombined = false; + else if (params.get(VARIANT_KEY) === VariantType.COMBINED) + app.isCombined = true; + } else { + app.isCombined = !isPinnedToTaskbar; + } + }); + } + + return { + initialize: initialize + }; +}); + +document.addEventListener('DOMContentLoaded', inline.initialize); diff --git a/chromium/chrome/browser/resources/welcome/win10/sectioned.css b/chromium/chrome/browser/resources/welcome/win10/sectioned.css new file mode 100644 index 00000000000..77ec67445a7 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/win10/sectioned.css @@ -0,0 +1,296 @@ +/* Copyright 2016 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. */ + +body { + box-sizing: border-box; + color: var(--paper-grey-900); + display: flex; + flex-direction: column; + font-size: 100%; + justify-content: center; + margin: 0; + min-height: 100vh; +} + +a { + color: var(--google-blue-500); + text-decoration: none; +} + +ol { + margin: 0; + padding: 0; +} + +strong { + font-weight: 500; +} + +.content { + padding: 64px 24px 24px 24px; +} + +.header-logo { + content: url(chrome://welcome-win10/logo-large.png); + height: 4em; +} + +.text { + margin: 0 auto; + max-width: 45em; +} + +.heading { + font-size: 2.125em; + margin-bottom: .25em; + margin-top: 1.5em; +} + +.subheading { + color: var(--google-grey-500); + font-size: 1em; + margin-bottom: 1.5em; + margin-top: .25em; + text-align: center; +} + +.sections { + margin-bottom: 2em; +} + +.section.expandable { + border-top: 1px solid var(--google-grey-300); +} + +.section.expandable:last-child { + border-bottom: 1px solid var(--google-grey-300); +} + +.section.expandable .section-heading { + color: var(--google-blue-500); + cursor: pointer; +} + +.section-heading { + align-items: center; + display: flex; + padding: 1.5em 0; +} + +.section-heading-text { + flex: 1; + font-weight: 500; +} + +.section.expandable .section-heading-text { + font-weight: normal; +} + +.section.expandable.expanded .section-heading-text { + font-weight: 500; +} + +.section-heading-expand { + height: 1.25em; + opacity: 0.54; + transition: transform 150ms cubic-bezier(.4, .2, 0, 1) 50ms; + width: 1.25em; +} + +.section.expandable.expanded .section-heading-expand { + transform: rotate(180deg); + transition-delay: 150ms; +} + +.section-steps { + overflow: hidden; +} + +.section-steps li { + -webkit-margin-start: 1.25em; + -webkit-padding-start: 1em; + margin-bottom: 1em; +} + +.section-steps li:last-child { + margin-bottom: 1em; +} + +.section.expandable .section-steps { + max-height: 0; + opacity: 0; + transition: max-height 300ms cubic-bezier(.4, .2, 0, 1) 50ms, opacity 150ms; +} + +.section.expandable.expanded .section-steps { + max-height: 8.75em; + opacity: 1; + transition: max-height 300ms cubic-bezier(.4, .2, 0, 1) 50ms, + opacity 150ms 250ms; +} + +.button { + -webkit-font-smoothing: antialiased; + background: var(--google-blue-500); + border-radius: 2px; + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1); + color: #fff; + display: inline-block; + font-size: .8125em; + font-weight: 500; + line-height: 2.25rem; + padding: 0 1em; + text-align: center; + transition: 300ms cubic-bezier(.4, .2, 0, 1); + will-change: box-shadow; +} + +.button:hover { + background: var(--paper-blue-a400); + box-shadow: inset 0 0 0 1px rgba(0, 0, 0, .1), 0 1px 2px rgba(0, 0, 0, .24); +} + +.bg { + background: var(--paper-light-blue-700); + flex: 1; + margin-top: 96px; + padding: 24px; +} + +.logo-small { + content: url(chrome://welcome-win10/logo-small.png); + display: inline; + height: 1.25em; + vertical-align: top; + width: 1.25em; +} + +.screenshots { + display: block; + height: 440px; + margin: 0 auto; + max-width: 100%; + position: relative; + top: -96px; + width: 720px; +} + +.screenshot-image { + box-shadow: 0 0 8px rgba(0, 0, 0, .12), 0 4px 16px rgba(0, 0, 0, .24); + height: 56vw; + max-height: 440px; + max-width: 720px; + min-height: 294px; + min-width: 480px; + position: absolute; + transition: opacity 150ms; + width: 92vw; +} + +.screenshot-image.hidden { + opacity: 0; +} + +#screenshot-image--default { + background: -webkit-image-set( + url(https://www.gstatic.com/chrome/login/win10/default-large.webp) 1x, + url(https://www.gstatic.com/chrome/login/win10/default-large@2x.webp) 2x); + background-repeat: no-repeat; + background-size: cover; +} + +#screenshot-image--taskbar { + background: -webkit-image-set( + url(https://www.gstatic.com/chrome/login/win10/pin-large.webp) 1x, + url(https://www.gstatic.com/chrome/login/win10/pin-large@2x.webp) 2x); + background-repeat: no-repeat; + background-size: cover; +} + +.screenshot-html-overlay { + box-sizing: border-box; + font-size: 7px; + line-height: 0; + position: absolute; +} + +#screenshot-html-overlay--browser { + left: 35.8%; + top: 75.8%; +} + +#screenshot-html-overlay--edge { + left: 41.5%; + top: 82.4%; +} + +#screenshot-html-overlay--taskbar { + left: 62.2%; + top: 81.5%; +} + +#screenshot-html-overlay--taskbar div { + color: #ccc; + font-family: Tahoma, Verdana, Segoe, sans-serif; + font-weight: 500; +} + +#screenshot-html-overlay--icon { + background-image: url(/logo-small.png); + background-size: cover; + height: 5.8%; + left: 70.60%; + top: 93.1%; + width: 3.5%; +} + +/* This value is precisely set so that the text over the screenshot starts + * scaling at the same time the image starts scaling too. */ +@media (min-width: 520px) { + .screenshot-html-overlay { + font-size: 1.35vw; + } +} + +/* Font-size used when the screenshot exactly reaches its max size. */ +@media (min-width: 780px) { + .screenshot-html-overlay { + font-size: 10.5px; + } +} + +@media (min-width: 1280px) { + body { + flex-direction: row; + } + + .content { + align-items: center; + display: flex; + flex: 1; + justify-content: flex-end; + padding: 96px; + } + + .text { + margin: 0 180px; + max-width: none; + width: 400px; + } + + .bg { + align-items: center; + display: flex; + flex: 1; + margin: 0; + max-width: 42%; + padding: 0; + } + + .screenshots { + margin-left: -180px; + max-width: none; + top: 0; + } +} diff --git a/chromium/chrome/browser/resources/welcome/win10/sectioned.html b/chromium/chrome/browser/resources/welcome/win10/sectioned.html new file mode 100644 index 00000000000..d148da25008 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/win10/sectioned.html @@ -0,0 +1,88 @@ +<!DOCTYPE html> +<html> +<head> + <title>$i18n{headerText}</title> + + <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/html/polymer.html"> + <link rel="import" href="chrome://resources/html/util.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-button/paper-button.html"> + <link rel="import" href="chrome://resources/polymer/v1_0/paper-styles/color.html"> + + <link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css"> + <link rel="stylesheet" href="/welcome.css"> + + <script src="/welcome.js"></script> +</head> +<body> + <template is="dom-bind" id="sectioned-app"> + <div class="content"> + <div class="text"> + <div class="header-logo"></div> + <div class="heading">$i18n{headerText}</div> + <div class="sections"> + <div class$="[[computeClasses(isCombined)]]"> + <div class="section-heading" on-tap="onToggle"> + <div class="section-heading-text"> + $i18n{defaultBrowserSubheaderText} + </div> + <template is="dom-if" if="[[isCombined]]"> + <iron-icon class="section-heading-expand" icon="cr:expand-more"> + </iron-icon> + </template> + </div> + <ol class="section-steps"> + <li> + <a href="#" on-tap="onOpenSettings">$i18n{openSettingsText}</a> + </li> + <li>$i18nRaw{clickEdgeText}</li> + <li>$i18nRaw{clickSelectChrome}</li> + </ol> + </div> + <template is="dom-if" if="[[isCombined]]"> + <div class="section expandable"> + <div class="section-heading" on-tap="onToggle"> + <div class="section-heading-text">$i18n{pinSubheaderText}</div> + <iron-icon class="section-heading-expand" icon="cr:expand-more"> + </iron-icon> + </div> + <ol class="section-steps"> + <li>$i18nRaw{rightClickText}</li> + <li>$i18nRaw{pinInstructionText}</li> + </ol> + </div> + </template> + </div> + <paper-button class="button" on-tap="onContinue"> + $i18n{continueText} + </paper-button> + </div> + </div> + <div class="bg"> + <div class="screenshots"> + <div class="screenshot-image" id="screenshot-image--default"> + <div class="screenshot-html-overlay" + id="screenshot-html-overlay--browser"> + <div>$i18n{webBrowserLabel}</div> + </div> + <div class="screenshot-html-overlay" + id="screenshot-html-overlay--edge"> + <div>$i18n{microsoftEdgeLabel}</div> + </div> + </div> + <div class="screenshot-image hidden" id="screenshot-image--taskbar"> + <div class="screenshot-html-overlay" + id="screenshot-html-overlay--taskbar"> + <div>$i18n{pinToTaskbarLabel}</div> + </div> + <div class="screenshot-html-overlay" + id="screenshot-html-overlay--icon"> + </div> + </div> + </div> + </div> + </template> +</body> +</html> diff --git a/chromium/chrome/browser/resources/welcome/win10/sectioned.js b/chromium/chrome/browser/resources/welcome/win10/sectioned.js new file mode 100644 index 00000000000..9d5e07f71a8 --- /dev/null +++ b/chromium/chrome/browser/resources/welcome/win10/sectioned.js @@ -0,0 +1,79 @@ +// Copyright 2016 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('sectioned', function() { + 'use strict'; + + function computeClasses(isCombined) { + if (isCombined) + return 'section expandable expanded'; + return 'section'; + } + + function onContinue() { + chrome.send('handleContinue'); + } + + function onOpenSettings() { + chrome.send('handleSetDefaultBrowser'); + } + + function onToggle(app) { + if (app.isCombined) { + // Toggle sections. + var sections = document.querySelectorAll('.section.expandable'); + sections.forEach(function(section) { + section.classList.toggle('expanded'); + }); + // Toggle screenshots. + var screenshots = document.querySelectorAll('.screenshot-image'); + screenshots.forEach(function(screenshot) { + screenshot.classList.toggle('hidden'); + }); + } + } + + function initialize() { + var app = $('sectioned-app'); + + // Set variables. + // Determines if the combined variant should be displayed. The combined + // variant includes instructions on how to pin Chrome to the taskbar. + app.isCombined = false; + + // Set handlers. + app.computeClasses = computeClasses; + app.onContinue = onContinue; + app.onOpenSettings = onOpenSettings; + app.onToggle = onToggle.bind(this, app); + + + // Asynchronously check if Chrome is pinned to the taskbar. + cr.sendWithPromise('getPinnedToTaskbarState').then( + function(isPinnedToTaskbar) { + // Allow overriding of the result via a query parameter. + // TODO(pmonette): Remove these checks when they are no longer needed. + /** @const */ var VARIANT_KEY = 'variant'; + var VariantType = { + DEFAULT_ONLY: 'defaultonly', + COMBINED: 'combined' + }; + var params = new URLSearchParams(location.search.slice(1)); + if (params.has(VARIANT_KEY)) { + if (params.get(VARIANT_KEY) === VariantType.DEFAULT_ONLY) + app.isCombined = false; + else if (params.get(VARIANT_KEY) === VariantType.COMBINED) + app.isCombined = true; + } else { + app.isCombined = !isPinnedToTaskbar; + } + }); + } + + return { + initialize: initialize + }; +}); + +document.addEventListener('DOMContentLoaded', sectioned.initialize); diff --git a/chromium/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc b/chromium/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc index cbc29eb08e6..ed77bc7619b 100644 --- a/chromium/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc +++ b/chromium/chrome/browser/spellchecker/spellcheck_custom_dictionary.cc @@ -18,8 +18,8 @@ #include "chrome/common/chrome_constants.h" #include "components/spellcheck/browser/spellcheck_host_metrics.h" #include "components/spellcheck/common/spellcheck_common.h" -#include "components/sync/api/sync_change.h" -#include "components/sync/api/sync_error_factory.h" +#include "components/sync/model/sync_change.h" +#include "components/sync/model/sync_error_factory.h" #include "components/sync/protocol/sync.pb.h" #include "content/public/browser/browser_thread.h" @@ -425,7 +425,8 @@ void SpellcheckCustomDictionary::OnLoaded( Apply(dictionary_change); Sync(dictionary_change); is_loaded_ = true; - FOR_EACH_OBSERVER(Observer, observers_, OnCustomDictionaryLoaded()); + for (Observer& observer : observers_) + observer.OnCustomDictionaryLoaded(); if (!result->is_valid_file) { // Save cleaned up data only after startup. fix_invalid_file_.Reset( @@ -522,7 +523,6 @@ void SpellcheckCustomDictionary::Notify(const Change& dictionary_change) { DCHECK_CURRENTLY_ON(BrowserThread::UI); if (!IsLoaded() || dictionary_change.empty()) return; - FOR_EACH_OBSERVER(Observer, - observers_, - OnCustomDictionaryChanged(dictionary_change)); + for (Observer& observer : observers_) + observer.OnCustomDictionaryChanged(dictionary_change); } diff --git a/chromium/chrome/browser/spellchecker/spellcheck_custom_dictionary.h b/chromium/chrome/browser/spellchecker/spellcheck_custom_dictionary.h index 0bc158f5154..d1da70ae676 100644 --- a/chromium/chrome/browser/spellchecker/spellcheck_custom_dictionary.h +++ b/chromium/chrome/browser/spellchecker/spellcheck_custom_dictionary.h @@ -15,10 +15,10 @@ #include "base/memory/weak_ptr.h" #include "base/observer_list.h" #include "components/spellcheck/browser/spellcheck_dictionary.h" -#include "components/sync/api/sync_data.h" -#include "components/sync/api/sync_error.h" -#include "components/sync/api/sync_merge_result.h" -#include "components/sync/api/syncable_service.h" +#include "components/sync/model/sync_data.h" +#include "components/sync/model/sync_error.h" +#include "components/sync/model/sync_merge_result.h" +#include "components/sync/model/syncable_service.h" namespace syncer { class SyncErrorFactory; diff --git a/chromium/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc b/chromium/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc index f53f63c8f27..14e9cf3a5e7 100644 --- a/chromium/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc +++ b/chromium/chrome/browser/spellchecker/spellcheck_custom_dictionary_unittest.cc @@ -24,11 +24,11 @@ #include "chrome/test/base/testing_profile.h" #include "components/spellcheck/browser/spellcheck_host_metrics.h" #include "components/spellcheck/common/spellcheck_common.h" -#include "components/sync/api/sync_change.h" -#include "components/sync/api/sync_change_processor_wrapper_for_test.h" -#include "components/sync/api/sync_data.h" -#include "components/sync/api/sync_error_factory.h" -#include "components/sync/api/sync_error_factory_mock.h" +#include "components/sync/model/sync_change.h" +#include "components/sync/model/sync_change_processor_wrapper_for_test.h" +#include "components/sync/model/sync_data.h" +#include "components/sync/model/sync_error_factory.h" +#include "components/sync/model/sync_error_factory_mock.h" #include "components/sync/protocol/sync.pb.h" #include "content/public/test/test_browser_thread_bundle.h" #include "net/url_request/test_url_fetcher_factory.h" diff --git a/chromium/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc b/chromium/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc index bd49e1fab7a..04f44b5bc3e 100644 --- a/chromium/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc +++ b/chromium/chrome/browser/spellchecker/spellcheck_hunspell_dictionary.cc @@ -20,6 +20,7 @@ #include "components/data_use_measurement/core/data_use_user_data.h" #include "components/spellcheck/browser/spellcheck_platform.h" #include "components/spellcheck/common/spellcheck_common.h" +#include "components/spellcheck/spellcheck_build_features.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_process_host.h" #include "net/base/load_flags.h" @@ -116,7 +117,7 @@ SpellcheckHunspellDictionary::~SpellcheckHunspellDictionary() { void SpellcheckHunspellDictionary::Load() { DCHECK_CURRENTLY_ON(BrowserThread::UI); -#if defined(USE_BROWSER_SPELLCHECKER) +#if BUILDFLAG(USE_BROWSER_SPELLCHECKER) if (spellcheck_platform::SpellCheckerAvailable() && spellcheck_platform::PlatformSupportsLanguage(language_)) { use_browser_spellchecker_ = true; @@ -247,8 +248,8 @@ void SpellcheckHunspellDictionary::DownloadDictionary(GURL url) { DCHECK(request_context_getter_); download_status_ = DOWNLOAD_IN_PROGRESS; - FOR_EACH_OBSERVER(Observer, observers_, - OnHunspellDictionaryDownloadBegin(language_)); + for (Observer& observer : observers_) + observer.OnHunspellDictionaryDownloadBegin(language_); fetcher_ = net::URLFetcher::Create(url, net::URLFetcher::GET, this); data_use_measurement::DataUseUserData::AttachToFetcher( @@ -360,9 +361,8 @@ void SpellcheckHunspellDictionary::SaveDictionaryDataComplete( if (dictionary_saved) { download_status_ = DOWNLOAD_NONE; - FOR_EACH_OBSERVER(Observer, - observers_, - OnHunspellDictionaryDownloadSuccess(language_)); + for (Observer& observer : observers_) + observer.OnHunspellDictionaryDownloadSuccess(language_); Load(); } else { InformListenersOfDownloadFailure(); @@ -371,13 +371,12 @@ void SpellcheckHunspellDictionary::SaveDictionaryDataComplete( } void SpellcheckHunspellDictionary::InformListenersOfInitialization() { - FOR_EACH_OBSERVER(Observer, observers_, - OnHunspellDictionaryInitialized(language_)); + for (Observer& observer : observers_) + observer.OnHunspellDictionaryInitialized(language_); } void SpellcheckHunspellDictionary::InformListenersOfDownloadFailure() { download_status_ = DOWNLOAD_FAILED; - FOR_EACH_OBSERVER(Observer, - observers_, - OnHunspellDictionaryDownloadFailure(language_)); + for (Observer& observer : observers_) + observer.OnHunspellDictionaryDownloadFailure(language_); } diff --git a/chromium/chrome/browser/spellchecker/spellcheck_message_filter.cc b/chromium/chrome/browser/spellchecker/spellcheck_message_filter.cc index 3a51d9d239f..43c9a36f94e 100644 --- a/chromium/chrome/browser/spellchecker/spellcheck_message_filter.cc +++ b/chromium/chrome/browser/spellchecker/spellcheck_message_filter.cc @@ -17,6 +17,7 @@ #include "components/spellcheck/browser/spelling_service_client.h" #include "components/spellcheck/common/spellcheck_marker.h" #include "components/spellcheck/common/spellcheck_messages.h" +#include "components/spellcheck/spellcheck_build_features.h" #include "content/public/browser/render_process_host.h" #include "net/url_request/url_fetcher.h" @@ -37,7 +38,7 @@ void SpellCheckMessageFilter::OverrideThreadForMessage( message.type() == SpellCheckHostMsg_NotifyChecked::ID || message.type() == SpellCheckHostMsg_RespondDocumentMarkers::ID) *thread = BrowserThread::UI; -#if !defined(USE_BROWSER_SPELLCHECKER) +#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER) if (message.type() == SpellCheckHostMsg_CallSpellingService::ID) *thread = BrowserThread::UI; #endif @@ -52,7 +53,7 @@ bool SpellCheckMessageFilter::OnMessageReceived(const IPC::Message& message) { OnNotifyChecked) IPC_MESSAGE_HANDLER(SpellCheckHostMsg_RespondDocumentMarkers, OnRespondDocumentMarkers) -#if !defined(USE_BROWSER_SPELLCHECKER) +#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER) IPC_MESSAGE_HANDLER(SpellCheckHostMsg_CallSpellingService, OnCallSpellingService) #endif @@ -106,7 +107,7 @@ void SpellCheckMessageFilter::OnRespondDocumentMarkers( render_process_id_, markers); } -#if !defined(USE_BROWSER_SPELLCHECKER) +#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER) void SpellCheckMessageFilter::OnCallSpellingService( int route_id, int identifier, diff --git a/chromium/chrome/browser/spellchecker/spellcheck_message_filter.h b/chromium/chrome/browser/spellchecker/spellcheck_message_filter.h index 6e02fdcd60e..84347affd46 100644 --- a/chromium/chrome/browser/spellchecker/spellcheck_message_filter.h +++ b/chromium/chrome/browser/spellchecker/spellcheck_message_filter.h @@ -11,6 +11,7 @@ #include "base/compiler_specific.h" #include "components/spellcheck/browser/spelling_service_client.h" +#include "components/spellcheck/spellcheck_build_features.h" #include "content/public/browser/browser_message_filter.h" class SpellCheckMarker; @@ -36,7 +37,7 @@ class SpellCheckMessageFilter : public content::BrowserMessageFilter { void OnSpellCheckerRequestDictionary(); void OnNotifyChecked(const base::string16& word, bool misspelled); void OnRespondDocumentMarkers(const std::vector<uint32_t>& markers); -#if !defined(USE_BROWSER_SPELLCHECKER) +#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER) void OnCallSpellingService(int route_id, int identifier, const base::string16& text, diff --git a/chromium/chrome/browser/spellchecker/spellcheck_message_filter_unittest.cc b/chromium/chrome/browser/spellchecker/spellcheck_message_filter_unittest.cc index ad933ea2542..7781c26b44c 100644 --- a/chromium/chrome/browser/spellchecker/spellcheck_message_filter_unittest.cc +++ b/chromium/chrome/browser/spellchecker/spellcheck_message_filter_unittest.cc @@ -15,6 +15,7 @@ #include "chrome/test/base/testing_profile.h" #include "components/spellcheck/common/spellcheck_marker.h" #include "components/spellcheck/common/spellcheck_messages.h" +#include "components/spellcheck/spellcheck_build_features.h" #include "content/public/test/test_browser_thread_bundle.h" #include "ipc/ipc_message.h" #include "testing/gtest/include/gtest/gtest.h" @@ -34,7 +35,7 @@ class TestingSpellCheckMessageFilter : public SpellCheckMessageFilter { return spellcheck_.get(); } -#if !defined(USE_BROWSER_SPELLCHECKER) +#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER) void OnTextCheckComplete(int route_id, int identifier, const std::vector<SpellCheckMarker>& markers, @@ -63,7 +64,7 @@ TEST(SpellCheckMessageFilterTest, TestOverrideThread) { SpellCheckHostMsg_RequestDictionary::ID, SpellCheckHostMsg_NotifyChecked::ID, SpellCheckHostMsg_RespondDocumentMarkers::ID, -#if !defined(USE_BROWSER_SPELLCHECKER) +#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER) SpellCheckHostMsg_CallSpellingService::ID, #endif }; @@ -80,7 +81,7 @@ TEST(SpellCheckMessageFilterTest, TestOverrideThread) { } } -#if !defined(USE_BROWSER_SPELLCHECKER) +#if !BUILDFLAG(USE_BROWSER_SPELLCHECKER) TEST(SpellCheckMessageFilterTest, OnTextCheckCompleteTestCustomDictionary) { static const std::string kCustomWord = "Helllo"; static const int kRouteId = 0; diff --git a/chromium/chrome/browser/spellchecker/spellcheck_service.cc b/chromium/chrome/browser/spellchecker/spellcheck_service.cc index 7de1e826422..e60a310ed8d 100644 --- a/chromium/chrome/browser/spellchecker/spellcheck_service.cc +++ b/chromium/chrome/browser/spellchecker/spellcheck_service.cc @@ -24,6 +24,7 @@ #include "components/spellcheck/common/spellcheck_bdict_language.h" #include "components/spellcheck/common/spellcheck_common.h" #include "components/spellcheck/common/spellcheck_messages.h" +#include "components/spellcheck/spellcheck_build_features.h" #include "components/user_prefs/user_prefs.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" @@ -53,7 +54,7 @@ SpellcheckService::SpellcheckService(content::BrowserContext* context) dictionaries_pref.Init(spellcheck::prefs::kSpellCheckDictionaries, prefs); std::string first_of_dictionaries; -#if defined(USE_BROWSER_SPELLCHECKER) +#if BUILDFLAG(USE_BROWSER_SPELLCHECKER) // Ensure that the renderer always knows the platform spellchecking language. // This language is used for initialization of the text iterator. If the // iterator is not initialized, then the context menu does not show spellcheck @@ -80,7 +81,7 @@ SpellcheckService::SpellcheckService(content::BrowserContext* context) } single_dictionary_pref.SetValue(""); -#endif // defined(USE_BROWSER_SPELLCHECKER) +#endif // BUILDFLAG(USE_BROWSER_SPELLCHECKER) std::string language_code; std::string country_code; diff --git a/chromium/chrome/browser/ui/BUILD.gn b/chromium/chrome/browser/ui/BUILD.gn index 7bd09571b9d..d3982542152 100644 --- a/chromium/chrome/browser/ui/BUILD.gn +++ b/chromium/chrome/browser/ui/BUILD.gn @@ -8,7 +8,9 @@ import("//build/config/features.gni") import("//build/config/ui.gni") import("//build/split_static_library.gni") import("//chrome/common/features.gni") +import("//extensions/features/features.gni") import("//media/media_options.gni") +import("//printing/features/features.gni") config("ui_warnings") { if (is_clang) { @@ -104,8 +106,6 @@ split_static_library("ui") { "find_bar/find_tab_helper.cc", "find_bar/find_tab_helper.h", "javascript_dialogs/chrome_javascript_native_dialog_factory.h", - "javascript_dialogs/javascript_dialog_tab_helper.cc", - "javascript_dialogs/javascript_dialog_tab_helper.h", "login/login_handler.cc", "login/login_handler.h", "login/login_interstitial_delegate.cc", @@ -195,6 +195,7 @@ split_static_library("ui") { "views/platform_keys_certificate_selector_chromeos.cc", "views/platform_keys_certificate_selector_chromeos.h", "web_contents_sizer.h", + "website_settings/permission_prompt.h", "website_settings/website_settings.cc", "website_settings/website_settings.h", "website_settings/website_settings_ui.cc", @@ -231,6 +232,8 @@ split_static_library("ui") { "webui/chromeos/keyboard_overlay_ui.h", "webui/chromeos/login/app_launch_splash_screen_handler.cc", "webui/chromeos/login/app_launch_splash_screen_handler.h", + "webui/chromeos/login/arc_terms_of_service_screen_handler.cc", + "webui/chromeos/login/arc_terms_of_service_screen_handler.h", "webui/chromeos/login/authenticated_user_email_retriever.cc", "webui/chromeos/login/authenticated_user_email_retriever.h", "webui/chromeos/login/auto_enrollment_check_screen_handler.cc", @@ -436,7 +439,6 @@ split_static_library("ui") { ":ui_warnings", "//build/config:precompiled_headers", "//build/config/compiler:wexit_time_destructors", - "//third_party/WebKit/public:debug_devtools", ] # Since browser and browser_ui actually depend on each other, @@ -462,6 +464,7 @@ split_static_library("ui") { "//chrome/app/resources:platform_locale_settings", "//chrome/app/theme:chrome_unscaled_resources", "//chrome/app/theme:theme_resources", + "//chrome/browser:resource_prefetch_predictor_proto", "//chrome/browser/devtools", "//chrome/browser/ui/webui/engagement:mojo_bindings", "//chrome/browser/ui/webui/omnibox:mojo_bindings", @@ -524,11 +527,13 @@ split_static_library("ui") { "//components/rappor", "//components/renderer_context_menu", "//components/resources", + "//components/safe_browsing_db:safe_browsing_prefs", "//components/safe_json", "//components/search", "//components/search_engines", "//components/security_interstitials/core", - "//components/security_state", + "//components/security_state/content", + "//components/security_state/core", "//components/sessions", "//components/signin/core/account_id", "//components/signin/core/browser", @@ -540,8 +545,8 @@ split_static_library("ui") { "//components/suggestions/proto", "//components/supervised_user_error_page", "//components/sync", + "//components/sync_preferences", "//components/sync_sessions", - "//components/syncable_prefs", "//components/toolbar", "//components/tracing:startup_tracing", "//components/undo", @@ -559,18 +564,21 @@ split_static_library("ui") { "//content/app/resources", "//content/public/common", "//crypto", + "//device/base", "//device/bluetooth/public/interfaces:experimental_interfaces", - "//device/core", "//device/usb", + "//extensions/features", "//media", "//net:net_with_v8", - "//services/shell/runner/common", + "//printing/features", + "//services/service_manager/runner/common", "//skia", "//storage/browser", "//storage/common", + "//third_party/WebKit/public:features", "//third_party/WebKit/public:resources", "//third_party/adobe/flash:flapper_version_h", - "//third_party/brotli", + "//third_party/brotli:dec", "//third_party/cacheinvalidation", "//third_party/cld:cld_version", "//third_party/icu", @@ -580,7 +588,6 @@ split_static_library("ui") { "//third_party/zlib", "//ui/accessibility", "//ui/base", - "//ui/base", "//ui/base/ime", "//ui/compositor", "//ui/content_accelerators", @@ -726,6 +733,11 @@ split_static_library("ui") { "global_error/global_error_service_factory.h", "infobar_container_delegate.cc", "infobar_container_delegate.h", + "javascript_dialogs/javascript_dialog.h", + "javascript_dialogs/javascript_dialog_tab_helper.cc", + "javascript_dialogs/javascript_dialog_tab_helper.h", + "javascript_dialogs/javascript_dialog_views.cc", + "javascript_dialogs/javascript_dialog_views.h", "layout_constants.cc", "layout_constants.h", "location_bar/location_bar.cc", @@ -871,7 +883,6 @@ split_static_library("ui") { "website_settings/chooser_bubble_delegate.h", "website_settings/permission_menu_model.cc", "website_settings/permission_menu_model.h", - "website_settings/permission_prompt.h", "website_settings/website_settings_infobar_delegate.cc", "website_settings/website_settings_infobar_delegate.h", "webui/app_launcher_login_handler.cc", @@ -912,6 +923,8 @@ split_static_library("ui") { "webui/identity_internals_ui.h", "webui/inspect_ui.cc", "webui/inspect_ui.h", + "webui/md_bookmarks/md_bookmarks_ui.cc", + "webui/md_bookmarks/md_bookmarks_ui.h", "webui/md_downloads/downloads_list_tracker.cc", "webui/md_downloads/downloads_list_tracker.h", "webui/md_downloads/md_downloads_dom_handler.cc", @@ -996,6 +1009,7 @@ split_static_library("ui") { "webui/options/easy_unlock_handler.h", "webui/options/font_settings_handler.cc", "webui/options/font_settings_handler.h", + "webui/options/font_settings_utils.cc", "webui/options/font_settings_utils.h", "webui/options/font_settings_utils_linux.cc", "webui/options/font_settings_utils_mac.mm", @@ -1080,6 +1094,8 @@ split_static_library("ui") { "webui/settings/chromeos/internet_handler.h", "webui/settings/downloads_handler.cc", "webui/settings/downloads_handler.h", + "webui/settings/extension_control_handler.cc", + "webui/settings/extension_control_handler.h", "webui/settings/font_handler.cc", "webui/settings/font_handler.h", "webui/settings/languages_handler.cc", @@ -1090,6 +1106,8 @@ split_static_library("ui") { "webui/settings/md_settings_ui.h", "webui/settings/metrics_reporting_handler.cc", "webui/settings/metrics_reporting_handler.h", + "webui/settings/on_startup_handler.cc", + "webui/settings/on_startup_handler.h", "webui/settings/people_handler.cc", "webui/settings/people_handler.h", "webui/settings/profile_info_handler.cc", @@ -1098,12 +1116,16 @@ split_static_library("ui") { "webui/settings/protocol_handlers_handler.h", "webui/settings/reset_settings_handler.cc", "webui/settings/reset_settings_handler.h", + "webui/settings/safe_browsing_handler.cc", + "webui/settings/safe_browsing_handler.h", "webui/settings/search_engines_handler.cc", "webui/settings/search_engines_handler.h", "webui/settings/settings_clear_browsing_data_handler.cc", "webui/settings/settings_clear_browsing_data_handler.h", "webui/settings/settings_cookies_view_handler.cc", "webui/settings/settings_cookies_view_handler.h", + "webui/settings/settings_import_data_handler.cc", + "webui/settings/settings_import_data_handler.h", "webui/settings/settings_manage_profile_handler.cc", "webui/settings/settings_manage_profile_handler.h", "webui/settings/settings_media_devices_selection_handler.cc", @@ -1265,16 +1287,14 @@ split_static_library("ui") { "ash/ash_init.h", "ash/ash_util.cc", "ash/ash_util.h", - "ash/cast_config_delegate_chromeos.cc", - "ash/cast_config_delegate_chromeos.h", "ash/cast_config_delegate_media_router.cc", "ash/cast_config_delegate_media_router.h", "ash/chrome_keyboard_ui.cc", "ash/chrome_keyboard_ui.h", "ash/chrome_launcher_prefs.cc", "ash/chrome_launcher_prefs.h", - "ash/chrome_new_window_delegate.cc", - "ash/chrome_new_window_delegate.h", + "ash/chrome_new_window_client.cc", + "ash/chrome_new_window_client.h", "ash/chrome_screenshot_grabber.cc", "ash/chrome_screenshot_grabber.h", "ash/chrome_shell_content_state.cc", @@ -1282,10 +1302,10 @@ split_static_library("ui") { "ash/chrome_shell_content_state_chromeos.cc", "ash/chrome_shell_delegate.cc", "ash/chrome_shell_delegate.h", - "ash/chrome_wallpaper_manager.cc", - "ash/chrome_wallpaper_manager.h", "ash/ime_controller_chromeos.cc", "ash/ime_controller_chromeos.h", + "ash/ime_driver_ash.cc", + "ash/ime_driver_ash.h", "ash/keyboard_ui_service.cc", "ash/keyboard_ui_service.h", "ash/launcher/app_shortcut_launcher_item_controller.cc", @@ -1316,8 +1336,6 @@ split_static_library("ui") { "ash/launcher/chrome_launcher_controller_mus.h", "ash/launcher/chrome_launcher_controller_util.cc", "ash/launcher/chrome_launcher_controller_util.h", - "ash/launcher/chrome_mash_shelf_controller.cc", - "ash/launcher/chrome_mash_shelf_controller.h", "ash/launcher/desktop_shell_launcher_context_menu.cc", "ash/launcher/desktop_shell_launcher_context_menu.h", "ash/launcher/extension_app_window_launcher_controller.cc", @@ -1366,8 +1384,6 @@ split_static_library("ui") { "ash/multi_user/user_switch_animator_chromeos.h", "ash/multi_user/user_switch_util.cc", "ash/multi_user/user_switch_util.h", - "ash/network_connect_delegate_chromeos.cc", - "ash/network_connect_delegate_chromeos.h", "ash/networking_config_delegate_chromeos.cc", "ash/networking_config_delegate_chromeos.h", "ash/palette_delegate_chromeos.cc", @@ -1399,8 +1415,10 @@ split_static_library("ui") { "//ash/common/strings", "//ash/public/cpp", "//ash/public/interfaces", + "//components/session_manager/core", "//components/user_manager", "//services/ui/public/cpp", + "//services/ui/public/interfaces", "//ui/app_list/presenter", "//ui/app_list/presenter:mojom", "//ui/keyboard:mojom", @@ -1439,8 +1457,6 @@ split_static_library("ui") { "views/apps/native_app_window_frame_view_mac.mm", "views/autofill/card_unmask_prompt_views.cc", "views/autofill/card_unmask_prompt_views.h", - "views/autofill/decorated_textfield.cc", - "views/autofill/decorated_textfield.h", "views/autofill/info_bubble.cc", "views/autofill/info_bubble.h", "views/autofill/tooltip_icon.cc", @@ -1476,6 +1492,12 @@ split_static_library("ui") { "views/extensions/extension_keybinding_registry_views.h", "views/frame/native_widget_mac_frameless_nswindow.h", "views/frame/native_widget_mac_frameless_nswindow.mm", + "views/harmony/harmony_layout_delegate.cc", + "views/harmony/harmony_layout_delegate.h", + "views/harmony/layout_delegate.cc", + "views/harmony/layout_delegate.h", + "views/layout_utils.cc", + "views/layout_utils.h", "views/location_bar/location_bar_bubble_delegate_view.cc", "views/location_bar/location_bar_bubble_delegate_view.h", "views/login_handler_views.cc", @@ -1492,6 +1514,8 @@ split_static_library("ui") { "views/website_settings/chosen_object_row.cc", "views/website_settings/chosen_object_row.h", "views/website_settings/chosen_object_row_observer.h", + "views/website_settings/non_accessible_image_view.cc", + "views/website_settings/non_accessible_image_view.h", "views/website_settings/permission_prompt_impl.cc", "views/website_settings/permission_prompt_impl.h", "views/website_settings/permission_selector_row.cc", @@ -1520,8 +1544,6 @@ split_static_library("ui") { sources += [ "external_protocol_dialog_delegate.cc", "external_protocol_dialog_delegate.h", - "views/chrome_browser_main_extra_parts_views_linux.cc", - "views/chrome_browser_main_extra_parts_views_linux.h", "views/external_protocol_dialog.cc", "views/external_protocol_dialog.h", "views/frame/opaque_browser_frame_view.cc", @@ -1542,6 +1564,18 @@ split_static_library("ui") { "views/sync/profile_signin_confirmation_dialog_views.h", ] } + + # These files do Gtk+-based theming, but Gtk+ is not available on + # Ozone builds, or on common environments where Ozone will be used. + # + # TODO(tonikitoo): It seems sensible to make it possible to opt-in + # the use of these files in case Gtk is available with its Wayland. + if (use_aura && !use_ozone && is_desktop_linux) { + sources += [ + "views/chrome_browser_main_extra_parts_views_linux.cc", + "views/chrome_browser_main_extra_parts_views_linux.h", + ] + } if (enable_extensions && (!is_mac || mac_views_browser)) { sources += [ "views/extensions/bookmark_app_confirmation_view.cc", @@ -1574,6 +1608,8 @@ split_static_library("ui") { } if (!is_mac || mac_views_browser) { sources += [ + "javascript_dialogs/javascript_dialog.cc", + # This test header is included because it contains forward declarations # needed for "friend" statements for use in tests. "translate/translate_bubble_test_utils.h", @@ -1633,8 +1669,6 @@ split_static_library("ui") { "views/dropdown_bar_host.cc", "views/dropdown_bar_host.h", "views/dropdown_bar_host_delegate.h", - "views/dropdown_bar_view.cc", - "views/dropdown_bar_view.h", "views/elevation_icon_setter.cc", "views/elevation_icon_setter.h", "views/find_bar_host.cc", @@ -1857,18 +1891,16 @@ split_static_library("ui") { "//services/ui/public/cpp", "//services/ui/public/interfaces", ] + } - # TODO(erg): These files hard depend on mus, and thus can't be in a gyp - # build. When gyp goes away, merge this back into the sources list. + # TODO(ellyjones): Mus is not supported on Mac (there is no ui::Window + # apart from aura::Window, which is also not supported). + if (!is_mac) { sources += [ "views/tabs/window_finder_mus.cc", "views/tabs/window_finder_mus.h", ] - } - # TODO(ellyjones): This target fails to build on Mac because of - # incompatible uses of gpu::AcceleratedWidget vs gpu::SurfaceHandle. - if (!is_mac) { deps += [ "//ui/views/mus" ] } } @@ -1896,11 +1928,12 @@ split_static_library("ui") { deps += [ "//build/linux/libgio" ] } if (use_aura && !use_ozone && is_desktop_linux) { - deps += [ - # gtk2 is the only component that can interact with gtk2 in our new - # world. - "//chrome/browser/ui/libgtk2ui", - ] + # These are the only components that can interact with gtk. + if (use_gtk3) { + deps += [ "//chrome/browser/ui/libgtkui:libgtk3ui" ] + } else { + deps += [ "//chrome/browser/ui/libgtkui:libgtk2ui" ] + } } if (is_win || is_mac || is_desktop_linux) { sources += [ @@ -1956,8 +1989,6 @@ split_static_library("ui") { "webui/signin/sync_confirmation_ui.h", "webui/signin/user_manager_screen_handler.cc", "webui/signin/user_manager_screen_handler.h", - "webui/signin/user_manager_ui.cc", - "webui/signin/user_manager_ui.h", "webui/welcome_handler.cc", "webui/welcome_handler.h", "webui/welcome_ui.cc", @@ -2078,6 +2109,7 @@ split_static_library("ui") { "webui/theme_source.cc", "webui/theme_source.h", ] + deps += [ "//chrome/browser:theme_properties" ] } if (enable_print_preview) { sources += [ @@ -2087,11 +2119,20 @@ split_static_library("ui") { "webui/print_preview/print_preview_handler.h", "webui/print_preview/print_preview_ui.cc", "webui/print_preview/print_preview_ui.h", + "webui/print_preview/printer_backend_proxy.h", + "webui/print_preview/printer_capabilities.cc", + "webui/print_preview/printer_capabilities.h", "webui/print_preview/printer_handler.cc", "webui/print_preview/printer_handler.h", "webui/print_preview/sticky_settings.cc", "webui/print_preview/sticky_settings.h", ] + + if (is_chromeos) { + sources += [ "webui/print_preview/printer_backend_proxy_chromeos.cc" ] + } else { + sources += [ "webui/print_preview/printer_backend_proxy.cc" ] + } } if (is_android) { @@ -2119,13 +2160,9 @@ split_static_library("ui") { "android/autofill/password_generation_popup_view_android.h", "android/bluetooth_chooser_android.cc", "android/bluetooth_chooser_android.h", - "android/certificate_viewer_android.cc", - "android/certificate_viewer_android.h", "android/chrome_http_auth_handler.cc", "android/chrome_http_auth_handler.h", "android/color_chooser_dialog_android.cc", - "android/connection_info_popup_android.cc", - "android/connection_info_popup_android.h", "android/content_settings/popup_blocked_infobar_delegate.cc", "android/content_settings/popup_blocked_infobar_delegate.h", "android/content_settings/subresource_filter_infobar_delegate.cc", @@ -2142,8 +2179,8 @@ split_static_library("ui") { "android/infobars/confirm_infobar.h", "android/infobars/data_reduction_promo_infobar.cc", "android/infobars/data_reduction_promo_infobar.h", - "android/infobars/download_overwrite_infobar.cc", - "android/infobars/download_overwrite_infobar.h", + "android/infobars/duplicate_download_infobar.cc", + "android/infobars/duplicate_download_infobar.h", "android/infobars/generated_password_saved_infobar.cc", "android/infobars/generated_password_saved_infobar.h", "android/infobars/grouped_permission_infobar.cc", @@ -2156,8 +2193,8 @@ split_static_library("ui") { "android/infobars/instant_apps_infobar.h", "android/infobars/permission_infobar.cc", "android/infobars/permission_infobar.h", - "android/infobars/save_password_infobar.cc", - "android/infobars/save_password_infobar.h", + "android/infobars/search_geolocation_disclosure_infobar.cc", + "android/infobars/search_geolocation_disclosure_infobar.h", "android/infobars/simple_confirm_infobar_builder.cc", "android/infobars/simple_confirm_infobar_builder.h", "android/infobars/subresource_filter_infobar.cc", @@ -2172,6 +2209,12 @@ split_static_library("ui") { "android/omnibox/omnibox_url_emphasizer.h", "android/omnibox/omnibox_view_util.cc", "android/omnibox/omnibox_view_util.h", + "android/page_info/certificate_viewer_android.cc", + "android/page_info/certificate_viewer_android.h", + "android/page_info/connection_info_popup_android.cc", + "android/page_info/connection_info_popup_android.h", + "android/page_info/website_settings_popup_android.cc", + "android/page_info/website_settings_popup_android.h", "android/simple_message_box_android.cc", "android/snackbars/auto_signin_prompt_controller.cc", "android/snackbars/auto_signin_prompt_controller.h", @@ -2195,16 +2238,12 @@ split_static_library("ui") { "android/usb_chooser_dialog_android.h", "android/view_android_helper.cc", "android/view_android_helper.h", - "android/website_settings_popup_android.cc", - "android/website_settings_popup_android.h", "browser_otr_state_android.cc", "screen_capture_notification_ui_stub.cc", "webui/offline/offline_internals_ui.cc", "webui/offline/offline_internals_ui.h", "webui/offline/offline_internals_ui_message_handler.cc", "webui/offline/offline_internals_ui_message_handler.h", - "webui/popular_sites_internals_message_handler.cc", - "webui/popular_sites_internals_message_handler.h", "webui/popular_sites_internals_ui.cc", "webui/popular_sites_internals_ui.h", "webui/snippets_internals_message_handler.cc", @@ -2212,8 +2251,10 @@ split_static_library("ui") { "webui/snippets_internals_ui.cc", "webui/snippets_internals_ui.h", ] - if (enable_vr_shell) { - defines += [ "ENABLE_VR_SHELL" ] + if (enable_vr_shell || enable_webvr) { + if (enable_vr_shell) { + defines += [ "ENABLE_VR_SHELL" ] + } sources += [ "webui/vr_shell/vr_shell_ui_message_handler.cc", "webui/vr_shell/vr_shell_ui_message_handler.h", @@ -2221,7 +2262,7 @@ split_static_library("ui") { "webui/vr_shell/vr_shell_ui_ui.h", ] configs += [ "//third_party/gvr-android-sdk:libgvr_config" ] - deps += [ "//chrome/browser/android/vr_shell:vr_shell" ] + deps += [ "//chrome/browser/android/vr_shell:vr_common" ] } if (enable_vr_shell_ui_dev) { assert(enable_vr_shell) @@ -2241,8 +2282,6 @@ split_static_library("ui") { sources += [ "certificate_viewer_mac.h", "certificate_viewer_mac.mm", - "chrome_style.cc", - "chrome_style.h", "cocoa/accelerator_utils_cocoa.mm", "cocoa/accelerators_cocoa.h", "cocoa/accelerators_cocoa.mm", @@ -2260,6 +2299,8 @@ split_static_library("ui") { "cocoa/browser_window_command_handler.mm", "cocoa/chrome_command_dispatcher_delegate.h", "cocoa/chrome_command_dispatcher_delegate.mm", + "cocoa/chrome_style.cc", + "cocoa/chrome_style.h", "cocoa/color_chooser_mac.mm", "cocoa/confirm_quit.h", "cocoa/confirm_quit_panel_controller.h", @@ -2644,10 +2685,20 @@ split_static_library("ui") { "cocoa/framed_browser_window.mm", "cocoa/full_size_content_window.h", "cocoa/full_size_content_window.mm", + "cocoa/fullscreen/fullscreen_menubar_tracker.h", + "cocoa/fullscreen/fullscreen_menubar_tracker.mm", + "cocoa/fullscreen/fullscreen_toolbar_animation_controller.h", + "cocoa/fullscreen/fullscreen_toolbar_animation_controller.mm", + "cocoa/fullscreen/fullscreen_toolbar_controller.h", + "cocoa/fullscreen/fullscreen_toolbar_controller.mm", + "cocoa/fullscreen/fullscreen_toolbar_mouse_tracker.h", + "cocoa/fullscreen/fullscreen_toolbar_mouse_tracker.mm", + "cocoa/fullscreen/fullscreen_toolbar_visibility_lock_controller.h", + "cocoa/fullscreen/fullscreen_toolbar_visibility_lock_controller.mm", + "cocoa/fullscreen/immersive_fullscreen_controller.h", + "cocoa/fullscreen/immersive_fullscreen_controller.mm", "cocoa/fullscreen_low_power_coordinator.h", "cocoa/fullscreen_low_power_coordinator.mm", - "cocoa/fullscreen_toolbar_controller.h", - "cocoa/fullscreen_toolbar_controller.mm", "cocoa/fullscreen_window.h", "cocoa/fullscreen_window.mm", "cocoa/global_error_bubble_controller.h", @@ -2747,6 +2798,8 @@ split_static_library("ui") { "cocoa/omnibox/omnibox_popup_view_mac.mm", "cocoa/omnibox/omnibox_view_mac.h", "cocoa/omnibox/omnibox_view_mac.mm", + "cocoa/omnibox_decoration_bubble_controller.h", + "cocoa/omnibox_decoration_bubble_controller.mm", "cocoa/one_click_signin_dialog_controller.h", "cocoa/one_click_signin_dialog_controller.mm", "cocoa/one_click_signin_view_controller.h", @@ -2914,6 +2967,9 @@ split_static_library("ui") { # See crbug.com/590850 "content_settings/content_setting_media_menu_model.cc", "content_settings/content_setting_media_menu_model.h", + "javascript_dialogs/javascript_dialog_cocoa.h", + "javascript_dialogs/javascript_dialog_cocoa.mm", + "javascript_dialogs/javascript_dialog_mac.cc", "proximity_auth/proximity_auth_error_bubble_stub.cc", ] } @@ -2953,6 +3009,10 @@ split_static_library("ui") { "webui/cast/cast_ui.h", "webui/conflicts_ui.cc", "webui/conflicts_ui.h", + "webui/welcome_win10_handler.cc", + "webui/welcome_win10_handler.h", + "webui/welcome_win10_ui.cc", + "webui/welcome_win10_ui.h", ] public_deps += [ "//ui/views", @@ -2998,9 +3058,6 @@ split_static_library("ui") { "views/first_run_dialog.cc", "views/first_run_dialog.h", "views/frame/browser_desktop_window_tree_host.h", - "views/frame/desktop_browser_frame_auralinux.cc", - "views/frame/desktop_browser_frame_auralinux.h", - "views/frame/native_browser_frame_factory_auralinux.cc", "views/status_icons/status_icon_linux_wrapper.cc", "views/status_icons/status_icon_linux_wrapper.h", "webui/help/version_updater_basic.cc", @@ -3015,14 +3072,23 @@ split_static_library("ui") { sources += [ "views/frame/browser_desktop_window_tree_host_x11.cc", "views/frame/browser_desktop_window_tree_host_x11.h", + "views/frame/desktop_browser_frame_aurax11.cc", + "views/frame/desktop_browser_frame_aurax11.h", "views/frame/global_menu_bar_registrar_x11.cc", "views/frame/global_menu_bar_registrar_x11.h", "views/frame/global_menu_bar_x11.cc", "views/frame/global_menu_bar_x11.h", + "views/frame/native_browser_frame_factory_aurax11.cc", "views/javascript_app_modal_dialog_views_x11.cc", "views/javascript_app_modal_dialog_views_x11.h", ] } + if (use_ozone) { + sources += [ + "views/frame/browser_desktop_window_tree_host_ozone.cc", + "views/frame/native_browser_frame_factory_ozone.cc", + ] + } } if (is_linux) { # Both desktop Linux and ChromeOS. sources += [ @@ -3043,17 +3109,19 @@ split_static_library("ui") { sources += [ "views/javascript_app_modal_event_blocker_x11.cc", "views/javascript_app_modal_event_blocker_x11.h", - "views/tabs/window_finder_x11.cc", ] configs += [ "//build/config/linux:x11" ] deps += [ "//ui/events/devices", "//ui/events/devices/x11", ] - if (is_chromeos) { - sources -= [ "views/tabs/window_finder_x11.cc" ] + if (is_desktop_linux) { + sources += [ "views/tabs/window_finder_x11.cc" ] } } + if (use_ozone) { + sources += [ "views/tabs/window_finder_ozone.cc" ] + } } if (use_udev) { @@ -3073,10 +3141,6 @@ split_static_library("ui") { "app_list/app_list_model_builder.h", "app_list/app_list_positioner.cc", "app_list/app_list_positioner.h", - "app_list/app_list_prefs.cc", - "app_list/app_list_prefs.h", - "app_list/app_list_prefs_factory.cc", - "app_list/app_list_prefs_factory.h", "app_list/app_list_service.cc", "app_list/app_list_service.h", "app_list/app_list_service_impl.cc", @@ -3103,8 +3167,6 @@ split_static_library("ui") { "app_list/google_now_extension.h", "app_list/launcher_page_event_dispatcher.cc", "app_list/launcher_page_event_dispatcher.h", - "app_list/model_pref_updater.cc", - "app_list/model_pref_updater.h", "app_list/profile_loader.cc", "app_list/profile_loader.h", "app_list/profile_store.h", @@ -3167,6 +3229,7 @@ split_static_library("ui") { sources += [ "app_list/arc/arc_app_context_menu.cc", "app_list/arc/arc_app_context_menu.h", + "app_list/arc/arc_app_dialog.h", "app_list/arc/arc_app_icon.cc", "app_list/arc/arc_app_icon.h", "app_list/arc/arc_app_icon_loader.cc", @@ -3197,6 +3260,8 @@ split_static_library("ui") { "ash/launcher/arc_app_deferred_launcher_controller.h", "ash/launcher/arc_app_deferred_launcher_item_controller.cc", "ash/launcher/arc_app_deferred_launcher_item_controller.h", + "ash/launcher/arc_app_shelf_id.cc", + "ash/launcher/arc_app_shelf_id.h", "ash/launcher/arc_app_window_launcher_controller.cc", "ash/launcher/arc_app_window_launcher_controller.h", "ash/launcher/arc_app_window_launcher_item_controller.cc", @@ -3205,6 +3270,7 @@ split_static_library("ui") { "ash/launcher/arc_launcher_context_menu.h", "ash/launcher/launcher_arc_app_updater.cc", "ash/launcher/launcher_arc_app_updater.h", + "views/arc_app_dialog_view.cc", ] } if (is_desktop_linux) { diff --git a/chromium/chrome/browser/ui/cocoa/notifications/BUILD.gn b/chromium/chrome/browser/ui/cocoa/notifications/BUILD.gn index be1d42dfd36..4fb22a78839 100644 --- a/chromium/chrome/browser/ui/cocoa/notifications/BUILD.gn +++ b/chromium/chrome/browser/ui/cocoa/notifications/BUILD.gn @@ -18,6 +18,8 @@ mac_app_bundle("alert_notification_xpc_service") { "notification_service_delegate.h", "notification_service_delegate.mm", "xpc_service_main.mm", + "xpc_transaction_handler.h", + "xpc_transaction_handler.mm", ] deps = [ diff --git a/chromium/chrome/browser/ui/libgtk2ui/BUILD.gn b/chromium/chrome/browser/ui/libgtk2ui/BUILD.gn deleted file mode 100644 index 8758227c0ac..00000000000 --- a/chromium/chrome/browser/ui/libgtk2ui/BUILD.gn +++ /dev/null @@ -1,134 +0,0 @@ -# Copyright 2014 The Chromium Authors. All rights reserved. -# Use of this source code is governed by a BSD-style license that can be -# found in the LICENSE file. - -assert(is_linux, "This file should only be referenced on Linux") - -import("//build/config/features.gni") -import("//build/config/ui.gni") - -# gn orders flags on a target before flags from configs. The default config -# adds -Wall, and these flags have to be after -Wall -- so they need to come -# from a config and can't be on the target directly. -config("libgtk2ui_warnings") { - if (is_clang) { - cflags = [ - # G_DEFINE_TYPE automatically generates a *get_instance_private inline - # function after glib 2.37. That's unused. Prevent to complain about it. - "-Wno-unused-function", - - # G_STATIC_ASSERT uses a typedef as a static_assert. - "-Wno-unused-local-typedef", - ] - } -} - -component("libgtk2ui") { - sources = [ - "app_indicator_icon.cc", - "app_indicator_icon.h", - "app_indicator_icon_menu.cc", - "app_indicator_icon_menu.h", - "chrome_gtk_frame.cc", - "chrome_gtk_frame.h", - "chrome_gtk_menu_subclasses.cc", - "chrome_gtk_menu_subclasses.h", - "gtk2_event_loop.cc", - "gtk2_event_loop.h", - "gtk2_key_bindings_handler.cc", - "gtk2_key_bindings_handler.h", - "gtk2_status_icon.cc", - "gtk2_status_icon.h", - "gtk2_ui.cc", - "gtk2_ui.h", - "gtk2_util.cc", - "gtk2_util.h", - "libgtk2ui_export.h", - "menu_util.cc", - "menu_util.h", - "native_theme_gtk2.cc", - "native_theme_gtk2.h", - "print_dialog_gtk2.cc", - "print_dialog_gtk2.h", - "printing_gtk2_util.cc", - "printing_gtk2_util.h", - "select_file_dialog_impl.cc", - "select_file_dialog_impl.h", - "select_file_dialog_impl_gtk2.cc", - "select_file_dialog_impl_gtk2.h", - "select_file_dialog_impl_kde.cc", - "skia_utils_gtk2.cc", - "skia_utils_gtk2.h", - "unity_service.cc", - "unity_service.h", - "x11_input_method_context_impl_gtk2.cc", - "x11_input_method_context_impl_gtk2.h", - ] - - if (use_gconf) { - sources += [ - "gconf_listener.cc", - "gconf_listener.h", - ] - configs += [ "//build/config/linux/gconf" ] - } - defines = [ "LIBGTK2UI_IMPLEMENTATION" ] - - if (use_cups) { - configs += [ "//printing:cups" ] - } - - # GTK2 pulls pangoft2 as dependency, and pangoft2 depends on harfbuzz. - # To avoid missing indirectly referenced harfbuzz symbols from pango, - # some hack is required when bundled harfbuzz is used and component build is - # disabled. - # See crbug.com/462689 for details. - all_dependent_configs = [ "//third_party/harfbuzz-ng:pangoft2_link_hack" ] - - configs += [ - ":libgtk2ui_warnings", - "//build/config/linux:x11", - ] - - deps = [ - "//base", - "//base:i18n", - "//base/third_party/dynamic_annotations", - "//chrome:extra_resources", - "//chrome:resources", - "//chrome:strings", - "//chrome/app:command_ids", - "//chrome/app/theme:theme_resources", - "//components/resources", - "//content/public/browser", - "//printing", - "//skia", - "//ui/aura", - "//ui/base", - "//ui/base/ime", - "//ui/display", - "//ui/events", - "//ui/events:events_base", - "//ui/events/platform/x11", - "//ui/gfx", - "//ui/gfx/geometry", - "//ui/gfx/x", - "//ui/native_theme", - "//ui/resources", - "//ui/shell_dialogs", - "//ui/strings", - "//ui/views", - ] - - if (use_gtk3) { - deps += [ - "//build/config/linux/gtk3", - "//build/config/linux/gtk3:gtkprint3", - ] - } else { - deps += [ - "//build/config/linux/gtk2", - "//build/config/linux/gtk2:gtkprint2", - ] - } -} diff --git a/chromium/chrome/browser/ui/libgtkui/BUILD.gn b/chromium/chrome/browser/ui/libgtkui/BUILD.gn new file mode 100644 index 00000000000..41ca1920417 --- /dev/null +++ b/chromium/chrome/browser/ui/libgtkui/BUILD.gn @@ -0,0 +1,150 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +assert(is_linux, "This file should only be referenced on Linux") + +import("//build/config/features.gni") +import("//build/config/ui.gni") +import("//printing/features/features.gni") + +# gn orders flags on a target before flags from configs. The default config +# adds -Wall, and these flags have to be after -Wall -- so they need to come +# from a config and can't be on the target directly. +config("libgtkui_warnings") { + if (is_clang) { + cflags = [ + # G_DEFINE_TYPE automatically generates a *get_instance_private inline + # function after glib 2.37. That's unused. Prevent to complain about it. + "-Wno-unused-function", + + # G_STATIC_ASSERT uses a typedef as a static_assert. + "-Wno-unused-local-typedef", + ] + } +} + +common_sources = [ + "app_indicator_icon.cc", + "app_indicator_icon.h", + "app_indicator_icon_menu.cc", + "app_indicator_icon_menu.h", + "chrome_gtk_frame.cc", + "chrome_gtk_frame.h", + "chrome_gtk_menu_subclasses.cc", + "chrome_gtk_menu_subclasses.h", + "gtk_event_loop.cc", + "gtk_event_loop.h", + "gtk_key_bindings_handler.cc", + "gtk_key_bindings_handler.h", + "gtk_status_icon.cc", + "gtk_status_icon.h", + "gtk_ui.cc", + "gtk_ui.h", + "gtk_util.cc", + "gtk_util.h", + "libgtkui_export.h", + "menu_util.cc", + "menu_util.h", + "native_theme_gtk.cc", + "native_theme_gtk.h", + "print_dialog_gtk.cc", + "print_dialog_gtk.h", + "printing_gtk_util.cc", + "printing_gtk_util.h", + "select_file_dialog_impl.cc", + "select_file_dialog_impl.h", + "select_file_dialog_impl_gtk.cc", + "select_file_dialog_impl_gtk.h", + "select_file_dialog_impl_kde.cc", + "skia_utils_gtk.cc", + "skia_utils_gtk.h", + "unity_service.cc", + "unity_service.h", + "x11_input_method_context_impl_gtk.cc", + "x11_input_method_context_impl_gtk.h", +] + +common_configs = [] + +if (use_gconf) { + common_sources += [ + "gconf_listener.cc", + "gconf_listener.h", + ] + common_configs += [ "//build/config/linux/gconf" ] +} + +if (use_cups) { + common_configs += [ "//printing:cups" ] +} + +common_configs += [ + ":libgtkui_warnings", + "//build/config/linux:x11", +] + +common_deps = [ + "//base", + "//base:i18n", + "//base/third_party/dynamic_annotations", + "//chrome:extra_resources", + "//chrome:resources", + "//chrome:strings", + "//chrome/app:command_ids", + "//chrome/app/theme:theme_resources", + "//components/resources", + "//content/public/browser", + "//printing", + "//skia", + "//ui/aura", + "//ui/base", + "//ui/base/ime", + "//ui/display", + "//ui/events", + "//ui/events:events_base", + "//ui/events/platform/x11", + "//ui/gfx", + "//ui/gfx/geometry", + "//ui/gfx/x", + "//ui/native_theme", + "//ui/resources", + "//ui/shell_dialogs", + "//ui/strings", + "//ui/views", +] + +component("libgtk2ui") { + sources = common_sources + configs += common_configs + defines = [ "LIBGTKUI_IMPLEMENTATION" ] + + # GTK2 pulls pangoft2 as dependency, and pangoft2 depends on harfbuzz. + # To avoid missing indirectly referenced harfbuzz symbols from pango, + # some hack is required when bundled harfbuzz is used and component build is + # disabled. + # See crbug.com/462689 for details. + all_dependent_configs = [ "//third_party/harfbuzz-ng:pangoft2_link_hack" ] + + deps = common_deps + [ + "//build/config/linux/gtk2", + "//build/config/linux/gtk2:gtkprint2", + ] + public_deps = [ + "//chrome/browser:theme_properties", + ] +} + +component("libgtk3ui") { + sources = common_sources + configs += common_configs + defines = [ "LIBGTKUI_IMPLEMENTATION" ] + + deps = common_deps + [ + "//build/config/linux/gtk3", + "//build/config/linux/gtk3:gtkprint3", + ] + public_deps = [ + "//chrome/browser:theme_properties", + ] +} diff --git a/chromium/chrome/browser/ui/views/BUILD.gn b/chromium/chrome/browser/ui/views/BUILD.gn index 3cea4308c28..47aa8b5bdbc 100644 --- a/chromium/chrome/browser/ui/views/BUILD.gn +++ b/chromium/chrome/browser/ui/views/BUILD.gn @@ -27,6 +27,7 @@ component("views") { deps = [ "//base", "//chrome/app:command_ids", + "//printing/features", "//skia", "//ui/base", "//ui/events", diff --git a/chromium/chrome/browser/ui/webui/engagement/BUILD.gn b/chromium/chrome/browser/ui/webui/engagement/BUILD.gn index 3c3971b57e5..d0da3192949 100644 --- a/chromium/chrome/browser/ui/webui/engagement/BUILD.gn +++ b/chromium/chrome/browser/ui/webui/engagement/BUILD.gn @@ -12,6 +12,4 @@ mojom("mojo_bindings") { public_deps = [ "//url/mojo:url_mojom_gurl", ] - - use_new_wrapper_types = false } diff --git a/chromium/chrome/browser/ui/webui/omnibox/BUILD.gn b/chromium/chrome/browser/ui/webui/omnibox/BUILD.gn index 33a8500aaba..bf547a06b42 100644 --- a/chromium/chrome/browser/ui/webui/omnibox/BUILD.gn +++ b/chromium/chrome/browser/ui/webui/omnibox/BUILD.gn @@ -8,6 +8,4 @@ mojom("mojo_bindings") { sources = [ "omnibox.mojom", ] - - use_new_wrapper_types = false } diff --git a/chromium/chrome/browser/ui/webui/plugins/BUILD.gn b/chromium/chrome/browser/ui/webui/plugins/BUILD.gn index 1ca674ed984..6d35c06b4c4 100644 --- a/chromium/chrome/browser/ui/webui/plugins/BUILD.gn +++ b/chromium/chrome/browser/ui/webui/plugins/BUILD.gn @@ -7,6 +7,4 @@ mojom("mojo_bindings") { sources = [ "plugins.mojom", ] - - use_new_wrapper_types = false } |